embedded RTOS class project.

Fork of RTOS_project by Mike Moore

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*----------------------------------------------//------------------------------
00002     student   : m-moore
00003     email     : gated.clock@gmail.com
00004     class     : embedded RTOS
00005     directory : RTOS_project
00006     file      : main.cpp
00007     date      : september 19, 2013.
00008 ----copyright-----------------------------------//------------------------------   
00009     licensed for personal and academic use.
00010     commercial use of original code must be approved by the account-holder of
00011     gated.clock@gmail.com
00012 ----revision------------------------------------//------------------------------
00013     this is the embedded RTOS class revision.
00014     changes made since the USB device class release:
00015     
00016     1. a 'read all registers' feature has been added, which speeds up
00017        CPU execution, since the UI obtains all of the register states after
00018        each CPU clock.  originally, each register was individually read.
00019        now, all registers are read at once, if so requested by the python code.
00020        
00021     2. some 'if' statements were changed to 'switch' statements (neatening).
00022     
00023     3. added watchdog timers for the three threads.  this via a meta-watchdog thread.
00024     
00025     4. added #defined-based option to either boot on error detection
00026        (such as malloc fail) or use error(); function.
00027        
00028     5. the LCD is updated only if a display value is changed - reduced power
00029        usage a little & reduces potential 'blinkieness'.
00030        
00031     6. BOOT notification on LCD.
00032 ----description---------------------------------//------------------------------
00033     overview:
00034     program to provide round-trip communication between a python test-control
00035     program running on a pc host, and a device-under-test CPU implemented on
00036     an altera board.  the pc-host communication is over USBSerial, and the
00037     altera communication is over SPI.
00038     
00039     features:
00040     1. multi-threaded design, use of memory-pools to transfer data between threads.
00041     2. use of USBDevice library for communication with PC host.
00042     3. use of mmSPI_RTOS custom library for communication with FPGA.
00043     4. main thread provides USBSerial communication to/from host.
00044     5. SPI processing thread provides SPI communication to/from DUT.
00045     6. mmSPI_RTOS library generates non-overlapping SPI and CPU clocks.
00046     7. background diagnostic thread provides LCD & error updates.
00047     8. meta watchdog thread monitors itself & the other threads.
00048 
00049     indicators: (led<3:0> = LED<1:4>)
00050     1. LCD  provides running counts for SPI and CPU clock cycles.
00051     2. led0 indicates main     thread processing.
00052     3. led1 indicates SPI      thread processing.
00053     4. led2 indicates LCD      thread processing.
00054     5. led3 indicates watchdog thread processing.
00055     
00056     implementation:
00057     1. main.processIncomingSerial(): accept incoming serial data from host,
00058        and map it into tFromHost structures.
00059     2. SPIprocessingThread: take the incoming data structures instances, and
00060        feed their content into mmSPI_RTOS commands.
00061     3. mmSPI_RTOS object: given commands/data passed from caller,
00062        map them into SPI outgoing vectors and scan them into the FPGA.
00063     4. mmSPI_RTOS object: receive incoming SPI vectors from FPGA.
00064        make FPGA payload data available to caller.
00065     5. SPIprocessingThread: load tToHost structures with said FPGA payload data.
00066     6. main.processOutgoingSerial(): transfer tToHost structure data into a
00067        serial outgoing buffer, and block-transfer it to the host PC.
00068        
00069     electrical:
00070     1. four pins (and ground) attached to the zigbee header,
00071        programmed as three SPI pins and the CPU clock.
00072     2. each of the four signals over twisted-pair.
00073     3. but some ribbon cable is used at the FPGA end.
00074     4. best if only the mbed application board USB cable is attached
00075        to the host; if the mbed CPU board USB cable is also attached to
00076        the host, then the python program may attempt to use the wrong USB
00077        connection.
00078     5. no particular power sequence is needed for this system to work.
00079     
00080     timing critical path:  serial processing.  the python code needs
00081     a delay between serial access of 40mS conservatively.
00082     
00083     testing:
00084     the python UI provides the main testing mechanism.
00085     
00086         USB connect.
00087     00. press 'CONNECT' button in UI.  verify connection info in shell.
00088     
00089         CPU register w/r
00090     01. type values into {R0,R1,R2,R3,PC,IR} UI entry-forms.
00091     02. press 'REG WRITE' UI button.
00092     03. press 'REG READ'  UI button.
00093     04. verify that the read data is correct.
00094     
00095         CPU main-memory w/r
00096     05. type an address into 'mmADR' UI entry-form.
00097     06. type data into 'mmVAL' UI entry-form.
00098     07. press 'MM WRITE' UI button.
00099     08. type a different address into 'mmADR' UI entry-form.
00100     09. type different data into 'mmVAL' UI entry-form.
00101     10. press 'MM WRITE' UI button.
00102     11. type address from (05) into 'mmADR' UI entry-form.
00103     12. press 'MM READ' UI button.
00104     13. verify that the data from (06) is seen in the 'mmVAL' entry form.
00105     14. type address from (08) into 'mmADR' UI entry-form.
00106     15. press 'MM READ' UI button.
00107     16. verify that the data from (09) is seen in the 'mmVAL' entry form.  
00108     
00109         CPU main-memory full load/dump.
00110     17. press 'PROGRAM' in the UI.  select a program file in the dialog-popup.  
00111     18. watch the load process in the shell text.
00112     19. press 'DUMP     in the UI.  select a main-memory dump file in the diaglog-popup.
00113     20. watch the dump process in the shell text.
00114     
00115         CPU step function.
00116     21. press 'STEP' in the UI repeatedly, watch the UI display the 
00117         CPU register states as the current program is executed one CPU clock
00118         at a time.
00119         
00120         CPU run function.
00121     22. press 'RUN'  in the UI.  watch the current program run at high speed.
00122     23. press 'SLOW' in the UI.  watch the current program run at slow speed.
00123     24. press 'STOP' in the UI.  the program will stop execution.
00124     
00125         CPU test function.
00126     25. press 'TEST' in the UI.  the program will load,execute,dump,compare.
00127     26. tail -f testlog.txt to see test status.
00128     27. the test will repeat until 'STOP TEST' is pressed.
00129     28. long test performed by allowing this mode to continue.
00130     
00131         UI exit function.
00132     29. press 'EXIT' in the UI.  it will exit.
00133 -----includes-----------------------------------//----------------------------*/
00134     #include "mbed.h"                           // general.
00135     #include "USBSerial.h"                      // serial over USB.
00136     #include "C12832_lcd.h"                     // LCD display.
00137     #include "rtos.h"                           // RTOS.
00138     #include "mmSPI_RTOS.h"                     // SPI.
00139     #include "watchdog_RTOS.h"                  // watchdog.
00140 //---defines------------------------------------//------------------------------
00141     #define LCD1 lcd.locate(0, 0);              // LCD line 1.
00142     #define LCD2 lcd.locate(0,11);              // LCD line 2.
00143     #define LCD3 lcd.locate(0,22);              // LCD line 3.
00144     #define LCD3 lcd.locate(0,22);              // LCD line 3.  
00145     #define WATCHDOG_S     10                   // watchdog timeout, in seconds.
00146     #define ERROR_BOOT      1                   // 1 means boot rather than error().
00147     #define SPI_BYTES       8                   // number of SPI bytes. 
00148     #define SPI_HZ     100000                   // SPI frequency in Hz.
00149     #define SER_BYTES      18                   // serial in/out # of bytes.
00150     #define SER_ALIGN       7                   // '$' location in shift-register.
00151     #define THREAD_0_WAIT   8                   // multitasking wait mS.
00152     #define THREAD_1_WAIT   2                   // multitasking wait mS. 
00153     #define THREAD_2_WAIT 128                   // multitasking wait mS. 
00154     #define THREAD_3_WAIT 128                   // multitasking wait mS.
00155     #define HB_MODULO      64                   // heartbeat slowdown factor.
00156     #define POOL_LEN       16                   // memory pool dimension.
00157     #define HCMD_SETREG     1                   // host command 'set register'.
00158     #define HCMD_GETREG     2                   // host command 'get register'.
00159     #define HCMD_SETMM      3                   // host command 'set main-memory.'
00160     #define HCMD_GETMM      4                   // host command 'get main-memory.'
00161     #define HCMD_STEP       5                   // host command 'step-CPU'.
00162     #define HCMD_SETIR      6                   // host command 'set-IR'.
00163     #define HCMD_GETALLREG  7                   // host command 'get-all-registers'.
00164     #define CPU_REG_0       0                   // CPU register 0.
00165     #define CPU_REG_1       1                   // CPU register 1.
00166     #define CPU_REG_2       2                   // CPU register 2.
00167     #define CPU_REG_3       3                   // CPU register 3.
00168     #define CPU_REG_PC      4                   // CPU Program Counter.
00169     #define CPU_IR_H        5                   // CPU IR high-byte.
00170     #define CPU_IR_L        6                   // CPU IR low-byte.
00171 //--externals-----------------------------------//------------------------------    
00172     extern "C" void mbed_reset();               // processor reset.
00173 //--global_definitions--------------------------//------------------------------
00174     struct tFromHost                            // command from host.
00175     {
00176       char cCommand;                            // command from host.
00177       char cRegisterID;                         // which CPU register.
00178       char cRegisterValue;                      // write this to CPU register.
00179       char cIRValueH;                           // write this to IR.
00180       char cIRValueL;                           // write this to IR.
00181       char cMMaddress;                          // access this MM address.
00182       char cMMdataH;                            // MM content high byte.
00183       char cMMdataL;                            // MM content low  byte.
00184     };
00185     MemoryPool<tFromHost, POOL_LEN> mPoolFromHost;
00186     Queue     <tFromHost, POOL_LEN> qFromHost;
00187     
00188 //----  
00189     
00190     struct tToHost                              // reply to host.
00191     {
00192       char cCommand;                            // command executed.
00193       char cRegisterID;                         // which CPU register read.
00194       char cRegisterValue;                      // data from CPU register.
00195       char cMMaddress;                          // which MM address read.
00196       char cMMdataH;                            // MM content high byte.
00197       char cMMdataL;                            // MM content low  byte.   
00198       char cReg0;                               // data from R0.
00199       char cReg1;                               // data from R1.
00200       char cReg2;                               // data from R2.
00201       char cReg3;                               // data from R3.
00202       char cPC;                                 // data from program counter.
00203       char cIRH;                                // high byte from instruction register.
00204       char cIRL;                                // low  byte from instruction register.   
00205     };
00206     MemoryPool<tToHost, POOL_LEN> mPoolToHost;
00207     Queue     <tToHost, POOL_LEN> qToHost;
00208     
00209     Queue<int, POOL_LEN> queueWatchdogThread_0; // main thread watchdog notice.
00210     Queue<int, POOL_LEN> queueWatchdogThread_1; // thread 1    watchdog notice.
00211     Queue<int, POOL_LEN> queueWatchdogThread_2; // thread 2    watchdog notice.
00212 //--global_variables----------------------------//------------------------------ 
00213     char          gpcSerialFromHost[SER_BYTES]; // incoming serial buffer.
00214     char          gpcSerialToHost  [SER_BYTES]; // outgoing serial buffer.
00215     char          gcNewCommand;                 // new command from host.
00216     int           gdRoundTrip;                  // +1 from host, -1 to host.
00217     tToHost     * gpToHost;                     // to-host structure.
00218     osEvent       gqToHostEvent;                // incoming message event.
00219     unsigned long gulSPIclkCount;               // SPI clock count.
00220     unsigned long gulCPUclkCount;               // CPU clock count.
00221 //--global_instances----------------------------//------------------------------ 
00222     USBSerial  serial;                          // serial over usb.
00223     C12832_LCD lcd;                             // LCD display.
00224     DigitalOut led0(LED4);                      // thread heartbeat.
00225     DigitalOut led1(LED3);                      // thread heartbeat.
00226     DigitalOut led2(LED2);                      // thread heartbeat.
00227     DigitalOut led3(LED1);                      // SPI reply underflow warning.
00228 //-------prototypes-----------------------------//------------------------------
00229     int  main();                                // main.
00230     void processIncomingSerial();               // process incoming host data.    
00231     void processOutgoingSerial();               // process outgoing data to host.   
00232     void SPIprocessingThread(void const *args); // SPI-side processing.   
00233     void diagnosticThread   (void const *args); // LCD and LED notifications.  
00234     void watchdogThread     (void const *args); // overall watchdog. 
00235     char ascii_nibble_to_binary(char cAscii);   // ascii nibble -> binary.
00236     char binary_to_ascii_nibble(char cBinary);  // binary -> ascii nibble.                
00237     void clear_tFromHost(tFromHost *ptFromHost);// initialize structure.
00238     void clear_tToHost  (tToHost   *ptToHost);  // initialize structure.  
00239 //==============================================//==============================
00240     int main(void)                              // USBSerial processing thread.
00241     {
00242       int dHeartbeat;                           // heartbeat counter.
00243       int dLoop;                                // loop index.
00244 
00245       gpToHost       = NULL;                    // initialize global.
00246       gcNewCommand   =    0;                    // initialize global.
00247       gdRoundTrip    = 1024;                    // initialize global.
00248       gulSPIclkCount =    0;                    // initialize global.
00249       gulCPUclkCount =    0;                    // initialize global.
00250       led0           =    0;                    // initialize global.
00251       led1           =    0;                    // initialize global.
00252       led2           =    0;                    // initialize global.
00253       led3           =    0;                    // initialize global.
00254       dHeartbeat     =    0;                    // initialize local.
00255       dLoop          =    0;                    // initialize local.
00256       
00257                                                 // BOOT notification.
00258       lcd.cls(); LCD2; lcd.printf("           BOOT"); wait(1.0);
00259 
00260                                                 // initialize serial-in shift-register.
00261       for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialFromHost[dLoop] = 0;
00262       
00263                                                 // thread-out SPI-side processing.
00264       Thread thread_1(SPIprocessingThread,NULL,osPriorityHigh,DEFAULT_STACK_SIZE,NULL);
00265       
00266                                                 // thread-out diagnostics.
00267       Thread thread_2(diagnosticThread,   NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL);
00268       
00269                                                 // thread-out universal watchdog.
00270       Thread thread_3(watchdogThread,     NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL);
00271       
00272       while(1)                                  // main loop.
00273       {   
00274         processIncomingSerial();                // process data in from host.
00275         processOutgoingSerial();                // process data out to host.
00276                         
00277         dHeartbeat++;                           // thread heartbeat.
00278         if (!(dHeartbeat % HB_MODULO)) led0 = !led0;
00279         queueWatchdogThread_0.put((int *) 0,1); // adds 1mS to wait.
00280         Thread::wait(THREAD_0_WAIT - 1);        // multitasking.   
00281       }                                         // main loop.
00282     }                                           // main.
00283 /*----------------------------------------------//----------------------------*/
00284 /*
00285    the python program running on the host is sending/receiving ascii characters
00286    which represent command/data binary nibbles.  the python program will send
00287    the '$' character for command-string alignment.  this function reads-in the
00288    incoming serial stream when any serial data is available, into a shift-register,
00289    and breaks upon detection of the '$' alignment character for python
00290    command-processing. at that point the shift-register will look something like
00291    [0] [1] [2] [3] [4] [5] [6] [7]
00292    '1' '2' '3' '4'  x   x   x  '$'  (means write 0x34 to CPU R2).
00293 
00294 
00295     command-host register-number interpretation:
00296     0 = CPU R0.
00297     1 = CPU R1.
00298     2 = CPU R2.
00299     3 = CPU R3.
00300     4 = CPU program-counter.
00301     5 = CPU instruction-register high-byte.
00302     6 = CPU instruction-register low-byte.
00303     
00304     instruction-register write is specially implemented,
00305     instruction-register read  is implemented as two standard register-reads.
00306 
00307     host-command shift-register interpretation:
00308     
00309     gpcSerialFromHost[0] = command.  
00310     subsequent interpretation depends on the command.
00311     
00312 ----   
00313     if command = HCMD_SETREG (write-CPU-register) or HCMD_GETREG (read-CPU-register):
00314     
00315       gpcSerialFromHost[1] = register number (see above).
00316       gpcSerialFromHost[2] = register content, high nibble.
00317       gpcSerialFromHost[3] = register content, low  nibble.
00318       gpcSerialFromHost[4] = not used.
00319       gpcSerialFromHost[5] = not used.
00320       gpcSerialFromHost[6] = not used.
00321 
00322 ----
00323     if command = HCMD_SETIR (write-CPU-instruction-register):
00324     
00325       gpcSerialFromHost[1] = IR register number, implied anyway.
00326       gpcSerialFromHost[2] = IR write value high byte high nibble.
00327       gpcSerialFromHost[3] = IR write value high byte low  nibble.
00328       gpcSerialFromHost[4] = IR write value low  byte high nibble.
00329       gpcSerialFromHost[5] = IR write value low  byte low  nibble.
00330       gpcSerialFromHost[6] = not used.
00331 
00332 ----    
00333     if command = HCMD_SETMM (write to CPU main-memory) or HCMD_GETMM (read from CPU main-memory):
00334     
00335       gpcSerialFromHost[1] = MM address high nibble.
00336       gpcSerialFromHost[2] = MM address low  nibble.
00337       gpcSerialFromHost[3] = MM content high byte high nibble.
00338       gpcSerialFromHost[4] = MM content high byte low  nibble.
00339       gpcSerialFromHost[5] = MM content low  byte high nibble.
00340       gpcSerialFromHost[6] = MM content low  byte low  nibble.
00341       
00342       the above also applies to function 'processOutgoingSerial'.
00343 */
00344 
00345     void processIncomingSerial(void)            // process incoming serial data.
00346     {
00347       int         dLoop;                        // loop index.
00348       tFromHost * pFromHost;                    // from-host structure.
00349       
00350       while(serial.available())                 // while data from host is available.
00351       {
00352                                                 // shift-in the serial stream.
00353         for (dLoop = 0; dLoop < (SER_BYTES - 1); dLoop++)
00354         gpcSerialFromHost[dLoop] = gpcSerialFromHost[dLoop + 1];
00355         gpcSerialFromHost[SER_BYTES - 1] = serial._getc();
00356         
00357         if (gpcSerialFromHost[SER_ALIGN] == '$')// data from host is aligned.
00358         {
00359           gcNewCommand = 1;                     // new host command just recognised.
00360           break;                                // need to process aligned data.
00361         }                                       // data from host is aligned. 
00362       }                                         // while data from host is available.
00363       
00364                                                 // even if more data awaits from the
00365                                                 // incoming serial stream, we now need
00366                                                 // to process the aligned data recognised
00367                                                 // as a command from the host.  
00368                                                 
00369       if (gcNewCommand)                         // execute once per new command.
00370       {
00371         pFromHost = mPoolFromHost.alloc();      // allocate next pool entry.
00372         if (!pFromHost)                         // failure detection.
00373         {
00374           if (ERROR_BOOT) mbed_reset(); else
00375           error("\n\r processIncomingSerial : FATAL malloc error for pFromHost. \n\r"); 
00376         }
00377         
00378         clear_tFromHost(pFromHost);             // initialize structure.
00379         
00380                                                 // copy-in host message.
00381         pFromHost->cCommand = ascii_nibble_to_binary(gpcSerialFromHost[0]);
00382         
00383 //----
00384 
00385         switch(pFromHost->cCommand)             // command dependency.
00386         {
00387           case HCMD_SETREG :                    // host command 'set register'.
00388           {
00389             pFromHost->cRegisterID    =   ascii_nibble_to_binary(gpcSerialFromHost[1]);
00390             pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + 
00391                                           ascii_nibble_to_binary(gpcSerialFromHost[3]);          
00392             break;
00393           }                                     // host command 'set register'.
00394         
00395           case HCMD_GETREG :                    // host command 'get register'.
00396           {
00397             pFromHost->cRegisterID    =   ascii_nibble_to_binary(gpcSerialFromHost[1]);
00398             pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + 
00399                                           ascii_nibble_to_binary(gpcSerialFromHost[3]);   
00400             gdRoundTrip++;                      // expected reply to host is pending.       
00401             break;
00402           }                                     // host command 'get register'.
00403                  
00404           case HCMD_SETMM :                     // host command 'set main-memory.'
00405           {
00406             pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + 
00407                                       ascii_nibble_to_binary(gpcSerialFromHost[2]);  
00408             pFromHost->cMMdataH   = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + 
00409                                       ascii_nibble_to_binary(gpcSerialFromHost[4]);         
00410             pFromHost->cMMdataL   = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + 
00411                                       ascii_nibble_to_binary(gpcSerialFromHost[6]);           
00412             break;
00413           }                                     // host command 'set main-memory.'
00414                
00415           case HCMD_GETMM :                     // host command 'get main-memory.'
00416           {
00417             pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + 
00418                                       ascii_nibble_to_binary(gpcSerialFromHost[2]);  
00419             pFromHost->cMMdataH   = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + 
00420                                       ascii_nibble_to_binary(gpcSerialFromHost[4]);         
00421             pFromHost->cMMdataL   = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + 
00422                                       ascii_nibble_to_binary(gpcSerialFromHost[6]);    
00423                                       
00424             gdRoundTrip++;                      // expected reply to host is pending.        
00425             break;
00426           }                                     // host command 'get main-memory.'
00427                 
00428           case HCMD_STEP :                      // host command 'step-CPU'.
00429           {
00430             break;
00431           }                                     // host command 'step-CPU'.
00432             
00433           case HCMD_SETIR :                     // host command 'set-IR'.
00434           {
00435             pFromHost->cIRValueH = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + 
00436                                      ascii_nibble_to_binary(gpcSerialFromHost[3]);     
00437             pFromHost->cIRValueL = ((ascii_nibble_to_binary(gpcSerialFromHost[4])) << 4) + 
00438                                      ascii_nibble_to_binary(gpcSerialFromHost[5]);            
00439             break;
00440           }                                     // host command 'set-IR'.
00441             
00442           case HCMD_GETALLREG :                 // host command 'get-all-registers'.
00443           {
00444             gdRoundTrip++;                      // expected reply to host is pending.
00445             break;
00446           }                                     // host command 'get-all-registers'.
00447         
00448           default :                             // default.
00449           {
00450             if (ERROR_BOOT) mbed_reset(); else
00451             error("\n\r processIncomingSerial : ERROR unrecognised command from host. \n\r");
00452             break;
00453           }                                     // default.
00454         }                                       // command dependency.
00455         
00456 //----
00457                    
00458         qFromHost.put(pFromHost);               // send out for processing.    
00459         gcNewCommand = 0;                       // don't execute until next new command.
00460       }                                         // execute once per new command.
00461       Thread::wait(THREAD_0_WAIT);              // multitasking.  
00462     }                                           // processIncomingSerial
00463 /*----------------------------------------------//----------------------------*/
00464     void processOutgoingSerial(void)            // prepare/transmit data to host.
00465     {
00466       int dLoop;                                // loop index.
00467 
00468       gqToHostEvent = qToHost.get(1);           // check for reply back to host.
00469           
00470                                                 // if new reply to host:
00471       if (gqToHostEvent.status == osEventMessage) 
00472       {
00473                                                 // bring it in from the queue.
00474         gpToHost = (tToHost *) gqToHostEvent.value.p;
00475         if (!gpToHost)                         // failure detection.
00476         {
00477           if (ERROR_BOOT) mbed_reset(); else
00478           error("\n\r processOutgoingSerial : FATAL NULL gpToHost pointer. \n\r"); 
00479         }
00480           
00481                                                 // clear outgoing buffer.
00482         for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialToHost[dLoop] = 0;
00483                                                                                                            
00484         switch(gpToHost->cCommand)              // the from-host command was looped to here.
00485         {
00486           case HCMD_SETREG :                    // host command 'set register'.
00487           {
00488             break;
00489           }                                     // host command 'set register'.
00490         
00491           case HCMD_GETREG :                    // host command 'get register'.
00492           {
00493             gpcSerialToHost[0] = binary_to_ascii_nibble(  gpToHost->cCommand);
00494             gpcSerialToHost[1] = binary_to_ascii_nibble(  gpToHost->cRegisterID);
00495             gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 4) & 0x0F);
00496             gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 0) & 0x0F);
00497             gpcSerialToHost[4] = '\n';          // signals end of transfer.
00498              
00499                                                 // transmit to the host.
00500             serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES);        
00501             gdRoundTrip--;                      // expected reply sent to host.       
00502             break;
00503           }                                     // host command 'get register'.
00504                  
00505           case HCMD_SETMM :                     // host command 'set main-memory.'
00506           {
00507             break;
00508           }                                     // host command 'set main-memory.'
00509                
00510           case HCMD_GETMM :                     // host command 'get main-memory.'
00511           {
00512             gpcSerialToHost[0] = binary_to_ascii_nibble(  gpToHost->cCommand);
00513             gpcSerialToHost[1] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 4) & 0x0F);
00514             gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 0) & 0x0F);
00515             gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cMMdataH  ) >> 4) & 0x0F);
00516             gpcSerialToHost[4] = binary_to_ascii_nibble(((gpToHost->cMMdataH  ) >> 0) & 0x0F);
00517             gpcSerialToHost[5] = binary_to_ascii_nibble(((gpToHost->cMMdataL  ) >> 4) & 0x0F);
00518             gpcSerialToHost[6] = binary_to_ascii_nibble(((gpToHost->cMMdataL  ) >> 0) & 0x0F);   
00519             gpcSerialToHost[7] = '\n';          // signals end of transfer.    
00520              
00521                                                 // transmit to the host.
00522             serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES);    
00523             gdRoundTrip--;                      // expected reply sent to host.        
00524             break;
00525           }                                     // host command 'get main-memory.'
00526                 
00527           case HCMD_STEP :                      // host command 'step-CPU'.
00528           {
00529             break;
00530           }                                     // host command 'step-CPU'.
00531             
00532           case HCMD_SETIR :                     // host command 'set-IR'.
00533           {
00534             break;
00535           }                                     // host command 'set-IR'.
00536             
00537           case HCMD_GETALLREG :                 // host command 'get-all-registers'.
00538           {
00539             gpcSerialToHost[ 0] = binary_to_ascii_nibble(  gpToHost->cCommand);
00540             gpcSerialToHost[ 1] = binary_to_ascii_nibble(((gpToHost->cReg0) >> 4) & 0x0F);
00541             gpcSerialToHost[ 2] = binary_to_ascii_nibble(((gpToHost->cReg0) >> 0) & 0x0F);
00542             gpcSerialToHost[ 3] = binary_to_ascii_nibble(((gpToHost->cReg1) >> 4) & 0x0F);
00543             gpcSerialToHost[ 4] = binary_to_ascii_nibble(((gpToHost->cReg1) >> 0) & 0x0F);
00544             gpcSerialToHost[ 5] = binary_to_ascii_nibble(((gpToHost->cReg2) >> 4) & 0x0F);
00545             gpcSerialToHost[ 6] = binary_to_ascii_nibble(((gpToHost->cReg2) >> 0) & 0x0F);
00546             gpcSerialToHost[ 7] = binary_to_ascii_nibble(((gpToHost->cReg3) >> 4) & 0x0F);
00547             gpcSerialToHost[ 8] = binary_to_ascii_nibble(((gpToHost->cReg3) >> 0) & 0x0F);
00548             gpcSerialToHost[ 9] = binary_to_ascii_nibble(((gpToHost->cPC)   >> 4) & 0x0F);
00549             gpcSerialToHost[10] = binary_to_ascii_nibble(((gpToHost->cPC)   >> 0) & 0x0F);
00550             gpcSerialToHost[11] = binary_to_ascii_nibble(((gpToHost->cIRH)  >> 4) & 0x0F);
00551             gpcSerialToHost[12] = binary_to_ascii_nibble(((gpToHost->cIRH)  >> 0) & 0x0F);          
00552             gpcSerialToHost[13] = binary_to_ascii_nibble(((gpToHost->cIRL)  >> 4) & 0x0F);
00553             gpcSerialToHost[14] = binary_to_ascii_nibble(((gpToHost->cIRL)  >> 0) & 0x0F);                 
00554             gpcSerialToHost[15] = '\n';         // signals end of transfer.         
00555           
00556                                                 // transmit to the host.
00557             serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES);        
00558             gdRoundTrip--;                      // expected reply sent to host.  
00559             break;
00560           }                                     // host command 'get-all-registers'.
00561         
00562           default :
00563           {
00564             if (ERROR_BOOT) mbed_reset(); else
00565             error("\n\r processOutgoingSerial : ERROR unrecognised command from host. \n\r");
00566             break;
00567           }                                     // default.
00568         }                                       // switch(gpToHost->cCommand)                                         
00569                                                 
00570         mPoolToHost.free(gpToHost);             // done with this queue entry.
00571         gpToHost = NULL;                        // clear pointer.
00572       }                                         // if new reply to host.     
00573     }                                           // processOutgoingSerial.
00574 /*----------------------------------------------//----------------------------*/      
00575 //  the pcSendBuffer and pcReceiveBuffer arrays are not used by this function,
00576 //  but they are declared by this function, and their pointers are passed
00577 //  down to the mmSPI_RTOS library for its use of them.
00578 //  note- the prefix 'pc' means 'pointer of type character', not 'personal computer'.
00579 
00580     void SPIprocessingThread(void const *args)  // process host-commands via SPI.
00581     {
00582       char         pcSendBuffer   [SPI_BYTES];  // SPI send buffer.
00583       char         pcReceiveBuffer[SPI_BYTES];  // SPI receive buffer.
00584       char         pcRegisters    [SPI_BYTES];  // fetch-all-registers vector.
00585       int          dHeartbeat;                  // heartbeat counter.
00586       int          dMemoryRead;                 // read main-memory into this.
00587       int          dLoop;                       // loop index.
00588       osEvent      qFromHostEvent;              // incoming message event.
00589       tFromHost  * pFromHost;                   // message structure.
00590       tToHost    * gpToHost;                    // message structure.
00591       mmSPI_RTOS * pSPI;                        // SPI.
00592       
00593       pFromHost   = NULL;                       // NULL pointers.
00594       gpToHost    = NULL;
00595       pSPI        = NULL;
00596       dHeartbeat  = 0;                          // clear variables.
00597       dMemoryRead = 0;
00598       dLoop       = 0;
00599                                                 // clear SPI vectors.
00600       for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcSendBuffer   [dLoop] = 0;
00601       for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcReceiveBuffer[dLoop] = 0;
00602  
00603       pSPI = new mmSPI_RTOS;                    // SPI allocation.      
00604       if (!pSPI)                                // failure detection.
00605       {
00606         if (ERROR_BOOT) mbed_reset(); else
00607         error("\n\r SPIprocessingThread : FATAL new error for pSPI. \n\r"); 
00608       }      
00609       
00610       pSPI->setSendBuffer   (pcSendBuffer);     // set SPI send buffer.
00611       pSPI->setReceiveBuffer(pcReceiveBuffer);  // set SPI receive buffer.
00612       pSPI->setNumberOfBytes(SPI_BYTES);        // set SPI number of bytes.
00613       pSPI->setSPIfrequency (SPI_HZ);           // set SPI clock frequency.
00614       
00615       while(1)                                  // thread loop.
00616       {
00617         qFromHostEvent = qFromHost.get(1);      // check for incoming host command.
00618         
00619                                                 // if new host command:
00620         if (qFromHostEvent.status == osEventMessage) 
00621         {
00622                                                 // bring it in from the queue.
00623           pFromHost = (tFromHost *) qFromHostEvent.value.p;
00624           if (!pFromHost)                       // failure detection.
00625           {
00626             if (ERROR_BOOT) mbed_reset(); else
00627             error("\n\r SPIprocessingThread : FATAL NULL pFromHost pointer. \n\r");  
00628           }
00629           
00630           switch(pFromHost->cCommand)           // host command decode.
00631           {
00632             case HCMD_SETREG :                  // set CPU register.
00633             {
00634               switch(pFromHost->cRegisterID)    // which register to write to.
00635               {
00636                 case CPU_REG_0  : {pSPI->write_register(CPU_REG_0 , pFromHost->cRegisterValue); break;}
00637                 case CPU_REG_1  : {pSPI->write_register(CPU_REG_1 , pFromHost->cRegisterValue); break;}
00638                 case CPU_REG_2  : {pSPI->write_register(CPU_REG_2 , pFromHost->cRegisterValue); break;}
00639                 case CPU_REG_3  : {pSPI->write_register(CPU_REG_3 , pFromHost->cRegisterValue); break;}
00640                 case CPU_REG_PC : {pSPI->write_register(CPU_REG_PC, pFromHost->cRegisterValue); break;}
00641                 default         : {break;}
00642               }                                 // which register to write to.
00643               break;
00644             }                                   // set CPU register.
00645             
00646             case HCMD_SETIR:                    // set instruction register.
00647             {
00648               pSPI->write_IR(pFromHost->cIRValueH, pFromHost->cIRValueL);
00649               break;
00650             }                                   // set instruction register.
00651             
00652             case HCMD_GETREG :                  // get CPU register.
00653             {
00654               gpToHost = mPoolToHost.alloc();   // allocate next pool entry.
00655               if (!gpToHost)                    // failure detection.
00656               {
00657                 if (ERROR_BOOT) mbed_reset(); else
00658                 error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); 
00659               }              
00660               
00661               clear_tToHost(gpToHost);          // initialize structure.
00662             
00663               switch(pFromHost->cRegisterID)    // which register to read from.
00664               {
00665                 case CPU_REG_0  : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_0 ); break;}
00666                 case CPU_REG_1  : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_1 ); break;}
00667                 case CPU_REG_2  : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_2 ); break;}
00668                 case CPU_REG_3  : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_3 ); break;}
00669                 case CPU_REG_PC : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_PC); break;}
00670                 case CPU_IR_H   : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_H  ); break;}
00671                 case CPU_IR_L   : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_L  ); break;}
00672                 default         : {break;}    
00673               }                                 // which register to read from.
00674               
00675                                                 // loop-back to host.
00676               gpToHost->cCommand    = pFromHost->cCommand;
00677               gpToHost->cRegisterID = pFromHost->cRegisterID;  
00678                           
00679               qToHost.put(gpToHost);            // send up for processing.    
00680               break; 
00681             }                                   // get CPU register.     
00682             
00683             case HCMD_GETALLREG :               // get all CPU registers.
00684             {
00685               gpToHost = mPoolToHost.alloc();   // allocate next pool entry.              
00686               if (!gpToHost)                    // failure detection.
00687               {
00688                 if (ERROR_BOOT) mbed_reset(); else
00689                 error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r");
00690               }              
00691               
00692               clear_tToHost(gpToHost);          // initialize structure.
00693               
00694                                                 // tell SPI to return all reg content.
00695               pSPI->read_all_registers(pcRegisters);
00696               
00697               gpToHost->cReg0 = pcRegisters[6]; // transfer to outgoing structure.
00698               gpToHost->cReg1 = pcRegisters[5];
00699               gpToHost->cReg2 = pcRegisters[4];
00700               gpToHost->cReg3 = pcRegisters[3];
00701               gpToHost->cPC   = pcRegisters[2];
00702               gpToHost->cIRH  = pcRegisters[1];
00703               gpToHost->cIRL  = pcRegisters[0];
00704               
00705                                                 // loop-back to host.
00706               gpToHost->cCommand = pFromHost->cCommand;
00707               qToHost.put(gpToHost);            // send up for processing. 
00708               
00709               break;
00710             }                                   // get all CPU registers.
00711             
00712             case HCMD_SETMM  :                  // do main-memory write.
00713             {
00714               pSPI->write_memory(pFromHost->cMMdataH, pFromHost->cMMdataL, pFromHost->cMMaddress);     
00715               break;
00716             }                                   // do main-memory write.                   
00717             
00718             case HCMD_GETMM  :                  // do main-memory read.
00719             {
00720               gpToHost = mPoolToHost.alloc();   // allocate next pool entry.   
00721               if (!gpToHost)                    // failure detection.
00722               {
00723                 if (ERROR_BOOT) mbed_reset(); else
00724                 error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); 
00725               }              
00726               
00727               clear_tToHost(gpToHost);          // initialize structure.
00728             
00729                                                 // read from CPU memory.
00730               dMemoryRead = pSPI->read_memory(pFromHost->cMMaddress); 
00731               gpToHost->cMMdataH = (dMemoryRead >> 8) & 0xFF;
00732               gpToHost->cMMdataL = (dMemoryRead >> 0) & 0xFF;
00733               
00734                                                 // loop-back to host.
00735               gpToHost->cCommand   = pFromHost->cCommand;
00736               gpToHost->cMMaddress = pFromHost->cMMaddress;
00737                       
00738               qToHost.put(gpToHost);            // send up for processing.
00739               break;
00740             }                                   // do main-memory read.
00741             
00742             case HCMD_STEP   :                  // step the CPU.
00743             {
00744               pSPI->step();
00745               break;
00746             }                                   // step the CPU.
00747             default          : break;
00748           }                                     // host command decode.            
00749           mPoolFromHost.free(pFromHost);        // done with this queue entry.
00750           pFromHost = NULL;                     // clear pointer.
00751         }                                       // if new host command.
00752         
00753         gulSPIclkCount = pSPI->SPIClockCount(); // propagate to global variable.
00754         gulCPUclkCount = pSPI->CPUClockCount(); // propagate to global variable.
00755  
00756                                                 // thread heartbeat.
00757         dHeartbeat++; if (!(dHeartbeat % HB_MODULO)) led1 = !led1;
00758         queueWatchdogThread_1.put((int *) 0,1); // adds 1mS to wait.
00759         Thread::wait(THREAD_1_WAIT - 1);        // cooperative multitasking.      
00760       }                                         // thread loop.
00761     }                                           // SPIprocessingThread.
00762 /*----------------------------------------------//----------------------------*/
00763     void diagnosticThread(void const *args)     // LCD notification & error check.
00764     {
00765                                                 // track previous values.
00766       static unsigned long ulLastSPIclkCount = 1;      
00767       static unsigned long ulLastCPUclkCount = 1;
00768       int                  dHeartbeat;          // heartbeat counter.
00769       
00770       dHeartbeat = 0;                           // initialize.
00771             
00772       while(1)                                  // thread loop.
00773       {
00774                                                 // if message round trip 
00775                                                 // count not consistent.
00776         if (gdRoundTrip > 1025 || gdRoundTrip < 1024)
00777         {
00778           if (ERROR_BOOT) mbed_reset(); else
00779           error("\n\r diagnosticThread : ERROR serial reply underflow. \n\r");         
00780         }
00781         
00782                                                 // update LCD only if a display
00783                                                 // value has changed.  anti-blink,
00784                                                 // save a bit of power.
00785         if (gulSPIclkCount != ulLastSPIclkCount ||
00786             gulCPUclkCount != ulLastCPUclkCount   )
00787         {
00788           lcd.cls();                            // clear LCD display.
00789           LCD1;                                 // lcd line 1.
00790           lcd.printf(" RTOS CLASS PROJECT");
00791         
00792           LCD2;                                 // lcd line 2.
00793           lcd.printf(" %11lu = SPI clocks",gulSPIclkCount);
00794         
00795           LCD3;                                 // lcd line 3.
00796           lcd.printf(" %11lu = CPU clocks",gulCPUclkCount);
00797         }
00798         
00799         ulLastSPIclkCount = gulSPIclkCount;     // pipeline.
00800         ulLastCPUclkCount = gulCPUclkCount;     // pipeline.
00801        
00802         dHeartbeat++;                           // thread heartbeat.
00803         if (!(dHeartbeat % HB_MODULO)) led2 = !led2;
00804         queueWatchdogThread_2.put((int *) 0,1); // adds 1mS to wait.
00805         Thread::wait(THREAD_2_WAIT - 1);        // multitasking.
00806       }                                         // thread loop.
00807     }                                           // diagnosticThread.
00808 /*----------------------------------------------//----------------------------*/
00809                                                 // this is its own watchdog.
00810 
00811     void watchdogThread(void const *args)       // overall watchdog.
00812     {
00813       int           dHeartbeat;                 // heartbeat counter.
00814       Watchdog_RTOS watchdog;                   // the one and only watchdog.
00815       
00816       dHeartbeat = 0;                           // initialize.
00817 
00818       watchdog.kick(WATCHDOG_S);                // initialize watchdog.
00819     
00820       while (1)                                 // thread loop.
00821       {
00822                                                 // all other threads report-in.
00823                                                 // blocking wait on all of them.
00824         queueWatchdogThread_0.get(osWaitForever); 
00825         queueWatchdogThread_1.get(osWaitForever);
00826         queueWatchdogThread_2.get(osWaitForever);  
00827 
00828         watchdog.kick();                        // reset watchdog timer.
00829         
00830         dHeartbeat++;                           // thread heartbeat.
00831         if (!(dHeartbeat % HB_MODULO)) led3 = !led3;
00832         Thread::wait(THREAD_3_WAIT);            // multitasking.
00833       }                                         // thread loop.
00834     }
00835 /*----------------------------------------------//----------------------------*/
00836     char ascii_nibble_to_binary(char cAscii)    // ascii nibble -> binary.
00837     {
00838       char cBinary;                             // converted value.
00839       
00840       switch(cAscii)
00841       {
00842         case 'F' : {cBinary = 15; break;}
00843         case 'E' : {cBinary = 14; break;}
00844         case 'D' : {cBinary = 13; break;}
00845         case 'C' : {cBinary = 12; break;}
00846         case 'B' : {cBinary = 11; break;}
00847         case 'A' : {cBinary = 10; break;}
00848         case 'f' : {cBinary = 15; break;}
00849         case 'e' : {cBinary = 14; break;}
00850         case 'd' : {cBinary = 13; break;}
00851         case 'c' : {cBinary = 12; break;}
00852         case 'b' : {cBinary = 11; break;}
00853         case 'a' : {cBinary = 10; break;}
00854         case '9' : {cBinary =  9; break;}
00855         case '8' : {cBinary =  8; break;}
00856         case '7' : {cBinary =  7; break;}
00857         case '6' : {cBinary =  6; break;}
00858         case '5' : {cBinary =  5; break;}
00859         case '4' : {cBinary =  4; break;}
00860         case '3' : {cBinary =  3; break;}
00861         case '2' : {cBinary =  2; break;}
00862         case '1' : {cBinary =  1; break;}
00863         case '0' : {cBinary =  0; break;}
00864         default  : {cBinary =  0; break;}
00865       }                                         // switch(cAscii).
00866       return(cBinary);                          // return the binary.
00867     }                                           // ascii_nibble_to_binary.
00868 /*----------------------------------------------//----------------------------*/
00869     char binary_to_ascii_nibble(char cBinary)   // binary -> ascii nibble.
00870     {
00871       char cAscii;                              // converted value.
00872       
00873       switch(cBinary)
00874       {
00875         case 15 : {cAscii = 'F'; break;}
00876         case 14 : {cAscii = 'E'; break;}
00877         case 13 : {cAscii = 'D'; break;}
00878         case 12 : {cAscii = 'C'; break;}
00879         case 11 : {cAscii = 'B'; break;}
00880         case 10 : {cAscii = 'A'; break;}
00881         case  9 : {cAscii = '9'; break;}
00882         case  8 : {cAscii = '8'; break;}
00883         case  7 : {cAscii = '7'; break;}
00884         case  6 : {cAscii = '6'; break;}
00885         case  5 : {cAscii = '5'; break;}
00886         case  4 : {cAscii = '4'; break;}
00887         case  3 : {cAscii = '3'; break;}
00888         case  2 : {cAscii = '2'; break;}
00889         case  1 : {cAscii = '1'; break;}
00890         case  0 : {cAscii = '0'; break;}
00891         default : {cAscii = '0'; break;}
00892       }                                         // switch(cBinary).
00893       return(cAscii);                           // return the binary.
00894     }                                           // binary_to_ascii_nibble.
00895 /*----------------------------------------------//----------------------------*/
00896     void clear_tFromHost(tFromHost * ptFromHost)// clear structure.
00897     {
00898       ptFromHost->cCommand       = 0x00;
00899       ptFromHost->cRegisterID    = 0x00;
00900       ptFromHost->cRegisterValue = 0x00;
00901       ptFromHost->cIRValueH      = 0x00;
00902       ptFromHost->cIRValueL      = 0x00;
00903       ptFromHost->cMMaddress     = 0x00;
00904       ptFromHost->cMMdataH       = 0x00;
00905       ptFromHost->cMMdataL       = 0x00;
00906     }                                           // clear_tFromHost.
00907 /*----------------------------------------------//----------------------------*/
00908     void clear_tToHost(tToHost * ptToHost)      // clear structure.
00909     {
00910       ptToHost->cCommand       = 0x00;
00911       ptToHost->cRegisterID    = 0x00;
00912       ptToHost->cRegisterValue = 0x00;
00913       ptToHost->cMMaddress     = 0x00;
00914       ptToHost->cMMdataH       = 0x00;
00915       ptToHost->cMMdataL       = 0x00; 
00916       ptToHost->cReg0          = 0x00;
00917       ptToHost->cReg1          = 0x00;
00918       ptToHost->cReg2          = 0x00;
00919       ptToHost->cReg3          = 0x00;
00920       ptToHost->cPC            = 0x00;
00921       ptToHost->cIRH           = 0x00;
00922       ptToHost->cIRL           = 0x00;   
00923     }                                           // clear_tToHost.
00924 /*----------------------------------------------//----------------------------*/