or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdbluetooth-communication.mdcore-protocol.mdgui-components.mdindex.mdmessage-handling.mdserial-communication.md

message-handling.mddocs/

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