Mike Moore / Mbed 2 deprecated USB_device_project

Dependencies:   C12832_lcd USBDevice mbed-rtos mbed mmSPI

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     : usb device drivers
00005     directory : USB_device_project
00006     file      : main.cpp
00007     date      : september 3, 2013.
00008 ----copyright-----------------------------------//------------------------------   
00009     licensed for personal and academic use.
00010     commercial use must be approved by the account-holder of
00011     gated.clock@gmail.com
00012 ----description---------------------------------//------------------------------
00013     overview:
00014     program to provide round-trip communication between a python test-control
00015     program running on a pc host, and a device-under-test CPU implemented on
00016     an altera board.  the pc-host communication is over USBSerial, and the
00017     altera communication is over SPI.
00018     
00019     features:
00020     1. multi-threaded design, use of memory-pools to transfer data between threads.
00021     2. use of USBDevice library for communication with PC host.
00022     3. use of mmSPI custom library for communication with FPGA.
00023     4. main thread provides USBSerial communication to/from host.
00024     5. SPI processing thread provides SPI communication to/from DUT.
00025     6. mmSPI library generates non-overlapping SPI and CPU clocks.
00026     7. background diagnostic thread provides LCD & LED updates.
00027 
00028     indicators: (led<3:0> = LED<1:4>)
00029     1. LCD  provides running counts for SPI and CPU clock cycles.
00030     2. led0 indicates main thread processing.
00031     3. led1 indicates SPI  thread processing.
00032     4. led2 indicates LCD  thread processing.
00033     5. led3 indicates reply-to-host underflow (should never turn on).
00034     
00035     implementation:
00036     1. main.processIncomingSerial(): accept incoming serial data from host,
00037        and map it into tFromHost structures.
00038     2. SPIprocessingThread: take the incoming data structures instances, and
00039        feed their content into mmSPI commands.
00040     3. mmSPI object: given commands/data passed from caller,
00041        map them into SPI outgoing vectors and scan them into the FPGA.
00042     4. mmSPI object: receive incoming SPI vectors from FPGA.
00043        make FPGA payload data available to caller.
00044     5. SPIprocessingThread: load tToHost structures with said FPGA payload data.
00045     6. main.processOutgoingSerial(): transfer tToHost structure data into a
00046        serial outgoing buffer, and block-transfer it to the host PC.
00047        
00048     electrical:
00049     1. four pins (and ground) attached to the zigbee header,
00050        programmed as three SPI pins and the CPU clock.
00051     2. each of the four signals over twisted-pair.
00052     3. but some ribbon cable is used at the FPGA end.
00053     4. best if only the mbed application board USB cable is attached
00054        to the host; if the mbed CPU board USB cable is also attached to
00055        the host, then the python program may attempt to use the wrong USB
00056        connection.
00057     5. no particular power sequence is needed for this system to work.
00058     
00059     
00060     testing:
00061     the python UI provides the main testing mechanism.
00062     
00063         USB connect.
00064     00. press 'CONNECT' button in UI.  verify connection info in shell.
00065     
00066         CPU register w/r
00067     01. type values into {R0,R1,R2,R3,PC,IR} UI entry-forms.
00068     02. press 'REG WRITE' UI button.
00069     03. press 'REG READ'  UI button.
00070     04. verify that the read data is correct.
00071     
00072         CPU main-memory w/r
00073     05. type an address into 'mmADR' UI entry-form.
00074     06. type data into 'mmVAL' UI entry-form.
00075     07. press 'MM WRITE' UI button.
00076     08. type a different address into 'mmADR' UI entry-form.
00077     09. type different data into 'mmVAL' UI entry-form.
00078     10. press 'MM WRITE' UI button.
00079     11. type address from (05) into 'mmADR' UI entry-form.
00080     12. press 'MM READ' UI button.
00081     13. verify that the data from (06) is seen in the 'mmVAL' entry form.
00082     14. type address from (08) into 'mmADR' UI entry-form.
00083     15. press 'MM READ' UI button.
00084     16. verify that the data from (09) is seen in the 'mmVAL' entry form.  
00085     
00086         CPU main-memory full load/dump.
00087     17. press 'PROGRAM' in the UI.  select a program file in the dialog-popup.  
00088     18. watch the load process in the shell text.
00089     19. press 'DUMP     in the UI.  select a main-memory dump file in the diaglog-popup.
00090     20. watch the dump process in the shell text.
00091     
00092         CPU step function.
00093     21. press 'STEP' in the UI repeatedly, watch the UI display the 
00094         CPU register states as the current program is executed one CPU clock
00095         at a time.
00096         
00097         CPU run function.
00098     22. press 'RUN'  in the UI.  watch the current program run at high speed.
00099     23. press 'SLOW' in the UI.  watch the current program run at slow speed.
00100     24. press 'STOP' in the UI.  the program will stop execution.
00101     
00102         CPU test function.
00103     25. press 'TEST' in the UI.  the program will load,execute,dump,compare.
00104     26. tail -f testlog.txt to see test status.
00105     27. the test will repeat until 'STOP TEST' is pressed.
00106     28. long test performed by allowing this mode to continue.
00107     
00108         UI exit function.
00109     29. press 'EXIT' in the UI.  it will exit.
00110 -----includes-----------------------------------//----------------------------*/
00111     #include "mbed.h"                           // general.
00112     #include "USBSerial.h"                      // serial over USB.
00113     #include "C12832_lcd.h"                     // LCD display.
00114     #include "rtos.h"                           // RTOS.
00115     #include "mmSPI.h"                          // SPI.
00116 //---defines------------------------------------//------------------------------
00117     #define LCD1 lcd.locate(0, 0);              // LCD line 1.
00118     #define LCD2 lcd.locate(0,11);              // LCD line 2.
00119     #define LCD3 lcd.locate(0,22);              // LCD line 3.
00120     #define LCD3 lcd.locate(0,22);              // LCD line 3.  
00121     #define SPI_BYTES       8                   // number of SPI bytes. 
00122     #define SPI_HZ     100000                   // SPI frequency in Hz.
00123     #define SER_BYTES       8                   // serial in/out # of bytes.
00124     #define SER_ALIGN       7                   // '$' location in shift-register.
00125     #define THREAD_0_WAIT   8                   // multitasking wait mS.
00126     #define THREAD_1_WAIT   2                   // multitasking wait mS. 
00127     #define THREAD_2_WAIT 128                   // multitasking wait mS. 
00128     #define HB_MODULO      64                   // heartbeat slowdown factor.
00129     #define POOL_LEN       16                   // memory pool dimension.
00130     #define HCMD_SETREG     1                   // host command 'set register'.
00131     #define HCMD_GETREG     2                   // host command 'get register'.
00132     #define HCMD_SETMM      3                   // host command 'set main-memory.'
00133     #define HCMD_GETMM      4                   // host command 'get main-memory.'
00134     #define HCMD_STEP       5                   // host command 'step-CPU'.
00135     #define HCMD_SETIR      6                   // host command 'set-IR'.
00136     #define CPU_REG_0       0                   // CPU register 0.
00137     #define CPU_REG_1       1                   // CPU register 1.
00138     #define CPU_REG_2       2                   // CPU register 2.
00139     #define CPU_REG_3       3                   // CPU register 3.
00140     #define CPU_REG_PC      4                   // CPU Program Counter.
00141     #define CPU_IR_H        5                   // CPU IR high-byte.
00142     #define CPU_IR_L        6                   // CPU IR low-byte.
00143 //--global_definitions--------------------------//------------------------------
00144     struct tFromHost                            // command from host.
00145     {
00146       char cCommand;                            // command from host.
00147       char cRegisterID;                         // which CPU register.
00148       char cRegisterValue;                      // write this to CPU register.
00149       char cIRValueH;                           // write this to IR.
00150       char cIRValueL;                           // write this to IR.
00151       char cMMaddress;                          // access this MM address.
00152       char cMMdataH;                            // MM content high byte.
00153       char cMMdataL;                            // MM content low  byte.
00154     };
00155     MemoryPool<tFromHost, POOL_LEN> mPoolFromHost;
00156     Queue     <tFromHost, POOL_LEN> qFromHost;
00157     
00158 //----  
00159     
00160     struct tToHost                              // reply to host.
00161     {
00162       char cCommand;                            // command executed.
00163       char cRegisterID;                         // which CPU register read.
00164       char cRegisterValue;                      // data from CPU register.
00165       char cMMaddress;                          // which MM address read.
00166       char cMMdataH;                            // MM content high byte.
00167       char cMMdataL;                            // MM content low  byte.      
00168     };
00169     MemoryPool<tToHost, POOL_LEN> mPoolToHost;
00170     Queue     <tToHost, POOL_LEN> qToHost;
00171 //--global_variables----------------------------//------------------------------ 
00172     char          gpcSerialFromHost[SER_BYTES]; // incoming serial buffer.
00173     char          gpcSerialToHost  [SER_BYTES]; // outgoing serial buffer.
00174     char          gcNewCommand;                 // new command from host.
00175     int           gdRoundTrip;                  // +1 from host, -1 to host.
00176     tToHost     * gpToHost;                     // to-host structure.
00177     osEvent       gqToHostEvent;                // incoming message event.
00178     unsigned long gulSPIclkCount;               // SPI clock count.
00179     unsigned long gulCPUclkCount;               // CPU clock count.
00180 //--global_instances----------------------------//------------------------------ 
00181     USBSerial  serial;                          // serial over usb.
00182     C12832_LCD lcd;                             // LCD display.
00183     DigitalOut led0(LED4);                      // thread heartbeat.
00184     DigitalOut led1(LED3);                      // thread heartbeat.
00185     DigitalOut led2(LED2);                      // thread heartbeat.
00186     DigitalOut led3(LED1);                      // SPI reply underflow warning.
00187 //-------prototypes-----------------------------//------------------------------
00188     int  main();                                // main.
00189     void processIncomingSerial();               // process incoming host data.    
00190     void processOutgoingSerial();               // process outgoing data to host.   
00191     void SPIprocessingThread(void const *args); // SPI-side processing.   
00192     void diagnosticThread   (void const *args); // LCD and LED notifications.   
00193     char ascii_nibble_to_binary(char cAscii);   // ascii nibble -> binary.
00194     char binary_to_ascii_nibble(char cBinary);  // binary -> ascii nibble.                
00195     void clear_tFromHost(tFromHost *ptFromHost);// initialize structure.
00196     void clear_tToHost  (tToHost   *ptToHost);  // initialize structure.  
00197 //==============================================//==============================
00198     int main(void)                              // USBSerial processing thread.
00199     {
00200       int dHeartbeat;                           // heartbeat counter.
00201       int dLoop;                                // loop index.
00202 
00203       gpToHost       = NULL;                    // initialize global.
00204       gcNewCommand   =    0;                    // initialize global.
00205       gdRoundTrip    = 1024;                    // initialize global.
00206       gulSPIclkCount =    0;                    // initialize global.
00207       gulCPUclkCount =    0;                    // initialize global.
00208       dHeartbeat     =    0;                    // initialize local.
00209       dLoop          =    0;                    // initialize local.
00210 
00211                                                 // initialize serial-in shift-register.
00212       for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialFromHost[dLoop] = 0;
00213       
00214                                                 // thread-out SPI-side processing.
00215       Thread thread_1(SPIprocessingThread,NULL,osPriorityHigh,DEFAULT_STACK_SIZE,NULL);
00216       
00217                                                 // thread-out diagnostics.
00218       Thread thread_2(diagnosticThread,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL);
00219  
00220       while(1)                                  // main loop.
00221       {   
00222         processIncomingSerial();                // process data in from host.
00223         processOutgoingSerial();                // process data out to host.
00224                         
00225         dHeartbeat++;                           // thread heartbeat.
00226         if (!(dHeartbeat % HB_MODULO)) led0 = !led0;
00227         Thread::wait(THREAD_0_WAIT);            // multitasking.   
00228       }                                         // main loop.
00229     }                                           // main.
00230 /*----------------------------------------------//----------------------------*/
00231 /*
00232    the python program running on the host is sending/receiving ascii characters
00233    which represent command/data binary nibbles.  the python program will send
00234    the '$' character for command-string alignment.  this function reads-in the
00235    incoming serial stream when any serial data is available, into a shift-register,
00236    and breaks upon detection of the '$' alignment character for python
00237    command-processing. at that point the shift-register will look something like
00238    [0] [1] [2] [3] [4] [5] [6] [7]
00239    '1' '2' '3' '4'  x   x   x  '$'  (means write 0x34 to CPU R2).
00240 
00241 
00242     command-host register-number interpretation:
00243     0 = CPU R0.
00244     1 = CPU R1.
00245     2 = CPU R2.
00246     3 = CPU R3.
00247     4 = CPU program-counter.
00248     5 = CPU instruction-register high-byte.
00249     6 = CPU instruction-register low-byte.
00250     
00251     instruction-register write is specially implemented,
00252     instruction-register read  is implemented as two standard register-reads.
00253 
00254     host-command shift-register interpretation:
00255     
00256     gpcSerialFromHost[0] = command.  
00257     subsequent interpretation depends on the command.
00258     
00259 ----   
00260     if command = HCMD_SETREG (write-CPU-register) or HCMD_GETREG (read-CPU-register):
00261     
00262       gpcSerialFromHost[1] = register number (see above).
00263       gpcSerialFromHost[2] = register content, high nibble.
00264       gpcSerialFromHost[3] = register content, low  nibble.
00265       gpcSerialFromHost[4] = not used.
00266       gpcSerialFromHost[5] = not used.
00267       gpcSerialFromHost[6] = not used.
00268 
00269 ----
00270     if command = HCMD_SETIR (write-CPU-instruction-register):
00271     
00272       gpcSerialFromHost[1] = IR register number, implied anyway.
00273       gpcSerialFromHost[2] = IR write value high byte high nibble.
00274       gpcSerialFromHost[3] = IR write value high byte low  nibble.
00275       gpcSerialFromHost[4] = IR write value low  byte high nibble.
00276       gpcSerialFromHost[5] = IR write value low  byte low  nibble.
00277       gpcSerialFromHost[6] = not used.
00278 
00279 ----    
00280     if command = HCMD_SETMM (write to CPU main-memory) or HCMD_GETMM (read from CPU main-memory):
00281     
00282       gpcSerialFromHost[1] = MM address high nibble.
00283       gpcSerialFromHost[2] = MM address low  nibble.
00284       gpcSerialFromHost[3] = MM content high byte high nibble.
00285       gpcSerialFromHost[4] = MM content high byte low  nibble.
00286       gpcSerialFromHost[5] = MM content low  byte high nibble.
00287       gpcSerialFromHost[6] = MM content low  byte low  nibble.
00288       
00289       the above also applies to function 'processOutgoingSerial'.
00290 */
00291 
00292     void processIncomingSerial(void)            // process incoming serial data.
00293     {
00294       int         dLoop;                        // loop index.
00295       tFromHost * pFromHost;                    // from-host structure.
00296       
00297       while(serial.available())                 // while data from host is available.
00298       {
00299                                                 // shift-in the serial stream.
00300         for (dLoop = 0; dLoop < (SER_BYTES - 1); dLoop++)
00301         gpcSerialFromHost[dLoop] = gpcSerialFromHost[dLoop + 1];
00302         gpcSerialFromHost[SER_BYTES - 1] = serial._getc();
00303         
00304         if (gpcSerialFromHost[SER_ALIGN] == '$')// data from host is aligned.
00305         {
00306           gcNewCommand = 1;                     // new host command just recognised.
00307           break;                                // need to process aligned data.
00308         }                                       // data from host is aligned. 
00309       }                                         // while data from host is available.
00310       
00311                                                 // even if more data awaits from the
00312                                                 // incoming serial stream, we now need
00313                                                 // to process the aligned data recognised
00314                                                 // as a command from the host.  
00315                                                 
00316       if (gcNewCommand)                         // execute once per new command.
00317       {
00318         pFromHost = mPoolFromHost.alloc();      // allocate next pool entry.
00319         if (!pFromHost) error("\n\r processIncomingSerial : FATAL malloc error for pFromHost. \n\r"); 
00320         clear_tFromHost(pFromHost);             // initialize structure.
00321         
00322                                                 // copy-in host message.
00323         pFromHost->cCommand = ascii_nibble_to_binary(gpcSerialFromHost[0]);
00324                     
00325                                                 // host requests register access.
00326         if (pFromHost->cCommand == HCMD_SETREG || pFromHost->cCommand == HCMD_GETREG)
00327         {
00328           pFromHost->cRegisterID    =   ascii_nibble_to_binary(gpcSerialFromHost[1]);
00329           pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + 
00330                                         ascii_nibble_to_binary(gpcSerialFromHost[3]);                
00331         }
00332         
00333                                                 
00334         if (pFromHost->cCommand == HCMD_SETIR)  // host requests IR write.
00335         {
00336           pFromHost->cIRValueH = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + 
00337                                    ascii_nibble_to_binary(gpcSerialFromHost[3]);     
00338           pFromHost->cIRValueL = ((ascii_nibble_to_binary(gpcSerialFromHost[4])) << 4) + 
00339                                    ascii_nibble_to_binary(gpcSerialFromHost[5]);         
00340         }
00341         
00342         
00343                                                 // host requests main-memory access.
00344         if (pFromHost->cCommand == HCMD_SETMM || pFromHost->cCommand == HCMD_GETMM)
00345         {
00346           pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + 
00347                                     ascii_nibble_to_binary(gpcSerialFromHost[2]);  
00348           pFromHost->cMMdataH   = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + 
00349                                     ascii_nibble_to_binary(gpcSerialFromHost[4]);         
00350           pFromHost->cMMdataL   = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + 
00351                                     ascii_nibble_to_binary(gpcSerialFromHost[6]);        
00352         }                                       // host requests main-memory access.
00353         
00354         if (pFromHost->cCommand == HCMD_GETREG || pFromHost->cCommand == HCMD_GETMM)
00355         gdRoundTrip++;                          // expected reply to host is pending.           
00356         qFromHost.put(pFromHost);               // send out for processing.    
00357         gcNewCommand = 0;                       // don't execute until next new command.
00358       }                                         // execute once per new command.
00359       Thread::wait(THREAD_0_WAIT);              // multitasking.  
00360     }                                           // processIncomingSerial
00361 /*----------------------------------------------//----------------------------*/
00362     void processOutgoingSerial(void)            // prepare/transmit data to host.
00363     {
00364       int dLoop;                                // loop index.
00365 
00366       gqToHostEvent = qToHost.get(1);           // check for reply back to host.
00367           
00368                                                 // if new reply to host:
00369       if (gqToHostEvent.status == osEventMessage) 
00370       {
00371                                                 // bring it in from the queue.
00372         gpToHost = (tToHost *) gqToHostEvent.value.p;
00373         if (!gpToHost) error("\n\r processOutgoingSerial : FATAL NULL gpToHost pointer. \n\r"); 
00374           
00375                                                 // clear outgoing buffer.
00376         for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialToHost[dLoop] = 0;
00377                                                            
00378                                                 // the commands from the host were
00379                                                 // looped-back into the to-host struct,
00380                                                 // make use of them here.
00381                                            
00382         if (gpToHost->cCommand == HCMD_GETREG)  // reading from a register.                                             
00383         {
00384           gpcSerialToHost[0] = binary_to_ascii_nibble(  gpToHost->cCommand);
00385           gpcSerialToHost[1] = binary_to_ascii_nibble(  gpToHost->cRegisterID);
00386           gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 4) & 0x0F);
00387           gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 0) & 0x0F);
00388           gpcSerialToHost[4] = '\n';            // signals end of transfer.
00389              
00390                                                 // transmit to the host.
00391           serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES);        
00392           gdRoundTrip--;                        // expected reply sent to host.                           
00393         }                                  
00394                                                          
00395         if (gpToHost->cCommand == HCMD_GETMM)  // reading from main-memory.                                              
00396         {
00397           gpcSerialToHost[0] = binary_to_ascii_nibble(  gpToHost->cCommand);
00398           gpcSerialToHost[1] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 4) & 0x0F);
00399           gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 0) & 0x0F);
00400           gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cMMdataH  ) >> 4) & 0x0F);
00401           gpcSerialToHost[4] = binary_to_ascii_nibble(((gpToHost->cMMdataH  ) >> 0) & 0x0F);
00402           gpcSerialToHost[5] = binary_to_ascii_nibble(((gpToHost->cMMdataL  ) >> 4) & 0x0F);
00403           gpcSerialToHost[6] = binary_to_ascii_nibble(((gpToHost->cMMdataL  ) >> 0) & 0x0F);   
00404           gpcSerialToHost[7] = '\n';            // signals end of transfer.    
00405              
00406                                                 // transmit to the host.
00407           serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES);    
00408           gdRoundTrip--;                        // expected reply sent to host.
00409         }           
00410         mPoolToHost.free(gpToHost);             // done with this queue entry.
00411         gpToHost = NULL;                        // clear pointer.
00412       }                                         // if new reply to host.     
00413     }                                           // processOutgoingSerial.
00414 /*----------------------------------------------//----------------------------*/      
00415 //  the pcSendBuffer and pcReceiveBuffer arrays are not used by this function,
00416 //  but they are declared by this function, and their pointers are passed
00417 //  down to the mmSPI library for its use of them.
00418 //  note- the prefix 'pc' means 'pointer of type character', not 'personal computer'.
00419 
00420     void SPIprocessingThread(void const *args)  // process host-commands via SPI.
00421     {
00422       char        pcSendBuffer   [SPI_BYTES];   // SPI send buffer.
00423       char        pcReceiveBuffer[SPI_BYTES];   // SPI receive buffer.
00424       int         dHeartbeat;                   // heartbeat counter.
00425       int         dMemoryRead;                  // read main-memory into this.
00426       int         dLoop;                        // loop index.
00427       osEvent     qFromHostEvent;               // incoming message event.
00428       tFromHost * pFromHost;                    // message structure.
00429       tToHost   * gpToHost;                     // message structure.
00430       mmSPI     * pSPI;                         // SPI.
00431       
00432       pFromHost   = NULL;                       // NULL pointers.
00433       gpToHost    = NULL;
00434       pSPI        = NULL;
00435       dHeartbeat  = 0;                          // clear variables.
00436       dMemoryRead = 0;
00437       dLoop       = 0;
00438                                                 // clear SPI vectors.
00439       for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcSendBuffer   [dLoop] = 0;
00440       for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcReceiveBuffer[dLoop] = 0;
00441  
00442       pSPI = new mmSPI;                         // SPI allocation.
00443       if (!pSPI)  error("\n\r SPIprocessingThread : FATAL new error for pSPI. \n\r");
00444       
00445       pSPI->setSendBuffer   (pcSendBuffer);     // set SPI send buffer.
00446       pSPI->setReceiveBuffer(pcReceiveBuffer);  // set SPI receive buffer.
00447       pSPI->setNumberOfBytes(SPI_BYTES);        // set SPI number of bytes.
00448       pSPI->setSPIfrequency (SPI_HZ);           // set SPI clock frequency.
00449       
00450       while(1)                                  // thread loop.
00451       {
00452         qFromHostEvent = qFromHost.get(1);      // check for incoming host command.
00453         
00454                                                 // if new host command:
00455         if (qFromHostEvent.status == osEventMessage) 
00456         {
00457                                                 // bring it in from the queue.
00458           pFromHost = (tFromHost *) qFromHostEvent.value.p;
00459           if (!pFromHost) error("\n\r SPIprocessingThread : FATAL NULL pFromHost pointer. \n\r"); 
00460           
00461           switch(pFromHost->cCommand)           // host command decode.
00462           {
00463             case HCMD_SETREG :                  // set CPU register.
00464             {
00465               switch(pFromHost->cRegisterID)    // which register to write to.
00466               {
00467                 case CPU_REG_0  : {pSPI->write_register(CPU_REG_0 , pFromHost->cRegisterValue); break;}
00468                 case CPU_REG_1  : {pSPI->write_register(CPU_REG_1 , pFromHost->cRegisterValue); break;}
00469                 case CPU_REG_2  : {pSPI->write_register(CPU_REG_2 , pFromHost->cRegisterValue); break;}
00470                 case CPU_REG_3  : {pSPI->write_register(CPU_REG_3 , pFromHost->cRegisterValue); break;}
00471                 case CPU_REG_PC : {pSPI->write_register(CPU_REG_PC, pFromHost->cRegisterValue); break;}
00472                 default         : {break;}
00473               }                                 // which register to write to.
00474               break;
00475             }                                   // set CPU register.
00476             
00477             case HCMD_SETIR:                    // set instruction register.
00478             {
00479               pSPI->write_IR(pFromHost->cIRValueH, pFromHost->cIRValueL);
00480               break;
00481             }                                   // set instruction register.
00482             
00483             case HCMD_GETREG :                  // get CPU register.
00484             {
00485               gpToHost = mPoolToHost.alloc();   // allocate next pool entry.
00486               if (!gpToHost) error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); 
00487               clear_tToHost(gpToHost);          // initialize structure.
00488             
00489               switch(pFromHost->cRegisterID)    // which register to read from.
00490               {
00491                 case CPU_REG_0  : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_0 ); break;}
00492                 case CPU_REG_1  : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_1 ); break;}
00493                 case CPU_REG_2  : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_2 ); break;}
00494                 case CPU_REG_3  : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_3 ); break;}
00495                 case CPU_REG_PC : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_PC); break;}
00496                 case CPU_IR_H   : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_H  ); break;}
00497                 case CPU_IR_L   : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_L  ); break;}
00498                 default         : {break;}    
00499               }                                 // which register to read from.
00500               
00501                                                 // loop-back to host.
00502               gpToHost->cCommand    = pFromHost->cCommand;
00503               gpToHost->cRegisterID = pFromHost->cRegisterID;  
00504                           
00505               qToHost.put(gpToHost);            // send up for processing.    
00506               break; 
00507             }                                   // get CPU register.     
00508             
00509             case HCMD_SETMM  :                  // do main-memory write.
00510             {
00511               pSPI->write_memory(pFromHost->cMMdataH, pFromHost->cMMdataL, pFromHost->cMMaddress);     
00512               break;
00513             }                                   // do main-memory write.                   
00514             
00515             case HCMD_GETMM  :                  // do main-memory read.
00516             {
00517               gpToHost = mPoolToHost.alloc();   // allocate next pool entry.
00518               if (!gpToHost) error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); 
00519               clear_tToHost(gpToHost);          // initialize structure.
00520             
00521                                                 // read from CPU memory.
00522               dMemoryRead = pSPI->read_memory(pFromHost->cMMaddress); 
00523               gpToHost->cMMdataH = (dMemoryRead >> 8) & 0xFF;
00524               gpToHost->cMMdataL = (dMemoryRead >> 0) & 0xFF;
00525               
00526                                                 // loop-back to host.
00527               gpToHost->cCommand   = pFromHost->cCommand;
00528               gpToHost->cMMaddress = pFromHost->cMMaddress;
00529                       
00530               qToHost.put(gpToHost);            // send up for processing.
00531               break;
00532             }                                   // do main-memory read.
00533             
00534             case HCMD_STEP   :                  // step the CPU.
00535             {
00536               pSPI->step();
00537               break;
00538             }                                   // step the CPU.
00539             default          : break;
00540           }                                     // host command decode.            
00541           mPoolFromHost.free(pFromHost);        // done with this queue entry.
00542           pFromHost = NULL;                     // clear pointer.
00543         }                                       // if new host command.
00544         
00545         gulSPIclkCount = pSPI->SPIClockCount(); // propagate to global variable.
00546         gulCPUclkCount = pSPI->CPUClockCount(); // propagate to global variable.
00547  
00548                                                 // thread heartbeat.
00549         dHeartbeat++; if (!(dHeartbeat % HB_MODULO)) led1 = !led1;
00550         Thread::wait(THREAD_1_WAIT);            // cooperative multitasking.      
00551       }                                         // thread loop.
00552     }                                           // SPIprocessingThread.
00553 /*----------------------------------------------//----------------------------*/
00554     void diagnosticThread(void const *args)     // LCD and LED notifications.
00555     {
00556       int dHeartbeat;                           // heartbeat counter.
00557     
00558       dHeartbeat = 0;                           // initialize.
00559       led3       = 0;                           // initialize.
00560       
00561       while(1)                                  // thread loop.
00562       {
00563                                                 // if message round trip 
00564                                                 // count not consistent.
00565         if (gdRoundTrip > 1025 || gdRoundTrip < 1024) led3 = 1;
00566         
00567         lcd.cls();                              // clear LCD display.
00568         LCD1;                                   // lcd line 1.
00569         lcd.printf(" USB DEV CLASS PROJECT");
00570         
00571         LCD2;                                   // lcd line 2.
00572         lcd.printf(" %11lu = SPI clocks",gulSPIclkCount);
00573         
00574         LCD3;                                   // lcd line 3.
00575         lcd.printf(" %11lu = CPU clocks",gulCPUclkCount);
00576        
00577         dHeartbeat++;                           // thread heartbeat.
00578         if (!(dHeartbeat % HB_MODULO)) led2 = !led2;
00579         Thread::wait(THREAD_2_WAIT);            // multitasking.
00580       }                                         // thread loop.
00581     }                                           // diagnosticThread.
00582 /*----------------------------------------------//----------------------------*/
00583     char ascii_nibble_to_binary(char cAscii)    // ascii nibble -> binary.
00584     {
00585       char cBinary;                             // converted value.
00586       
00587       switch(cAscii)
00588       {
00589         case 'F' : {cBinary = 15; break;}
00590         case 'E' : {cBinary = 14; break;}
00591         case 'D' : {cBinary = 13; break;}
00592         case 'C' : {cBinary = 12; break;}
00593         case 'B' : {cBinary = 11; break;}
00594         case 'A' : {cBinary = 10; break;}
00595         case 'f' : {cBinary = 15; break;}
00596         case 'e' : {cBinary = 14; break;}
00597         case 'd' : {cBinary = 13; break;}
00598         case 'c' : {cBinary = 12; break;}
00599         case 'b' : {cBinary = 11; break;}
00600         case 'a' : {cBinary = 10; break;}
00601         case '9' : {cBinary =  9; break;}
00602         case '8' : {cBinary =  8; break;}
00603         case '7' : {cBinary =  7; break;}
00604         case '6' : {cBinary =  6; break;}
00605         case '5' : {cBinary =  5; break;}
00606         case '4' : {cBinary =  4; break;}
00607         case '3' : {cBinary =  3; break;}
00608         case '2' : {cBinary =  2; break;}
00609         case '1' : {cBinary =  1; break;}
00610         case '0' : {cBinary =  0; break;}
00611         default  : {cBinary =  0; break;}
00612       }                                         // switch(cAscii).
00613       return(cBinary);                          // return the binary.
00614     }                                           // ascii_nibble_to_binary.
00615 /*----------------------------------------------//----------------------------*/
00616     char binary_to_ascii_nibble(char cBinary)   // binary -> ascii nibble.
00617     {
00618       char cAscii;                              // converted value.
00619       
00620       switch(cBinary)
00621       {
00622         case 15 : {cAscii = 'F'; break;}
00623         case 14 : {cAscii = 'E'; break;}
00624         case 13 : {cAscii = 'D'; break;}
00625         case 12 : {cAscii = 'C'; break;}
00626         case 11 : {cAscii = 'B'; break;}
00627         case 10 : {cAscii = 'A'; break;}
00628         case  9 : {cAscii = '9'; break;}
00629         case  8 : {cAscii = '8'; break;}
00630         case  7 : {cAscii = '7'; break;}
00631         case  6 : {cAscii = '6'; break;}
00632         case  5 : {cAscii = '5'; break;}
00633         case  4 : {cAscii = '4'; break;}
00634         case  3 : {cAscii = '3'; break;}
00635         case  2 : {cAscii = '2'; break;}
00636         case  1 : {cAscii = '1'; break;}
00637         case  0 : {cAscii = '0'; break;}
00638         default : {cAscii = '0'; break;}
00639       }                                         // switch(cBinary).
00640       return(cAscii);                           // return the binary.
00641     }                                           // binary_to_ascii_nibble.
00642 /*----------------------------------------------//----------------------------*/
00643     void clear_tFromHost(tFromHost * ptFromHost)// clear structure.
00644     {
00645       ptFromHost->cCommand       = 0x00;
00646       ptFromHost->cRegisterID    = 0x00;
00647       ptFromHost->cRegisterValue = 0x00;
00648       ptFromHost->cIRValueH      = 0x00;
00649       ptFromHost->cIRValueL      = 0x00;
00650       ptFromHost->cMMaddress     = 0x00;
00651       ptFromHost->cMMdataH       = 0x00;
00652       ptFromHost->cMMdataL       = 0x00;
00653     }                                           // clear_tFromHost.
00654 /*----------------------------------------------//----------------------------*/
00655     void clear_tToHost(tToHost * ptToHost)      // clear structure.
00656     {
00657       ptToHost->cCommand       = 0x00;
00658       ptToHost->cRegisterID    = 0x00;
00659       ptToHost->cRegisterValue = 0x00;
00660       ptToHost->cMMaddress     = 0x00;
00661       ptToHost->cMMdataH       = 0x00;
00662       ptToHost->cMMdataL       = 0x00;
00663     }                                           // clear_tToHost.
00664 /*----------------------------------------------//----------------------------*/