1616 * 8 | EEPROM IO6
1717 * 9 | EEPROM IO7
1818 * ----+--------------
19- * 10 | 74HC595 SER
20- * 11 | 74HC595 RCLK
21- * 12 | 74HC595 SCLK
19+ * A3 | 74HC595 OE
20+ * A4 | 74HC595 SER
21+ * 11 | 74HC595 SCLK
22+ * 12 | 74HC595 RCLK
23+ * 13 | 74HC595 CLR
2224 * ----+--------------
23- * A0 | EEPROM CE
25+ * A0 | EEPROM WE
2426 * A1 | EEPROM OE
25- * A2 | EEPROM WE
27+ * A2 | EEPROM CE
2628 * ----+--------------
2729 * 13 | Activity LED
2830 * ----+--------------
4244 * limitations under the License.
4345 */
4446enum MODE {STANDBY, READ, WRITE};
47+ typedef enum {
48+ OK,
49+ E_RESET, // reset command received
50+ E_CORRUPT, // inbound packet corrupt
51+ E_UNEXPECTED, // unexpected packet received
52+ E_UNKNOWN // unknown error
53+ } error;
54+
4555const unsigned int MAX_PAYLOAD = 63 ;
4656const unsigned int DELAY_US = 10 ;
4757
@@ -64,6 +74,7 @@ const unsigned int ACT_LED = 10;
6474const unsigned int dataPins[] = {2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 };
6575
6676MODE mode = NULL ;
77+ error errno = OK;
6778
6879
6980void setup () {
@@ -91,12 +102,13 @@ void setup() {
91102
92103/*
93104 * Reads the next message from the serial port and copies its payload into
94- * the global `buf` byte array.
105+ * the specified `buf` byte array.
95106 *
96107 * This function can participate in explicit flow control by sending an
97108 * explicit acknowledgement message if `sendAck` is `true`.
98109 *
99- * Returns the number of bytes that were copied into `buf` (0 for acks).
110+ * Returns the number of bytes that were copied into `buf` (0 for acks), or -1
111+ * if there was an error (check global `errno`).
100112 */
101113int receive (byte *buf, size_t len, bool sendAck) {
102114 int l;
@@ -106,11 +118,12 @@ int receive(byte *buf, size_t len, bool sendAck) {
106118
107119 if (l > 0 ) {
108120 if (Serial.readBytes (buf, min (l, len)) != l) {
109- error ();
121+ errno = E_CORRUPT;
122+ return -1 ;
110123 }
111124 }
112- if (sendAck) {
113- send ( NULL , 0 , false ) ;
125+ if (sendAck && send ( NULL , 0 , false ) == - 1 ) {
126+ return - 1 ;
114127 }
115128 return l;
116129}
@@ -121,18 +134,29 @@ int receive(byte *buf, size_t len, bool sendAck) {
121134 *
122135 * This function enforces flow control, blocking until the client has
123136 * acknowledged receipt with a 0-byte ack.
137+ *
138+ * Returns 0 on success, or -1 if an error occurred, in which case the global
139+ * `errno` variable gets set.
124140 */
125- void send (byte *buf, size_t len, bool waitForAck) {
141+ int send (byte *buf, size_t len, bool waitForAck) {
126142 Serial.write (len);
127143 if (len > 0 ) {
128144 Serial.write (buf, len);
129145 }
130146 if (waitForAck) {
131147 byte buf[1 + MAX_PAYLOAD];
132- if (receive (buf, MAX_PAYLOAD, false ) != 0 ) {
133- error ();
148+ int len = receive (buf, MAX_PAYLOAD, false );
149+ if (len != 0 ) {
150+ if (len == 1 && buf[0 ] == ' r' ) {
151+ // reset
152+ errno = E_RESET;
153+ } else if (len != -1 ) {
154+ errno = E_UNEXPECTED;
155+ }
156+ return -1 ;
134157 }
135158 }
159+ return 0 ;
136160}
137161
138162void pulse (int pin) {
@@ -198,8 +222,11 @@ void writeAddr(unsigned int addr, byte val) {
198222/*
199223 * Writes the full contents of the EEPROM to the serial port in sequential
200224 * messages of up to 63 bytes, waiting for explicit acknowledgement of each.
225+ *
226+ * Returns 0 on success, -1 on error, in which case the global `errno` variable
227+ * will be set.
201228 */
202- void dump () {
229+ int dump () {
203230 byte payload[MAX_PAYLOAD];
204231 unsigned int i = 0 ;
205232
@@ -208,42 +235,55 @@ void dump() {
208235
209236 if (addr > 0 && i == 0 ) {
210237 // payload at capacity, send out:
211- send (payload, sizeof (payload), true );
238+ if (send (payload, sizeof (payload), true ) == -1 ) {
239+ return -1 ; // abort immediately
240+ }
212241 }
213242 payload[i++] = readAddr (addr);
214243 }
215244
216245 if (i) {
217246 // send remainder
218- send (payload, i, true );
247+ return send (payload, i, true );
219248 }
249+ return 0 ;
220250}
221251
222252/*
223253 * Reads the specified number of bytes from the serial port and writes them
224254 * to the EEPROM.
225255 *
226256 * This requires the Arduino to be in WRITE mode.
257+ *
258+ * Returns 0 on success, -1 on error, in which case the global `errno` variable
259+ * gets set.
227260 */
228- void load (unsigned int len) {
261+ int load (unsigned int len) {
229262 unsigned int addr = 0 ;
230263 byte buf[1 + MAX_PAYLOAD];
231264
232265 while (addr < len) {
233- unsigned int cnt = receive (buf, sizeof (buf), true );
266+ int cnt = receive (buf, sizeof (buf), true );
267+ if (cnt == -1 ) {
268+ // unexpected error; abort immediately
269+ return -1 ;
270+ }
234271
235- for (unsigned int i = 0 ; i < cnt; i++) {
272+ for (int i = 0 ; i < cnt; i++) {
236273 writeAddr (addr++, buf[i]);
237274 delay (5 );
238275 }
239276 }
277+ return 0 ;
240278}
241279
242280/*
243281 * Switches the pin mode for the I/O pins to OUTPUT, pulls EEPROM_CE LOW and
244282 * EEPROM_OE HIGH.
283+ *
284+ * Returns 0 on success, or -1 on error.
245285 */
246- void writeMode () {
286+ int writeMode () {
247287 digitalWrite (EEPROM_CE, LOW);
248288 digitalWrite (EEPROM_OE, HIGH);
249289 digitalWrite (EEPROM_WE, HIGH);
@@ -254,13 +294,16 @@ void writeMode() {
254294
255295 delayMicroseconds (DELAY_US);
256296 mode = WRITE;
297+ return 0 ;
257298}
258299
259300/* *
260301 * Switches the pin mode for the I/O pins to INPUT, pulls EEPROM_CE LOW,
261302 * EEPROM_OE LOW and EEPROM_WE HIGH.
303+ *
304+ * Returns 0 on success, or -1 on error.
262305 */
263- void readMode () {
306+ int readMode () {
264307 if (mode != READ) {
265308 for (unsigned int i = 0 ; i < 8 ; i++) {
266309 pinMode (dataPins[i], INPUT);
@@ -273,9 +316,10 @@ void readMode() {
273316 delayMicroseconds (DELAY_US);
274317 mode = READ;
275318 }
319+ return 0 ;
276320}
277321
278- void standbyMode () {
322+ int standbyMode () {
279323 for (unsigned int i = 0 ; i < 8 ; i++) {
280324 pinMode (dataPins[i], INPUT);
281325 }
@@ -286,43 +330,57 @@ void standbyMode() {
286330
287331 delayMicroseconds (DELAY_US);
288332 mode = STANDBY;
333+ return 0 ;
289334}
290335
291- void error () {
292- for (int i = 0 ; i < 5 ; i++) {
293- digitalWrite (ACT_LED, LOW);
294- delay (100 );
295- digitalWrite (ACT_LED, HIGH);
296- delay (100 );
336+ /* *
337+ * Flashes out the errno value and resets the errno variable.
338+ */
339+ void processError () {
340+ // TODO: different patterns for different errors
341+ if (errno != OK) {
342+ for (int i = 0 ; i < 5 ; i++) {
343+ digitalWrite (ACT_LED, HIGH);
344+ delay (100 );
345+ digitalWrite (ACT_LED, LOW);
346+ delay (100 );
347+ }
297348 }
349+ // clear global error state
350+ errno = OK;
298351}
299352
300353void loop () {
301354 if (Serial.available () > 0 ) {
302355 byte buf[1 + MAX_PAYLOAD];
303356 digitalWrite (ACT_LED, HIGH);
304357
305- unsigned int len = receive (buf, sizeof (buf), false );
358+ const int len = receive (buf, sizeof (buf), false );
359+ if (len > 0 ) {
360+ if (buf[0 ] == 0x72 && len == 3 ) {
361+ byte val = readAddr ((buf[1 ] << 8 ) + buf[2 ]);
362+ send (&val, 1 , false );
363+
364+ } else if (buf[0 ] == 0x77 && len == 4 ) {
365+ writeAddr ((buf[1 ] << 8 ) + buf[2 ], buf[3 ]);
366+ // signal operation completion
367+ send (NULL , 0 , false );
306368
307- if (buf[0 ] == 0x72 && len == 3 ) {
308- byte val = readAddr ((buf[1 ] << 8 ) + buf[2 ]);
309- send (&val, 1 , false );
369+ } else if (buf[0 ] == 0x64 && len == 1 ) {
370+ dump ();
310371
311- } else if (buf[0 ] == 0x77 && len == 4 ) {
312- writeAddr ((buf[1 ] << 8 ) + buf[2 ], buf[3 ]);
313- // signal operation completion
314- send (NULL , 0 , false );
372+ } else if (buf[0 ] == 0x6c && len == 3 ) {
373+ send (NULL , 0 , false ); // acknowledge cmd message
374+ load ((buf[1 ] << 8 ) + buf[2 ]);
315375
316- } else if (buf[0 ] == 0x64 && len == 1 ) {
317- dump ();
318-
319- } else if (buf[0 ] == 0x6c && len == 3 ) {
320- send (NULL , 0 , false ); // acknowledge cmd message
321- load ((buf[1 ] << 8 ) + buf[2 ]);
376+ } else if (buf[0 ] == 0x72 && len == 1 ) {
377+ // ignore reset command
322378
323- } else {
324- error ();
379+ } else {
380+ errno = E_UNKNOWN;
381+ }
325382 }
326383 digitalWrite (ACT_LED, LOW);
327384 }
385+ processError ();
328386}
0 commit comments