or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

analog-io.mdconnection.mddigital-io.mdevents.mdindex.mdservo.mdsysex.md

sysex.mddocs/

0

# SysEx Messaging

1

2

Custom system exclusive messaging for extended Arduino functionality beyond standard Firmata operations, enabling custom protocols and advanced device communication.

3

4

## Capabilities

5

6

### SysEx Message Transmission

7

8

Send custom SysEx messages to Arduino for extended functionality and custom protocols.

9

10

```javascript { .api }

11

/**

12

* Send SysEx (System Exclusive) message to Arduino

13

* Enables custom protocols and extended functionality beyond standard Firmata

14

* @param command - SysEx command byte (0-127, automatically masked to 7-bit)

15

* @param data - Optional array of data bytes (each automatically masked to 7-bit)

16

* @param callback - Optional callback function called when message is sent

17

*/

18

sysex(command: number, data?: number[], callback?: Function): void;

19

```

20

21

**Parameters:**

22

- **command**: Custom command byte (0-127)

23

- **data**: Array of data bytes (each 0-127, automatically masked to 7-bit values)

24

- **callback**: Optional function called after message transmission

25

26

**Usage Examples:**

27

28

```javascript

29

// Send simple command without data

30

arduino.sysex(0x01);

31

32

// Send command with data array

33

arduino.sysex(0x01, [13, 5, 2]); // Command 0x01 with three data bytes

34

35

// With callback

36

arduino.sysex(0x01, [13, 5, 2], function() {

37

console.log('SysEx message sent');

38

});

39

40

// Send empty data array explicitly

41

arduino.sysex(0x05, [], function() {

42

console.log('Command 0x05 sent without data');

43

});

44

```

45

46

### SysEx Message Reception

47

48

Handle incoming SysEx messages from Arduino for bidirectional custom communication.

49

50

```javascript { .api }

51

// Event: sysex

52

// Fired when a SysEx message is received from Arduino

53

// Event object properties:

54

interface SysexEvent {

55

command: number; // SysEx command byte (0-127)

56

data: number[]; // Array of data bytes received

57

}

58

```

59

60

**Usage Example:**

61

62

```javascript

63

arduino.on('sysex', function(event) {

64

console.log(`SysEx received - Command: 0x${event.command.toString(16)}`);

65

console.log('Data bytes:', event.data);

66

67

// Handle specific commands

68

switch(event.command) {

69

case 0x01:

70

console.log('LED blink command response received');

71

break;

72

case 0x02:

73

if (event.data.length >= 2) {

74

const sensorId = event.data[0];

75

const sensorValue = event.data[1];

76

console.log(`Sensor ${sensorId} reading: ${sensorValue}`);

77

}

78

break;

79

default:

80

console.log('Unknown SysEx command:', event.command);

81

}

82

});

83

```

84

85

### Bidirectional SysEx Communication

86

87

Complete example showing both sending and receiving SysEx messages.

88

89

```javascript

90

const ArduinoFirmata = require('arduino-firmata');

91

const arduino = new ArduinoFirmata();

92

93

arduino.connect();

94

95

arduino.on('connect', function() {

96

console.log('Arduino connected - SysEx communication ready');

97

98

// Set up SysEx message handler

99

arduino.on('sysex', function(event) {

100

console.log(`Received SysEx command: 0x${event.command.toString(16)}`);

101

console.log('Data:', event.data);

102

103

// Echo protocol - respond to command 0x10

104

if (event.command === 0x10) {

105

arduino.sysex(0x11, event.data); // Echo back with command 0x11

106

console.log('Echoed SysEx message');

107

}

108

});

109

110

// Send periodic SysEx commands

111

setInterval(function() {

112

arduino.sysex(0x01, [13, 3, 10]); // LED blink: pin 13, 3 times, 1000ms interval

113

}, 5000);

114

});

115

```

116

117

### Custom Protocol Example

118

119

Implement a custom sensor reading protocol using SysEx.

120

121

