Saturday, May 30, 2026

Java: enumerate com serial using fazecast jSerialComm

Simple code to enumerate serial com port


/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 */

package com.dedetok.enumcomport;

import com.fazecast.jSerialComm.SerialPort;

/**
 *
 * @author dedetok
 */
public class EnumComPort {

    public static void main(String[] args) {
        System.out.println("Hello World!");

        SerialPort[] ports = SerialPort.getCommPorts();

        if (ports.length == 0) {
            System.out.println("No serial ports detected.");
            return;
        }

        System.out.println("Available Serial Ports:");
        System.out.println("------------------------");

        for (SerialPort port : ports) {

            System.out.println("System Port Name : " + port.getSystemPortName());
            System.out.println("Descriptive Name: " + port.getDescriptivePortName());
            System.out.println("Port Description: " + port.getPortDescription());
            System.out.println("System Location : " + port.getSystemPortPath());
            System.out.println("------------------------");
        }
        
    }
}

Note: lpx device (e.g /dev/usb/lp1) does not use serial com, you need to send hex code direct via OutputStream.

Java: Hook shutdown to run java application as systemd

This is minimum java code to hook shutdown


/*
 * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
 */

package com.dedetok.javaservicetest;

/**
 *
 * @author dedetok
 */
public class JavaServiceTest {

    private static volatile boolean running = true;
        
    public static void main(String[] args) {
        System.out.println("Hello World!");
        
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("Shutdown hook triggered");

            running = false;

            // Cleanup resources here
            // Close database connections
            // Flush logs
            // Stop worker threads
            // Main shutdown path
            //cleanupResources();

            System.out.println("Cleanup complete");
        }));

        System.out.println("Daemon started");

        while (running) {
            System.out.println("Working...");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ex) {
                System.getLogger(JavaServiceTest.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex);
            }
        }

    }
}

to run/test this application, you can not run it inside netbeans. use terminal to run it, go to your project root and run


$ java -cp target/classes \
     com.dedetok.javaservicetest.JavaServiceTest
Hello World!
Daemon started
Working...
Working...
^CShutdown hook triggered
Cleanup complete

 

 

Java Netbeans: upgrade binary Netbeans 29 to Netbeans 30

 This step is straight forward:

  1. go to your root directory (e.g your home dir ~/), and rename old folder e.g ~/netbeans29.
  2. extract netbeans 30 binary and put it in root directory to replace old folder (e.g your home dir ~/).
  3. Run your netbeans 30, import previous configuration
  4. if no error found you safe to remove
    1. old netbeans 29 (e.g ~/netbeans29) 
    2. ~/.netbeans/29
    3. ~/.cache/netbeans/29

 

Monday, May 25, 2026

Java: maven escpos-coffee library, output to binary file

This is working demo how to create print preview and generate output.bin which is valid byte format to send to thermal printer.

Edit pom.xml and add escpos-coffee

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.dedetok</groupId>
    <artifactId>myapp</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.6.3</version>
                <configuration>
                    <mainClass>com.dedetok.myapp.App</mainClass>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.4.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.dedetok.myapp.App</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

        </plugins>
    </build>

	<dependencies>

		<dependency>
			<groupId>com.github.anastaciocintra</groupId>
			<artifactId>escpos-coffee</artifactId>
			<version>4.1.0</version>
		</dependency>

	</dependencies>
</project>

run package or compile to download library

$ mvn compile

Edit App.java


package com.dedetok.myapp;

import com.github.anastaciocintra.escpos.EscPos;
import com.github.anastaciocintra.escpos.EscPosConst;
import com.github.anastaciocintra.escpos.Style;
import com.github.anastaciocintra.output.PrinterOutputStream;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;

public class App extends JFrame {

    private JTextArea txtPreview;
    private DecimalFormat formatter;

