D:/DRISSI/arduino-0022/arduino-0022/libraries/ArduinoTestSuite/ArduinoTestSuite.cpp
00001 //************************************************************************
00002 //*     Arduino Test Suite
00003 //*             (C) 2010 by Mark Sproul
00004 //*             Open source as per standard Arduino code
00005 //*     
00006 //*       This library is free software; you can redistribute it and/or
00007 //*       modify it under the terms of the GNU Lesser General Public
00008 //*       License as published by the Free Software Foundation; either
00009 //*       version 2.1 of the License, or (at your option) any later version.
00010 //*     
00011 //*       This library is distributed in the hope that it will be useful,
00012 //*       but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //*       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 //*       Lesser General Public License for more details.
00015 //************************************************************************
00016 //*     Aug 31, 2010    <MLS> Started on TestArduino
00017 //*     Oct 18, 2010    <MLS> Added memory testing
00018 //************************************************************************
00019 
00020 #include        <avr/pgmspace.h>
00021 #include        <avr/io.h>
00022 #include        <avr/eeprom.h>
00023 
00024 
00025 
00026 #include        "ArduinoTestSuite.h"
00027 
00028 
00029 #include        "WProgram.h"
00030 #include        "HardwareSerial.h"
00031 #include        "pins_arduino.h"
00032 
00033 
00034 #include        "avr_cpunames.h"
00035 
00036 #if defined(USART3_RX_vect)
00037         #define SERIAL_PORT_COUNT               4
00038 #elif  defined(USART1_RX_vect)
00039         #define SERIAL_PORT_COUNT               2
00040 #else
00041         #define SERIAL_PORT_COUNT               1
00042 #endif
00043 
00044 
00045 
00046 
00047 //************************************************************************
00048 enum 
00049 {
00050         ATS_Manufacturer        =       1,
00051         ATS_CPU,
00052         ATS_GCC_version,
00053         ATS_LIBC_version,
00054         ATS_CompiledDate,
00055         ATS_TestSuiteName,
00056         ATS_FreeMemory,
00057         
00058         
00059 };
00060 unsigned long   gTestStartTime;
00061 short                   gTagIndent;
00062 int                             gYotalErrors;
00063 int                             gTestCount;
00064 
00065 
00066 
00067 prog_char       gTextMsg_Manufacturer[]                 PROGMEM =       "MANUFACTURER";
00068 prog_char       gTextMsg_CPUname[]                              PROGMEM =       "CPU-NAME";
00069 prog_char       gTextMsg_GCC_VERSION[]                  PROGMEM =       "GCC-Version";
00070 prog_char       gTextMsg_AVR_LIBC[]                             PROGMEM =       "AVR-LibC-Ver";
00071 prog_char       gTextMsg_COMPILED_DATE[]                PROGMEM =       "Compiled-date";
00072 prog_char       gTextMsg_TEST_SUITE_NAME[]              PROGMEM =       "Test-Suite-Name";
00073 prog_char       gTextMsg_memoryUsage[]                  PROGMEM =       "Free-memory";
00074 prog_char       gTextMsg_dotdotdot[]                    PROGMEM =       "... ";
00075 prog_char       gTextMsg_ok[]                                   PROGMEM =       "ok";
00076 prog_char       gTextMsg_FAIL[]                                 PROGMEM =       "FAIL";
00077 prog_char       gTextMsg_spaceEqual[]                   PROGMEM =       " = ";
00078 prog_char       gTextMsg_info[]                                 PROGMEM =       "info.";
00079 prog_char       gTextMsg_dashLine[]                             PROGMEM =       "--------------------------";
00080 prog_char       gTextMsg_DigitalRW[]                    PROGMEM =       "DigitalReadWrite_";
00081 prog_char       gTextMsg_PWMoutput[]                    PROGMEM =       "PWMoutput_";
00082 prog_char       gTextMsg_AnalogInput[]                  PROGMEM =       "AnalogInput_";
00083 
00084 //************************************************************************
00085 void Serial_print_P(prog_char *flashMemStr)
00086 {
00087 char    theChar;
00088 int             ii;
00089 
00090         ii              =       0;
00091 #if (FLASHEND > 0x10000)
00092         while (theChar  =       pgm_read_byte_far(flashMemStr + ii++))
00093 #else
00094         while (theChar  =       pgm_read_byte_near(flashMemStr + ii++))
00095 #endif
00096         {
00097                 Serial.print(theChar);
00098         }
00099 }
00100 
00101 //************************************************************************
00102 void Serial_println_P(prog_char *flashMemStr)
00103 {
00104         Serial_print_P(flashMemStr);
00105         Serial.println();
00106 }
00107 
00108 //************************************************************************
00109 //*     this is for internal use only, not made pubic to the API
00110 static void     ATS_PrintProperty(      int             propertyTagNum,
00111                                                                 char    *propertyName,
00112                                                                 char    *propertyValue)
00113 {
00114 char    lineBuffer[64];
00115 
00116         strcpy_P(lineBuffer, gTextMsg_info);
00117         switch(propertyTagNum)
00118         {
00119                 case 0:
00120                         strcat(lineBuffer, propertyName);
00121                         break;
00122                         
00123                 case ATS_Manufacturer:
00124                         strcat_P(lineBuffer, gTextMsg_Manufacturer);
00125                         break;
00126 
00127                 case ATS_CPU:
00128                         strcat_P(lineBuffer, gTextMsg_CPUname);
00129                         break;
00130 
00131                 case ATS_GCC_version:
00132                         strcat_P(lineBuffer, gTextMsg_GCC_VERSION);
00133                         break;
00134 
00135                 case ATS_LIBC_version:
00136                         strcat_P(lineBuffer, gTextMsg_AVR_LIBC);
00137                         break;
00138 
00139                 case ATS_CompiledDate:
00140                         strcat_P(lineBuffer, gTextMsg_COMPILED_DATE);
00141                         break;
00142 
00143                 case ATS_TestSuiteName:
00144                         strcat_P(lineBuffer, gTextMsg_TEST_SUITE_NAME);
00145                         break;
00146 
00147                 case ATS_FreeMemory:
00148                         strcat_P(lineBuffer, gTextMsg_memoryUsage);
00149                         break;
00150         }
00151 
00152         while (strlen(lineBuffer) < 20)
00153         {
00154                 strcat(lineBuffer, " ");
00155         }
00156         
00157         strcat_P(lineBuffer, gTextMsg_spaceEqual);
00158         if (propertyValue != 0)
00159         {
00160                 strcat(lineBuffer, propertyValue);
00161         }
00162         Serial.println(lineBuffer);
00163 
00164 }
00165 
00166 
00167 
00168 
00169 //************************************************************************
00170 void    ATS_begin(char *manufName, char *testSuiteName)
00171 {
00172 int             freeMemory;
00173 char    memoryMsg[48];
00174 
00175         gYotalErrors    =       0;
00176         gTestCount              =       0;
00177 
00178         Serial.begin(9600);
00179         delay(1000);
00180         
00181         gTestStartTime  =       millis();
00182 
00183         Serial.println();
00184         Serial.println();
00185         Serial.println();
00186 
00187         ATS_PrintProperty(ATS_Manufacturer,             0,      manufName);
00188         ATS_PrintProperty(ATS_CPU,                              0,      _AVR_CPU_NAME_);
00189         ATS_PrintProperty(ATS_GCC_version,              0,      __VERSION__);
00190         ATS_PrintProperty(ATS_LIBC_version,             0,      __AVR_LIBC_VERSION_STRING__);
00191         ATS_PrintProperty(ATS_CompiledDate,             0,      __DATE__);
00192         ATS_PrintProperty(ATS_TestSuiteName,    0,      testSuiteName);
00193 
00194         freeMemory      =       ATS_GetFreeMemory();
00195         sprintf(memoryMsg, "%d bytes", freeMemory);
00196         ATS_PrintProperty(ATS_FreeMemory,       0,      memoryMsg);
00197 
00198         randomSeed(analogRead(0));
00199 
00200 }
00201 
00202 //************************************************************************
00203 void    ATS_end()
00204 {
00205 long    seconds;
00206 long    milliSecs;
00207 
00208 
00209         Serial_println_P(gTextMsg_dashLine);
00210         
00211         //      Ran 4 tests in 0.000s
00212         Serial.print("Ran ");
00213         Serial.print(gTestCount);
00214         Serial.print(" tests in ");
00215         
00216         seconds         =       millis() / 1000;
00217         milliSecs       =       millis() % 1000;
00218         Serial.print(seconds);
00219         Serial.print('.');
00220         Serial.print(milliSecs);
00221         Serial.print('s');
00222         Serial.println();
00223         Serial.println();
00224 
00225         if (gYotalErrors == 0)
00226         {
00227                 Serial.print("OK");
00228         }
00229         else
00230         {
00231                 Serial.print("FAILED (failures=");
00232                 Serial.print(gYotalErrors);
00233                 Serial.print(")");
00234         }
00235         Serial.println();
00236         
00237         //*     send control D to terminate (End Of File)
00238         Serial.write(0x04);
00239 }
00240 
00241 
00242 
00243 //************************************************************************
00244 void ATS_PrintTestStatus(char *testString, boolean passed)
00245 {
00246 int     sLen;
00247 
00248         Serial.print(testString);
00249         sLen    =       strlen(testString);
00250         while (sLen < 60)
00251         {
00252                 Serial.print(' ');
00253                 sLen++;
00254         }
00255         Serial_print_P(gTextMsg_dotdotdot);
00256         if (passed)
00257         {
00258                 Serial_print_P(gTextMsg_ok);
00259         }
00260         else
00261         {
00262                 Serial_print_P(gTextMsg_FAIL);
00263                 gYotalErrors++;
00264         }
00265         Serial.println();
00266         
00267         gTestCount++;
00268 }
00269 
00270 
00271 
00272 //************************************************************************
00273 //*     returns true if no errors, false if there is an error
00274 int     ATS_Test_DigitalPinWithHelper(uint8_t digitalPinToTest, uint8_t helperpin)
00275 {
00276 boolean passedOK;
00277 int             pinValue;
00278 char    testName[64];
00279 char    numString[32];
00280 
00281         strcpy_P(testName, gTextMsg_DigitalRW);
00282         sprintf(numString, "%02d", digitalPinToTest);
00283         strcat(testName, numString);
00284 
00285         passedOK        =       true;
00286         
00287         //*     test senario 1
00288         pinMode(digitalPinToTest, OUTPUT);
00289         pinMode(helperpin, INPUT);
00290 
00291         digitalWrite(digitalPinToTest, HIGH);
00292         pinValue        =       digitalRead(helperpin);
00293         if (pinValue != HIGH)
00294         {
00295                 passedOK        =       false;
00296         }
00297 
00298         digitalWrite(digitalPinToTest, LOW);
00299         pinValue        =       digitalRead(helperpin);
00300         if (pinValue != LOW)
00301         {
00302                 passedOK        =       false;
00303         }
00304 
00305         
00306         //*     now reverse the input/output
00307         pinMode(digitalPinToTest, INPUT);
00308         pinMode(helperpin, OUTPUT);
00309         
00310         digitalWrite(helperpin, HIGH);
00311         pinValue        =       digitalRead(digitalPinToTest);
00312         if (pinValue != HIGH)
00313         {
00314                 passedOK        =       false;
00315         }
00316 
00317         digitalWrite(helperpin, LOW);
00318         pinValue        =       digitalRead(digitalPinToTest);
00319         if (pinValue != LOW)
00320         {
00321                 passedOK        =       false;
00322         }
00323 
00324 
00325         if (! passedOK)
00326         {
00327                 sprintf(numString, " (helper pin=%02d)", helperpin);
00328                 strcat(testName, numString);
00329         }
00330         ATS_PrintTestStatus(testName, passedOK);
00331         return(passedOK);
00332 }
00333 
00334 //************************************************************************
00335 boolean ATS_Test_DigitalPin(uint8_t digitalPinToTest)
00336 {
00337 boolean passedOK;
00338 uint8_t helperpin;
00339 
00340         if ((digitalPinToTest % 2) == 0)
00341         {
00342                 //*     if its EVEN, add 1
00343                 helperpin       =       digitalPinToTest + 1;
00344         }
00345         else
00346         {
00347                 //*     if its ODD
00348                 helperpin       =       digitalPinToTest - 1;
00349         }
00350         passedOK        =       ATS_Test_DigitalPinWithHelper(digitalPinToTest, helperpin);
00351         return(passedOK);
00352 }
00353 
00354 
00355 
00356 //************************************************************************
00357 //*     returns true if no errors, false if there is an error
00358 int     ATS_TestTimer(  uint8_t timerPinNumber,
00359                                         uint8_t inputPin,
00360                                         char *statusString,
00361                                         char *errorString)
00362 {
00363 boolean                 passedOK;
00364 unsigned long   loopCounter;
00365 unsigned long   lowCount;
00366 unsigned long   highCount;
00367 unsigned long   startTime;
00368 int                             percentLow;
00369 int                             percentHigh;
00370 int                             pinValue;
00371 char                    numString[48];
00372 int                             pwmValue;
00373 
00374         pwmValue        =       128;
00375         loopCounter     =       0;
00376         lowCount        =       0;
00377         highCount       =       0;
00378         passedOK        =       true;
00379         
00380         startTime       =       millis();
00381         pinMode(inputPin, INPUT);
00382         analogWrite(timerPinNumber, pwmValue);
00383         while ((millis() - startTime) < 500)
00384         {
00385                 pinValue        =       digitalRead(inputPin);
00386                 if (pinValue == HIGH)
00387                 {
00388                         highCount++;
00389                 }
00390                 else
00391                 {
00392                         lowCount++;
00393                 }
00394         }
00395         analogWrite(timerPinNumber, 0);
00396 
00397         //*     the difference should be about 50%
00398         percentLow      =       lowCount / ((lowCount + highCount) / 100);
00399         percentHigh     =       highCount / ((lowCount + highCount) / 100);
00400         if ((percentLow > 45) && (percentLow < 55))
00401         {
00402                 passedOK        =       true;
00403         }
00404         else
00405         {
00406                 passedOK        =       false;
00407                 strcat(errorString, " PWM ERROR");
00408         }
00409         sprintf(numString, "  (PWM=%02d %d%% LOW %d%% HIGH)", pwmValue, percentLow, percentHigh);
00410         strcat(statusString, numString);
00411 
00412         return(passedOK);
00413 }
00414 
00415 
00416 //************************************************************************
00417 //*     returns true if no errors, false if there is an error
00418 boolean ATS_Test_PWMPinWithHelper(uint8_t pwmPinToTest, uint8_t helperpin)
00419 {
00420 boolean passedOK;
00421 char    testName[64];
00422 char    errorString[48];
00423 char    numString[8];
00424 uint8_t timerNumber;
00425 
00426 
00427 
00428         strcpy_P(testName, gTextMsg_PWMoutput);
00429         sprintf(numString, "%02d", pwmPinToTest);
00430         strcat(testName, numString);
00431 
00432         passedOK                =       true;
00433         errorString[0]  =       0;
00434         
00435 
00436         //*     is pin1 a timer?
00437         timerNumber     =       digitalPinToTimer(pwmPinToTest);
00438         if (timerNumber != NOT_ON_TIMER)
00439         {
00440                 passedOK        =       ATS_TestTimer(pwmPinToTest, helperpin, testName, errorString);
00441         }
00442         else
00443         {
00444                 //*     we should not get here
00445                 passedOK        =       false;
00446         }
00447 
00448         ATS_PrintTestStatus(testName, passedOK);
00449 
00450         
00451         return(passedOK);
00452 }
00453 
00454 //************************************************************************
00455 boolean ATS_Test_PWM_Pin(uint8_t pwmPinToTest)
00456 {
00457 boolean passedOK;
00458 uint8_t helperpin;
00459 
00460         if ((pwmPinToTest % 2) == 0)
00461         {
00462                 //*     if its EVEN, add 1
00463                 helperpin       =       pwmPinToTest + 1;
00464         }
00465         else
00466         {
00467                 //*     if its ODD
00468                 helperpin       =       pwmPinToTest - 1;
00469         }
00470         passedOK        =       ATS_Test_PWMPinWithHelper(pwmPinToTest, helperpin);
00471         return(passedOK);
00472 }
00473 
00474 
00475 #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
00476         #define kAnalogPinOffset        54
00477 #else
00478         #define kAnalogPinOffset        14
00479 #endif
00480 
00481 
00482 //************************************************************************
00483 boolean ATS_Test_AnalogInputWithHelper(uint8_t analogPintoTest, uint8_t helperPin)
00484 {
00485 boolean passedOK;
00486 char    testName[64];
00487 char    infoString[48];
00488 int             analogValueHigh;
00489 int             analogValueLow;
00490 
00491 
00492         //*     first we have to set the ANALOG pin to INPUT
00493         pinMode(analogPintoTest + kAnalogPinOffset, INPUT);
00494         
00495         passedOK        =       true;
00496         
00497         strcpy_P(testName, gTextMsg_AnalogInput);
00498         sprintf(infoString, "%02d", analogPintoTest);
00499         strcat(testName, infoString);
00500 
00501 
00502         pinMode(helperPin, OUTPUT);
00503 
00504         digitalWrite(helperPin, LOW);
00505         analogValueLow  =       analogRead(analogPintoTest);
00506         if (analogValueLow > 100)
00507         {
00508                 passedOK        =       false;
00509         }
00510 
00511 
00512         digitalWrite(helperPin, HIGH);
00513         analogValueHigh =       analogRead(analogPintoTest);
00514         if (analogValueHigh < 1000)
00515         {
00516                 passedOK        =       false;
00517         }
00518 
00519 
00520         sprintf(infoString, " (Low=%4d High=%4d helper pin=%d)", analogValueLow, analogValueHigh, helperPin);
00521         strcat(testName, infoString);
00522         
00523         ATS_PrintTestStatus(testName, passedOK);
00524 
00525         return(passedOK);
00526 }
00527 
00528 
00529 //************************************************************************
00530 boolean ATS_Test_AnalogInput(uint8_t analogPinToTest)
00531 {
00532 boolean passedOK;
00533 uint8_t helperpin;
00534 
00535         if ((analogPinToTest % 2) == 0)
00536         {
00537                 //*     if its EVEN, add 1
00538                 helperpin       =       kAnalogPinOffset + analogPinToTest + 1;
00539         }
00540         else
00541         {
00542                 //*     if its ODD
00543                 helperpin       =       kAnalogPinOffset + analogPinToTest - 1;
00544         }
00545         passedOK        =       ATS_Test_AnalogInputWithHelper(analogPinToTest, helperpin);
00546         return(passedOK);
00547 }
00548 
00549 
00550 #define kSerialTestBaudRate     9600
00551 #define kSerialTestDelay        3
00552 
00553 
00554 #if (SERIAL_PORT_COUNT > 1) && !defined(__AVR_ATmega32U4__)
00555 //************************************************************************
00556 //*     retunrs 0 if no errors, 1 if an error occured
00557 short   ATS_TestSerialLoopback(HardwareSerial *theSerialPort, char *serialPortName)
00558 {
00559 char    xmitChar;
00560 char    rcvChar;
00561 short   ii;
00562 short   serialErrCt;
00563 short   timeOutLoopCtr;
00564 
00565 
00566         serialErrCt     =       1;
00567         if (theSerialPort != 0)
00568         {
00569                 serialErrCt     =       0;
00570                 theSerialPort->begin(kSerialTestBaudRate);
00571                 
00572                 for (ii=0; ii<150; ii++)
00573                 {
00574                         xmitChar        =       ii;
00575                         theSerialPort->print(xmitChar);
00576                         
00577                         timeOutLoopCtr  =       0;
00578                         //*     wait for data to come back or timeout
00579                         while (!theSerialPort->available() && (timeOutLoopCtr < kSerialTestDelay))
00580                         {
00581                                 delay(1);
00582                                 timeOutLoopCtr++;
00583                         }
00584                         
00585                         if (theSerialPort->available())
00586                         {
00587                                 //*     get the char
00588                                 rcvChar =       theSerialPort->read();
00589                                 if (rcvChar != xmitChar)
00590                                 {
00591                                         serialErrCt     =       1;
00592                                 }
00593                         }
00594                         else
00595                         {
00596                                 serialErrCt     =       1;
00597                         }
00598                 }
00599                 theSerialPort->end();
00600 
00601                 if (serialErrCt == 0)
00602                 {
00603                         ATS_PrintTestStatus(serialPortName, PASSED);
00604                 }
00605                 else
00606                 {
00607                         ATS_PrintTestStatus(serialPortName, FAILED);
00608                 }
00609         }
00610         
00611         return(serialErrCt);
00612 }
00613 #endif
00614 
00615 
00616 //************************************************************************
00617 boolean ATS_Test_EEPROM(void)
00618 {
00619 boolean         passedOK;
00620 uint8_t         dataByte;
00621 uint8_t         dataByteRead;
00622 uint16_t        dataWord;
00623 uint16_t        dataWordRead;
00624 uint32_t        dataLongWord;
00625 uint32_t        dataLongWordRead;
00626 int                     addressPtr;
00627 char            reportString[48];
00628 
00629         passedOK                =       true;
00630         //*     test BYTE read/write
00631         addressPtr              =       random(E2END);
00632         dataByte                =       0x5A;
00633         eeprom_write_byte((uint8_t *)addressPtr, dataByte);
00634         dataByteRead    =       eeprom_read_byte((uint8_t *)addressPtr);
00635 
00636         sprintf(reportString, "EEPROM_byte_rw  (addr= 0x%04X)", addressPtr);
00637         if (dataByteRead == dataByte)
00638         {
00639                 ATS_PrintTestStatus(reportString, PASSED);
00640         }
00641         else
00642         {
00643                 ATS_PrintTestStatus(reportString, FAILED);
00644                 passedOK                =       false;
00645         }
00646 
00647 
00648         //*     test WORD read/write
00649         addressPtr              =       random(E2END);
00650         dataWord                =       0xA55A;
00651         eeprom_write_word((uint16_t *)addressPtr, dataWord);
00652         dataWordRead    =       eeprom_read_word((uint16_t *)addressPtr);
00653 
00654         sprintf(reportString, "EEPROM_word_rw  (addr= 0x%04X)", addressPtr);
00655         if (dataWordRead == dataWord)
00656         {
00657                 ATS_PrintTestStatus(reportString, PASSED);
00658         }
00659         else
00660         {
00661                 ATS_PrintTestStatus(reportString, FAILED);
00662                 passedOK                =       false;
00663         }
00664 
00665 
00666         //*     test Long WORD read/write
00667         addressPtr              =       random(E2END);
00668         dataLongWord    =       0x5AA5A55A;
00669         eeprom_write_dword((uint32_t *)addressPtr, dataLongWord);
00670         dataLongWordRead        =       eeprom_read_dword((uint32_t *)addressPtr);
00671 
00672         sprintf(reportString, "EEPROM_dword_rw (addr= 0x%04X)", addressPtr);
00673         if (dataLongWordRead == dataLongWord)
00674         {
00675                 ATS_PrintTestStatus(reportString, PASSED);
00676         }
00677         else
00678         {
00679                 ATS_PrintTestStatus(reportString, FAILED);
00680                 passedOK                =       false;
00681         }
00682 
00683 
00684         return(passedOK);
00685 }
00686 
00687 
00688 
00689 //************************************************************************
00690 extern unsigned int __data_start;
00691 extern unsigned int __data_end;
00692 extern unsigned int __bss_start;
00693 extern unsigned int __bss_end;
00694 extern unsigned int __heap_start;
00695 extern void *__brkval;
00696 
00697 
00698 
00699 //************************************************************************
00700 int     ATS_GetFreeMemory()
00701 {
00702 int free_memory;
00703 
00704         if((int)__brkval == 0)
00705         {
00706                 free_memory = ((int)&free_memory) - ((int)&__bss_end);
00707         }
00708         else
00709         {
00710                 free_memory = ((int)&free_memory) - ((int)__brkval);
00711         }
00712         return free_memory;
00713 }
00714 
00715