```javascript

122

class CustomSensorProtocol {

123

constructor(arduino) {

124

this.arduino = arduino;

125

this.sensorReadings = {};

126

127

// Set up SysEx handler for sensor responses

128

this.arduino.on('sysex', (event) => {

129

this.handleSysexMessage(event);

130

});

131

}

132

133

// Request sensor reading

134

requestSensor(sensorId) {

135

console.log(`Requesting reading from sensor ${sensorId}`);

136

this.arduino.sysex(0x20, [sensorId]); // Command 0x20 = read sensor

137

}

138

139

// Request all sensors

140

requestAllSensors() {

141

console.log('Requesting all sensor readings');

142

this.arduino.sysex(0x21); // Command 0x21 = read all sensors

143

}

144

145

// Handle incoming SysEx messages

146

handleSysexMessage(event) {

147

switch(event.command) {

148

case 0x30: // Sensor reading response

149

if (event.data.length >= 3) {

150

const sensorId = event.data[0];

151

const valueHigh = event.data[1];

152

const valueLow = event.data[2];

153

const value = (valueHigh << 7) | valueLow; // Reconstruct 14-bit value

154

155

this.sensorReadings[sensorId] = value;

156

console.log(`Sensor ${sensorId}: ${value}`);

157

}

158

break;

159

160

case 0x31: // All sensors response

161

console.log('All sensors data received');

162

for (let i = 0; i < event.data.length; i += 3) {

163

if (i + 2 < event.data.length) {

164

const sensorId = event.data[i];

165

const valueHigh = event.data[i + 1];

166

const valueLow = event.data[i + 2];

167

const value = (valueHigh << 7) | valueLow;

168

this.sensorReadings[sensorId] = value;

169

}

170

}

171

break;

172

}

173

}

174

175

// Get cached sensor reading

176

getSensorReading(sensorId) {

177

return this.sensorReadings[sensorId] || null;

178

}

179

}

180

181

// Usage

182

arduino.on('connect', function() {

183

const sensorProtocol = new CustomSensorProtocol(arduino);

184

185

// Request individual sensor

186

sensorProtocol.requestSensor(1);

187

188

// Request all sensors periodically

189

setInterval(() => {

190

sensorProtocol.requestAllSensors();

191

}, 2000);

192

});

193

```

194

195

### LED Control via SysEx

196

197

Example implementation matching the sample code from the repository.

198

199

```javascript

200

// LED blink control using SysEx (matches StandardFirmataWithLedBlink)

201

arduino.on('connect', function() {

202

console.log('LED blink controller ready');

203

204

// Blink LED on pin 13: 5 times with 200ms intervals

205

arduino.sysex(0x01, [13, 5, 2]); // pin, count, interval (200ms = 2 * 100ms)

206

207

// Blink LED on pin 12: 3 times with 1000ms intervals

208

arduino.sysex(0x01, [12, 3, 10]); // pin, count, interval (1000ms = 10 * 100ms)

209

210

// Handle blink completion notifications

211

arduino.on('sysex', function(event) {

212

if (event.command === 0x01) {

213

console.log('LED blink sequence completed');

214

console.log('Response data:', event.data);

215

}

216

});

217

});

218

```

219

220

### Data Encoding for SysEx

221

222

SysEx messages use 7-bit data encoding, requiring special handling for larger values.

223

224

```javascript

225

// Helper functions for encoding/decoding multi-byte values

226

function encode14bit(value) {

227

// Split 14-bit value into two 7-bit bytes

228

const high = (value >> 7) & 0x7F;

229

const low = value & 0x7F;

230

return [high, low];

231

}

232

233

function decode14bit(high, low) {

234

// Reconstruct 14-bit value from two 7-bit bytes

235

return (high << 7) | low;

236

}

237

238

// Send 14-bit sensor threshold value

239

const threshold = 5000;

240

const [thresholdHigh, thresholdLow] = encode14bit(threshold);

241

arduino.sysex(0x40, [1, thresholdHigh, thresholdLow]); // Sensor 1 threshold

242

243

// Receive and decode 14-bit values

244

arduino.on('sysex', function(event) {

245

if (event.command === 0x41 && event.data.length >= 3) {

246

const sensorId = event.data[0];

247

const value = decode14bit(event.data[1], event.data[2]);

248

console.log(`14-bit sensor ${sensorId} reading: ${value}`);

249

}

250

});

251

```

252

253

### Protocol Documentation Example

254

255

When implementing custom SysEx protocols, document the command structure:

256

257

```javascript

258

/*

259

* Custom SysEx Protocol Documentation

260

*

261

* Command 0x01 - LED Blink Control

262

* Data: [pin, count, interval]

263

* - pin: LED pin number (0-13)

264

* - count: Number of blinks (1-127)

265

* - interval: Interval in 100ms units (1-127)

266

* Response: Command 0x01 with completion status

267

*

268

* Command 0x20 - Request Sensor Reading

269

* Data: [sensor_id]

270

* - sensor_id: Sensor identifier (0-127)

271

* Response: Command 0x30 with sensor data

272

*

273

* Command 0x30 - Sensor Reading Response

274

* Data: [sensor_id, value_high, value_low]

275

* - sensor_id: Sensor identifier (0-127)

276

* - value_high: Upper 7 bits of 14-bit value

277

* - value_low: Lower 7 bits of 14-bit value

278

*/

279

280

const SYSEX_COMMANDS = {

281

LED_BLINK: 0x01,

282

REQUEST_SENSOR: 0x20,

283

SENSOR_RESPONSE: 0x30,

284

SET_CONFIG: 0x40,

285

GET_STATUS: 0x50

286

};

287

288

// Use named constants for better code maintenance

289

arduino.sysex(SYSEX_COMMANDS.LED_BLINK, [13, 5, 2]);

290

```

