PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
unitTests.c
Go to the documentation of this file.
1 /** \file
2  * \brief Implements unit tests for the PIC comm protocol.
3  *
4  * A very simple test runner, runAllTests(), executes the
5  * tests. \ref ASSERT statements provide verification.
6  */
7 
8 #include "dataXfer.h"
9 #include <string.h>
10 #include <stdio.h>
11 
12 /// \name Tests for the command-finding state machine
13 //@{
14 
15 /// Run all normal chars through the machine
16 void findChar() {
17  char c_in, c_out;
18 
19  for (c_in = 0; c_in < ESCAPED_CMD; c_in++) {
21  ASSERT(cmdOutput == OUTPUT_CMD_CHAR);
22  ASSERT(c_in == c_out);
23  }
24  for (c_in = ESCAPED_CMD + 1; c_in <= ((char) 0xFF); c_in++) {
26  ASSERT(cmdOutput == OUTPUT_CMD_CHAR);
27  ASSERT(c_in == c_out);
28  }
29 }
30 
31 /// Run an escaped command through the machine.
33  char c_out;
34 
36  ASSERT(cmdOutput == OUTPUT_CMD_NONE);
37  cmdOutput = stepCommandFindMachine(ESCAPED_CMD, &c_out);
38  ASSERT(cmdOutput == OUTPUT_CMD_CHAR);
39  ASSERT(c_out == CMD_TOKEN);
40 }
41 
42 /// Look for all the normal (unescaped) commands.
43 void findCommand() {
44  char c_in, c_out;
45 
46  for (c_in = 0; c_in < ESCAPED_CMD; c_in++) {
48  ASSERT(cmdOutput == OUTPUT_CMD_NONE);
49  cmdOutput = stepCommandFindMachine(c_in, &c_out);
50  ASSERT(cmdOutput == OUTPUT_CMD_CMD);
51  ASSERT(c_in == c_out);
52  }
53  for (c_in = ESCAPED_CMD + 1; c_in <= ((char) 0xFF); c_in++) {
55  ASSERT(cmdOutput == OUTPUT_CMD_NONE);
56  cmdOutput = stepCommandFindMachine(c_in, &c_out);
57  ASSERT(cmdOutput == OUTPUT_CMD_CMD);
58  ASSERT(c_in == c_out);
59  }
60 }
61 
62 /// Run an escaped command through the machine
64  char c_out;
65 
67  ASSERT(cmdOutput == OUTPUT_CMD_NONE);
68  cmdOutput = stepCommandFindMachine(CMD_TOKEN, &c_out);
69  ASSERT(cmdOutput == OUTPUT_CMD_NONE);
70  cmdOutput = stepCommandFindMachine(ESCAPED_CMD, &c_out);
71  ASSERT(cmdOutput == OUTPUT_CMD_CMD);
72  ASSERT(c_out == CMD_TOKEN);
73 }
74 
75 /// Verify that the sequence CMD_TOKEN CMD_TOKEN CMD_TOKEN is recognized
76 /// as a repeated wait.
78  char c_out;
79 
81  ASSERT(cmdOutput == OUTPUT_CMD_NONE);
82  cmdOutput = stepCommandFindMachine(CMD_TOKEN, &c_out);
83  ASSERT(cmdOutput == OUTPUT_CMD_NONE);
84  cmdOutput = stepCommandFindMachine(CMD_TOKEN, &c_out);
85  ASSERT(cmdOutput == OUTPUT_CMD_REPEATED_WAIT);
86 }
87 
88 /// \todo Cases still to unit test:
89 /// - (repeated wait)
90 /// - CMD_TOKEN CMD_TOKEN c (repeated command)
92  char c_out;
93 
95  ASSERT(cmdOutput == OUTPUT_CMD_NONE);
96  cmdOutput = stepCommandFindMachine(CMD_TOKEN, &c_out);
97  ASSERT(cmdOutput == OUTPUT_CMD_NONE);
98  cmdOutput = stepCommandFindMachine(0, &c_out);
99  ASSERT(cmdOutput == OUTPUT_CMD_REPEATED_CMD);
100  ASSERT(c_out == 0);
101 }
102 //@}
103 
104 
105 
106 
107 
108 /// \name Tests for the receive state machine
109 //@{
110 
111 void sendData(uint8_t* pu8_data, uint u_len);
112 
113 
114 /// Sending a normal char shold report that char receivd
115 /// \param c_charToSend The character to send. This character will NOT
116 /// be esacaped -- an 0x55 will be sent as just an
117 /// 0x55.
118 void sendOneNormalChar(char c_charToSend) {
119  stepReceiveMachine(c_charToSend);
121  ASSERT(getReceiveMachineOutChar() == c_charToSend);
122 };
123 
124 
125 /// Sending a letter should report that letter received
126 void sendLetter() {
127  sendOneNormalChar('c');
128 }
129 
130 
131 /// Sending the char 0x00 shold report that char receivd
132 void send0x00() {
133  sendOneNormalChar(0x00);
134 }
135 
136 
137 /// Sending the char 0xFF shold report that char receivd
138 void send0xFF() {
139  sendOneNormalChar((char) 0xFF);
140 }
141 
142 
143 /// Check sending an escaped command
145  uint8_t au8_data[] = { CMD_TOKEN, ESCAPED_CMD };
146  sendData(au8_data, 2);
147 
150 }
151 
152 /// Set up the xferData structure for receiving
153 /// some data.
154 /// \param u_index Index of data to be received
155 /// \param u_len Length (in bytes) of data to be received
157  // A place to store the max amount of data.
158  static uint8_t au_data[256];
159 
160  // Check params
161  ASSERT(u_index < NUM_XFER_VARS);
162  ASSERT(u_len <= 256);
163 
164  // Set up structure
165  xferVar[u_index].u8_size = u_len - 1; // Value is length-1
166  xferVar[u_index].pu8_data = au_data;
167  assignBit(u_index, TRUE);
168 }
169 
170 /// Check sending a one-byte piece of data
171 /// 0x00 == 000000 00 : index 0, length 0 (1 byte)
173  // Set up index 0 for 1 byte of data
174  setupXferData(0, 1);
175  uint8_t au8_data[] = { CMD_TOKEN, 0x00, 0x12 };
176  sendData(au8_data, 3);
177 
180  ASSERT(xferVar[0].pu8_data[0] == au8_data[2]);
181 }
182 
183 
184 /// Check sending a four-byte piece of data
186  setupXferData(0, 4);
187  // 0x03: index 0, length 3 (4 bytes); following are data bytes
188  uint8_t au8_data[] = { CMD_TOKEN, 0x03, 0x00, 0x01, 0x02, 0x03 };
189  sendData(au8_data, 6);
190 
193  uint i;
194  for (i = 0; i < 4; i++)
195  ASSERT(xferVar[0].pu8_data[i] == i);
196 }
197 
198 
199 /// Check sending a four-byte piece of data which
200 /// contains four \ref CMD_TOKEN bytes.
201 /// 0x00 == 000000 11 : index 0, length 3 (4 bytes)
203  setupXferData(0, 4);
204  // 0x03: index 0, length 3; following are data bytes
205  uint8_t au8_data[] = { CMD_TOKEN, 0x03, CMD_TOKEN, ESCAPED_CMD,
207  };
208  sendData(au8_data, 10);
209 
212  uint i;
213  for (i = 0; i < 4; i++)
214  ASSERT(xferVar[0].pu8_data[i] == ((uint8_t) CMD_TOKEN));
215 }
216 
217 
218 /// Send a repeated command and make sure both an error is reported
219 /// and data can be received (error recovery works).
221  // 0x00: index 0, length 1.
222  uint8_t au8_data[] = { CMD_TOKEN, CMD_TOKEN, 0x00, 0xFF };
223  // Send first three bytes and check for repeated command.
224  setupXferData(0, 1);
225  sendData(au8_data, 2);
226  // Send third byte manually, since it reports an error
227  stepReceiveMachine(au8_data[2]);
229  // Send last byte
230  sendData(&au8_data[3], 1);
231 
234  ASSERT(xferVar[0].pu8_data[0] == au8_data[3]);
235 }
236 
237 
238 /// Send a command of CMD_TOKEN
240  // Set up and send command
242  uint u_len = getVarLength(CMD_TOKEN);
243  setupXferData(u_index, u_len);
244  uint8_t au8_data[7] = { CMD_TOKEN, CMD_TOKEN, ESCAPED_CMD };
245  uint u;
246  for (u = 0; u < u_len; u++)
247  au8_data[u + 3] = u;
248  sendData(au8_data, 3 + u_len);
249 
250  // Check received data
252  ASSERT(getReceiveMachineIndex() == u_index);
253  for (u = 0; u < u_len; u++)
254  ASSERT(xferVar[u_index].pu8_data[u] == u);
255 }
256 
257 
258 /// Send a repeated command followed by a command of CMD_TOKEN
260  // Set up and send command
262  uint u_len = getVarLength(CMD_TOKEN);
263  setupXferData(u_index, u_len);
264  uint8_t au8_data[8] = { CMD_TOKEN, CMD_TOKEN, CMD_TOKEN, ESCAPED_CMD };
265  uint u;
266  for (u = 0; u < u_len; u++)
267  au8_data[u + 4] = u;
268  // Send first two bytes (no error yet)
269  sendData(au8_data, 2);
270  // Send 3rd command (should be a repeated command error)
271  stepReceiveMachine(au8_data[2]);
273  // Send remaining data (ESCAPED_CMD followed by u_len data bytes)
274  sendData(&au8_data[3], 1 + u_len);
275 
276  // Check received data
278  ASSERT(getReceiveMachineIndex() == u_index);
279  for (u = 0; u < u_len; u++)
280  ASSERT(xferVar[u_index].pu8_data[u] == u);
281 }
282 
283 /// Test timeout detection.
285  setupXferData(0, 4);
286  // 0x03: index 0, length 3 (4 bytes); following are data bytes
287  uint8_t au8_data[] = { CMD_TOKEN, 0x03, 0x00, 0x01, 0x02, 0x03 };
288 
289  // Create a timeout at each point in the transmission of the data
290  uint u;
291  for (u = 0; u < 6; u++) {
292  // Start fresh each time
294  // Send u-1 bytes with no timeout
295  if (u > 0)
296  sendData(au8_data, u);
297  // Send the final byte with a timeout
298  notifyOfTimeout();
299  RECEIVE_ERROR re = stepReceiveMachine(au8_data[u]);
300  // Except for the first byte, make sure a timeout is reported
301  if (u > 0)
302  ASSERT(re == ERR_TIMEOUT);
303  }
304 }
305 
306 /// Test sending a second command before the first completes.
308  setupXferData(0, 4);
309  // CMD_TOKEN, 0x03: index 0, length 3 (4 bytes)
310  uint8_t au8_data[] = { CMD_TOKEN, 0x03, 0x00, CMD_TOKEN, 0x03, 0x00, 0x01, 0x02, 0x03 };
311 
312  // Send the first command then interrupt it
313  sendData(au8_data, 4);
314  RECEIVE_ERROR re = stepReceiveMachine(au8_data[4]);
317 
318  // Make sure the second command competes
319  sendData(au8_data + 5, 4);
322  uint i;
323  for (i = 0; i < 4; i++)
324  ASSERT(xferVar[0].pu8_data[i] == i);
325 }
326 
327 /// Test sending data to an unspecified index
329  // CMD_TOKEN, 0x03: index 0, length 3 (4 bytes)
330  uint8_t au8_data[] = { CMD_TOKEN, 0x03 };
331 
332  sendData(au8_data, 1);
333  RECEIVE_ERROR re = stepReceiveMachine(au8_data[1]);
335 }
336 
337 /// Test sending data to an index beyond the end of the variable
338 /// storage area
340  // This test only works if NUM_XFER_VARS is less than the max;
341  // otherwise, there's no "beyond" index to test.
343 
344  // CMD_TOKEN, 0x03: index NUM_XFER_VARS, length 3 (4 bytes)
345  uint8_t au8_data[] = { CMD_TOKEN, (NUM_XFER_VARS << 2) | 0x03 };
346  sendData(au8_data, 1);
347  RECEIVE_ERROR re = stepReceiveMachine(au8_data[1]);
348  ASSERT(re == ERR_INDEX_TOO_HIGH);
349 }
350 
351 /// Test sending incorrectly-sized data to a variable.
353  setupXferData(0, 4);
354  // CMD_TOKEN, 0x03: index 0, length 2 (3 bytes)
355  uint8_t au8_data[] = { CMD_TOKEN, 0x02 };
356  sendData(au8_data, 1);
357  RECEIVE_ERROR re = stepReceiveMachine(au8_data[1]);
359 }
360 
361 /// Test sending long data to an unspecified index
363  // CMD_TOKEN, CMD_LONG_VAR, 0x03: index 0, length 3 (4 bytes)
364  uint8_t au8_data[] = { CMD_TOKEN, CMD_LONG_VAR, 0x03 };
365 
366  sendData(au8_data, 2);
367  RECEIVE_ERROR re = stepReceiveMachine(au8_data[2]);
369 }
370 
371 /// Test sending long data to an index beyond the end of the variable
372 /// storage area
374  // This test only works if NUM_XFER_VARS is less than the max;
375  // otherwise, there's no "beyond" index to test.
377 
378  // CMD_TOKEN, CMD_LONG_VAR, index NUM_XFER_VARS, length 3 (4 bytes)
379  uint8_t au8_data[] = { CMD_TOKEN, CMD_LONG_VAR, NUM_XFER_VARS, 0x03 };
380  sendData(au8_data, 2);
381  RECEIVE_ERROR re = stepReceiveMachine(au8_data[2]);
382  ASSERT(re == ERR_INDEX_TOO_HIGH);
383 }
384 
385 /// Test sending incorrectly-sized data to a long variable.
387  setupXferData(0, 4);
388  // CMD_TOKEN, CMD_LONG_BAR, index 0, length 2 (3 bytes)
389  uint8_t au8_data[] = { CMD_TOKEN, CMD_LONG_VAR, 0, 0x02 };
390  sendData(au8_data, 3);
391  RECEIVE_ERROR re = stepReceiveMachine(au8_data[3]);
393 }
394 
395 /// Test sending 256 bytes of data.
396 void sendLongData() {
397  uint i;
398 
399  setupXferData(0, 256);
400  // CMD_TOKEN, CMD_LONG_VAR, index 0, length 0xFF = 256 bytes
401  uint8_t au8_data[256 + 5] = { CMD_TOKEN, CMD_LONG_VAR, 0, 0xFF };
402  // Fill array with data, escaping the CMD_TOKEN.
403  // Do horrible casts (to 8 bit, then to uint) to avoid sign-extension
404  // problems that make this loop run too far (0xAA < 0, without a cast
405  // is sign-extended to 0xFFFFFFAA, which is a *NOT* 0x00AA).
406  for (i = 0; i <= ((uint) ((uint8_t) CMD_TOKEN)); i++)
407  au8_data[i + 4] = i;
408  au8_data[i + 4] = ESCAPED_CMD;
409  for (; i < 256; i++)
410  au8_data[i + 5] = i;
411  // Send it, then check the data received
412  sendData(au8_data, 256 + 5);
413  for (i = 0; i < 256; i++)
414  ASSERT(xferVar[0].pu8_data[i] == i);
415 }
416 
417 #ifdef __PIC__
418 /// Test sending data to a read-only variable. Only applies to the PIC.
419 void sendReadOnly() {
420  // Set up index 0 for 1 byte of data, read-only
421  setupXferData(0, 1);
422  assignBit(0, FALSE);
423  uint8_t au8_data[] = { CMD_TOKEN, 0x00 };
424  sendData(au8_data, 1);
425 
426  RECEIVE_ERROR re = stepReceiveMachine(au8_data[1]);
427  ASSERT(re == ERR_READ_ONLY_VAR);
428 }
429 
430 
431 /// Test sending a var spec
432 void sendVarSpecPic() {
433  // Set up index 0 for 1 byte of data, read-only
434  setupXferData(0, 1);
435  uint8_t au8_data[] = { CMD_TOKEN, CMD_SEND_ONLY };
436  sendData(au8_data, 1);
437 
438  RECEIVE_ERROR re = stepReceiveMachine(au8_data[1]);
439  ASSERT(re == ERR_PIC_VAR_SPEC);
440 }
441 #endif
442 
443 #ifndef __PIC__
444 /// Used to create strings with commands in them below.
445 #define CMD_TOKEN_STR "\xAA"
446 #define CMD_SEND_ONLY_STR "\xFE"
447 #define CMD_SEND_RECEIVE_VAR_STR "\xFF"
448 
449 /// Test sending a variable specification
450 void sendVarSpec() {
451  // index, length, size, format, name, description
452  uint8_t au8_data[17] = CMD_TOKEN_STR CMD_SEND_ONLY_STR "\x00" "\x0C" "\x03" "%x\x00" "test\x00" "ing";
453  sendData(au8_data, 17);
455  ASSERT(xferVar[0].u8_size == 3);
456  ASSERT(xferVar[0].pu8_data != NULL); // Verify that some storage was allocated for this variable
457  ASSERT(!isVarWriteable(0));
458  ASSERT(strcmp(xferVar[0].psz_format, "%x") == 0);
459  ASSERT(strcmp(xferVar[0].psz_name, "test") == 0);
460  ASSERT(strcmp(xferVar[0].psz_desc, "ing") == 0);
461 }
462 
463 /// Test sending a variable specification, then sending a different spec
465  sendVarSpec();
466  // index, length, size, format, name, description
467  uint8_t au8_data[17] = CMD_TOKEN_STR CMD_SEND_ONLY_STR "\x00" "\x0C" "\xFF" "%y\x00" "book\x00" "let";
468  sendData(au8_data, 17);
470  ASSERT(xferVar[0].u8_size == 255);
471  ASSERT(xferVar[0].pu8_data != NULL); // Verify that some storage was allocated for this variable
472  ASSERT(!isVarWriteable(0));
473  ASSERT(strcmp(xferVar[0].psz_format, "%y") == 0);
474  ASSERT(strcmp(xferVar[0].psz_name, "book") == 0);
475  ASSERT(strcmp(xferVar[0].psz_desc, "let") == 0);
476 }
477 
478 /// Test sending a variable specification
480  // index, length, size, format, name, description
481  uint8_t au8_data[17] = CMD_TOKEN_STR CMD_SEND_RECEIVE_VAR_STR "\x00" "\x0C" "\x03" "%x\x00" "test\x00" "ing";
482  sendData(au8_data, 17);
484  ASSERT(xferVar[0].u8_size == 3);
485  ASSERT(xferVar[0].pu8_data != NULL); // Verify that some storage was allocated for this variable
487  ASSERT(strcmp(xferVar[0].psz_format, "%x") == 0);
488  ASSERT(strcmp(xferVar[0].psz_name, "test") == 0);
489  ASSERT(strcmp(xferVar[0].psz_desc, "ing") == 0);
490 }
491 
492 /// Test sending a variable specification with no strings
494  // index, length, size
495  uint8_t au8_data[6] = CMD_TOKEN_STR CMD_SEND_RECEIVE_VAR_STR "\x00" "\x00" "\x03";
496  sendData(au8_data, 5);
498  ASSERT(xferVar[0].u8_size == 3);
499  ASSERT(xferVar[0].pu8_data != NULL); // Verify that some storage was allocated for this variable
501  ASSERT(strcmp(xferVar[0].psz_format, "") == 0);
502  ASSERT(strcmp(xferVar[0].psz_name, "") == 0);
503  ASSERT(strcmp(xferVar[0].psz_desc, "") == 0);
504 }
505 
506 /// Test sending a variable specification with only a format
508  // index, length, size, format
509  uint8_t au8_data[8] = CMD_TOKEN_STR CMD_SEND_RECEIVE_VAR_STR "\x00" "\x03" "\x03" "%x";
510  sendData(au8_data, 8);
512  ASSERT(xferVar[0].u8_size == 3);
513  ASSERT(xferVar[0].pu8_data != NULL); // Verify that some storage was allocated for this variable
515  ASSERT(strcmp(xferVar[0].psz_format, "%x") == 0);
516  ASSERT(strcmp(xferVar[0].psz_name, "") == 0);
517  ASSERT(strcmp(xferVar[0].psz_desc, "") == 0);
518 }
519 
520 /// Test sending a variable specification with only a format
522  // index, length, size, format, name
523  uint8_t au8_data[11] = CMD_TOKEN_STR CMD_SEND_RECEIVE_VAR_STR "\x00" "\x06" "\x03" "\x00" "test";
524  sendData(au8_data, 11);
526  ASSERT(xferVar[0].u8_size == 3);
527  ASSERT(xferVar[0].pu8_data != NULL); // Verify that some storage was allocated for this variable
529  ASSERT(strcmp(xferVar[0].psz_format, "") == 0);
530  ASSERT(strcmp(xferVar[0].psz_name, "test") == 0);
531  ASSERT(strcmp(xferVar[0].psz_desc, "") == 0);
532 }
533 
534 /// Test sending a spec followed by actual data
536  sendVarSpec();
537 
538  // 0x03: index 0, length 3 (4 bytes); following are data bytes
539  uint8_t au8_data[] = { CMD_TOKEN, 0x03, 0x00, 0x01, 0x02, 0x03 };
540  sendData(au8_data, 6);
541 
544  for (uint i = 0; i < 4; i++)
545  ASSERT(xferVar[0].pu8_data[i] == i);
546 }
547 #endif
548 
549 /// Run a sequence of characters through the receive state machine,
550 /// verifying that nothing is received until the final character
551 /// and that no errors occurred.
552 void sendData(uint8_t* pu8_data, uint u_len) {
553  while (u_len--) {
554  RECEIVE_ERROR re = stepReceiveMachine(*pu8_data++);
555  ASSERT(re == ERR_NONE);
556  if (u_len)
558  }
559 }
560 //@}
561 
562 /// \name Tests for the specify and send functions
563 //@{
564 
565 /// The length of an array of characters used to check OUT_CHAR's usage.
566 static size_t st_outCharLen = 0;
567 
568 /// An index into the array of check characters.
569 static size_t st_outCharIndex = 0;
570 
571 /// A pointer to an array containing the expected characters to be output.
572 static uint8_t* au8_outCharData = NULL;
573 
574 /// Reset all the OUT_CHAR associated data (the variables above).
575 void clearOutChar() {
576  st_outCharLen = 0;
577  st_outCharIndex = 0;
578  au8_outCharData = NULL;
579 }
580 
581 /// An outChar function which simply checks to see that the output character
582 /// matches the expected string.
583 #ifdef __cplusplus
584 extern "C"
585 #endif
587  ASSERT(au8_outCharData != NULL);
588  ASSERT(st_outCharIndex < st_outCharLen);
589  ASSERT(au8_outCharData[st_outCharIndex++] == c);
590 }
591 
592 /** Test support: ASSERT if an exception isn't thrown.
593  * \param code Code which when executed should cause a specific ASSERT.
594  * \param expectedMsg String the ASSERT should throw.
595  * This macro expects to test ASSERT statements of the form
596  * ASSERT("a string" && someCondition). The "a string" portion is always
597  * true, but also provides a hackish way to name an assert. To make
598  * testing easier, only the text inside the quotes is tested: the
599  * expectedString in this case is "a string".
600  */
601 #ifdef __cplusplus
602 #define REQUIRE_ASSERT(code, expectedMsg) \
603  do { \
604  BOOL didAssert = FALSE; \
605  try { \
606  code; \
607  } catch (char* psz_msg) { \
608  didAssert = strncmp(psz_msg, expectedMsg, strlen(expectedMsg)) ? FALSE : TRUE; \
609  } \
610  ASSERT(didAssert); \
611  } while (FALSE)
612 #else
613 // Do nothing, since C doesn't support exceptions
614 #define REQUIRE_ASSERT(code, expectedMsg) (void) 0
615 #endif
616 
617 /// Send to a index that's too high
619  REQUIRE_ASSERT(sendVar(NUM_XFER_VARS + 1), "sendVar:indexTooHigh");
620 }
621 
622 /// Send to an unconfigured index
624  REQUIRE_ASSERT(sendVar(0), "sendVar:indexNotSpecified");
625 }
626 
627 /// Send to a read-only variable (PC only)
628 #ifndef __PIC__
630  // Set up index 0 for 1 byte of data, read-only
631  setupXferData(0, 1);
632  assignBit(0, FALSE);
633  // Expected transmission
634  REQUIRE_ASSERT(sendVar(0), "sendVar:notWriteable");
635 }
636 #endif
637 
638 /// A macro to send a variable and check the resulting output
639 void checkSendVar(uint8_t u8_index, uint u_len, uint8_t* au8_data) {
640  au8_outCharData = au8_data;
641  st_outCharLen = u_len;
642  sendVar(u8_index);
643  ASSERT(st_outCharIndex == st_outCharLen);
644 }
645 
646 /// Send a one-byte variable
648  // Set up index 0 for 1 byte of data
649  setupXferData(0, 1);
650  // Assign data
651  xferVar[0].pu8_data[0] = 0;
652  // Expected transmission
653  uint8_t au8_data[3] = { CMD_TOKEN, 0x00, 0x00 };
654  checkSendVar(0, 3, au8_data);
655 }
656 
657 /// Send a one-byte variable that needs to be escaped
659  // Set up index 0 for 1 byte of data
660  setupXferData(0, 1);
661  // Assign data
662  xferVar[0].pu8_data[0] = CMD_TOKEN;
663  // Expected transmission
664  uint8_t au8_data[4] = { CMD_TOKEN, 0, CMD_TOKEN, ESCAPED_CMD };
665  checkSendVar(0, 4, au8_data);
666 }
667 
668 /// Send a four-byte variable
670  // Set up index 0 for 4 bytes of data
671  setupXferData(0, 4);
672  // Assign data
673  uint u_i;
674  for (u_i = 0; u_i < 4; u_i++)
675  xferVar[0].pu8_data[u_i] = u_i;
676  // Expected transmission
677  uint8_t au8_data[6] = { CMD_TOKEN, 0x03, 0x00, 0x01, 0x02, 0x03 };
678  checkSendVar(0, 6, au8_data);
679 }
680 
681 /// Send a 256-byte variable
683  // Set up index 0 for 256 bytes of data
684  setupXferData(0, 256);
685  // Assign data
686  uint u_i;
687  for (u_i = 0; u_i < 256; u_i++)
688  xferVar[0].pu8_data[u_i] = u_i;
689  // Expected transmission
690  uint8_t au8_data[261] = { CMD_TOKEN, CMD_LONG_VAR, 0x00, 0xFF };
691  // Do horrible casts (to 8 bit, then to uint) to avoid sign-extension
692  // problems that make this loop run too far (0xAA < 0, without a cast
693  // is sign-extended to 0xFFFFFFAA, which is a *NOT* 0x00AA).
694  for (u_i = 0; u_i <= ((uint) ((uint8_t) CMD_TOKEN)); u_i++)
695  au8_data[u_i + 4] = u_i;
696  au8_data[u_i + 4] = ESCAPED_CMD;
697  for (; u_i < 256; u_i++)
698  au8_data[u_i + 5] = u_i;
699  checkSendVar(0, 261, au8_data);
700 }
701 
702 /// Specify an index that's too high
704  // Dummy buffer to hold variable data
705  uint8_t au8_buf[1];
706  REQUIRE_ASSERT(specifyVar(NUM_XFER_VARS + 1, au8_buf, 1, TRUE, "", "", ""),
707  "specifyVar:indexTooHigh");
708 }
709 
710 /// Specify with NULL data
712  REQUIRE_ASSERT(specifyVar(0, NULL, 1, TRUE, "", "", ""),
713  "specifyVar:nullData");
714 }
715 
716 /// Specify with an invalid size
718  // Dummy buffer to hold variable data
719  uint8_t au8_buf[1];
720  REQUIRE_ASSERT(specifyVar(0, au8_buf, 0, TRUE, "", "", ""),
721  "specifyVar:invalidSize");
722  REQUIRE_ASSERT(specifyVar(0, au8_buf, 257, TRUE, "", "", ""),
723  "specifyVar:invalidSize");
724 }
725 
726 /// Minimally specify a variable
728  // Dummy buffer to hold variable data
729  uint8_t au8_buf[1];
730  // Expected transmission
731  uint8_t au8_data[5 + 3] = { CMD_TOKEN, CMD_SEND_RECEIVE_VAR, 0 /* u_varIndex */,
732  3 /* length of rest - 1 */, /* var size - 1 */ 0, /* data */ 0, 0, 0
733  };
734  // Test it out
735  au8_outCharData = au8_data;
736  st_outCharLen = 8;
737  specifyVar(0 /* u_varIndex */, au8_buf, 1 /* u_size */,
738  TRUE /* b_isWriteable */, "", "", "");
739  ASSERT(st_outCharIndex == st_outCharLen);
740  // Make sure data structure was updated
741  ASSERT(xferVar[0].pu8_data == au8_buf);
742  ASSERT(xferVar[0].u8_size == 0);
744 }
745 
746 /// Test specifying a var with a format string which exceeds the max length.
747 /// Also check a send-only variable.
749  // Dummy buffer to hold variable data
750  uint8_t au8_buf[1];
751  // Expected transmission
752  uint8_t au8_data[5 + 256] = { CMD_TOKEN, CMD_SEND_ONLY, 0 /* u_varIndex */,
753  255 /* length of rest - 1 */, /* var size - 1 */ 0, /* data -- filled in below */
754  };
755  uint u_i;
756  for (u_i = 5; u_i < 5 + 256; u_i++)
757  au8_data[u_i] = ' ';
758 
759  // Test it out
760  au8_outCharData = au8_data;
761  st_outCharLen = 5 + 256;
762  specifyVar(0 /* u_varIndex */, au8_buf, 1 /* u_size */,
763  FALSE /* b_isWriteable */, // a looong format string
764  " "
765  " "
766  " "
767  " "
768  " ",
769  "", "");
770  ASSERT(st_outCharIndex == st_outCharLen);
771  // Make sure data structure was updated
772  ASSERT(xferVar[0].pu8_data == au8_buf);
773  ASSERT(xferVar[0].u8_size == 0);
774  ASSERT(!isVarWriteable(0));
775 }
776 
777 /// Test specifying a var with a name string which exceeds the max length.
778 /// Also check a send-only variable.
780  // Dummy buffer to hold variable data
781  uint8_t au8_buf[1];
782  // Expected transmission
783  uint8_t au8_data[5 + 256] = { CMD_TOKEN, CMD_SEND_ONLY, 0 /* u_varIndex */,
784  255 /* length of rest - 1 */, /* var size - 1 */ 0, /* data -- filled in below */ 0
785  };
786  uint u_i;
787  for (u_i = 6; u_i < 6 + 256; u_i++)
788  au8_data[u_i] = ' ';
789 
790  // Test it out
791  au8_outCharData = au8_data;
792  st_outCharLen = 5 + 256;
793  specifyVar(0 /* u_varIndex */, au8_buf, 1 /* u_size */,
794  FALSE /* b_isWriteable */, "", // a looong name string
795  " "
796  " "
797  " "
798  " "
799  " ",
800  "");
801  ASSERT(st_outCharIndex == st_outCharLen);
802  // Make sure data structure was updated
803  ASSERT(xferVar[0].pu8_data == au8_buf);
804  ASSERT(xferVar[0].u8_size == 0);
805  ASSERT(!isVarWriteable(0));
806 }
807 
808 /// Test specifying a var with a description string which exceeds the max length.
809 /// Also check a send-only variable.
811  // Dummy buffer to hold variable data
812  uint8_t au8_buf[1];
813  // Expected transmission
814  uint8_t au8_data[5 + 256] = { CMD_TOKEN, CMD_SEND_ONLY, 0 /* u_varIndex */,
815  255 /* length of rest - 1 */, /* var size - 1 */ 0, /* data -- filled in below */ 0, 0
816  };
817  uint u_i;
818  for (u_i = 7; u_i < 7 + 256; u_i++)
819  au8_data[u_i] = ' ';
820 
821  // Test it out
822  au8_outCharData = au8_data;
823  st_outCharLen = 5 + 256;
824  specifyVar(0 /* u_varIndex */, au8_buf, 1 /* u_size */,
825  FALSE /* b_isWriteable */, "", "", // a looong description string
826  " "
827  " "
828  " "
829  " "
830  " ");
831  ASSERT(st_outCharIndex == st_outCharLen);
832  // Make sure data structure was updated
833  ASSERT(xferVar[0].pu8_data == au8_buf);
834  ASSERT(xferVar[0].u8_size == 0);
835  ASSERT(!isVarWriteable(0));
836 }
837 
838 /// Send to a index that's too high
840  char psz_buf[200];
841  REQUIRE_ASSERT(formatVar(NUM_XFER_VARS + 1, psz_buf), "formatVar:indexTooHigh");
842 }
843 
844 /// Send to an unconfigured index
846  char psz_buf[200];
847  REQUIRE_ASSERT(formatVar(0, psz_buf), "formatVar:indexNotSpecified");
848 }
849 
850 //@}
851 
852 /// A list of functions which comprise tests to be run,
853 /// terminated with a NULL.
854 void (*afp_testList[])() = {
855  findChar,
857  findCommand,
861  sendLetter,
862  send0x00,
863  send0xFF,
879  sendLongData, // FAIL - crashes xUnit
883 #ifdef __PIC__
884  sendReadOnly,
885  sendVarSpecPic,
886 #else
887  sendVarSpec,
897 #endif
908  NULL
909 };
910 
911 
912 /// Execute one test. This resets the state machines before a run to
913 /// create a clean slate for every test.
914 /// \param u_index Index of test to run. NO BOUNDS CHECKING is performed
915 /// on this index. Be careful.
917  initDataXfer();
918  clearOutChar();
919  (afp_testList[u_index])(); // Execute the specified test
920 }
921 
922 /// Run all the tests by executing everything in the list of tests.
923 void runAllTests() {
924  uint u_index;
925  for (u_index = 0; afp_testList[u_index] != NULL; u_index++) {
926  printf("Running test %d...", u_index + 1);
927  runTest(u_index);
928  printf("success.\n");
929  }
930  printf("All %d tests passed.\n", u_index);
931 }