CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-sintef-jarduino--org-sintef-jarduino

A comprehensive Java library for interfacing with Arduino boards through serial, Bluetooth, and Ethernet connections

Overview
Eval results
Files

advanced-features.mddocs/

Advanced Arduino Features

Specialized Arduino functionality including interrupts, tone generation, pulse measurement, and EEPROM operations for advanced hardware control. These features enable sophisticated Arduino applications with real-time event handling, audio output, timing measurements, and persistent data storage.

Capabilities

External Interrupts

Hardware interrupt support for real-time event handling on Arduino interrupt-capable pins.

enum InterruptPin {
    PIN_2_INT0, // Arduino Uno pin 2 (interrupt 0)
    PIN_3_INT1; // Arduino Uno pin 3 (interrupt 1)

    byte getValue();
    static InterruptPin fromValue(byte b);
}

enum InterruptTrigger {
    CHANGE,  // Trigger on any logic change
    RISING,  // Trigger on rising edge (LOW to HIGH)
    FALLING, // Trigger on falling edge (HIGH to LOW)
    LOW;     // Trigger when pin is LOW
}

// Interrupt management commands
static FixedSizePacket createAttachInterrupt(InterruptPin interrupt, InterruptTrigger mode);
static FixedSizePacket createDetachInterrupt(InterruptPin interrupt);

// Interrupt notification message
class InterruptNotificationMsg extends JArduinoProtocolPacket {
    InterruptPin getInterrupt();
}

Tone Generation

Audio tone generation capability for buzzers, speakers, and audio feedback.

// Tone generation commands
static FixedSizePacket createTone(DigitalPin pin, short frequency, short duration);
static FixedSizePacket createNoTone(DigitalPin pin);

// Tone command messages
class ToneMsg extends JArduinoProtocolPacket {
    DigitalPin getPin();
    short getFrequency(); // Hz (20 - 20000)
    short getDuration();  // milliseconds (0 = continuous)
}

class NoToneMsg extends JArduinoProtocolPacket {
    DigitalPin getPin();
}

Pulse Measurement

Precise timing measurement for ultrasonic sensors, encoders, and timing-critical applications.

// Pulse measurement command
static FixedSizePacket createPulseIn(DigitalPin pin, DigitalState state);

// Pulse measurement messages
class PulseInMsg extends JArduinoProtocolPacket {
    DigitalPin getPin();
    DigitalState getState(); // HIGH or LOW pulse to measure
}

class PulseInResultMsg extends JArduinoProtocolPacket {
    int getValue(); // Pulse duration in microseconds
}

EEPROM Operations

Non-volatile memory operations for persistent configuration and data storage.

// EEPROM commands
static FixedSizePacket createEeprom_read(short address);
static FixedSizePacket createEeprom_write(short address, byte value);
static FixedSizePacket createEeprom_sync_write(short address, byte value);

// EEPROM messages
class Eeprom_readMsg extends JArduinoProtocolPacket {
    short getAddress(); // EEPROM address (0-1023 for Arduino Uno)
}

class Eeprom_writeMsg extends JArduinoProtocolPacket {
    short getAddress();
    byte getValue();
}

class Eeprom_sync_writeMsg extends JArduinoProtocolPacket {
    short getAddress();
    byte getValue();
}

// EEPROM result messages
class Eeprom_valueMsg extends JArduinoProtocolPacket {
    short getAddress();
    byte getValue();
}

class Eeprom_write_ackMsg extends JArduinoProtocolPacket {
    short getAddress();
}

Communication Testing

Built-in connectivity testing for Arduino communication reliability.

// Ping/pong commands for connection testing
static FixedSizePacket createPing();
static FixedSizePacket createPong();

// Ping/pong messages
class PingMsg extends JArduinoProtocolPacket;
class PongMsg extends JArduinoProtocolPacket;

Usage Examples

External Interrupt Handling

import org.sintef.jarduino.*;
import org.sintef.jarduino.observer.JArduinoObserver;

public class InterruptExample implements JArduinoObserver {
    private Serial4JArduino arduino;

    public void setupInterrupts() {
        arduino = new Serial4JArduino("COM3");
        arduino.register(this);

        // Attach interrupt on pin 2 for button press detection
        FixedSizePacket attachBtn = JArduinoProtocol.createAttachInterrupt(
            InterruptPin.PIN_2_INT0,
            InterruptTrigger.RISING
        );
        arduino.receiveMsg(attachBtn.getPacket());

        // Attach interrupt on pin 3 for motion sensor
        FixedSizePacket attachMotion = JArduinoProtocol.createAttachInterrupt(
            InterruptPin.PIN_3_INT1,
            InterruptTrigger.CHANGE
        );
        arduino.receiveMsg(attachMotion.getPacket());
    }

