USB Device Programming class project. This project allows a Python/Tk program running on a PC host to monitor/control a test-CPU programmed into an altera development board.
Dependencies: C12832_lcd USBDevice mbed-rtos mbed mmSPI
main.cpp
- Committer:
- gatedClock
- Date:
- 2013-09-01
- Revision:
- 12:d10f526ca443
- Parent:
- 9:81726c95be74
File content as of revision 12:d10f526ca443:
/*----------------------------------------------//------------------------------ student : m-moore email : gated.clock@gmail.com class : usb device drivers directory : USB_device_project file : main.cpp date : september 3, 2013. ----copyright-----------------------------------//------------------------------ licensed for personal and academic use. commercial use must be approved by the account-holder of gated.clock@gmail.com ----description---------------------------------//------------------------------ overview: program to provide round-trip communication between a python test-control program running on a pc host, and a device-under-test CPU implemented on an altera board. the pc-host communication is over USBSerial, and the altera communication is over SPI. features: 1. multi-threaded design, use of memory-pools to transfer data between threads. 2. use of USBDevice library for communication with PC host. 3. use of mmSPI custom library for communication with FPGA. 4. main thread provides USBSerial communication to/from host. 5. SPI processing thread provides SPI communication to/from DUT. 6. mmSPI library generates non-overlapping SPI and CPU clocks. 7. background diagnostic thread provides LCD & LED updates. indicators: (led<3:0> = LED<1:4>) 1. LCD provides running counts for SPI and CPU clock cycles. 2. led0 indicates main thread processing. 3. led1 indicates SPI thread processing. 4. led2 indicates LCD thread processing. 5. led3 indicates reply-to-host underflow (should never turn on). implementation: 1. main.processIncomingSerial(): accept incoming serial data from host, and map it into tFromHost structures. 2. SPIprocessingThread: take the incoming data structures instances, and feed their content into mmSPI commands. 3. mmSPI object: given commands/data passed from caller, map them into SPI outgoing vectors and scan them into the FPGA. 4. mmSPI object: receive incoming SPI vectors from FPGA. make FPGA payload data available to caller. 5. SPIprocessingThread: load tToHost structures with said FPGA payload data. 6. main.processOutgoingSerial(): transfer tToHost structure data into a serial outgoing buffer, and block-transfer it to the host PC. electrical: 1. four pins (and ground) attached to the zigbee header, programmed as three SPI pins and the CPU clock. 2. each of the four signals over twisted-pair. 3. but some ribbon cable is used at the FPGA end. 4. best if only the mbed application board USB cable is attached to the host; if the mbed CPU board USB cable is also attached to the host, then the python program may attempt to use the wrong USB connection. 5. no particular power sequence is needed for this system to work. testing: the python UI provides the main testing mechanism. USB connect. 00. press 'CONNECT' button in UI. verify connection info in shell. CPU register w/r 01. type values into {R0,R1,R2,R3,PC,IR} UI entry-forms. 02. press 'REG WRITE' UI button. 03. press 'REG READ' UI button. 04. verify that the read data is correct. CPU main-memory w/r 05. type an address into 'mmADR' UI entry-form. 06. type data into 'mmVAL' UI entry-form. 07. press 'MM WRITE' UI button. 08. type a different address into 'mmADR' UI entry-form. 09. type different data into 'mmVAL' UI entry-form. 10. press 'MM WRITE' UI button. 11. type address from (05) into 'mmADR' UI entry-form. 12. press 'MM READ' UI button. 13. verify that the data from (06) is seen in the 'mmVAL' entry form. 14. type address from (08) into 'mmADR' UI entry-form. 15. press 'MM READ' UI button. 16. verify that the data from (09) is seen in the 'mmVAL' entry form. CPU main-memory full load/dump. 17. press 'PROGRAM' in the UI. select a program file in the dialog-popup. 18. watch the load process in the shell text. 19. press 'DUMP in the UI. select a main-memory dump file in the diaglog-popup. 20. watch the dump process in the shell text. CPU step function. 21. press 'STEP' in the UI repeatedly, watch the UI display the CPU register states as the current program is executed one CPU clock at a time. CPU run function. 22. press 'RUN' in the UI. watch the current program run at high speed. 23. press 'SLOW' in the UI. watch the current program run at slow speed. 24. press 'STOP' in the UI. the program will stop execution. CPU test function. 25. press 'TEST' in the UI. the program will load,execute,dump,compare. 26. tail -f testlog.txt to see test status. 27. the test will repeat until 'STOP TEST' is pressed. 28. long test performed by allowing this mode to continue. UI exit function. 29. press 'EXIT' in the UI. it will exit. -----includes-----------------------------------//----------------------------*/ #include "mbed.h" // general. #include "USBSerial.h" // serial over USB. #include "C12832_lcd.h" // LCD display. #include "rtos.h" // RTOS. #include "mmSPI.h" // SPI. //---defines------------------------------------//------------------------------ #define LCD1 lcd.locate(0, 0); // LCD line 1. #define LCD2 lcd.locate(0,11); // LCD line 2. #define LCD3 lcd.locate(0,22); // LCD line 3. #define LCD3 lcd.locate(0,22); // LCD line 3. #define SPI_BYTES 8 // number of SPI bytes. #define SPI_HZ 100000 // SPI frequency in Hz. #define SER_BYTES 8 // serial in/out # of bytes. #define SER_ALIGN 7 // '$' location in shift-register. #define THREAD_0_WAIT 8 // multitasking wait mS. #define THREAD_1_WAIT 2 // multitasking wait mS. #define THREAD_2_WAIT 128 // multitasking wait mS. #define HB_MODULO 64 // heartbeat slowdown factor. #define POOL_LEN 16 // memory pool dimension. #define HCMD_SETREG 1 // host command 'set register'. #define HCMD_GETREG 2 // host command 'get register'. #define HCMD_SETMM 3 // host command 'set main-memory.' #define HCMD_GETMM 4 // host command 'get main-memory.' #define HCMD_STEP 5 // host command 'step-CPU'. #define HCMD_SETIR 6 // host command 'set-IR'. #define CPU_REG_0 0 // CPU register 0. #define CPU_REG_1 1 // CPU register 1. #define CPU_REG_2 2 // CPU register 2. #define CPU_REG_3 3 // CPU register 3. #define CPU_REG_PC 4 // CPU Program Counter. #define CPU_IR_H 5 // CPU IR high-byte. #define CPU_IR_L 6 // CPU IR low-byte. //--global_definitions--------------------------//------------------------------ struct tFromHost // command from host. { char cCommand; // command from host. char cRegisterID; // which CPU register. char cRegisterValue; // write this to CPU register. char cIRValueH; // write this to IR. char cIRValueL; // write this to IR. char cMMaddress; // access this MM address. char cMMdataH; // MM content high byte. char cMMdataL; // MM content low byte. }; MemoryPool<tFromHost, POOL_LEN> mPoolFromHost; Queue <tFromHost, POOL_LEN> qFromHost; //---- struct tToHost // reply to host. { char cCommand; // command executed. char cRegisterID; // which CPU register read. char cRegisterValue; // data from CPU register. char cMMaddress; // which MM address read. char cMMdataH; // MM content high byte. char cMMdataL; // MM content low byte. }; MemoryPool<tToHost, POOL_LEN> mPoolToHost; Queue <tToHost, POOL_LEN> qToHost; //--global_variables----------------------------//------------------------------ char gpcSerialFromHost[SER_BYTES]; // incoming serial buffer. char gpcSerialToHost [SER_BYTES]; // outgoing serial buffer. char gcNewCommand; // new command from host. int gdRoundTrip; // +1 from host, -1 to host. tToHost * gpToHost; // to-host structure. osEvent gqToHostEvent; // incoming message event. unsigned long gulSPIclkCount; // SPI clock count. unsigned long gulCPUclkCount; // CPU clock count. //--global_instances----------------------------//------------------------------ USBSerial serial; // serial over usb. C12832_LCD lcd; // LCD display. DigitalOut led0(LED4); // thread heartbeat. DigitalOut led1(LED3); // thread heartbeat. DigitalOut led2(LED2); // thread heartbeat. DigitalOut led3(LED1); // SPI reply underflow warning. //-------prototypes-----------------------------//------------------------------ int main(); // main. void processIncomingSerial(); // process incoming host data. void processOutgoingSerial(); // process outgoing data to host. void SPIprocessingThread(void const *args); // SPI-side processing. void diagnosticThread (void const *args); // LCD and LED notifications. char ascii_nibble_to_binary(char cAscii); // ascii nibble -> binary. char binary_to_ascii_nibble(char cBinary); // binary -> ascii nibble. void clear_tFromHost(tFromHost *ptFromHost);// initialize structure. void clear_tToHost (tToHost *ptToHost); // initialize structure. //==============================================//============================== int main(void) // USBSerial processing thread. { int dHeartbeat; // heartbeat counter. int dLoop; // loop index. gpToHost = NULL; // initialize global. gcNewCommand = 0; // initialize global. gdRoundTrip = 1024; // initialize global. gulSPIclkCount = 0; // initialize global. gulCPUclkCount = 0; // initialize global. dHeartbeat = 0; // initialize local. dLoop = 0; // initialize local. // initialize serial-in shift-register. for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialFromHost[dLoop] = 0; // thread-out SPI-side processing. Thread thread_1(SPIprocessingThread,NULL,osPriorityHigh,DEFAULT_STACK_SIZE,NULL); // thread-out diagnostics. Thread thread_2(diagnosticThread,NULL,osPriorityIdle,DEFAULT_STACK_SIZE,NULL); while(1) // main loop. { processIncomingSerial(); // process data in from host. processOutgoingSerial(); // process data out to host. dHeartbeat++; // thread heartbeat. if (!(dHeartbeat % HB_MODULO)) led0 = !led0; Thread::wait(THREAD_0_WAIT); // multitasking. } // main loop. } // main. /*----------------------------------------------//----------------------------*/ /* the python program running on the host is sending/receiving ascii characters which represent command/data binary nibbles. the python program will send the '$' character for command-string alignment. this function reads-in the incoming serial stream when any serial data is available, into a shift-register, and breaks upon detection of the '$' alignment character for python command-processing. at that point the shift-register will look something like [0] [1] [2] [3] [4] [5] [6] [7] '1' '2' '3' '4' x x x '$' (means write 0x34 to CPU R2). command-host register-number interpretation: 0 = CPU R0. 1 = CPU R1. 2 = CPU R2. 3 = CPU R3. 4 = CPU program-counter. 5 = CPU instruction-register high-byte. 6 = CPU instruction-register low-byte. instruction-register write is specially implemented, instruction-register read is implemented as two standard register-reads. host-command shift-register interpretation: gpcSerialFromHost[0] = command. subsequent interpretation depends on the command. ---- if command = HCMD_SETREG (write-CPU-register) or HCMD_GETREG (read-CPU-register): gpcSerialFromHost[1] = register number (see above). gpcSerialFromHost[2] = register content, high nibble. gpcSerialFromHost[3] = register content, low nibble. gpcSerialFromHost[4] = not used. gpcSerialFromHost[5] = not used. gpcSerialFromHost[6] = not used. ---- if command = HCMD_SETIR (write-CPU-instruction-register): gpcSerialFromHost[1] = IR register number, implied anyway. gpcSerialFromHost[2] = IR write value high byte high nibble. gpcSerialFromHost[3] = IR write value high byte low nibble. gpcSerialFromHost[4] = IR write value low byte high nibble. gpcSerialFromHost[5] = IR write value low byte low nibble. gpcSerialFromHost[6] = not used. ---- if command = HCMD_SETMM (write to CPU main-memory) or HCMD_GETMM (read from CPU main-memory): gpcSerialFromHost[1] = MM address high nibble. gpcSerialFromHost[2] = MM address low nibble. gpcSerialFromHost[3] = MM content high byte high nibble. gpcSerialFromHost[4] = MM content high byte low nibble. gpcSerialFromHost[5] = MM content low byte high nibble. gpcSerialFromHost[6] = MM content low byte low nibble. the above also applies to function 'processOutgoingSerial'. */ void processIncomingSerial(void) // process incoming serial data. { int dLoop; // loop index. tFromHost * pFromHost; // from-host structure. while(serial.available()) // while data from host is available. { // shift-in the serial stream. for (dLoop = 0; dLoop < (SER_BYTES - 1); dLoop++) gpcSerialFromHost[dLoop] = gpcSerialFromHost[dLoop + 1]; gpcSerialFromHost[SER_BYTES - 1] = serial._getc(); if (gpcSerialFromHost[SER_ALIGN] == '$')// data from host is aligned. { gcNewCommand = 1; // new host command just recognised. break; // need to process aligned data. } // data from host is aligned. } // while data from host is available. // even if more data awaits from the // incoming serial stream, we now need // to process the aligned data recognised // as a command from the host. if (gcNewCommand) // execute once per new command. { pFromHost = mPoolFromHost.alloc(); // allocate next pool entry. if (!pFromHost) error("\n\r processIncomingSerial : FATAL malloc error for pFromHost. \n\r"); clear_tFromHost(pFromHost); // initialize structure. // copy-in host message. pFromHost->cCommand = ascii_nibble_to_binary(gpcSerialFromHost[0]); // host requests register access. if (pFromHost->cCommand == HCMD_SETREG || pFromHost->cCommand == HCMD_GETREG) { pFromHost->cRegisterID = ascii_nibble_to_binary(gpcSerialFromHost[1]); pFromHost->cRegisterValue = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + ascii_nibble_to_binary(gpcSerialFromHost[3]); } if (pFromHost->cCommand == HCMD_SETIR) // host requests IR write. { pFromHost->cIRValueH = ((ascii_nibble_to_binary(gpcSerialFromHost[2])) << 4) + ascii_nibble_to_binary(gpcSerialFromHost[3]); pFromHost->cIRValueL = ((ascii_nibble_to_binary(gpcSerialFromHost[4])) << 4) + ascii_nibble_to_binary(gpcSerialFromHost[5]); } // host requests main-memory access. if (pFromHost->cCommand == HCMD_SETMM || pFromHost->cCommand == HCMD_GETMM) { pFromHost->cMMaddress = ((ascii_nibble_to_binary(gpcSerialFromHost[1])) << 4) + ascii_nibble_to_binary(gpcSerialFromHost[2]); pFromHost->cMMdataH = ((ascii_nibble_to_binary(gpcSerialFromHost[3])) << 4) + ascii_nibble_to_binary(gpcSerialFromHost[4]); pFromHost->cMMdataL = ((ascii_nibble_to_binary(gpcSerialFromHost[5])) << 4) + ascii_nibble_to_binary(gpcSerialFromHost[6]); } // host requests main-memory access. if (pFromHost->cCommand == HCMD_GETREG || pFromHost->cCommand == HCMD_GETMM) gdRoundTrip++; // expected reply to host is pending. qFromHost.put(pFromHost); // send out for processing. gcNewCommand = 0; // don't execute until next new command. } // execute once per new command. Thread::wait(THREAD_0_WAIT); // multitasking. } // processIncomingSerial /*----------------------------------------------//----------------------------*/ void processOutgoingSerial(void) // prepare/transmit data to host. { int dLoop; // loop index. gqToHostEvent = qToHost.get(1); // check for reply back to host. // if new reply to host: if (gqToHostEvent.status == osEventMessage) { // bring it in from the queue. gpToHost = (tToHost *) gqToHostEvent.value.p; if (!gpToHost) error("\n\r processOutgoingSerial : FATAL NULL gpToHost pointer. \n\r"); // clear outgoing buffer. for (dLoop = 0; dLoop < SER_BYTES; dLoop++) gpcSerialToHost[dLoop] = 0; // the commands from the host were // looped-back into the to-host struct, // make use of them here. if (gpToHost->cCommand == HCMD_GETREG) // reading from a register. { gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); gpcSerialToHost[1] = binary_to_ascii_nibble( gpToHost->cRegisterID); gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 4) & 0x0F); gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cRegisterValue) >> 0) & 0x0F); gpcSerialToHost[4] = '\n'; // signals end of transfer. // transmit to the host. serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); gdRoundTrip--; // expected reply sent to host. } if (gpToHost->cCommand == HCMD_GETMM) // reading from main-memory. { gpcSerialToHost[0] = binary_to_ascii_nibble( gpToHost->cCommand); gpcSerialToHost[1] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 4) & 0x0F); gpcSerialToHost[2] = binary_to_ascii_nibble(((gpToHost->cMMaddress) >> 0) & 0x0F); gpcSerialToHost[3] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 4) & 0x0F); gpcSerialToHost[4] = binary_to_ascii_nibble(((gpToHost->cMMdataH ) >> 0) & 0x0F); gpcSerialToHost[5] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 4) & 0x0F); gpcSerialToHost[6] = binary_to_ascii_nibble(((gpToHost->cMMdataL ) >> 0) & 0x0F); gpcSerialToHost[7] = '\n'; // signals end of transfer. // transmit to the host. serial.writeBlock((uint8_t *) gpcSerialToHost, (uint16_t) SER_BYTES); gdRoundTrip--; // expected reply sent to host. } mPoolToHost.free(gpToHost); // done with this queue entry. gpToHost = NULL; // clear pointer. } // if new reply to host. } // processOutgoingSerial. /*----------------------------------------------//----------------------------*/ // the pcSendBuffer and pcReceiveBuffer arrays are not used by this function, // but they are declared by this function, and their pointers are passed // down to the mmSPI library for its use of them. // note- the prefix 'pc' means 'pointer of type character', not 'personal computer'. void SPIprocessingThread(void const *args) // process host-commands via SPI. { char pcSendBuffer [SPI_BYTES]; // SPI send buffer. char pcReceiveBuffer[SPI_BYTES]; // SPI receive buffer. int dHeartbeat; // heartbeat counter. int dMemoryRead; // read main-memory into this. int dLoop; // loop index. osEvent qFromHostEvent; // incoming message event. tFromHost * pFromHost; // message structure. tToHost * gpToHost; // message structure. mmSPI * pSPI; // SPI. pFromHost = NULL; // NULL pointers. gpToHost = NULL; pSPI = NULL; dHeartbeat = 0; // clear variables. dMemoryRead = 0; dLoop = 0; // clear SPI vectors. for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcSendBuffer [dLoop] = 0; for (dLoop = 0; dLoop < SPI_BYTES; dLoop++) pcReceiveBuffer[dLoop] = 0; pSPI = new mmSPI; // SPI allocation. if (!pSPI) error("\n\r SPIprocessingThread : FATAL new error for pSPI. \n\r"); pSPI->setSendBuffer (pcSendBuffer); // set SPI send buffer. pSPI->setReceiveBuffer(pcReceiveBuffer); // set SPI receive buffer. pSPI->setNumberOfBytes(SPI_BYTES); // set SPI number of bytes. pSPI->setSPIfrequency (SPI_HZ); // set SPI clock frequency. while(1) // thread loop. { qFromHostEvent = qFromHost.get(1); // check for incoming host command. // if new host command: if (qFromHostEvent.status == osEventMessage) { // bring it in from the queue. pFromHost = (tFromHost *) qFromHostEvent.value.p; if (!pFromHost) error("\n\r SPIprocessingThread : FATAL NULL pFromHost pointer. \n\r"); switch(pFromHost->cCommand) // host command decode. { case HCMD_SETREG : // set CPU register. { switch(pFromHost->cRegisterID) // which register to write to. { case CPU_REG_0 : {pSPI->write_register(CPU_REG_0 , pFromHost->cRegisterValue); break;} case CPU_REG_1 : {pSPI->write_register(CPU_REG_1 , pFromHost->cRegisterValue); break;} case CPU_REG_2 : {pSPI->write_register(CPU_REG_2 , pFromHost->cRegisterValue); break;} case CPU_REG_3 : {pSPI->write_register(CPU_REG_3 , pFromHost->cRegisterValue); break;} case CPU_REG_PC : {pSPI->write_register(CPU_REG_PC, pFromHost->cRegisterValue); break;} default : {break;} } // which register to write to. break; } // set CPU register. case HCMD_SETIR: // set instruction register. { pSPI->write_IR(pFromHost->cIRValueH, pFromHost->cIRValueL); break; } // set instruction register. case HCMD_GETREG : // get CPU register. { gpToHost = mPoolToHost.alloc(); // allocate next pool entry. if (!gpToHost) error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); clear_tToHost(gpToHost); // initialize structure. switch(pFromHost->cRegisterID) // which register to read from. { case CPU_REG_0 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_0 ); break;} case CPU_REG_1 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_1 ); break;} case CPU_REG_2 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_2 ); break;} case CPU_REG_3 : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_3 ); break;} case CPU_REG_PC : {gpToHost->cRegisterValue = pSPI->read_register(CPU_REG_PC); break;} case CPU_IR_H : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_H ); break;} case CPU_IR_L : {gpToHost->cRegisterValue = pSPI->read_register(CPU_IR_L ); break;} default : {break;} } // which register to read from. // loop-back to host. gpToHost->cCommand = pFromHost->cCommand; gpToHost->cRegisterID = pFromHost->cRegisterID; qToHost.put(gpToHost); // send up for processing. break; } // get CPU register. case HCMD_SETMM : // do main-memory write. { pSPI->write_memory(pFromHost->cMMdataH, pFromHost->cMMdataL, pFromHost->cMMaddress); break; } // do main-memory write. case HCMD_GETMM : // do main-memory read. { gpToHost = mPoolToHost.alloc(); // allocate next pool entry. if (!gpToHost) error("\n\r SPIprocessingThread : FATAL malloc error for gpToHost. \n\r"); clear_tToHost(gpToHost); // initialize structure. // read from CPU memory. dMemoryRead = pSPI->read_memory(pFromHost->cMMaddress); gpToHost->cMMdataH = (dMemoryRead >> 8) & 0xFF; gpToHost->cMMdataL = (dMemoryRead >> 0) & 0xFF; // loop-back to host. gpToHost->cCommand = pFromHost->cCommand; gpToHost->cMMaddress = pFromHost->cMMaddress; qToHost.put(gpToHost); // send up for processing. break; } // do main-memory read. case HCMD_STEP : // step the CPU. { pSPI->step(); break; } // step the CPU. default : break; } // host command decode. mPoolFromHost.free(pFromHost); // done with this queue entry. pFromHost = NULL; // clear pointer. } // if new host command. gulSPIclkCount = pSPI->SPIClockCount(); // propagate to global variable. gulCPUclkCount = pSPI->CPUClockCount(); // propagate to global variable. // thread heartbeat. dHeartbeat++; if (!(dHeartbeat % HB_MODULO)) led1 = !led1; Thread::wait(THREAD_1_WAIT); // cooperative multitasking. } // thread loop. } // SPIprocessingThread. /*----------------------------------------------//----------------------------*/ void diagnosticThread(void const *args) // LCD and LED notifications. { int dHeartbeat; // heartbeat counter. dHeartbeat = 0; // initialize. led3 = 0; // initialize. while(1) // thread loop. { // if message round trip // count not consistent. if (gdRoundTrip > 1025 || gdRoundTrip < 1024) led3 = 1; lcd.cls(); // clear LCD display. LCD1; // lcd line 1. lcd.printf(" USB DEV CLASS PROJECT"); LCD2; // lcd line 2. lcd.printf(" %11lu = SPI clocks",gulSPIclkCount); LCD3; // lcd line 3. lcd.printf(" %11lu = CPU clocks",gulCPUclkCount); dHeartbeat++; // thread heartbeat. if (!(dHeartbeat % HB_MODULO)) led2 = !led2; Thread::wait(THREAD_2_WAIT); // multitasking. } // thread loop. } // diagnosticThread. /*----------------------------------------------//----------------------------*/ char ascii_nibble_to_binary(char cAscii) // ascii nibble -> binary. { char cBinary; // converted value. switch(cAscii) { case 'F' : {cBinary = 15; break;} case 'E' : {cBinary = 14; break;} case 'D' : {cBinary = 13; break;} case 'C' : {cBinary = 12; break;} case 'B' : {cBinary = 11; break;} case 'A' : {cBinary = 10; break;} case 'f' : {cBinary = 15; break;} case 'e' : {cBinary = 14; break;} case 'd' : {cBinary = 13; break;} case 'c' : {cBinary = 12; break;} case 'b' : {cBinary = 11; break;} case 'a' : {cBinary = 10; break;} case '9' : {cBinary = 9; break;} case '8' : {cBinary = 8; break;} case '7' : {cBinary = 7; break;} case '6' : {cBinary = 6; break;} case '5' : {cBinary = 5; break;} case '4' : {cBinary = 4; break;} case '3' : {cBinary = 3; break;} case '2' : {cBinary = 2; break;} case '1' : {cBinary = 1; break;} case '0' : {cBinary = 0; break;} default : {cBinary = 0; break;} } // switch(cAscii). return(cBinary); // return the binary. } // ascii_nibble_to_binary. /*----------------------------------------------//----------------------------*/ char binary_to_ascii_nibble(char cBinary) // binary -> ascii nibble. { char cAscii; // converted value. switch(cBinary) { case 15 : {cAscii = 'F'; break;} case 14 : {cAscii = 'E'; break;} case 13 : {cAscii = 'D'; break;} case 12 : {cAscii = 'C'; break;} case 11 : {cAscii = 'B'; break;} case 10 : {cAscii = 'A'; break;} case 9 : {cAscii = '9'; break;} case 8 : {cAscii = '8'; break;} case 7 : {cAscii = '7'; break;} case 6 : {cAscii = '6'; break;} case 5 : {cAscii = '5'; break;} case 4 : {cAscii = '4'; break;} case 3 : {cAscii = '3'; break;} case 2 : {cAscii = '2'; break;} case 1 : {cAscii = '1'; break;} case 0 : {cAscii = '0'; break;} default : {cAscii = '0'; break;} } // switch(cBinary). return(cAscii); // return the binary. } // binary_to_ascii_nibble. /*----------------------------------------------//----------------------------*/ void clear_tFromHost(tFromHost * ptFromHost)// clear structure. { ptFromHost->cCommand = 0x00; ptFromHost->cRegisterID = 0x00; ptFromHost->cRegisterValue = 0x00; ptFromHost->cIRValueH = 0x00; ptFromHost->cIRValueL = 0x00; ptFromHost->cMMaddress = 0x00; ptFromHost->cMMdataH = 0x00; ptFromHost->cMMdataL = 0x00; } // clear_tFromHost. /*----------------------------------------------//----------------------------*/ void clear_tToHost(tToHost * ptToHost) // clear structure. { ptToHost->cCommand = 0x00; ptToHost->cRegisterID = 0x00; ptToHost->cRegisterValue = 0x00; ptToHost->cMMaddress = 0x00; ptToHost->cMMdataH = 0x00; ptToHost->cMMdataL = 0x00; } // clear_tToHost. /*----------------------------------------------//----------------------------*/