1/*
2 Copyright (c) 2013 Arduino LLC. All right reserved.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "Bridge.h"
20
21BridgeClass::BridgeClass(Stream &_stream) :
22 index(0), stream(_stream), started(false), max_retries(0) {
23 // Empty
24}
25
26void BridgeClass::begin() {
27 if (started)
28 return;
29 started = true;
30
31 // Wait for U-boot to finish startup
32 do {
33 dropAll();
34 delay(1000);
35 } while (stream.available() > 0);
36
37 while (true) {
38 // Bridge interrupt:
39 // - Ask the bridge to close itself
40 uint8_t quit_cmd[] = {'X', 'X', 'X', 'X', 'X'};
41 max_retries = 1;
42 transfer(quit_cmd, 5);
43
44 // Bridge startup:
45 // - If the bridge is not running starts it safely
46 stream.print(CTRL_C);
47 delay(250);
48 stream.print(F("\n"));
49 delay(250);
50 stream.print(F("\n"));
51 delay(500);
52 // Wait for OpenWRT message
53 // "Press enter to activate console"
54 stream.print(F("run-bridge\n"));
55 delay(500);
56 dropAll();
57
58 // Reset the brigde to check if it is running
59 uint8_t cmd[] = {'X', 'X', '1', '0', '0'};
60 uint8_t res[4];
61 max_retries = 50;
62 uint16_t l = transfer(cmd, 5, res, 4);
63 if (l == TRANSFER_TIMEOUT) {
64 // Bridge didn't start...
65 // Maybe the board is starting-up?
66
67 // Wait and retry
68 delay(1000);
69 continue;
70 }
71 if (res[0] != 0)
72 while (true);
73
74 // Detect bridge version
75 if (l == 4) {
76 bridgeVersion = (res[1]-'0')*100 + (res[2]-'0')*10 + (res[3]-'0');
77 } else {
78 // Bridge v1.0.0 didn't send any version info
79 bridgeVersion = 100;
80 }
81
82 max_retries = 50;
83 return;
84 }
85}
86
87void BridgeClass::put(const char *key, const char *value) {
88 // TODO: do it in a more efficient way
89 String cmd = "D";
90 uint8_t res[1];
91 cmd += key;
92 cmd += "\xFE";
93 cmd += value;
94 transfer((uint8_t*)cmd.c_str(), cmd.length(), res, 1);
95}
96
97unsigned int BridgeClass::get(const char *key, uint8_t *value, unsigned int maxlen) {
98 uint8_t cmd[] = {'d'};
99 unsigned int l = transfer(cmd, 1, (uint8_t *)key, strlen(key), value, maxlen);
100 if (l < maxlen)
101 value[l] = 0; // Zero-terminate string
102 return l;
103}
104
105#if defined(ARDUINO_ARCH_AVR)
106// AVR use an optimized implementation of CRC
107#include <util/crc16.h>
108#else
109// Generic implementation for non-AVR architectures
110uint16_t _crc_ccitt_update(uint16_t crc, uint8_t data)
111{
112 data ^= crc & 0xff;
113 data ^= data << 4;
114 return ((((uint16_t)data << 8) | ((crc >> 8) & 0xff)) ^
115 (uint8_t)(data >> 4) ^
116 ((uint16_t)data << 3));
117}
118#endif
119
120void BridgeClass::crcUpdate(uint8_t c) {
121 CRC = _crc_ccitt_update(CRC, c);
122}
123
124void BridgeClass::crcReset() {
125 CRC = 0xFFFF;
126}
127
128void BridgeClass::crcWrite() {
129 stream.write((char)(CRC >> 8));
130 stream.write((char)(CRC & 0xFF));
131}
132
133bool BridgeClass::crcCheck(uint16_t _CRC) {
134 return CRC == _CRC;
135}
136
137uint16_t BridgeClass::transfer(const uint8_t *buff1, uint16_t len1,
138 const uint8_t *buff2, uint16_t len2,
139 const uint8_t *buff3, uint16_t len3,
140 uint8_t *rxbuff, uint16_t rxlen)
141{
142 uint16_t len = len1 + len2 + len3;
143 uint8_t retries = 0;
144 for ( ; retries < max_retries; retries++, delay(100), dropAll() /* Delay for retransmission */) {
145 // Send packet
146 crcReset();
147 stream.write((char)0xFF); // Start of packet (0xFF)
148 crcUpdate(0xFF);
149 stream.write((char)index); // Message index
150 crcUpdate(index);
151 stream.write((char)((len >> 8) & 0xFF)); // Message length (hi)
152 crcUpdate((len >> 8) & 0xFF);
153 stream.write((char)(len & 0xFF)); // Message length (lo)
154 crcUpdate(len & 0xFF);
155 for (uint16_t i = 0; i < len1; i++) { // Payload
156 stream.write((char)buff1[i]);
157 crcUpdate(buff1[i]);
158 }
159 for (uint16_t i = 0; i < len2; i++) { // Payload
160 stream.write((char)buff2[i]);
161 crcUpdate(buff2[i]);
162 }
163 for (uint16_t i = 0; i < len3; i++) { // Payload
164 stream.write((char)buff3[i]);
165 crcUpdate(buff3[i]);
166 }
167 crcWrite(); // CRC
168
169 // Wait for ACK in 100ms
170 if (timedRead(100) != 0xFF)
171 continue;
172 crcReset();
173 crcUpdate(0xFF);
174
175 // Check packet index
176 if (timedRead(5) != index)
177 continue;
178 crcUpdate(index);
179
180 // Recv len
181 int lh = timedRead(10);
182 if (lh < 0)
183 continue;
184 crcUpdate(lh);
185 int ll = timedRead(10);
186 if (ll < 0)
187 continue;
188 crcUpdate(ll);
189 uint16_t l = lh;
190 l <<= 8;
191 l += ll;
192
193 // Recv data
194 for (uint16_t i = 0; i < l; i++) {
195 // Cut received data if rxbuffer is too small
196 if (i >= rxlen)
197 break;
198 int c = timedRead(5);
199 if (c < 0)
200 continue;
201 rxbuff[i] = c;
202 crcUpdate(c);
203 }
204
205 // Check CRC
206 int crc_hi = timedRead(5);
207 if (crc_hi < 0)
208 continue;
209 int crc_lo = timedRead(5);
210 if (crc_lo < 0)
211 continue;
212 if (!crcCheck((crc_hi << 8) + crc_lo))
213 continue;
214
215 // Increase index
216 index++;
217
218 // Return bytes received
219 if (l > rxlen)
220 return rxlen;
221 return l;
222 }
223
224 // Max retries exceeded
225 return TRANSFER_TIMEOUT;
226}
227
228int BridgeClass::timedRead(unsigned int timeout) {
229 int c;
230 unsigned long _startMillis = millis();
231 do {
232 c = stream.read();
233 if (c >= 0) return c;
234 } while (millis() - _startMillis < timeout);
235 return -1; // -1 indicates timeout
236}
237
238void BridgeClass::dropAll() {
239 while (stream.available() > 0) {
240 stream.read();
241 }
242}
243
244#if defined(ARDUINO_ARCH_SAM)
245#include <Reset.h>
246#endif
247
248#if defined(ARDUINO_ARCH_SAM)
249void checkForRemoteSketchUpdate(uint8_t pin) {
250 // The host force pin LOW to signal that a new sketch is coming
251 pinMode(pin, INPUT_PULLUP);
252 delay(50);
253 if (digitalRead(pin) == LOW) {
254 initiateReset(1);
255 while (true)
256 ; // Wait for reset to SAM-BA
257 }
258
259 // Restore in standard state
260 pinMode(pin, INPUT);
261}
262#else
263void checkForRemoteSketchUpdate(uint8_t /* pin */) {
264 // Empty, bootloader is enough.
265}
266#endif
267
268// Bridge instance
269#if defined(SERIAL_PORT_LINUXBRIDGE)
270SerialBridgeClass Bridge(SERIAL_PORT_LINUXBRIDGE);
271#elif defined(SERIAL_PORT_HARDWARE)
272SerialBridgeClass Bridge(SERIAL_PORT_HARDWARE);
273#elif defined(SERIAL_PORT_HARDWARE_OPEN)
274SerialBridgeClass Bridge(SERIAL_PORT_HARDWARE_OPEN);
275#elif defined(__AVR_ATmega32U4__) // Legacy fallback
276// Leonardo variants (where HardwareSerial is Serial1)
277SerialBridgeClass Bridge(Serial1);
278#else
279SerialBridgeClass Bridge(Serial);
280#endif
281