    @Override
    public void receiveMsg(byte[] msg) {
        FixedSizePacket packet = JArduinoProtocol.createMessageFromPacket(msg);

        if (packet instanceof InterruptNotificationMsg) {
            InterruptNotificationMsg notification = (InterruptNotificationMsg) packet;
            InterruptPin interrupt = notification.getInterrupt();

            switch (interrupt) {
                case PIN_2_INT0:
                    handleButtonPress();
                    break;
                case PIN_3_INT1:
                    handleMotionDetected();
                    break;
            }
        }
    }

    private void handleButtonPress() {
        System.out.println("Button pressed!");
        // Trigger LED or other response
        FixedSizePacket ledOn = JArduinoProtocol.createDigitalWrite(
            DigitalPin.PIN_13, DigitalState.HIGH
        );
        arduino.receiveMsg(ledOn.getPacket());
    }

    private void handleMotionDetected() {
        System.out.println("Motion detected!");
        // Trigger alarm or recording
    }

    public void cleanup() {
        // Detach interrupts
        FixedSizePacket detach1 = JArduinoProtocol.createDetachInterrupt(InterruptPin.PIN_2_INT0);
        FixedSizePacket detach2 = JArduinoProtocol.createDetachInterrupt(InterruptPin.PIN_3_INT1);

        arduino.receiveMsg(detach1.getPacket());
        arduino.receiveMsg(detach2.getPacket());
        arduino.close();
    }
}

Tone Generation for Audio Feedback

public class AudioFeedbackExample {
    private Serial4JArduino arduino;

    public AudioFeedbackExample(Serial4JArduino arduino) {
        this.arduino = arduino;
    }

    public void playStartupSound() {
        // Play a sequence of tones
        playTone(DigitalPin.PIN_8, 440, 200);  // A4 for 200ms
        sleep(50);
        playTone(DigitalPin.PIN_8, 554, 200);  // C#5 for 200ms
        sleep(50);
        playTone(DigitalPin.PIN_8, 659, 400);  // E5 for 400ms
    }

    public void playErrorSound() {
        // Play error tone
        playTone(DigitalPin.PIN_8, 200, 500);  // Low frequency, 500ms
    }

    public void playSuccessSound() {
        // Play success chime
        playTone(DigitalPin.PIN_8, 800, 100);  // High frequency, short
        sleep(50);
        playTone(DigitalPin.PIN_8, 1000, 100);
    }

    public void startAlarm() {
        // Continuous alarm tone
        FixedSizePacket alarm = JArduinoProtocol.createTone(
            DigitalPin.PIN_8,
            (short) 1000,
            (short) 0  // 0 = continuous
        );
        arduino.receiveMsg(alarm.getPacket());
    }

    public void stopAlarm() {
        FixedSizePacket stopTone = JArduinoProtocol.createNoTone(DigitalPin.PIN_8);
        arduino.receiveMsg(stopTone.getPacket());
    }

    private void playTone(DigitalPin pin, int frequency, int duration) {
        FixedSizePacket tone = JArduinoProtocol.createTone(
            pin,
            (short) frequency,
            (short) duration
        );
        arduino.receiveMsg(tone.getPacket());
    }

    private void sleep(int ms) {
        try { Thread.sleep(ms); } catch (InterruptedException e) {}
    }
}

Ultrasonic Distance Sensor

public class UltrasonicSensor implements JArduinoObserver {
    private Serial4JArduino arduino;
    private DigitalPin triggerPin = DigitalPin.PIN_7;
    private DigitalPin echoPin = DigitalPin.PIN_8;

    public UltrasonicSensor(Serial4JArduino arduino) {
        this.arduino = arduino;
        arduino.register(this);
        setupPins();
    }

    private void setupPins() {
        // Set trigger pin as output, echo pin as input
        FixedSizePacket triggerMode = JArduinoProtocol.createPinMode(triggerPin, PinMode.OUTPUT);
        FixedSizePacket echoMode = JArduinoProtocol.createPinMode(echoPin, PinMode.INPUT);

        arduino.receiveMsg(triggerMode.getPacket());
        arduino.receiveMsg(echoMode.getPacket());
    }

