@@ -66,14 +66,57 @@ const
66
66
}
67
67
68
68
/* *
69
- * Split a 16-bit integer into two 7-bit values and write each value.
70
- * @param value The 16-bit value to be split and written separately.
69
+ * An alternative to the normal analog message, this extended version allows addressing beyond
70
+ * pin 15 and supports sending analog values with any number of bits.
71
+ * @param pin The analog pin to which the value is sent.
72
+ * @param bytec The size of the storage for the analog value
73
+ * @param bytev The pointer to the location of the analog value
71
74
*/
72
- void FirmataMarshaller::sendValueAsTwo7bitBytes ( uint16_t value )
75
+ void FirmataMarshaller::sendExtendedAnalog ( uint8_t pin, size_t bytec, uint8_t * bytev )
73
76
const
74
77
{
75
- FirmataStream->write (value & 0x7F ); // LSB
76
- FirmataStream->write (value >> 7 & 0x7F ); // MSB
78
+ if ( (Stream *)NULL == FirmataStream ) { return ; }
79
+ FirmataStream->write (START_SYSEX);
80
+ FirmataStream->write (EXTENDED_ANALOG);
81
+ FirmataStream->write (pin);
82
+ transformByteStreamToMessageBytes (bytec, bytev, bytec);
83
+ FirmataStream->write (END_SYSEX);
84
+ }
85
+
86
+ /* *
87
+ * Transform 8-bit stream into 7-bit message
88
+ * @param bytec The number of data bytes in the message.
89
+ * @param bytev A pointer to the array of data bytes to send in the message.
90
+ * @param max_bytes Force message to be n bytes, regardless of data bits.
91
+ */
92
+ void FirmataMarshaller::transformByteStreamToMessageBytes (size_t bytec, uint8_t * bytev, size_t max_bytes)
93
+ const
94
+ {
95
+ static const size_t transmit_bits = 7 ;
96
+ static const uint8_t transmit_mask = ((1 << transmit_bits) - 1 );
97
+
98
+ size_t bytes_sent = 0 ;
99
+ size_t outstanding_bits = 0 ;
100
+ uint8_t outstanding_bit_cache = *bytev;
101
+
102
+ if ( !max_bytes ) { max_bytes = static_cast <size_t >(-1 ); }
103
+ for (size_t i = 0 ; (i < bytec) && (bytes_sent < max_bytes) ; ++i) {
104
+ uint8_t transmit_byte = (outstanding_bit_cache|(bytev[i] << outstanding_bits));
105
+ FirmataStream->write (transmit_mask & transmit_byte);
106
+ ++bytes_sent;
107
+ outstanding_bit_cache = (bytev[i] >> (transmit_bits - outstanding_bits));
108
+ outstanding_bits = (outstanding_bits + (8 - transmit_bits));
109
+ for ( ; (outstanding_bits >= transmit_bits) && (bytes_sent < max_bytes) ; ) {
110
+ transmit_byte = outstanding_bit_cache;
111
+ FirmataStream->write (transmit_mask & transmit_byte);
112
+ ++bytes_sent;
113
+ outstanding_bit_cache >>= transmit_bits;
114
+ outstanding_bits -= transmit_bits;
115
+ }
116
+ }
117
+ if ( outstanding_bits && (bytes_sent < max_bytes) ) {
118
+ FirmataStream->write (static_cast <uint8_t >((1 << outstanding_bits) - 1 ) & outstanding_bit_cache);
119
+ }
77
120
}
78
121
79
122
// ******************************************************************************
@@ -116,6 +159,28 @@ void FirmataMarshaller::end(void)
116
159
// * Output Stream Handling
117
160
// ******************************************************************************
118
161
162
+ /* *
163
+ * Query the target's firmware name and version
164
+ */
165
+ void FirmataMarshaller::queryFirmwareVersion (void )
166
+ const
167
+ {
168
+ if ( (Stream *)NULL == FirmataStream ) { return ; }
169
+ FirmataStream->write (START_SYSEX);
170
+ FirmataStream->write (REPORT_FIRMWARE);
171
+ FirmataStream->write (END_SYSEX);
172
+ }
173
+
174
+ /* *
175
+ * Query the target's Firmata protocol version
176
+ */
177
+ void FirmataMarshaller::queryVersion (void )
178
+ const
179
+ {
180
+ if ( (Stream *)NULL == FirmataStream ) { return ; }
181
+ FirmataStream->write (REPORT_VERSION);
182
+ }
183
+
119
184
/* *
120
185
* Halt the stream of analog readings from the Firmata host application. The range of pins is
121
186
* limited to [0..15] when using the REPORT_ANALOG. The maximum result of the REPORT_ANALOG is limited to 14 bits
@@ -173,17 +238,20 @@ const
173
238
* when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits
174
239
* (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG
175
240
* message.
176
- * @param pin The analog pin to send the value of (limited to pins 0 - 15) .
241
+ * @param pin The analog pin to which the value is sent .
177
242
* @param value The value of the analog pin (0 - 1024 for 10-bit analog, 0 - 4096 for 12-bit, etc).
178
- * The maximum value is 14-bits (16384).
243
+ * @note The maximum value is 14-bits (16384).
179
244
*/
180
245
void FirmataMarshaller::sendAnalog (uint8_t pin, uint16_t value)
181
246
const
182
247
{
183
248
if ( (Stream *)NULL == FirmataStream ) { return ; }
184
- // pin can only be 0-15, so chop higher bits
185
- FirmataStream->write (ANALOG_MESSAGE | (pin & 0xF ));
186
- sendValueAsTwo7bitBytes (value);
249
+ if ( (0xF >= pin) && (0x3FFF >= value) ) {
250
+ FirmataStream->write (ANALOG_MESSAGE|pin);
251
+ transformByteStreamToMessageBytes (sizeof (value), reinterpret_cast <uint8_t *>(&value), sizeof (value));
252
+ } else {
253
+ sendExtendedAnalog (pin, sizeof (value), reinterpret_cast <uint8_t *>(&value));
254
+ }
187
255
}
188
256
189
257
/* *
@@ -236,8 +304,45 @@ const
236
304
{
237
305
if ( (Stream *)NULL == FirmataStream ) { return ; }
238
306
FirmataStream->write (DIGITAL_MESSAGE | (portNumber & 0xF ));
239
- FirmataStream->write ((uint8_t )portData % 128 ); // Tx bits 0-6 (protocol v1 and higher)
240
- FirmataStream->write (portData >> 7 ); // Tx bits 7-13 (bit 7 only for protocol v2 and higher)
307
+ // Tx bits 0-6 (protocol v1 and higher)
308
+ // Tx bits 7-13 (bit 7 only for protocol v2 and higher)
309
+ transformByteStreamToMessageBytes (sizeof (portData), reinterpret_cast <uint8_t *>(&portData), sizeof (portData));
310
+ }
311
+
312
+ /* *
313
+ * Sends the firmware name and version to the Firmata host application.
314
+ * @param major The major verison number
315
+ * @param minor The minor version number
316
+ * @param bytec The length of the firmware name
317
+ * @param bytev The firmware name array
318
+ */
319
+ void FirmataMarshaller::sendFirmwareVersion (uint8_t major, uint8_t minor, size_t bytec, uint8_t *bytev)
320
+ const
321
+ {
322
+ if ( (Stream *)NULL == FirmataStream ) { return ; }
323
+ size_t i;
324
+ FirmataStream->write (START_SYSEX);
325
+ FirmataStream->write (REPORT_FIRMWARE);
326
+ FirmataStream->write (major);
327
+ FirmataStream->write (minor);
328
+ for (i = 0 ; i < bytec; ++i) {
329
+ transformByteStreamToMessageBytes (sizeof (bytev[i]), reinterpret_cast <uint8_t *>(&bytev[i]), sizeof (bytev[i]));
330
+ }
331
+ FirmataStream->write (END_SYSEX);
332
+ }
333
+
334
+ /* *
335
+ * Send the Firmata protocol version to the Firmata host application.
336
+ * @param major The major verison number
337
+ * @param minor The minor version number
338
+ */
339
+ void FirmataMarshaller::sendVersion (uint8_t major, uint8_t minor)
340
+ const
341
+ {
342
+ if ( (Stream *)NULL == FirmataStream ) { return ; }
343
+ FirmataStream->write (REPORT_VERSION);
344
+ FirmataStream->write (major);
345
+ FirmataStream->write (minor);
241
346
}
242
347
243
348
/* *
@@ -256,6 +361,23 @@ const
256
361
FirmataStream->write (config);
257
362
}
258
363
364
+ /* *
365
+ * Send a pin state query to the Firmata host application. The resulting sysex message will have
366
+ * a PIN_STATE_RESPONSE command byte, followed by the pin number, the pin mode and a stream of
367
+ * bits to indicate any *data* written to the pin (pin state).
368
+ * @param pin The pin to query
369
+ * @note The pin state is any data written to the pin (i.e. pin state != pin value)
370
+ */
371
+ void FirmataMarshaller::sendPinStateQuery (uint8_t pin)
372
+ const
373
+ {
374
+ if ( (Stream *)NULL == FirmataStream ) { return ; }
375
+ FirmataStream->write (START_SYSEX);
376
+ FirmataStream->write (PIN_STATE_QUERY);
377
+ FirmataStream->write (pin);
378
+ FirmataStream->write (END_SYSEX);
379
+ }
380
+
259
381
/* *
260
382
* Send a sysex message where all values after the command byte are packet as 2 7-bit bytes
261
383
* (this is not always the case so this function is not always used to send sysex messages).
@@ -271,7 +393,7 @@ const
271
393
FirmataStream->write (START_SYSEX);
272
394
FirmataStream->write (command);
273
395
for (i = 0 ; i < bytec; ++i) {
274
- sendValueAsTwo7bitBytes ( bytev[i]);
396
+ transformByteStreamToMessageBytes ( sizeof ( bytev[i]), reinterpret_cast < uint8_t *>(&bytev[i]), sizeof (bytev[i]) );
275
397
}
276
398
FirmataStream->write (END_SYSEX);
277
399
}
@@ -283,5 +405,27 @@ const
283
405
void FirmataMarshaller::sendString (const char *string)
284
406
const
285
407
{
286
- sendSysex (STRING_DATA, strlen (string), (uint8_t *)string);
408
+ sendSysex (STRING_DATA, strlen (string), reinterpret_cast <uint8_t *>(const_cast <char *>(string)));
409
+ }
410
+
411
+ /* *
412
+ * The sampling interval sets how often analog data and i2c data is reported to the client.
413
+ * @param interval_ms The interval (in milliseconds) at which to sample
414
+ * @note The default sampling interval is 19ms
415
+ */
416
+ void FirmataMarshaller::setSamplingInterval (uint16_t interval_ms)
417
+ const
418
+ {
419
+ sendSysex (SAMPLING_INTERVAL, sizeof (interval_ms), reinterpret_cast <uint8_t *>(&interval_ms));
420
+ }
421
+
422
+ /* *
423
+ * Perform a software reset on the target. For example, StandardFirmata.ino will initialize
424
+ * everything to a known state and reset the parsing buffer.
425
+ */
426
+ void FirmataMarshaller::systemReset (void )
427
+ const
428
+ {
429
+ if ( (Stream *)NULL == FirmataStream ) { return ; }
430
+ FirmataStream->write (SYSTEM_RESET);
287
431
}
0 commit comments