This package contains a simple test of tests for various elements of the SmartBoard hardware, which is a simple baseboard designed for easy embedding. It is able to run both a semi-automatic test suite as well as allow interactive testing.

Dependencies:   EthernetNetIf NTPClient_NetServices mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SmartBoard_Tester.cpp Source File

SmartBoard_Tester.cpp

Go to the documentation of this file.
00001 /// @file SmartBoard_Tester.cpp is the simple test framework
00002 ///
00003 /// This file contains the startup, interactive, and test code
00004 /// to evaluate the SmartBoard baseboard.
00005 ///
00006 /// @note Copyright © 2011 by Smartware Computing, all rights reserved.
00007 ///     This software may be used to derive new software, as long as
00008 ///     this copyright statement remains in the source file.
00009 /// @author David Smart
00010 ///
00011 #include "mbed.h"
00012 #include "SmartBoard.h"
00013 #include "ShowTime.h"
00014 #include "EthernetNetIf.h"
00015 #include "NTPClient.h"
00016 #include "SDFileSystem.h"
00017 #include "MSCFileSystem.h"
00018 #include "Watchdog.h"
00019 
00020 extern "C" void HardFault_Handler() {
00021     printf("Hard Fault!\n");
00022     while (1);
00023 }
00024 
00025 Watchdog wdt;
00026 
00027 Serial pc(USBTX, USBRX);    ///!< Used as the console for interactively reporting progress
00028 
00029 const char * TicTocServer = "ntp.okstate.edu";  ///!< time server since it is closer than "0.uk.pool.ntp.org"
00030 const int tzOffsetHr = -6;      ///!< time zone offset hours to print time in local time
00031 const int tzOffsetMin = 0;      ///!< time zone offset minutes to print time in local time
00032 
00033 void LED_Tests(void);
00034 void PWM_Tests(void);
00035 void AnalogIn_Tests(void);
00036 void RTC_Tests(void);
00037 void RTC_Set(void);
00038 void MicroSD_Tests(void);
00039 void RS_232_Tests(void);
00040 void CAN_Tests(void);
00041 void Ethernet_Tests(void);
00042 void USBHost_Tests(void);
00043 void FileSystem_Tests(void);
00044 
00045 /// TestVector will execute a given test, based on the parameter
00046 ///
00047 /// It can show the list of available commands, as for an interactive
00048 /// test session, or it can simply execute the chosen test. This is
00049 /// used for both the automated testing and the interactive testing,
00050 /// so a couple of the commands for interactive would not be used
00051 /// for the automated testing.
00052 /// '?' causes it to display the available commands.
00053 ///
00054 /// @param i contains the single character value indicating the operation
00055 ///         to perform.
00056 /// @returns false if the input paramter was 'X'.
00057 /// @returns true if the input parameters was not 'X'.
00058 ///
00059 bool TestVector(int i) {
00060     bool r = true;  ///!< expect to return true
00061 
00062     switch (i) {
00063         default:
00064         case '?':
00065             pc.printf("Commands:\r\n"
00066                       "  L   LED_Tests();          // Blink each in turn\r\n"
00067                       "  P   PWM_Tests();          // Ramps the PWM channels\r\n"
00068                       "  A   AnalogIn_Tests();     // Measures voltage on each\r\n"
00069                       "  R   RTC_Tests();          // Saves current time, alters it, restores it\r\n"
00070                       "  M   MicroSD_Tests();      // Writes and Reads file on an installed card\r\n"
00071                       "  S   RS_232_Tests();       // Outputs simple text\r\n"
00072                       "  C   CAN_Tests();          // Requires CAN1 wired to CAN2, loops messages\r\n"
00073                       "  E   Ethernet_Tests();     // Sets the clock from a time server\r\n"
00074                       "  U   USBHost_Tests();      // Writes and Reads file on a memory stick\r\n"
00075                       "  F   FileSystems_Tests();  // Writes and Reads file on internal file system\r\n"
00076                       "  X   eXit to automatic testing\r\n");
00077             break;
00078         case 'X':
00079             r = false;
00080             break;
00081         case 'L':
00082             LED_Tests();
00083             break;
00084         case 'P':
00085             PWM_Tests();
00086             break;
00087         case 'A':
00088             AnalogIn_Tests();
00089             break;
00090         case 'R':
00091             RTC_Tests();
00092             break;
00093         case 'r':
00094             RTC_Set();
00095             break;
00096         case 'M':
00097             MicroSD_Tests();
00098             break;
00099         case 'S':
00100             RS_232_Tests();
00101             break;
00102         case 'C':
00103             CAN_Tests();
00104             break;
00105         case 'E':
00106             Ethernet_Tests();
00107             break;
00108         case 'U':
00109             USBHost_Tests();
00110             break;
00111         case 'F':
00112             FileSystem_Tests();
00113             break;
00114     }
00115     return r;
00116 }
00117 
00118 /// main is the main startup code.
00119 ///
00120 /// This initializes the test environment, shows a banner,
00121 /// and starts the automated testing.
00122 /// It also detects if the user is attempting to interact, and
00123 /// between each test category there is the possibility to transfer
00124 /// to the interactive test mode.
00125 /// When in interactive test mode, the user determines which test
00126 /// to run. The user can also exit interactive mode back to the
00127 /// automated test mode.
00128 ///
00129 /// @returns never
00130 ///
00131 int main() {
00132     bool init = true;                   ///!< init is slightly different
00133     bool interactive = false;           ///!< track when in interactive mode
00134     int test = 0;                       ///!< which test to run
00135     char TestList[] = "XLPARrMSCEU";    ///!< list of valid test commands AUTOTESTS are uppercase
00136 
00137     pc.printf("Set your baudrate from 9600 to 921600\r\n");
00138     pc.baud(921600);
00139     if (wdt.WatchdogCausedReset())
00140         pc.printf("Watchdog caused reset. WD is armed for 30s cycle.\r\n");
00141 
00142     wdt.Configure(30.0);     // longest test should be under this interval
00143 
00144     wait(3.0);  // just wait a little while in case they want to inject a '?'
00145     while (1) {
00146         wdt.Service();     // do this often enough
00147 
00148         if (pc.readable() || init) {
00149             pc.printf("\r\n\r\n");
00150             pc.printf("SmartBoard Hardware Tester [" __DATE__ " " __TIME__ "]\r\n");
00151             pc.printf("  SmartBoard Hardware                    v0.05\r\n");
00152             pc.printf("  SmartBoard Software                    v0.13\r\n");
00153             pc.printf("\r\n");
00154             pc.printf("                      [USB]       [Eth/USB]    \r\n");
00155             pc.printf(" +---------------+------------+---+-------+---+\r\n");
00156             pc.printf(" |O [RS232 1-2]  |  |       | |   |       |  O|\r\n");
00157             pc.printf(" |               |  |microSD| |   |       |   |\r\n");
00158             pc.printf(" |S              |  |       | |   |       |  C|\r\n");
00159             pc.printf(" |P              |  +-------+ |   |       |  A|\r\n");
00160             pc.printf(" |I              |            |   |Yl   Gr|  N|\r\n");
00161             pc.printf(" |1              |            |   +-------+  1|\r\n");
00162             pc.printf(" |-              |            |              -|\r\n");
00163             pc.printf(" |2              |     RTC    |              2|\r\n");
00164             pc.printf(" |               |  (Battery) |               |\r\n");
00165             pc.printf(" |               |            |               |\r\n");
00166             pc.printf(" |               | 1  2  3  4 |               |\r\n");
00167             pc.printf(" |               +------------+               |\r\n");
00168             pc.printf(" |O[Analog In ]        O        [PWM Out]    O|\r\n");
00169             pc.printf(" +--------------------------------------------+\r\n");
00170             pc.printf("\r\n");
00171             init = false;
00172         }
00173         if (pc.readable()) {
00174             interactive = true;
00175             while (pc.readable())
00176                 (void)pc.getc();
00177 
00178             while (interactive) {
00179                 wdt.Service();     // do this often enough
00180                 pc.printf("> ");
00181                 while (!pc.readable())
00182                     wdt.Service();
00183                 int i = pc.getc();
00184                 pc.putc(i);
00185                 pc.putc('\r');
00186                 pc.putc('\n');
00187                 interactive = TestVector(i);
00188             }
00189         } else {
00190             if (test == 0)
00191                 pc.printf("\x07"); // Bell character indicating start of tests
00192             if (TestList[test] >= 'A' && TestList[test] <= 'Z') // Tests are UPPER-case only
00193                 TestVector(TestList[test]);
00194             test++;
00195             if (TestList[test] == '\0')
00196                 test = 0;
00197             wait(5.0);  // Extra pause
00198         }
00199     }
00200 }
00201 
00202 /// LED_Tests performs some simple digital output to the
00203 /// LEDs.
00204 ///
00205 /// It will attempt to exercise the LEDs on the Ethernet ports
00206 /// as well, but by jumper configuration these may not be available.
00207 ///
00208 void LED_Tests(void) {
00209     int l;
00210     int i;
00211     struct {
00212         const char * name;
00213         DigitalOut led;
00214     } Leds[] = {
00215         {"Ethernet Green", ETHERGREEN},
00216         {"Ethernet Yellow", ETHERYELLOW},
00217         {"Led 1", LED1},
00218         {"Led 2", LED2},
00219         {"Led 3", LED3},
00220         {"Led 4", LED4}
00221     };
00222     const int numLeds = sizeof(Leds) / sizeof(Leds[0]);
00223 
00224     printf("LED Test:\r\n");
00225     for (l=0; l<numLeds; l++) {
00226         wdt.Service();
00227         printf("    Blink %s LED 3 times\r\n", Leds[l].name);
00228         for (i=0; i<3; i++) {
00229             Leds[l].led = true;
00230             wait(0.4);
00231             Leds[l].led = false;
00232             wait(0.4);
00233         }
00234     }
00235 }
00236 
00237 /// PWM_Tests performs some simple pwm output to the
00238 /// PWM channels and the LEDs.
00239 ///
00240 /// It will attempt to exercise the outputs with a simple ramping
00241 /// signal, but by jumper configuration these may not be available.
00242 ///
00243 void PWM_Tests(void) {
00244     int l;
00245     int i;
00246     float f;
00247     struct {
00248         const char * name;
00249         PwmOut pwm;
00250     } Pwms[] = {
00251         {"PWM 1", p21},
00252         {"PWM 2", p22},
00253         {"PWM 3", p23},
00254         {"PWM 4", p24},
00255         {"PWM 5", p25},
00256         {"PWM 6", p26},
00257         {"Led 1", LED1},
00258         {"Led 2", LED2},
00259         {"Led 3", LED3},
00260         {"Led 4", LED4}
00261     };
00262     const int numPwms = sizeof(Pwms) / sizeof(Pwms[0]);
00263 
00264     printf("PWM Test:\r\n");
00265     for (l=0; l<numPwms; l++) {
00266         wdt.Service();
00267         printf("    Ramp %s PWM 3 times\r\n", Pwms[l].name);
00268         for (i=0; i<3; i++) {
00269             for (f=0.0; f<=1.0; f+= 0.1) {
00270                 Pwms[l].pwm = f;
00271                 wait(0.1);
00272             }
00273         }
00274         Pwms[l].pwm = 0;    // off when done
00275     }
00276 }
00277 
00278 /// AnalogIn_Tests takes a few sample measurements on each channel
00279 ///
00280 /// It samples each channel a number of times and presents the
00281 /// converted results on the console.
00282 ///
00283 void AnalogIn_Tests(void) {
00284     int l;
00285     int i;
00286     const int samples = 20;
00287     struct {
00288         const char * name;
00289         AnalogIn in;
00290     } Analogs[] = {
00291         {"Ain 1", p15},
00292         {"Ain 2", p16},
00293         {"Ain 3", p17},
00294         {"Ain 4", p18},
00295         {"Ain 5", p19},
00296         {"Ain 6", p20}
00297     };
00298     const int numAnalogs = sizeof(Analogs) / sizeof(Analogs[0]);
00299 
00300     printf("Analog Test:\r\n");
00301     for (l=0; l<numAnalogs; l++) {
00302         wdt.Service();
00303         for (i=0; i<samples; i++) {
00304             uint16_t raw = Analogs[l].in.read_u16();
00305             float flt = Analogs[l].in.read();
00306             printf("    Analog %i is %04X, %3.2f, %3.2fv\r", l, raw, flt, flt*3.3);
00307             wait(0.1);
00308         }
00309         printf("\n");
00310     }
00311 }
00312 
00313 /// RTC_Tests will perform simple tests on the Real Time Clock
00314 ///
00315 /// It will first sample the time from the RTC and later restore
00316 /// it as best it can.
00317 /// In the middle of that it will set the clock, then simply show
00318 /// the time once per second for 5 seconds. After this it
00319 /// will restore the clock at best it can.
00320 ///
00321 void RTC_Tests(void) {
00322     time_t x;
00323     int i;
00324     const int oldTime = 1256729737;
00325 
00326     printf("RTC Test:\r\n");
00327     ShowTime(tzOffsetHr, tzOffsetMin);
00328     x = time(NULL);         // Save the time before the test
00329     printf("    Saving current time(%d)\r\n", x);
00330 
00331     set_time(oldTime);  // Set RTC time to Wed, 28 Oct 2009 11:35:37
00332     printf("    Set time to Wed, 28 Oct 2009 11:35:37\r\n");
00333 
00334     for (i=0; i<5; i++) {
00335         ShowTime();
00336         wait(1.0);
00337     }
00338     set_time(x + time(NULL) - 1256729737);          // Approximately restored
00339     ShowTime(tzOffsetHr, tzOffsetMin);
00340     wait(1.0);
00341     ShowTime(tzOffsetHr, tzOffsetMin);
00342 }
00343 
00344 /// GetNumber will get from the user a number using the
00345 /// specified number of digits.
00346 ///
00347 /// They can enter a number from 0 to 10^(digits-1)
00348 ///
00349 /// @param digits is the number of digits to enter
00350 /// @param pValue is a pointer to where to store the result
00351 /// @returns true if a number was entered
00352 /// @returns false if they entered a non-digit
00353 ///
00354 int GetNumber(int digits, int * pValue) {
00355     int tempValue = 0;
00356     int i;
00357 
00358     while (digits--) {
00359         while (!pc.readable())
00360             wdt.Service();
00361         i = pc.getc();
00362         if (i == ' ') i = '0';      // special case for leading blank
00363         if (i >= '0' && i <= '9') {
00364             pc.putc(i);
00365             tempValue = tempValue * 10 + (i - '0');
00366         } else
00367             return false;
00368     }
00369     *pValue = tempValue;
00370     return true;
00371 }
00372 
00373 /// RTC_Set will interactively set the Real Time Clock
00374 ///
00375 /// It will allow you to enter the date and time information
00376 /// and then create a timestamp. After this, it will set
00377 /// the RTC to that timestamp.
00378 ///
00379 void RTC_Set(void) {
00380     time_t seconds = time(NULL);
00381     struct tm *t = localtime(&seconds);
00382     int i;
00383 
00384     pc.printf("RTC Set:\r\n");
00385     ShowTime(seconds, tzOffsetHr, tzOffsetMin);
00386     pc.printf("    Enter the time MM/DD/YYYY HH:MM:SS\r\n");
00387     while (1) {
00388         int _m, _d, _y, _H, _M, _S;
00389         printf("                 > ");
00390         if (GetNumber(2, &_m)) {
00391             pc.putc('/');
00392             if (!GetNumber(2, &_d))
00393                 continue;
00394             pc.putc('/');
00395             if (!GetNumber(4, &_y))
00396                 continue;
00397             t->tm_mon = _m - 1;
00398             t->tm_mday = _d;
00399             t->tm_year = _y - 1900;
00400         } else {
00401             pc.printf("%02d/%02d/%04d", t->tm_mon+1, t->tm_mday, t->tm_year+1900);
00402         }
00403         pc.putc(' ');
00404         if (GetNumber(2, &_H)) {
00405             pc.putc(':');
00406             if (!GetNumber(2, &_M))
00407                 continue;
00408             pc.putc(':');
00409             if (!GetNumber(2, &_S))
00410                 continue;
00411             t->tm_hour = _H;
00412             t->tm_min = _M;
00413             t->tm_sec = _S;
00414             pc.printf("\r\n");
00415             pc.printf("%02d/%02d/%04d ", t->tm_mon+1, t->tm_mday, t->tm_year+1900);
00416             pc.printf("%02d:%02d:%02d\r\n", t->tm_hour, t->tm_min, t->tm_sec);
00417             // convert to timestamp and display (1256729737)
00418             time_t seconds = mktime(t);
00419             seconds = seconds - (time_t)(tzOffsetHr * 3600 + tzOffsetMin * 60);
00420             set_time(seconds);
00421             break;
00422         } else {
00423             pc.printf("%02d:%02d:%02d\r\n", t->tm_hour, t->tm_min, t->tm_sec);
00424             break;          // they can bail here
00425         }
00426     }
00427     for (i=0; i<5; i++) {
00428         ShowTime(tzOffsetHr, tzOffsetMin);
00429         wait(1.0);
00430     }
00431 }
00432 
00433 
00434 /// Ethernet_Tests will attempt to test the Ethernet interface
00435 ///
00436 /// It will connect to the network - if possible, then it will
00437 /// try to connect to a network time server and set the clock,
00438 /// using hard coded time server and time zone offset values.
00439 ///
00440 /// It appears that the Ethernet interface cannot be instantiated,
00441 /// destroyed, and later instantiated again (it would reliably "hang").
00442 /// So, this test is "runonce" protected.
00443 ///
00444 void Ethernet_Tests(void) {
00445     EthernetNetIf eth;
00446     NTPClient ntp;
00447     static bool runonce = true;
00448 
00449     printf("Ethernet Test:\r\n");
00450     if (runonce) {
00451         EthernetErr ethErr = eth.setup();
00452         if (ethErr) {
00453             printf("Error %d in setup.\r\n", ethErr);
00454             return;
00455         }
00456         printf("    Ethernet Setup OK\r\n");
00457         ShowTime(0, tzOffsetHr, tzOffsetMin);
00458         printf("    Setting clock to %s\r\n", TicTocServer);
00459         Host server(IpAddr(), 123, TicTocServer);
00460         ntp.setTime(server);
00461         printf("    Clock was set.\r\n");
00462         wait(1.0);
00463         ShowTime(0, tzOffsetHr, tzOffsetMin);
00464         runonce = false;
00465     } else {
00466         printf("   only runs once per cold-boot.\r\n");
00467     }
00468 }
00469 
00470 /// isPrint tests the passed in character for being 'printable'
00471 ///
00472 /// It will evaluate the character on a simple ASCII range of
00473 /// characters 0 to 127.
00474 ///
00475 /// @param i is the character to test
00476 /// @returns true if the character is in the printable set (including <space>)
00477 /// @returns false if the character is not printable (may be control code or extended character)
00478 ///
00479 bool isPrint(char i) {
00480     if (i >= ' ' && i <= '~')
00481         return true;
00482     else
00483         return false;
00484 }
00485 
00486 /// common file system test to write and then read a moderately large file
00487 ///
00488 /// This will create a folder and then open a file for write. It will write a
00489 /// text string to the file and defined number of times and close the file.
00490 /// It will then report the performance metrics in bytes/sec write.
00491 /// It will then open the same file for read and read the file back, one record
00492 /// at a time. It will then report the performance metrics for the read in bytes/sec.
00493 ///
00494 /// @param folder is the folder name to create
00495 /// @param file is the filename to create
00496 /// @param textMessage is the text message to use in the test
00497 /// @param COUNTLIMIT is the number of times the text is written to the file
00498 /// @returns nothing
00499 ///
00500 void RunFileSystemTest(const char * folder, const char * file, const char * textMessage, int COUNTLIMIT) {
00501     FILE *fp;
00502     Timer timer;
00503     char * buffer = (char *)malloc(strlen(textMessage)+2);  // just a bit bigger
00504 
00505     if (strlen(folder))
00506         mkdir(folder, 0777);
00507     // Write test
00508     printf("    Starting write test of %i chars.\r\n", strlen(textMessage) * COUNTLIMIT);
00509     int begin = timer.read_us();
00510     fp = fopen(file, "w");
00511     if (fp == NULL) {
00512         printf("    Could not open file for write\r\n");
00513     } else {
00514         int counter;
00515         for (counter=0; counter<COUNTLIMIT; counter++) {
00516             fprintf(fp, textMessage);
00517         }
00518         fclose(fp);
00519         int end = timer.read_us();
00520         printf("    Closed file. Wrote %i chars in %i uSec.\r\n",
00521                strlen(textMessage) * COUNTLIMIT,
00522                end - begin);
00523         printf("        %6.0f bytes/sec.\r\n",
00524                1.0e6f * (float)(strlen(textMessage) * COUNTLIMIT) / (end - begin));
00525 
00526         // read test
00527         printf("    Read test.\r\n");
00528         begin = timer.read_us();
00529         fp = fopen(file, "r");
00530         if (fp == NULL) {
00531             printf("    could not open file for read\r\n");
00532         } else {
00533             while (fgets(buffer, sizeof(buffer), fp)) {
00534                 while (strlen(buffer) > 0 && !isPrint(buffer[strlen(buffer)-1]))
00535                     buffer[strlen(buffer)-1] = '\0';    // chomp the <LF>
00536                 //printf("    Read: {%s}\r\n", buffer);
00537             }
00538             fclose(fp);
00539             end = timer.read_us();
00540             printf("    Closed file. Read %i chars in %i uSec.\r\n",
00541                    strlen(textMessage) * COUNTLIMIT,
00542                    end - begin);
00543             printf("        %6.0f bytes/sec.\r\n",
00544                    1.0e6f * (float)(strlen(textMessage) * COUNTLIMIT) / (end - begin));
00545         }
00546     }
00547     free(buffer);
00548 }
00549 
00550 
00551 
00552 
00553 /// MicroSD_Tests attempts to access and write a file on the micro SD card
00554 ///
00555 /// It will mount the file system, then attempt to write a simple
00556 /// file on the micro SD card.
00557 ///
00558 void MicroSD_Tests(void) {
00559     SDFileSystem sd(p5, p6, p7, p8, "ud"); // the pinout on the mbed Cool Components workshop board
00560     char folder[] = "/ud/testDir";
00561     char file[] = "/ud/testDir/sdtest.txt";
00562     DigitalIn cardIn(p11);
00563     const int COUNTLIMIT = 10000;
00564     const char textMessage[] = "Write a message to the micro SD card!   50 chars\r\n";
00565 
00566     printf("SD File System Tests: [installed microSD card required]\r\n");
00567     printf("    Card Detection: %s\r\n", (cardIn) ? "in" : "out");
00568     if (cardIn) {
00569         RunFileSystemTest(folder, file, textMessage, COUNTLIMIT);
00570     }
00571     printf("    test complete!\r\n");
00572 }
00573 
00574 /// USBHost_Tests attempts to access and write a file on USB stick
00575 ///
00576 /// It will mount the file system, then attempt to write a simple
00577 /// file on the USB interface.
00578 ///
00579 void USBHost_Tests(void) {
00580     MSCFileSystem fs ("fs");
00581     char folder[] = "/fs/testDir";
00582     char file[] = "/fs/testDir/sdtest.txt";
00583     const int COUNTLIMIT = 10000;
00584     const char textMessage[] = "Write a message to the USB Memory stick 50 chars\r\n";
00585 
00586     printf("USB Host Tests: [installed memory stick required]\r\n");
00587     RunFileSystemTest(folder, file, textMessage, COUNTLIMIT);
00588     printf("    test complete!\r\n");
00589 }
00590 
00591 
00592 /// FileSystem_Tests attempts to access and write a file on the local file system
00593 ///
00594 /// It will mount the file system, then attempt to write a simple
00595 /// file on the interface. While file handles are open, the USB drive will
00596 /// be unavailable.
00597 ///
00598 void FileSystem_Tests(void) {
00599     LocalFileSystem local("local");
00600     char folder[] = "";
00601     char file[] = "/local/fstest.txt";
00602     const int COUNTLIMIT = 10000;
00603     const char textMessage[] = "Write a message to the Local Files      50 chars\r\n";
00604 
00605     printf("Local File System Tests: [mbed onboard file system]\r\n");
00606     RunFileSystemTest(folder, file, textMessage, COUNTLIMIT);
00607     printf("    test complete!\r\n");
00608 }
00609 
00610 
00611 
00612 /// FormatMicroseconds will format a number of microseconds int ascii seconds.
00613 ///
00614 /// It will support formatting the number with decimal and thousands
00615 /// separators.
00616 ///
00617 /// @param value to format
00618 /// @returns the formatted string "0034.123456"
00619 ///
00620 char * FormatMicroseconds(int value) {
00621     static char result[15] = "";
00622     int uSec = value % 1000000;
00623     int Sec = value / 1000000;
00624 
00625     sprintf(result, "%04i.%06i", Sec, uSec);
00626     return result;
00627 }
00628 
00629 
00630 /// ShowCANMessage will print to the console as specified
00631 ///
00632 /// This format is used in other tools, and is not explained
00633 /// here beyond what you see
00634 ///
00635 /// +--- 'r'eceive or 't'ransmit
00636 /// |  +--- 'nrm' 11 bit identifier, 'xtd' 29 bit identifier
00637 /// |  |  +--- channel '1' to '2'
00638 /// |  |  |     +--- identifier in hex
00639 /// |  |  |     |     +-- dlc - data length control
00640 /// |  |  |     |     |  +--------------------+  data bytes 1 to 8
00641 /// |  |  |     |     |            |            +--- fixed zero for compatibility with other tools
00642 /// |  |  |     |     |            |            |   +-- fixed zero for compat
00643 /// |  |  |     |     |            |            |   |    +--- timestamp
00644 /// |  |  |     |     |            |            |   |    |
00645 /// _ ___ _ ________ __ _______________________ _ ___ ___________
00646 /// r xtd 2 1CF00400 08 11 22 33 44 55 66 77 88 0   0 1234.567890
00647 /// t xtd 1 18EAFF03 03 EE EE 00                0   0 1235.654321
00648 ///
00649 /// @param tx indicates it is a transmit message when non-zero, receive otherwise
00650 /// @param ch is the communication channel of this message
00651 /// @msg is the CAN message to be shown
00652 /// @uSec is the timestamp in microseconds
00653 /// @returns nothing
00654 ///
00655 void ShowCANMessage(int tx, int ch, CANMessage msg, int uSec) {
00656     pc.printf("%c %s %d %08X %02X ",
00657               (tx) ? 't' : 'r',
00658               (msg.format == CANExtended) ? "xtd" : "nrm", ch, msg.id, msg.len);
00659     for (int d=0; d<8; d++) {
00660         if (d < msg.len)
00661             pc.printf("%02X ", msg.data[d]);
00662         else
00663             pc.printf("   ");
00664     }
00665     pc.printf("0   0 %s\r\n", FormatMicroseconds(uSec));
00666 }
00667 
00668 
00669 /// CAN_Tests will send some packets on one CAN port and expect them on the other
00670 ///
00671 /// It will attempt to send 10 messages on one port and expect that
00672 /// all 10 messages were received on the other port. The two ports should
00673 /// be wired from one to the other with a loop-back cable and a termination
00674 /// resistor.
00675 ///
00676 void CAN_Tests(void) {
00677     CAN can1(p9, p10);
00678     CAN can2(p30, p29);
00679     char Txcounter = 0;
00680     char Rxcounter = 0;
00681     CANMessage tMsg;
00682     CANMessage rMsg;
00683     Timer timer;
00684     int i;
00685 
00686     pc.printf("CAN Tests:\r\n");
00687     i = can1.frequency(250000);
00688     pc.printf("    can1 frequency set: %i\r\n", i);
00689     i = can2.frequency(250000);
00690     pc.printf("    can2 frequency set: %i\r\n", i);
00691     timer.start();
00692     for (i=0; i<25; i++) {  // gets a few more passes to receive the messages
00693 
00694         for (int x=0; x<8; x++)
00695             tMsg.data[x] = (char)(rand());
00696         tMsg.data[0] = Txcounter;
00697         tMsg.id = rand();
00698         tMsg.len = rand() % 9;
00699         tMsg.type = CANData;
00700         tMsg.format  = (rand() & 1) ? CANExtended : CANStandard;
00701 
00702         if (Txcounter < 10 && can1.write(tMsg)) {
00703             pc.printf("    ");
00704             ShowCANMessage(1, 1, tMsg, timer.read_us());
00705             Txcounter++;
00706             //wait(0.05);
00707         }
00708         if (can2.read(rMsg)) {
00709             Rxcounter++;
00710             pc.printf("    ");
00711             ShowCANMessage(0, 2, rMsg, timer.read_us());
00712         }
00713         wait(0.005);
00714     }
00715     if (Txcounter == Rxcounter)
00716         printf("    passed.\r\n");
00717     else
00718         printf("    **** Txcounter (%d) != Rxcounter (%d) ****\r\n", Txcounter, Rxcounter);
00719 }
00720 
00721 /// RS_232_Tests will say hello on each of the RS-232 channels
00722 ///
00723 /// It will print a hello text string out each of the ports.
00724 ///
00725 void RS_232_Tests(void) {
00726     Serial s1(p13, p14);
00727     Serial s2(p28, p27);
00728 
00729     pc.printf("RS-232 Tests:\r\n");
00730     s1.printf("    Hello going out S1\r\n");
00731     s2.printf("    Hello going out S2\r\n");
00732     pc.printf("    end tests.\r\n");
00733 }