    public void measureDistance() {
        // Send 10μs trigger pulse
        FixedSizePacket triggerHigh = JArduinoProtocol.createDigitalWrite(triggerPin, DigitalState.HIGH);
        arduino.receiveMsg(triggerHigh.getPacket());

        try { Thread.sleep(1); } catch (InterruptedException e) {} // 1ms delay

        FixedSizePacket triggerLow = JArduinoProtocol.createDigitalWrite(triggerPin, DigitalState.LOW);
        arduino.receiveMsg(triggerLow.getPacket());

        // Measure HIGH pulse duration on echo pin
        FixedSizePacket pulseIn = JArduinoProtocol.createPulseIn(echoPin, DigitalState.HIGH);
        arduino.receiveMsg(pulseIn.getPacket());
    }

    @Override
    public void receiveMsg(byte[] msg) {
        FixedSizePacket packet = JArduinoProtocol.createMessageFromPacket(msg);

        if (packet instanceof PulseInResultMsg) {
            PulseInResultMsg result = (PulseInResultMsg) packet;
            int duration = result.getValue(); // Duration in microseconds

            // Calculate distance in centimeters
            // Speed of sound = 343 m/s = 0.0343 cm/μs
            // Distance = (duration * 0.0343) / 2 (divide by 2 for round trip)
            double distance = (duration * 0.0343) / 2.0;

            System.out.println("Distance: " + distance + " cm");
            handleDistanceMeasurement(distance);
        }
    }

    private void handleDistanceMeasurement(double distance) {
        if (distance < 10.0) {
            System.out.println("Object too close!");
            // Trigger warning
        } else if (distance > 200.0) {
            System.out.println("Object out of range");
        } else {
            System.out.println("Distance measured: " + distance + " cm");
        }
    }
}

EEPROM Configuration Management

public class ConfigurationManager implements JArduinoObserver {
    private Serial4JArduino arduino;
    private Map<Short, Byte> configCache = new HashMap<>();

    // Configuration addresses
    private static final short SENSOR_THRESHOLD_ADDR = 0;
    private static final short LED_BRIGHTNESS_ADDR = 1;
    private static final short ALARM_ENABLED_ADDR = 2;
    private static final short CALIBRATION_ADDR = 10; // Multiple bytes starting at 10

    public ConfigurationManager(Serial4JArduino arduino) {
        this.arduino = arduino;
        arduino.register(this);
    }

    public void loadConfiguration() {
        // Read configuration values from EEPROM
        readEEPROM(SENSOR_THRESHOLD_ADDR);
        readEEPROM(LED_BRIGHTNESS_ADDR);
        readEEPROM(ALARM_ENABLED_ADDR);

        // Read calibration data (multiple bytes)
        for (short addr = CALIBRATION_ADDR; addr < CALIBRATION_ADDR + 10; addr++) {
            readEEPROM(addr);
        }
    }

    public void saveConfiguration() {
        // Save current configuration to EEPROM
        writeEEPROM(SENSOR_THRESHOLD_ADDR, (byte) 128);  // Default threshold
        writeEEPROM(LED_BRIGHTNESS_ADDR, (byte) 255);    // Max brightness
        writeEEPROM(ALARM_ENABLED_ADDR, (byte) 1);       // Alarm enabled
    }

    public void setSensorThreshold(int threshold) {
        byte value = (byte) Math.min(255, Math.max(0, threshold));
        writeEEPROM(SENSOR_THRESHOLD_ADDR, value);
    }

    public void setLEDBrightness(int brightness) {
        byte value = (byte) Math.min(255, Math.max(0, brightness));
        writeEEPROM(LED_BRIGHTNESS_ADDR, value);
    }

    public void setAlarmEnabled(boolean enabled) {
        writeEEPROM(ALARM_ENABLED_ADDR, (byte) (enabled ? 1 : 0));
    }

    public void saveCalibrationData(byte[] calibrationData) {
        for (int i = 0; i < calibrationData.length && i < 10; i++) {
            writeEEPROM((short) (CALIBRATION_ADDR + i), calibrationData[i]);
        }
    }

    private void readEEPROM(short address) {
        FixedSizePacket read = JArduinoProtocol.createEeprom_read(address);
        arduino.receiveMsg(read.getPacket());
    }

    private void writeEEPROM(short address, byte value) {
        FixedSizePacket write = JArduinoProtocol.createEeprom_sync_write(address, value);
        arduino.receiveMsg(write.getPacket());
    }

