1 | /*
|
---|
2 | SerialFirmata.cpp
|
---|
3 | Copyright (C) 2016 Jeff Hoefs. All rights reserved.
|
---|
4 |
|
---|
5 | This library is free software; you can redistribute it and/or
|
---|
6 | modify it under the terms of the GNU Lesser General Public
|
---|
7 | License as published by the Free Software Foundation; either
|
---|
8 | version 2.1 of the License, or (at your option) any later version.
|
---|
9 |
|
---|
10 | See file LICENSE.txt for further informations on licensing terms.
|
---|
11 |
|
---|
12 | This version of SerialFirmata.cpp differs from the ConfigurableFirmata
|
---|
13 | version in the following ways:
|
---|
14 |
|
---|
15 | - handlePinMode calls Firmata::setPinMode
|
---|
16 |
|
---|
17 | Last updated by Jeff Hoefs: January 10th, 2016
|
---|
18 | */
|
---|
19 |
|
---|
20 | #include "SerialFirmata.h"
|
---|
21 |
|
---|
22 | SerialFirmata::SerialFirmata()
|
---|
23 | {
|
---|
24 | swSerial0 = NULL;
|
---|
25 | swSerial1 = NULL;
|
---|
26 | swSerial2 = NULL;
|
---|
27 | swSerial3 = NULL;
|
---|
28 |
|
---|
29 | serialIndex = -1;
|
---|
30 | }
|
---|
31 |
|
---|
32 | boolean SerialFirmata::handlePinMode(byte pin, int mode)
|
---|
33 | {
|
---|
34 | // used for both HW and SW serial
|
---|
35 | if (mode == PIN_MODE_SERIAL) {
|
---|
36 | Firmata.setPinMode(pin, PIN_MODE_SERIAL);
|
---|
37 | return true;
|
---|
38 | }
|
---|
39 | return false;
|
---|
40 | }
|
---|
41 |
|
---|
42 | void SerialFirmata::handleCapability(byte pin)
|
---|
43 | {
|
---|
44 | if (IS_PIN_SERIAL(pin)) {
|
---|
45 | Firmata.write(PIN_MODE_SERIAL);
|
---|
46 | Firmata.write(getSerialPinType(pin));
|
---|
47 | }
|
---|
48 | }
|
---|
49 |
|
---|
50 | boolean SerialFirmata::handleSysex(byte command, byte argc, byte *argv)
|
---|
51 | {
|
---|
52 | if (command == SERIAL_MESSAGE) {
|
---|
53 |
|
---|
54 | Stream *serialPort;
|
---|
55 | byte mode = argv[0] & SERIAL_MODE_MASK;
|
---|
56 | byte portId = argv[0] & SERIAL_PORT_ID_MASK;
|
---|
57 |
|
---|
58 | switch (mode) {
|
---|
59 | case SERIAL_CONFIG:
|
---|
60 | {
|
---|
61 | long baud = (long)argv[1] | ((long)argv[2] << 7) | ((long)argv[3] << 14);
|
---|
62 | serial_pins pins;
|
---|
63 |
|
---|
64 | if (portId < 8) {
|
---|
65 | serialPort = getPortFromId(portId);
|
---|
66 | if (serialPort != NULL) {
|
---|
67 | pins = getSerialPinNumbers(portId);
|
---|
68 | if (pins.rx != 0 && pins.tx != 0) {
|
---|
69 | Firmata.setPinMode(pins.rx, PIN_MODE_SERIAL);
|
---|
70 | Firmata.setPinMode(pins.tx, PIN_MODE_SERIAL);
|
---|
71 | // Fixes an issue where some serial devices would not work properly with Arduino Due
|
---|
72 | // because all Arduino pins are set to OUTPUT by default in StandardFirmata.
|
---|
73 | pinMode(pins.rx, INPUT);
|
---|
74 | }
|
---|
75 | ((HardwareSerial*)serialPort)->begin(baud);
|
---|
76 | }
|
---|
77 | } else {
|
---|
78 | #if defined(SoftwareSerial_h)
|
---|
79 | byte swTxPin, swRxPin;
|
---|
80 | if (argc > 4) {
|
---|
81 | swRxPin = argv[4];
|
---|
82 | swTxPin = argv[5];
|
---|
83 | } else {
|
---|
84 | // RX and TX pins must be specified when using SW serial
|
---|
85 | Firmata.sendString("Specify serial RX and TX pins");
|
---|
86 | return false;
|
---|
87 | }
|
---|
88 | switch (portId) {
|
---|
89 | case SW_SERIAL0:
|
---|
90 | if (swSerial0 == NULL) {
|
---|
91 | swSerial0 = new SoftwareSerial(swRxPin, swTxPin);
|
---|
92 | }
|
---|
93 | break;
|
---|
94 | case SW_SERIAL1:
|
---|
95 | if (swSerial1 == NULL) {
|
---|
96 | swSerial1 = new SoftwareSerial(swRxPin, swTxPin);
|
---|
97 | }
|
---|
98 | break;
|
---|
99 | case SW_SERIAL2:
|
---|
100 | if (swSerial2 == NULL) {
|
---|
101 | swSerial2 = new SoftwareSerial(swRxPin, swTxPin);
|
---|
102 | }
|
---|
103 | break;
|
---|
104 | case SW_SERIAL3:
|
---|
105 | if (swSerial3 == NULL) {
|
---|
106 | swSerial3 = new SoftwareSerial(swRxPin, swTxPin);
|
---|
107 | }
|
---|
108 | break;
|
---|
109 | }
|
---|
110 | serialPort = getPortFromId(portId);
|
---|
111 | if (serialPort != NULL) {
|
---|
112 | Firmata.setPinMode(swRxPin, PIN_MODE_SERIAL);
|
---|
113 | Firmata.setPinMode(swTxPin, PIN_MODE_SERIAL);
|
---|
114 | ((SoftwareSerial*)serialPort)->begin(baud);
|
---|
115 | }
|
---|
116 | #endif
|
---|
117 | }
|
---|
118 | break; // SERIAL_CONFIG
|
---|
119 | }
|
---|
120 | case SERIAL_WRITE:
|
---|
121 | {
|
---|
122 | byte data;
|
---|
123 | serialPort = getPortFromId(portId);
|
---|
124 | if (serialPort == NULL) {
|
---|
125 | break;
|
---|
126 | }
|
---|
127 | for (byte i = 1; i < argc; i += 2) {
|
---|
128 | data = argv[i] + (argv[i + 1] << 7);
|
---|
129 | serialPort->write(data);
|
---|
130 | }
|
---|
131 | break; // SERIAL_WRITE
|
---|
132 | }
|
---|
133 | case SERIAL_READ:
|
---|
134 | if (argv[1] == SERIAL_READ_CONTINUOUSLY) {
|
---|
135 | if (serialIndex + 1 >= MAX_SERIAL_PORTS) {
|
---|
136 | break;
|
---|
137 | }
|
---|
138 |
|
---|
139 | if (argc > 2) {
|
---|
140 | // maximum number of bytes to read from buffer per iteration of loop()
|
---|
141 | serialBytesToRead[portId] = (int)argv[2] | ((int)argv[3] << 7);
|
---|
142 | } else {
|
---|
143 | // read all available bytes per iteration of loop()
|
---|
144 | serialBytesToRead[portId] = 0;
|
---|
145 | }
|
---|
146 | serialIndex++;
|
---|
147 | reportSerial[serialIndex] = portId;
|
---|
148 | } else if (argv[1] == SERIAL_STOP_READING) {
|
---|
149 | byte serialIndexToSkip = 0;
|
---|
150 | if (serialIndex <= 0) {
|
---|
151 | serialIndex = -1;
|
---|
152 | } else {
|
---|
153 | for (byte i = 0; i < serialIndex + 1; i++) {
|
---|
154 | if (reportSerial[i] == portId) {
|
---|
155 | serialIndexToSkip = i;
|
---|
156 | break;
|
---|
157 | }
|
---|
158 | }
|
---|
159 | // shift elements over to fill space left by removed element
|
---|
160 | for (byte i = serialIndexToSkip; i < serialIndex + 1; i++) {
|
---|
161 | if (i < MAX_SERIAL_PORTS) {
|
---|
162 | reportSerial[i] = reportSerial[i + 1];
|
---|
163 | }
|
---|
164 | }
|
---|
165 | serialIndex--;
|
---|
166 | }
|
---|
167 | }
|
---|
168 | break; // SERIAL_READ
|
---|
169 | case SERIAL_CLOSE:
|
---|
170 | serialPort = getPortFromId(portId);
|
---|
171 | if (serialPort != NULL) {
|
---|
172 | if (portId < 8) {
|
---|
173 | ((HardwareSerial*)serialPort)->end();
|
---|
174 | } else {
|
---|
175 | #if defined(SoftwareSerial_h)
|
---|
176 | ((SoftwareSerial*)serialPort)->end();
|
---|
177 | if (serialPort != NULL) {
|
---|
178 | free(serialPort);
|
---|
179 | serialPort = NULL;
|
---|
180 | }
|
---|
181 | #endif
|
---|
182 | }
|
---|
183 | }
|
---|
184 | break; // SERIAL_CLOSE
|
---|
185 | case SERIAL_FLUSH:
|
---|
186 | serialPort = getPortFromId(portId);
|
---|
187 | if (serialPort != NULL) {
|
---|
188 | getPortFromId(portId)->flush();
|
---|
189 | }
|
---|
190 | break; // SERIAL_FLUSH
|
---|
191 | #if defined(SoftwareSerial_h)
|
---|
192 | case SERIAL_LISTEN:
|
---|
193 | // can only call listen() on software serial ports
|
---|
194 | if (portId > 7) {
|
---|
195 | serialPort = getPortFromId(portId);
|
---|
196 | if (serialPort != NULL) {
|
---|
197 | ((SoftwareSerial*)serialPort)->listen();
|
---|
198 | }
|
---|
199 | }
|
---|
200 | break; // SERIAL_LISTEN
|
---|
201 | #endif
|
---|
202 | } // end switch
|
---|
203 | return true;
|
---|
204 | }
|
---|
205 | return false;
|
---|
206 | }
|
---|
207 |
|
---|
208 | void SerialFirmata::update()
|
---|
209 | {
|
---|
210 | checkSerial();
|
---|
211 | }
|
---|
212 |
|
---|
213 | void SerialFirmata::reset()
|
---|
214 | {
|
---|
215 | #if defined(SoftwareSerial_h)
|
---|
216 | Stream *serialPort;
|
---|
217 | // free memory allocated for SoftwareSerial ports
|
---|
218 | for (byte i = SW_SERIAL0; i < SW_SERIAL3 + 1; i++) {
|
---|
219 | serialPort = getPortFromId(i);
|
---|
220 | if (serialPort != NULL) {
|
---|
221 | free(serialPort);
|
---|
222 | serialPort = NULL;
|
---|
223 | }
|
---|
224 | }
|
---|
225 | #endif
|
---|
226 |
|
---|
227 | serialIndex = -1;
|
---|
228 | for (byte i = 0; i < SERIAL_READ_ARR_LEN; i++) {
|
---|
229 | serialBytesToRead[i] = 0;
|
---|
230 | }
|
---|
231 | }
|
---|
232 |
|
---|
233 | // get a pointer to the serial port associated with the specified port id
|
---|
234 | Stream* SerialFirmata::getPortFromId(byte portId)
|
---|
235 | {
|
---|
236 | switch (portId) {
|
---|
237 | case HW_SERIAL0:
|
---|
238 | // block use of Serial (typically pins 0 and 1) until ability to reclaim Serial is implemented
|
---|
239 | //return &Serial;
|
---|
240 | return NULL;
|
---|
241 | #if defined(PIN_SERIAL1_RX)
|
---|
242 | case HW_SERIAL1:
|
---|
243 | return &Serial1;
|
---|
244 | #endif
|
---|
245 | #if defined(PIN_SERIAL2_RX)
|
---|
246 | case HW_SERIAL2:
|
---|
247 | return &Serial2;
|
---|
248 | #endif
|
---|
249 | #if defined(PIN_SERIAL3_RX)
|
---|
250 | case HW_SERIAL3:
|
---|
251 | return &Serial3;
|
---|
252 | #endif
|
---|
253 | #if defined(SoftwareSerial_h)
|
---|
254 | case SW_SERIAL0:
|
---|
255 | if (swSerial0 != NULL) {
|
---|
256 | // instances of SoftwareSerial are already pointers so simply return the instance
|
---|
257 | return swSerial0;
|
---|
258 | }
|
---|
259 | break;
|
---|
260 | case SW_SERIAL1:
|
---|
261 | if (swSerial1 != NULL) {
|
---|
262 | return swSerial1;
|
---|
263 | }
|
---|
264 | break;
|
---|
265 | case SW_SERIAL2:
|
---|
266 | if (swSerial2 != NULL) {
|
---|
267 | return swSerial2;
|
---|
268 | }
|
---|
269 | break;
|
---|
270 | case SW_SERIAL3:
|
---|
271 | if (swSerial3 != NULL) {
|
---|
272 | return swSerial3;
|
---|
273 | }
|
---|
274 | break;
|
---|
275 | #endif
|
---|
276 | }
|
---|
277 | return NULL;
|
---|
278 | }
|
---|
279 |
|
---|
280 | // Check serial ports that have READ_CONTINUOUS mode set and relay any data
|
---|
281 | // for each port to the device attached to that port.
|
---|
282 | void SerialFirmata::checkSerial()
|
---|
283 | {
|
---|
284 | byte portId, serialData;
|
---|
285 | int bytesToRead = 0;
|
---|
286 | int numBytesToRead = 0;
|
---|
287 | Stream* serialPort;
|
---|
288 |
|
---|
289 | if (serialIndex > -1) {
|
---|
290 |
|
---|
291 | // loop through all reporting (READ_CONTINUOUS) serial ports
|
---|
292 | for (byte i = 0; i < serialIndex + 1; i++) {
|
---|
293 | portId = reportSerial[i];
|
---|
294 | bytesToRead = serialBytesToRead[portId];
|
---|
295 | serialPort = getPortFromId(portId);
|
---|
296 | if (serialPort == NULL) {
|
---|
297 | continue;
|
---|
298 | }
|
---|
299 | #if defined(SoftwareSerial_h)
|
---|
300 | // only the SoftwareSerial port that is "listening" can read data
|
---|
301 | if (portId > 7 && !((SoftwareSerial*)serialPort)->isListening()) {
|
---|
302 | continue;
|
---|
303 | }
|
---|
304 | #endif
|
---|
305 | if (serialPort->available() > 0) {
|
---|
306 | Firmata.write(START_SYSEX);
|
---|
307 | Firmata.write(SERIAL_MESSAGE);
|
---|
308 | Firmata.write(SERIAL_REPLY | portId);
|
---|
309 |
|
---|
310 | if (bytesToRead == 0 || (serialPort->available() <= bytesToRead)) {
|
---|
311 | numBytesToRead = serialPort->available();
|
---|
312 | } else {
|
---|
313 | numBytesToRead = bytesToRead;
|
---|
314 | }
|
---|
315 |
|
---|
316 | // relay serial data to the serial device
|
---|
317 | while (numBytesToRead > 0) {
|
---|
318 | serialData = serialPort->read();
|
---|
319 | Firmata.write(serialData & 0x7F);
|
---|
320 | Firmata.write((serialData >> 7) & 0x7F);
|
---|
321 | numBytesToRead--;
|
---|
322 | }
|
---|
323 | Firmata.write(END_SYSEX);
|
---|
324 | }
|
---|
325 |
|
---|
326 | }
|
---|
327 | }
|
---|
328 | }
|
---|