0
# Message Handling and Observers
1
2
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.
3
4
## Capabilities
5
6
### Observer Pattern Interfaces
7
8
Core observer interfaces for Arduino message handling enabling asynchronous, event-driven communication.
9
10
```java { .api }
11
interface JArduinoObserver {
12
void receiveMsg(byte[] msg);
13
}
14
15
interface JArduinoSubject {
16
void register(JArduinoObserver observer);
17
void unregister(JArduinoObserver observer);
18
}
19
20
interface JArduinoClientObserver {
21
void receiveMsg(byte[] msg);
22
}
23
24
interface JArduinoClientSubject {
25
void register(JArduinoClientObserver observer);
26
void unregister(JArduinoClientObserver observer);
27
}
28
```
29
30
### Comprehensive Message Handler Interface
31
32
Complete interface for handling all types of Arduino messages with strongly-typed method signatures.
33
34
```java { .api }
35
interface IJArduinoMessageHandler {
36
// Command handlers
37
void handlePinMode(PinModeMsg msg);
38
void handleDigitalRead(DigitalReadMsg msg);
39
void handleDigitalWrite(DigitalWriteMsg msg);
40
void handleAnalogReference(AnalogReferenceMsg msg);
41
void handleAnalogRead(AnalogReadMsg msg);
42
void handleAnalogWrite(AnalogWriteMsg msg);
43
void handleTone(ToneMsg msg);
44
void handleNoTone(NoToneMsg msg);
45
void handlePulseIn(PulseInMsg msg);
46
void handlePing(PingMsg msg);
47
void handleAttachInterrupt(AttachInterruptMsg msg);
48
void handleDetachInterrupt(DetachInterruptMsg msg);
49
void handleEeprom_read(Eeprom_readMsg msg);
50
void handleEeprom_sync_write(Eeprom_sync_writeMsg msg);
51
void handleEeprom_write(Eeprom_writeMsg msg);
52
53
// Result handlers
54
void handleDigitalReadResult(DigitalReadResultMsg msg);
55
void handleAnalogReadResult(AnalogReadResultMsg msg);
56
void handlePulseInResult(PulseInResultMsg msg);
57
void handlePong(PongMsg msg);
58
void handleInterruptNotification(InterruptNotificationMsg msg);
59
void handleEeprom_value(Eeprom_valueMsg msg);
60
void handleEeprom_write_ack(Eeprom_write_ackMsg msg);
61
}
62
```
63
64
### Abstract Message Handler Classes
65
66
Base implementations providing partial message handling functionality.
67
68
```java { .api }
69
abstract class JArduinoMessageHandler implements IJArduinoMessageHandler;
70
abstract class JArduinoClientMessageHandler implements IJArduinoMessageHandler;
71
```
72
73
### Strongly-Typed Message Classes
74
75
Complete set of message classes for all Arduino operations, providing type safety and automatic serialization.
76
77
```java { .api }
78
// Command messages
79
class PinModeMsg extends JArduinoProtocolPacket {
80
DigitalPin getPin();
81
PinMode getMode();
82
}
83
84
class DigitalReadMsg extends JArduinoProtocolPacket {
85
DigitalPin getPin();
86
}
87
88
class DigitalWriteMsg extends JArduinoProtocolPacket {
89
DigitalPin getPin();
90
DigitalState getValue();
91
}
92
93
class AnalogReadMsg extends JArduinoProtocolPacket {
94
AnalogPin getPin();
95
}
96
97
class AnalogWriteMsg extends JArduinoProtocolPacket {
98
PWMPin getPin();
99
byte getValue();
100
}
101
102
class AnalogReferenceMsg extends JArduinoProtocolPacket {
103
AnalogReference getReference();
104
}
105
106
class ToneMsg extends JArduinoProtocolPacket {
107
DigitalPin getPin();
108
short getFrequency();
109
short getDuration();
110
}
111
112
class NoToneMsg extends JArduinoProtocolPacket {
113
DigitalPin getPin();
114
}
115
116
class PulseInMsg extends JArduinoProtocolPacket {
117
DigitalPin getPin();
118
DigitalState getState();
119
}
120
121
class AttachInterruptMsg extends JArduinoProtocolPacket {
122
InterruptPin getInterrupt();
123
InterruptTrigger getMode();
124
}
125
126
class DetachInterruptMsg extends JArduinoProtocolPacket {
127
InterruptPin getInterrupt();
128
}
129
130
class Eeprom_readMsg extends JArduinoProtocolPacket {
131
short getAddress();
132
}
133
134
class Eeprom_writeMsg extends JArduinoProtocolPacket {
135
short getAddress();
136
byte getValue();
137
}
138
139
class Eeprom_sync_writeMsg extends JArduinoProtocolPacket {
140
short getAddress();
141
byte getValue();
142
}
143
144
class PingMsg extends JArduinoProtocolPacket;
145
146
// Result messages
147
class DigitalReadResultMsg extends JArduinoProtocolPacket {
148
DigitalState getValue();
149
}
150
151
class AnalogReadResultMsg extends JArduinoProtocolPacket {
152
short getValue();
153
}
154
155
class PulseInResultMsg extends JArduinoProtocolPacket {
156
short getValue();
157
}
158
159
class PongMsg extends JArduinoProtocolPacket;
160
161
class InterruptNotificationMsg extends JArduinoProtocolPacket {
162
InterruptPin getInterrupt();
163
}
164
165
class Eeprom_valueMsg extends JArduinoProtocolPacket {
166
short getAddress();
167
byte getValue();
168
}
169
170
class Eeprom_write_ackMsg extends JArduinoProtocolPacket {
171
short getAddress();
172
}
173
```
174
175
## Usage Examples
176
177
### Basic Observer Implementation
178
179
```java
180
import org.sintef.jarduino.observer.*;
181
import org.sintef.jarduino.*;
182
183
public class BasicArduinoObserver implements JArduinoObserver {
184
@Override
185
public void receiveMsg(byte[] msg) {
186
// Parse incoming message
187
FixedSizePacket packet = JArduinoProtocol.createMessageFromPacket(msg);
188
189
// Handle different message types
190
if (packet instanceof AnalogReadResultMsg) {
191
AnalogReadResultMsg result = (AnalogReadResultMsg) packet;
192
System.out.println("Analog reading: " + result.getValue());
193
194
} else if (packet instanceof DigitalReadResultMsg) {
195
DigitalReadResultMsg result = (DigitalReadResultMsg) packet;
196
System.out.println("Digital state: " + result.getValue());
197
198
} else if (packet instanceof PongMsg) {
199
System.out.println("Arduino is alive (received pong)");
200
201
} else if (packet instanceof InterruptNotificationMsg) {
202
InterruptNotificationMsg notification = (InterruptNotificationMsg) packet;
203
System.out.println("Interrupt triggered on: " + notification.getInterrupt());
204
}
205
}
206
}
207
```
208
209
### Comprehensive Message Handler Implementation
210
211
```java
212
import org.sintef.jarduino.msg.*;
213
214
public class ComprehensiveArduinoHandler extends JArduinoMessageHandler {
215
@Override
216
public void handleDigitalReadResult(DigitalReadResultMsg msg) {
217
DigitalState state = msg.getValue();
218
System.out.println("Digital pin read: " + state);
219
220
// Respond to button press
221
if (state == DigitalState.HIGH) {
222
handleButtonPressed();
223
}
224
}
225
226
@Override
227
public void handleAnalogReadResult(AnalogReadResultMsg msg) {
228
short value = msg.getValue();
229
System.out.println("Analog reading: " + value);
230
231
// Convert to voltage (assuming 5V reference)
232
double voltage = (value / 1023.0) * 5.0;
233
System.out.println("Voltage: " + voltage + "V");
234
235
// Trigger actions based on sensor reading
236
if (value > 512) {
237
handleHighSensorValue();
238
}
239
}
240
241
@Override
242
public void handlePong(PongMsg msg) {
243
System.out.println("Arduino connection confirmed");
244
setConnectionStatus(true);
245
}
246
247
@Override
248
public void handleInterruptNotification(InterruptNotificationMsg msg) {
249
InterruptPin interrupt = msg.getInterrupt();
250
System.out.println("External interrupt: " + interrupt);
251
252
// Handle different interrupt sources
253
switch (interrupt) {
254
case PIN_2_INT0:
255
handleEmergencyStop();
256
break;
257
case PIN_3_INT1:
258
handleUserButton();
259
break;
260
}
261
}
262
263
@Override
264
public void handleEeprom_value(Eeprom_valueMsg msg) {
265
short address = msg.getAddress();
266
byte value = msg.getValue();
267
System.out.println("EEPROM[" + address + "] = " + value);
268
269
// Store configuration values
270
storeConfigValue(address, value);
271
}
272
273
@Override
274
public void handleEeprom_write_ack(Eeprom_write_ackMsg msg) {
275
short address = msg.getAddress();
276
System.out.println("EEPROM write confirmed at address: " + address);
277
}
278
279
@Override
280
public void handlePulseInResult(PulseInResultMsg msg) {
281
short duration = msg.getValue();
282
System.out.println("Pulse duration: " + duration + " microseconds");
283
284
// Calculate distance from ultrasonic sensor
285
double distance = (duration * 0.034) / 2.0; // cm
286
System.out.println("Distance: " + distance + " cm");
287
}
288
289
// Helper methods
290
private void handleButtonPressed() { /* ... */ }
291
private void handleHighSensorValue() { /* ... */ }
292
private void setConnectionStatus(boolean connected) { /* ... */ }
293
private void handleEmergencyStop() { /* ... */ }
294
private void handleUserButton() { /* ... */ }
295
private void storeConfigValue(short address, byte value) { /* ... */ }
296
}
297
```
298
299
### Observer Registration and Management
300
301
```java
302
import org.sintef.jarduino.serial.Serial4JArduino;
303
import org.sintef.jarduino.observer.*;
304
305
public class ObserverManagement {
306
private Serial4JArduino arduino;
307
private List<JArduinoObserver> observers;
308
309
public ObserverManagement(String port) {
310
arduino = new Serial4JArduino(port);
311
observers = new ArrayList<>();
312
}
313
314
public void setupObservers() {
315
// Create different observers for different purposes
316
JArduinoObserver sensorObserver = new SensorDataObserver();
317
JArduinoObserver loggingObserver = new LoggingObserver();
318
JArduinoObserver alertObserver = new AlertObserver();
319
320
// Register all observers
321
arduino.register(sensorObserver);
322
arduino.register(loggingObserver);
323
arduino.register(alertObserver);
324
325
observers.add(sensorObserver);
326
observers.add(loggingObserver);
327
observers.add(alertObserver);
328
}
329
330
public void cleanup() {
331
// Unregister all observers
332
for (JArduinoObserver observer : observers) {
333
arduino.unregister(observer);
334
}
335
observers.clear();
336
arduino.close();
337
}
338
}
339
```
340
341
### Custom Message Processing Pipeline
342
343
```java
344
public class MessageProcessingPipeline implements JArduinoObserver {
345
private List<MessageProcessor> processors;
346
347
public MessageProcessingPipeline() {
348
processors = new ArrayList<>();
349
processors.add(new MessageValidator());
350
processors.add(new MessageLogger());
351
processors.add(new MessageAnalyzer());
352
processors.add(new MessageDispatcher());
353
}
354
355
@Override
356
public void receiveMsg(byte[] msg) {
357
FixedSizePacket packet = JArduinoProtocol.createMessageFromPacket(msg);
358
359
// Process message through pipeline
360
for (MessageProcessor processor : processors) {
361
try {
362
packet = processor.process(packet);
363
if (packet == null) {
364
// Message was consumed by processor
365
break;
366
}
367
} catch (Exception e) {
368
System.err.println("Error processing message: " + e.getMessage());
369
break;
370
}
371
}
372
}
373
374
interface MessageProcessor {
375
FixedSizePacket process(FixedSizePacket packet);
376
}
377
378
class MessageValidator implements MessageProcessor {
379
@Override
380
public FixedSizePacket process(FixedSizePacket packet) {
381
// Validate message format and content
382
if (packet == null || packet.getPacket().length == 0) {
383
throw new IllegalArgumentException("Invalid message");
384
}
385
return packet;
386
}
387
}
388
389
class MessageLogger implements MessageProcessor {
390
@Override
391
public FixedSizePacket process(FixedSizePacket packet) {
392
System.out.println("[LOG] " + packet.toString());
393
return packet;
394
}
395
}
396
397
class MessageAnalyzer implements MessageProcessor {
398
@Override
399
public FixedSizePacket process(FixedSizePacket packet) {
400
// Analyze message patterns, frequencies, etc.
401
analyzeMessagePattern(packet);
402
return packet;
403
}
404
405
private void analyzeMessagePattern(FixedSizePacket packet) {
406
// Implementation for message analysis
407
}
408
}
409
410
class MessageDispatcher implements MessageProcessor {
411
@Override
412
public FixedSizePacket process(FixedSizePacket packet) {
413
// Dispatch to appropriate handlers based on message type
414
if (packet instanceof AnalogReadResultMsg) {
415
handleSensorData((AnalogReadResultMsg) packet);
416
} else if (packet instanceof InterruptNotificationMsg) {
417
handleInterrupt((InterruptNotificationMsg) packet);
418
}
419
return null; // Message consumed
420
}
421
422
private void handleSensorData(AnalogReadResultMsg msg) { /* ... */ }
423
private void handleInterrupt(InterruptNotificationMsg msg) { /* ... */ }
424
}
425
}
426
```
427
428
## Message Flow Architecture
429
430
The message handling system follows a clear flow:
431
432
1. **Message Reception**: Communication layer receives raw bytes
433
2. **Message Parsing**: `JArduinoProtocol.createMessageFromPacket()` creates typed objects
434
3. **Observer Notification**: All registered observers receive the message
435
4. **Type-based Handling**: Observers use `instanceof` or implement `IJArduinoMessageHandler`
436
5. **Application Logic**: Observers execute application-specific responses
437
438
## Error Handling
439
440
The observer system provides several error handling mechanisms:
441
442
- **Message Validation**: Invalid messages are detected during parsing
443
- **Exception Isolation**: Observer exceptions don't affect other observers
444
- **Connection Monitoring**: Observers can detect communication failures
445
- **Automatic Cleanup**: Proper observer unregistration prevents memory leaks
446
447
## Threading Considerations
448
449
- **Observer Callbacks**: Called on communication thread (not UI thread)
450
- **Thread Safety**: Observers should be thread-safe or use synchronization
451
- **UI Updates**: Use appropriate threading mechanisms (SwingUtilities.invokeLater, etc.)
452
- **Blocking Operations**: Avoid long-running operations in observer callbacks
453
454
## Dependencies
455
456
- **JArduino Core**: `org.sintef.jarduino.core` for protocol and message classes
457
- **Java Collections**: `java.util.*` for observer management
458
- **Concurrency**: `java.util.concurrent.*` for thread-safe implementations