    @Override
    public void receiveMsg(byte[] msg) {
        FixedSizePacket packet = JArduinoProtocol.createMessageFromPacket(msg);

        if (packet instanceof Eeprom_valueMsg) {
            Eeprom_valueMsg result = (Eeprom_valueMsg) packet;
            short address = result.getAddress();
            byte value = result.getValue();

            configCache.put(address, value);
            System.out.println("EEPROM[" + address + "] = " + (value & 0xFF));

            handleConfigurationValue(address, value);

        } else if (packet instanceof Eeprom_write_ackMsg) {
            Eeprom_write_ackMsg ack = (Eeprom_write_ackMsg) packet;
            System.out.println("EEPROM write confirmed at address: " + ack.getAddress());
        }
    }

    private void handleConfigurationValue(short address, byte value) {
        switch (address) {
            case SENSOR_THRESHOLD_ADDR:
                System.out.println("Sensor threshold: " + (value & 0xFF));
                break;
            case LED_BRIGHTNESS_ADDR:
                System.out.println("LED brightness: " + (value & 0xFF));
                break;
            case ALARM_ENABLED_ADDR:
                System.out.println("Alarm enabled: " + (value != 0));
                break;
            default:
                if (address >= CALIBRATION_ADDR && address < CALIBRATION_ADDR + 10) {
                    System.out.println("Calibration[" + (address - CALIBRATION_ADDR) + "] = " + (value & 0xFF));
                }
                break;
        }
    }

    public byte getCachedValue(short address) {
        return configCache.getOrDefault(address, (byte) 0);
    }
}

Connection Monitoring

public class ConnectionMonitor implements JArduinoObserver {
    private Serial4JArduino arduino;
    private boolean isConnected = false;
    private Timer pingTimer;

    public ConnectionMonitor(Serial4JArduino arduino) {
        this.arduino = arduino;
        arduino.register(this);
        startPeriodicPing();
    }

    private void startPeriodicPing() {
        pingTimer = new Timer(5000, e -> sendPing()); // Ping every 5 seconds
        pingTimer.start();
    }

    private void sendPing() {
        FixedSizePacket ping = JArduinoProtocol.createPing();
        arduino.receiveMsg(ping.getPacket());

        // Set timeout to detect disconnection
        Timer timeoutTimer = new Timer(2000, e -> handlePingTimeout());
        timeoutTimer.setRepeats(false);
        timeoutTimer.start();
    }

    @Override
    public void receiveMsg(byte[] msg) {
        FixedSizePacket packet = JArduinoProtocol.createMessageFromPacket(msg);

        if (packet instanceof PongMsg) {
            if (!isConnected) {
                System.out.println("Arduino connection established");
                isConnected = true;
                notifyConnectionRestored();
            }
        }
    }

    private void handlePingTimeout() {
        if (isConnected) {
            System.out.println("Arduino connection lost");
            isConnected = false;
            notifyConnectionLost();
        }
    }

    private void notifyConnectionRestored() {
        // Notify application that Arduino is connected
    }

    private void notifyConnectionLost() {
        // Notify application that Arduino is disconnected
        // Could trigger reconnection attempts
    }

    public boolean isConnected() {
        return isConnected;
    }

    public void cleanup() {
        if (pingTimer != null) {
            pingTimer.stop();
        }
    }
}

Advanced Features Summary

Interrupt Capabilities

  • Real-time event handling: Sub-millisecond response to external events
  • Multiple trigger modes: Rising, falling, change, and level detection
  • Two interrupt pins: PIN_2_INT0 and PIN_3_INT1 on Arduino Uno
  • Automatic notifications: Asynchronous interrupt messages to observers

Audio Features

  • Frequency range: 20 Hz to 20 kHz tone generation
  • Precise timing: Millisecond-accurate duration control
  • Continuous tones: Zero duration for ongoing audio
  • Multiple pins: Any digital pin can generate tones

Timing Measurements

  • Microsecond precision: High-resolution pulse measurement
  • Ultrasonic sensors: Perfect for HC-SR04 distance sensors
  • Encoder support: Measure pulse widths from rotary encoders
  • Timeout handling: Prevents blocking on missing pulses

EEPROM Storage

  • 1024 bytes: Full Arduino Uno EEPROM capacity (addresses 0-1023)
  • Synchronous/asynchronous: Choice of write modes
  • Wear leveling: Minimize EEPROM wear with strategic addressing
  • Configuration management: Perfect for persistent settings

Connection Reliability

  • Ping/pong protocol: Built-in connectivity testing
  • Automatic detection: Observer-based connection monitoring
  • Timeout handling: Configurable connection timeouts
  • Reconnection support: Framework for automatic reconnection

Install with Tessl CLI

npx tessl i tessl/maven-org-sintef-jarduino--org-sintef-jarduino

docs

advanced-features.md

bluetooth-communication.md

core-protocol.md

gui-components.md

index.md

message-handling.md

serial-communication.md

tile.json