@@ -66,14 +66,57 @@ const
6666}
6767
6868/* *
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
7174 */
72- void FirmataMarshaller::sendValueAsTwo7bitBytes ( uint16_t value )
75+ void FirmataMarshaller::sendExtendedAnalog ( uint8_t pin, size_t bytec, uint8_t * bytev )
7376const
7477{
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+ }
77120}
78121
79122// ******************************************************************************
@@ -173,17 +216,20 @@ const
173216 * when using the ANALOG_MESSAGE. The maximum value of the ANALOG_MESSAGE is limited to 14 bits
174217 * (16384). To increase the pin range or value, see the documentation for the EXTENDED_ANALOG
175218 * message.
176- * @param pin The analog pin to send the value of (limited to pins 0 - 15) .
219+ * @param pin The analog pin to which the value is sent .
177220 * @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).
179221 */
180222void FirmataMarshaller::sendAnalog (uint8_t pin, uint16_t value)
181223const
182224{
183225 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);
226+
227+ if ( (0xF >= pin) && (0x3FFF >= value) ) {
228+ FirmataStream->write (ANALOG_MESSAGE|pin);
229+ transformByteStreamToMessageBytes (sizeof (value), reinterpret_cast <uint8_t *>(&value), 2 );
230+ } else {
231+ sendExtendedAnalog (pin, sizeof (value), reinterpret_cast <uint8_t *>(&value));
232+ }
187233}
188234
189235/* *
@@ -236,8 +282,9 @@ const
236282{
237283 if ( (Stream *)NULL == FirmataStream ) { return ; }
238284 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)
285+ // Tx bits 0-6 (protocol v1 and higher)
286+ // Tx bits 7-13 (bit 7 only for protocol v2 and higher)
287+ transformByteStreamToMessageBytes (sizeof (portData), reinterpret_cast <uint8_t *>(&portData), 2 );
241288}
242289
243290/* *
@@ -284,7 +331,7 @@ const
284331 FirmataStream->write (START_SYSEX);
285332 FirmataStream->write (command);
286333 for (i = 0 ; i < bytec; ++i) {
287- sendValueAsTwo7bitBytes ( bytev[i]);
334+ transformByteStreamToMessageBytes ( sizeof ( bytev[i]), reinterpret_cast < uint8_t *>(&bytev[i]), 2 );
288335 }
289336 FirmataStream->write (END_SYSEX);
290337}
@@ -296,7 +343,7 @@ const
296343void FirmataMarshaller::sendString (const char *string)
297344const
298345{
299- sendSysex (STRING_DATA, strlen (string), ( uint8_t *) string);
346+ sendSysex (STRING_DATA, strlen (string), reinterpret_cast < uint8_t *>( const_cast < char *>( string)) );
300347}
301348
302349/* *
@@ -307,5 +354,5 @@ const
307354void FirmataMarshaller::setSamplingInterval (uint16_t interval_ms)
308355const
309356{
310- sendSysex (SAMPLING_INTERVAL, sizeof (interval_ms), &interval_ms);
357+ sendSysex (SAMPLING_INTERVAL, sizeof (interval_ms), reinterpret_cast < uint8_t *>( &interval_ms) );
311358}
0 commit comments