    public App() {

        setTitle("ESC/POS Receipt Preview");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(420, 700);
        setLocationRelativeTo(null);

        JPanel root = new JPanel(new GridBagLayout());
        root.setBackground(new Color(180, 180, 180));

        JPanel paper = new JPanel(new BorderLayout());
        paper.setPreferredSize(new Dimension(300, 600));
        paper.setBackground(Color.WHITE);

        txtPreview = new JTextArea();

        txtPreview.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 15));
        txtPreview.setEditable(false);
        txtPreview.setLineWrap(false);

        txtPreview.setBackground(Color.WHITE);
        txtPreview.setForeground(Color.BLACK);

        txtPreview.setBorder(new EmptyBorder(12, 12, 12, 12));

        JScrollPane scroll = new JScrollPane(txtPreview);
        scroll.setBorder(null);

        paper.add(scroll, BorderLayout.CENTER);

        root.add(paper);

        add(root);

        generatePreview();

        // generate ESC/POS binary file
        try {
            generateEscPosFile();
            System.out.println("ESC/POS output saved to output.bin");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void generatePreview() {

        DecimalFormatSymbols symbols = new DecimalFormatSymbols();
        symbols.setGroupingSeparator('.');

        formatter = new DecimalFormat("#,###", symbols);

        StringBuilder sb = new StringBuilder();

        sb.append(center("MY COFFEE SHOP")).append("\n");
        sb.append(center("Bluetooth ESC/POS")).append("\n");
        sb.append(center("Jl. Ubud Bali")).append("\n");

        sb.append("--------------------------------\n");

        addItem(sb, "Espresso", 2, 18000);
        addItem(sb, "Cappuccino", 1, 25000);
        addItem(sb, "Croissant", 3, 12000);

        sb.append("--------------------------------\n");

        sb.append(String.format("%-20s %10s\n",
                "SUBTOTAL",
                formatter.format(97000)));

        sb.append(String.format("%-20s %10s\n",
                "TAX",
                formatter.format(9700)));

        sb.append("--------------------------------\n");

        sb.append(String.format("%-20s %10s\n",
                "TOTAL",
                formatter.format(106700)));

        sb.append("\n");

        sb.append(center("THANK YOU")).append("\n");
        sb.append(center("PLEASE COME AGAIN")).append("\n");

        sb.append("\n\n\n");

        txtPreview.setText(sb.toString());
    }

    private void generateEscPosFile() throws IOException {

        FileOutputStream fos = new FileOutputStream("output.bin");

        EscPos escpos = new EscPos(fos);

        Style titleStyle = new Style()
                .setJustification(EscPosConst.Justification.Center)
                .setBold(true)
                .setFontSize(Style.FontSize._2, Style.FontSize._2);

        Style centerStyle = new Style()
                .setJustification(EscPosConst.Justification.Center);

        Style normalStyle = new Style();

        escpos.writeLF(titleStyle, "MY COFFEE SHOP");
        escpos.writeLF(centerStyle, "Bluetooth ESC/POS");
        escpos.writeLF(centerStyle, "Jl. Ubud Bali");

        escpos.writeLF("--------------------------------");

        addItemEscPos(escpos, "Espresso", 2, 18000);
        addItemEscPos(escpos, "Cappuccino", 1, 25000);
        addItemEscPos(escpos, "Croissant", 3, 12000);

        escpos.writeLF("--------------------------------");

        escpos.writeLF(normalStyle,
                String.format("%-20s %10s",
                        "SUBTOTAL",
                        formatter.format(97000)));

        escpos.writeLF(normalStyle,
                String.format("%-20s %10s",
                        "TAX",
                        formatter.format(9700)));

        escpos.writeLF("--------------------------------");

        escpos.writeLF(normalStyle,
                String.format("%-20s %10s",
                        "TOTAL",
                        formatter.format(106700)));

        escpos.writeLF("");

        escpos.writeLF(centerStyle, "THANK YOU");
        escpos.writeLF(centerStyle, "PLEASE COME AGAIN");

        escpos.feed(4);
        escpos.cut(EscPos.CutMode.FULL);

        escpos.close();
        fos.close();
    }

    private void addItemEscPos(EscPos escpos,
                               String item,
                               int qty,
                               int price) throws IOException {

        int total = qty * price;

        escpos.writeLF(item);

        escpos.writeLF(
                String.format(
                        " %2dx %-14s %10s",
                        qty,
                        "",
                        formatter.format(total)
                )
        );
    }

    private void addItem(StringBuilder sb,
                         String item,
                         int qty,
                         int price) {

        int total = qty * price;

        sb.append(item).append("\n");

        sb.append(String.format(
                " %2dx %-14s %10s\n",
                qty,
                "",
                formatter.format(total)
        ));
    }

    private String center(String text) {

        int width = 32;

        if (text.length() >= width)
            return text;

        int leftPadding = (width - text.length()) / 2;

        return " ".repeat(leftPadding) + text;
    }

    public static void main(String[] args) {

        SwingUtilities.invokeLater(() -> {
            new App().setVisible(true);
        });
    }
}

Note: lpx device (e.g /dev/usb/lp1) does not use serial com, you need to send hex code direct via OutputStream 

 

Sunday, May 24, 2026

Java: using maven in Debian 13

Apache Maven is an open-source build automation and project management tool primarily used for Java applications. It simplifies the development process by managing a project's build, reporting, and documentation from a single piece of information.

To install maven:

# apt install maven
Installing:                     
  maven

Installing dependencies:
...

Showing version

$ mvn --version
Apache Maven 3.9.9
Maven home: /usr/share/maven
Java version: 21.0.11, vendor: Debian, runtime: /usr/lib/jvm/java-21-openjdk-amd64
Default locale: en_US, platform encoding: UTF-8
OS name: "linux", version: "6.12.88+deb13-amd64", arch: "amd64", family: "unix"

Go to your workspace, and run

$ mvn archetype:generate \
  -DgroupId=com.dedetok.myapp \
  -DartifactId=myapp \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DarchetypeVersion=1.5 \
  -DinteractiveMode=false
...
$ ls myapp
pom.xml  src

DartifactId=myapp -> project root directory.

The main java code is ~/myapp/src/main/java/com/dedetok/myapp/App.java

package com.dedetok.myapp;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

To run the project using mvn, go to folder myapp, edit pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.dedetok</groupId>
    <artifactId>myapp</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.13.0</version>
            </plugin>

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.6.3</version>
                <configuration>
                    <mainClass>com.dedetok.myapp.App</mainClass>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.4.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.dedetok.myapp.App</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

        </plugins>
    </build>

</project>

then run:

$ mvn package

Run your application 


$ mvn exec:java -Dexec.mainClass="com.dedetok.myapp.App"
[INFO] Scanning for projects...
[INFO] 
[INFO] --------------------------< com.dedetok:myap >--------------------------
[INFO] Building myap 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- exec:3.6.3:java (default-cli) @ myap ---
Hello World!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  8.265 s
[INFO] Finished at: 2026-05-24T14:59:08+07:00
[INFO] -----------------------------------------

or

$ mvn exec:java
[INFO] Scanning for projects...
[INFO] 
[INFO] -------------------------< com.dedetok:myapp >--------------------------
[INFO] Building myapp 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- exec:3.6.3:java (default-cli) @ myapp ---
Hello World!
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.712 s
[INFO] Finished at: 2026-05-25T14:43:48+07:00
[INFO] ------------------------------------------------------------------------

To use old school java, copy library needed

$ mvn dependency:copy-dependencies

run using java


$ mvn compile
$ java -cp "target/classes:target/dependency/*" com.dedetok.myapp.App
Hello World!