A comprehensive Java library for interfacing with Arduino boards through serial, Bluetooth, and Ethernet connections
Observer pattern implementation for asynchronous Arduino message handling with strongly-typed message classes and automatic parsing. This system enables decoupled communication between Arduino hardware and Java applications through a publish-subscribe model.
Core observer interfaces for Arduino message handling enabling asynchronous, event-driven communication.
interface JArduinoObserver {
void receiveMsg(byte[] msg);
}
interface JArduinoSubject {
void register(JArduinoObserver observer);
void unregister(JArduinoObserver observer);
}
interface JArduinoClientObserver {
void receiveMsg(byte[] msg);
}
interface JArduinoClientSubject {
void register(JArduinoClientObserver observer);
void unregister(JArduinoClientObserver observer);
}Complete interface for handling all types of Arduino messages with strongly-typed method signatures.
interface IJArduinoMessageHandler {
// Command handlers
void handlePinMode(PinModeMsg msg);
void handleDigitalRead(DigitalReadMsg msg);
void handleDigitalWrite(DigitalWriteMsg msg);
void handleAnalogReference(AnalogReferenceMsg msg);
void handleAnalogRead(AnalogReadMsg msg);
void handleAnalogWrite(AnalogWriteMsg msg);
void handleTone(ToneMsg msg);
void handleNoTone(NoToneMsg msg);
void handlePulseIn(PulseInMsg msg);
void handlePing(PingMsg msg);
void handleAttachInterrupt(AttachInterruptMsg msg);
void handleDetachInterrupt(DetachInterruptMsg msg);
void handleEeprom_read(Eeprom_readMsg msg);
void handleEeprom_sync_write(Eeprom_sync_writeMsg msg);
void handleEeprom_write(Eeprom_writeMsg msg);
// Result handlers
void handleDigitalReadResult(DigitalReadResultMsg msg);
void handleAnalogReadResult(AnalogReadResultMsg msg);
void handlePulseInResult(PulseInResultMsg msg);
void handlePong(PongMsg msg);
void handleInterruptNotification(InterruptNotificationMsg msg);
void handleEeprom_value(Eeprom_valueMsg msg);
void handleEeprom_write_ack(Eeprom_write_ackMsg msg);
}Base implementations providing partial message handling functionality.
abstract class JArduinoMessageHandler implements IJArduinoMessageHandler;
abstract class JArduinoClientMessageHandler implements IJArduinoMessageHandler;Complete set of message classes for all Arduino operations, providing type safety and automatic serialization.
// Command messages
class PinModeMsg extends JArduinoProtocolPacket {
DigitalPin getPin();
PinMode getMode();
}
class DigitalReadMsg extends JArduinoProtocolPacket {
DigitalPin getPin();
}
class DigitalWriteMsg extends JArduinoProtocolPacket {
DigitalPin getPin();
DigitalState getValue();
}
class AnalogReadMsg extends JArduinoProtocolPacket {
AnalogPin getPin();
}
class AnalogWriteMsg extends JArduinoProtocolPacket {
PWMPin getPin();
byte getValue();
}
class AnalogReferenceMsg extends JArduinoProtocolPacket {
AnalogReference getReference();
}
class ToneMsg extends JArduinoProtocolPacket {
DigitalPin getPin();
short getFrequency();
short getDuration();
}
class NoToneMsg extends JArduinoProtocolPacket {
DigitalPin getPin();
}
class PulseInMsg extends JArduinoProtocolPacket {
DigitalPin getPin();
DigitalState getState();
}
class AttachInterruptMsg extends JArduinoProtocolPacket {
InterruptPin getInterrupt();
InterruptTrigger getMode();
}
class DetachInterruptMsg extends JArduinoProtocolPacket {
InterruptPin getInterrupt();
}
class Eeprom_readMsg extends JArduinoProtocolPacket {
short getAddress();
}
class Eeprom_writeMsg extends JArduinoProtocolPacket {
short getAddress();
byte getValue();
}
class Eeprom_sync_writeMsg extends JArduinoProtocolPacket {
short getAddress();
byte getValue();
}
class PingMsg extends JArduinoProtocolPacket;
// Result messages
class DigitalReadResultMsg extends JArduinoProtocolPacket {
DigitalState getValue();
}
class AnalogReadResultMsg extends JArduinoProtocolPacket {
short getValue();
}
class PulseInResultMsg extends JArduinoProtocolPacket {
short getValue();
}
class PongMsg extends JArduinoProtocolPacket;
class InterruptNotificationMsg extends JArduinoProtocolPacket {
InterruptPin getInterrupt();
}
class Eeprom_valueMsg extends JArduinoProtocolPacket {
short getAddress();
byte getValue();
}
class Eeprom_write_ackMsg extends JArduinoProtocolPacket {
short getAddress();
}import org.sintef.jarduino.observer.*;
import org.sintef.jarduino.*;
public class BasicArduinoObserver implements JArduinoObserver {
@Override
public void receiveMsg(byte[] msg) {
// Parse incoming message
FixedSizePacket packet = JArduinoProtocol.createMessageFromPacket(msg);
// Handle different message types
if (packet instanceof AnalogReadResultMsg) {
AnalogReadResultMsg result = (AnalogReadResultMsg) packet;
System.out.println("Analog reading: " + result.getValue());
} else if (packet instanceof DigitalReadResultMsg) {
DigitalReadResultMsg result = (DigitalReadResultMsg) packet;
System.out.println("Digital state: " + result.getValue());
} else if (packet instanceof PongMsg) {
System.out.println("Arduino is alive (received pong)");
} else if (packet instanceof InterruptNotificationMsg) {
InterruptNotificationMsg notification = (InterruptNotificationMsg) packet;
System.out.println("Interrupt triggered on: " + notification.getInterrupt());
}
}
}import org.sintef.jarduino.msg.*;
public class ComprehensiveArduinoHandler extends JArduinoMessageHandler {
@Override
public void handleDigitalReadResult(DigitalReadResultMsg msg) {
DigitalState state = msg.getValue();
System.out.println("Digital pin read: " + state);
// Respond to button press
if (state == DigitalState.HIGH) {
handleButtonPressed();
}
}
@Override
public void handleAnalogReadResult(AnalogReadResultMsg msg) {
short value = msg.getValue();
System.out.println("Analog reading: " + value);
// Convert to voltage (assuming 5V reference)
double voltage = (value / 1023.0) * 5.0;
System.out.println("Voltage: " + voltage + "V");
// Trigger actions based on sensor reading
if (value > 512) {
handleHighSensorValue();
}
}
@Override
public void handlePong(PongMsg msg) {
System.out.println("Arduino connection confirmed");
setConnectionStatus(true);
}
@Override
public void handleInterruptNotification(InterruptNotificationMsg msg) {
InterruptPin interrupt = msg.getInterrupt();
System.out.println("External interrupt: " + interrupt);
// Handle different interrupt sources
switch (interrupt) {
case PIN_2_INT0:
handleEmergencyStop();
break;
case PIN_3_INT1:
handleUserButton();
break;
}
}
@Override
public void handleEeprom_value(Eeprom_valueMsg msg) {
short address = msg.getAddress();
byte value = msg.getValue();
System.out.println("EEPROM[" + address + "] = " + value);
// Store configuration values
storeConfigValue(address, value);
}
@Override
public void handleEeprom_write_ack(Eeprom_write_ackMsg msg) {
short address = msg.getAddress();
System.out.println("EEPROM write confirmed at address: " + address);
}
@Override
public void handlePulseInResult(PulseInResultMsg msg) {
short duration = msg.getValue();
System.out.println("Pulse duration: " + duration + " microseconds");
// Calculate distance from ultrasonic sensor
double distance = (duration * 0.034) / 2.0; // cm
System.out.println("Distance: " + distance + " cm");
}
// Helper methods
private void handleButtonPressed() { /* ... */ }
private void handleHighSensorValue() { /* ... */ }
private void setConnectionStatus(boolean connected) { /* ... */ }
private void handleEmergencyStop() { /* ... */ }
private void handleUserButton() { /* ... */ }
private void storeConfigValue(short address, byte value) { /* ... */ }
}import org.sintef.jarduino.serial.Serial4JArduino;
import org.sintef.jarduino.observer.*;
public class ObserverManagement {
private Serial4JArduino arduino;
private List<JArduinoObserver> observers;
public ObserverManagement(String port) {
arduino = new Serial4JArduino(port);
observers = new ArrayList<>();
}
public void setupObservers() {
// Create different observers for different purposes
JArduinoObserver sensorObserver = new SensorDataObserver();
JArduinoObserver loggingObserver = new LoggingObserver();
JArduinoObserver alertObserver = new AlertObserver();
// Register all observers
arduino.register(sensorObserver);
arduino.register(loggingObserver);
arduino.register(alertObserver);
observers.add(sensorObserver);
observers.add(loggingObserver);
observers.add(alertObserver);
}
public void cleanup() {
// Unregister all observers
for (JArduinoObserver observer : observers) {
arduino.unregister(observer);
}
observers.clear();
arduino.close();
}
}public class MessageProcessingPipeline implements JArduinoObserver {
private List<MessageProcessor> processors;
public MessageProcessingPipeline() {
processors = new ArrayList<>();
processors.add(new MessageValidator());
processors.add(new MessageLogger());
processors.add(new MessageAnalyzer());
processors.add(new MessageDispatcher());
}
@Override
public void receiveMsg(byte[] msg) {
FixedSizePacket packet = JArduinoProtocol.createMessageFromPacket(msg);
// Process message through pipeline
for (MessageProcessor processor : processors) {
try {
packet = processor.process(packet);
if (packet == null) {
// Message was consumed by processor
break;
}
} catch (Exception e) {
System.err.println("Error processing message: " + e.getMessage());
break;
}
}
}
interface MessageProcessor {
FixedSizePacket process(FixedSizePacket packet);
}
class MessageValidator implements MessageProcessor {
@Override
public FixedSizePacket process(FixedSizePacket packet) {
// Validate message format and content
if (packet == null || packet.getPacket().length == 0) {
throw new IllegalArgumentException("Invalid message");
}
return packet;
}
}
class MessageLogger implements MessageProcessor {
@Override
public FixedSizePacket process(FixedSizePacket packet) {
System.out.println("[LOG] " + packet.toString());
return packet;
}
}
class MessageAnalyzer implements MessageProcessor {
@Override
public FixedSizePacket process(FixedSizePacket packet) {
// Analyze message patterns, frequencies, etc.
analyzeMessagePattern(packet);
return packet;
}
private void analyzeMessagePattern(FixedSizePacket packet) {
// Implementation for message analysis
}
}
class MessageDispatcher implements MessageProcessor {
@Override
public FixedSizePacket process(FixedSizePacket packet) {
// Dispatch to appropriate handlers based on message type
if (packet instanceof AnalogReadResultMsg) {
handleSensorData((AnalogReadResultMsg) packet);
} else if (packet instanceof InterruptNotificationMsg) {
handleInterrupt((InterruptNotificationMsg) packet);
}
return null; // Message consumed
}
private void handleSensorData(AnalogReadResultMsg msg) { /* ... */ }
private void handleInterrupt(InterruptNotificationMsg msg) { /* ... */ }
}
}The message handling system follows a clear flow:
JArduinoProtocol.createMessageFromPacket() creates typed objectsinstanceof or implement IJArduinoMessageHandlerThe observer system provides several error handling mechanisms:
org.sintef.jarduino.core for protocol and message classesjava.util.* for observer managementjava.util.concurrent.* for thread-safe implementationsInstall with Tessl CLI
npx tessl i tessl/maven-org-sintef-jarduino--org-sintef-jarduino