A comprehensive Java library for interfacing with Arduino boards through serial, Bluetooth, and Ethernet connections
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.
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();
}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();
}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
}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();
}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;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();
}
}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) {}
}
}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");
}
}
}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);
}
}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();
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-sintef-jarduino--org-sintef-jarduino