291

292

## Constants

293

294

```javascript { .api }

295

// SysEx protocol constants

296

ArduinoFirmata.START_SYSEX = 0xF0; // Start of SysEx message

297

ArduinoFirmata.END_SYSEX = 0xF7; // End of SysEx message

298

```

299

300

## SysEx Protocol Specifications

301

302

### Message Format

303

SysEx messages follow the MIDI SysEx format:

304

- **Start byte**: `0xF0` (START_SYSEX)

305

- **Command byte**: Custom command (0-127, 7-bit)

306

- **Data bytes**: Optional data (each 0-127, 7-bit)

307

- **End byte**: `0xF7` (END_SYSEX)

308

309

### Data Constraints

310

- All data bytes are automatically masked to 7 bits (0-127)

311

- Values above 127 are truncated: `value & 0x7F`

312

- For values > 127, use multi-byte encoding (see encoding examples above)

313

314

### Arduino-Side Implementation

315

To use SysEx messaging, your Arduino must be running firmware that handles custom SysEx commands:

316

317

```cpp

318

// Example Arduino SysEx handler (C++ code for Arduino)

319

void sysexCallback(byte command, byte argc, byte* argv) {

320

switch(command) {

321

case 0x01: // LED blink

322

if (argc >= 3) {

323

int pin = argv[0];

324

int count = argv[1];

325

int interval = argv[2] * 100; // Convert to milliseconds

326

blinkLED(pin, count, interval);

327

}

328

break;

329

}

330

}

331

```

332

333

## Use Cases

334

335

### Custom Sensors

336

- Multi-sensor data collection with timestamps

337

- Calibration parameter transmission

338

- Sensor configuration and threshold settings

339

340

### Advanced Motor Control

341

- Stepper motor control with acceleration profiles

342

- Multi-axis coordination commands

343

- Complex motion sequences

344

345

### Communication Protocols

346

- I2C device configuration via Arduino

347

- SPI device control and data transfer

348

- Custom serial protocol bridging

349

350

### Real-time Data Streaming

351

- High-frequency sensor data with custom formatting

352

- Compressed data transmission

353

- Synchronized multi-device communication

354

355

## Best Practices

356

357

### Protocol Design

358

1. **Document commands**: Maintain clear protocol documentation

359

2. **Use command constants**: Define named constants for command values

360

3. **Validate data**: Check data array lengths before processing

361

4. **Handle errors**: Implement error responses for invalid commands

362

5. **Version compatibility**: Include version information in protocols

363

364

### Performance Considerations

365

```javascript

366

// Batch SysEx messages to avoid flooding the Arduino

367

const messageQueue = [];

368

let sending = false;

369

370

function queueSysex(command, data, callback) {

371

messageQueue.push({ command, data, callback });

372

processSysexQueue();

373

}

374

375

function processSysexQueue() {

376

if (sending || messageQueue.length === 0) return;

377

378

sending = true;

379

const { command, data, callback } = messageQueue.shift();

380

381

arduino.sysex(command, data, function() {

382

sending = false;

383

if (callback) callback();

384

setTimeout(processSysexQueue, 10); // Small delay between messages

385

});

386

}

387

```

388

389

### Error Handling

390

```javascript

391

// Implement timeout for SysEx responses

392

function sysexWithTimeout(command, data, timeout = 5000) {

393

return new Promise((resolve, reject) => {

394

let responseReceived = false;

395

396

const timeoutId = setTimeout(() => {

397

if (!responseReceived) {

398

reject(new Error(`SysEx command 0x${command.toString(16)} timed out`));

399

}

400

}, timeout);

401

402

const responseHandler = (event) => {

403

if (event.command === command + 1) { // Assuming response is command + 1

404

responseReceived = true;

405

clearTimeout(timeoutId);

406

arduino.removeListener('sysex', responseHandler);

407

resolve(event.data);

408

}

409

};

410

411

arduino.on('sysex', responseHandler);

412

arduino.sysex(command, data);

413

});

414

}

415

416

// Usage with async/await

417

try {

418

const response = await sysexWithTimeout(0x20, [1]);

419

console.log('Sensor response:', response);

420

} catch (error) {

421

console.error('SysEx error:', error.message);

422

}

423

```