Super Vision / Mbed 2 deprecated sv_usb_firmware

Dependencies:   MODSERIAL USBDevice_for_Rev_C_HW mbed

Fork of mbed_sv_firmware_with_init by Bob Recny

main.cpp

Committer:
bob_tpc
Date:
2015-02-04
Revision:
15:713c26178a7d
Parent:
13:a390c4798a0d
Child:
16:b6230e4d0ed8

File content as of revision 15:713c26178a7d:

/**
 * @file   main.cpp
 * @date   January 2015
 * @brief  Freescale KL25Z firmware for USB-RFID adapter
 *
 * This firmware provided communication from a PC's USB host port to the following peripherals:
 *  RFID-FE over UART - SuperVision RFID reader module
 *  VL6180X over I2C - ST Microelectronics proximity and ambient light sensor
 *  GPIO - two LEDs and several control signals for the RFID module
 *  EEPROM - over I2C - Generic 24LC16B (untested since first revision prototype hardware does not have an EEPROM)
 */


#include "mbed.h"
#include "USBSerial.h"
#include "MODSERIAL.h"

// Constants
#define LEDON       0                   // Low active for LEDs - turns LED on
#define LEDOFF      1                   // Low active for LEDs - turns LED off
#define TRUE        1
#define FALSE       0

// Error return values
#define ERR_NONE                0x00    // Success
#define ERR_CDC_BAD_CMD         0x01    // First byte of PC to USB board needs to be 0xBB, 0xCC, 0xDD or 0xEE;
#define ERR_CDC_NO_TX_ENDMARK   0xA1    // message for no endmark on message to PC
#define ERR_UART_NOT_WRITEABLE  0xB1    // UART has no buffer space
#define ERR_UART_NOT_READABLE   0xB2    // UART has no buffer space
#define ERR_UART_NO_TX_ENDMARK  0xB3    // message for UART has no 0x7E end-mark
#define ERR_UART_NO_RX_ENDMARK  0xB4    // message received from UART has no end-mark
#define ERR_I2C_NOT_WRITEABLE   0xC1    // UART has no buffer space
#define ERR_I2C_NO_TX_ENDMARK   0xC2    // message for UART has no 0x7E end-mark
#define ERR_I2C_NO_RX_ENDMARK   0xC3    // message received from UART has no end-mark
#define ERR_NOT_IMPLEMENTED     0xFF    // method has not yet been implemented

// I2C addresses and parameters
#define PROX                    (0x29 << 1) // default I2C address of VL6180X, shift into upper 7 bits
#define EEPROM                  (0xA0)  // default I2C address of EEPROM, already shifted
#define I2CRATE                 400000  // I2C speed

// UART-RFID baud rate
#define RFIDBAUD                115200  // RFID-FE board default rate = 115.2Kbps
#define BUFFERSIZE              56      // default buffer sizes
#define RFIDLENLOW              5       // RFID message length location (length is 2 bytes)

// Peripherals
USBSerial cdc;                          // CDC Class USB<>Serial adapter.  Needs custom INF, but uses existing Windows drivers.
MODSERIAL uart(PTA2, PTA1);             // UART port connected to RFID-FE board
I2C i2c(PTB1, PTB0);                    // I2C port connected to VL6180X and EEPROM - note addresses above)

// GPIO signals
DigitalOut led_err(PTC1);               // Red LED shows error condition (active low)
DigitalOut led_com(PTC2);               // Yellow LED shows communication activity (active low)
DigitalOut rfid_int(PTD4);              // RFID FE power control (active high)
DigitalOut rfid_isp(PTD5);              // RFID FE In-System Programming (active high)
DigitalOut rfid_rst(PTD6);              // RFID FE Reset (active high)
DigitalOut rfid_pwr(PTE30);             // RFID power switch on USB board (active high for prototype 1, low for all others)
DigitalIn rfid_hot(PTE0);               // RFID over-current detection on USB board power switch (active low)
InterruptIn prox_int(PTD7);             // Proximity sensor interrupt (active low)

// buffers & variables
uint8_t gpio_values = 0x00;             // register to read GPIO values
uint8_t cdc_buffer_rx[BUFFERSIZE];      // buffers for cdc (USB-Serial port on PC)          
uint8_t cdc_buffer_tx[BUFFERSIZE];
uint8_t uart_buffer_rx[BUFFERSIZE];     // buffers for uart (RFID-FE board)
uint8_t uart_buffer_tx[BUFFERSIZE];
uint8_t gpio_buffer[BUFFERSIZE];        // buffer for GPIO messages
char i2c_buffer[BUFFERSIZE];            // buffer for I2C devices - Proximity sensor and EEPROM - up to 256 bytes data payload for EEPROM, up to 4 for proximity
int i, j;                               // index variables
int status = 0x00;                      // return value
uint8_t led_com_state = LEDOFF;         // initial LED state
uint8_t prox_irq_state = 0;             // interrupt state passed from service routine
uint8_t usb_irq_state = 0;              // interrupt state passed from service routine


/**
 * @name    prox_irq
 * @brief   Sets interrupt variable for use in the main loop.
 * The interrupt is triggered by the VL6180X GPIO1 (IRQ output)
 *
 * @param [in] none
 * @param [out] prox_irq_state = 1 indicates an interrupt occured.
 */
void prox_irq(void)
{
    prox_irq_state = 1;
}

void usb_irq(void)
{
    usb_irq_state = 1;
}

/**
 * @name    init_periph
 * @brief   Initializes the KL25Z peripheal interfaces
 * KL25Z interfaces:
 *  UART - connects to SuperVision RFID-FE module
 *  I2C - connects to the ST VL6180X proximity/ambient light sensor device and a 24LC16B EEPROM (future)
 *  GPIO - includes two LEDs and signals to control RFID reader.
 *
 * @param [in] none
 * @param [out] none
 * 
 * @retval ERR_NONE     No error
 */
 int init_periph(void)
{
    // Set up peripherals
    // RFID
    uart.baud(RFIDBAUD);                                            // RFID-FE baud rate
    
    cdc.attach(&usb_irq);
    
    rfid_int = 0;                                                   // RFID FE power control (active high)
    rfid_isp = 0;                                                   // RFID FE In-System Programming (active high)
    rfid_rst = 1;                                                   // RFID FE Reset (active high)
    rfid_pwr = 1;                                                   // RFID power switch on USB board (active high for prototype 1, low for all others)
    wait(0.25);                                                     // wait 250ms before...
    rfid_rst = 0;                                                   // ... taking RFID out of reset
    wait(0.25);
    
  while(!uart.readable())                                           // wait for RESET message from RFID
    {
        led_err.write(LEDON);                                       // flash LED until it arrives
        wait(0.1);
        led_err.write(LEDOFF);
        wait(0.1);
    }                                           
    
    uart.txBufferFlush();                                           // clear out UART buffers
    uart.rxBufferFlush();
    
    led_err.write(LEDOFF);
        
    // Prox & EEPROM
    i2c.frequency(I2CRATE);                                         // I2C speed = 400Kbps
    prox_int.mode(PullUp);                                          // pull up proximity sensor interrupt at MCU
    prox_int.fall(&prox_irq);                                       // VL6180X interrupt is low active
    prox_int.enable_irq();                                          // Enable proximity interrupt inputs
    
    // LEDs                                                         // Cycle through the LEDs.
    led_err.write(LEDON);
    led_com.write(LEDON);
    wait(0.5);
    led_err.write(LEDOFF);
    wait(0.5);
    led_com.write(LEDOFF);
    
    return ERR_NONE;
}

/**
 * @name    rfid_wr
 * @brief   Forwards command to RFID reader 
 *
 * RFID reader is connected to the KL25Z UART interface.  The host PC will have a USB CDC class COM port device driver.
 * The host PC sends the RFID command over the COM port.  Messages destined for the RFID reader (0xBB leading byte) are 
 * forwarded as-is to the RFID reader.  The reader then responds in kind.  All RFID commands are described in the
 * RFID-FE module manual.
 *
 * @param [out] uart_buffer_tx - messages to the RFID reader
 * 
 * @retval ERR_NONE                No error
 * @retval ERR_UART_NOT_WRITEABLE  UART has no buffer space
 * @retval ERR_UART_NO_TX_ENDMARK  message for UART has no 0x7E end-mark
 * @example
 * BB 00 03 00 01 02 7E 2E C9 = read 
 */
int rfid_wr(void)
{
    int em_pos = 0;
    
    for (i = 0; i < sizeof(uart_buffer_tx); i++)
    {
        if (uart_buffer_tx[i] == 0x7E) em_pos = (i + 1);            // allows 0x7E to appear in the data payload - uses last one for end-mark
    }

    if (em_pos == 0) 
    {
        led_err.write(LEDON);                                       // end mark never reached
        return ERR_UART_NO_TX_ENDMARK;
    }

    if (!uart.writeable()) 
    {
        led_err.write(LEDON);
        return ERR_UART_NOT_WRITEABLE;                              // if no space in uart, return error
    }

    for (i = 0; i < (em_pos + 2); i++)
    {
        uart.putc(uart_buffer_tx[i]);                               // send uart message
    }
    
    return ERR_NONE;
}    

/**
 * @name    rfid_rd
 * @brief   Sends RFID response to CDC  
 *
 * RFID reader is connected to the KL25Z UART interface.  The host PC will have a USB CDC class COM port device driver.
 * The host PC sends the RFID command over the COM port.  Messages destined for the RFID reader (0xBB leading byte) are 
 * forwarded as-is to the RFID reader.  The reader then responds in kind.  All RFID commands are described in the
 * RFID-FE module manual.
 
 * @param [in] uart_buffer_rx - messages from the RFID reader
 * 
 * @retval ERR_NONE                No error
 * @example
 * BB 00 03 00 01 02 7E 2E C9 = read 
 */
int rfid_rd(void)
{
    int rfid_len = 0;
    
    led_com.write(LEDON);
    for (i = 0; i < (RFIDLENLOW); i++)                              // Get first part of message to find out total count
    {
        uart_buffer_rx[i] = uart.getc();                            // get a byte from rfid
    }
    
    rfid_len = ((uart_buffer_rx[i-2]<<8) + (uart_buffer_rx[i-1]));  // location of message length for RFID

    for (i = RFIDLENLOW; i < (RFIDLENLOW + rfid_len + 3); i++)
    {
        uart_buffer_rx[i] = uart.getc();                            // get a byte from rfid
    }

    led_com.write(LEDOFF);
    return ERR_NONE;
}

/**
 * @name    prox_msg_wr
 * @brief   Forwards command to VL6180X sensor 
 *
 * Proximity/ALS reader is connected to the KL25Z I2C interface.  
 * The host PC sends the sensor command over the COM port.  Messages destined for the proximity/ALS sensor (0xCC leading byte) are 
 * forwarded to the proximity/ALS sensor after removing the leading byte and trailing bytes (0x7E endmark plus 2 bytes).  
 * The sensor then responds in kind.  Firmware re-attaches the leading 0xCC and trailing bytes before sending the response over the
 * CDC port to the host PC.
 *
 * I2C-prox messages:   
 * - 0xCC                (byte) leading value = 0xCC
 * - r/w#                (byte) 0 = write, 1 = read
 * - number of data bytes(byte) 0 to 32 (size of declared buffers)
 * - index               (2 bytes) 12-bit VL6801X register offset, high byte first
 * - data                (n bytes) number of data bytes noted above
 * - end_mark            (byte) 0x7E
 * - dummy               (2 bytes) values are don't-care - fillers for RFID CRC bytes
 *
 * Multiple registers can be read or written with single prox_msg_rd() or prox_msg_wr().  Location address increments for each byte.
 * VL6180X registers are defined in the sensor datasheet.
 *
 * @param [in] i2c_buffer - messages to and from the VL6180X and EEPROM
 * 
 * @retval 0            No error
 * @retval 1            I2C bus has NAK'd / failure
 *
 * @param [in/out] i2c_buffer - messages to and from the i2c bus - see above
 * 
 */
int prox_msg_wr()                                                   // write proximity I2C register
{
    int i2c_err;
    i2c_err = i2c.write(PROX, &i2c_buffer[3], i2c_buffer[2] + 2, 0);// I2C Address, pointer to buffer, number of bytes (for index + data), stop at end.
    return i2c_err;                                                 // 0 = ACK received, 1 = NAK/failure
}
    
/**
 * @name    prox_msg_rd
 * @brief   retrieves response from VL6180X sensor
 *
 * Proximity/ALS reader is connected to the KL25Z I2C interface.  
 * The host PC sends the sensor command over the COM port.  Messages destined for the proximity/ALS sensor (0xCC leading byte) are 
 * forwarded to the proximity/ALS sensor after removing the leading byte and trailing bytes (0x7E endmark plus 2 bytes).  
 * The sensor then responds in kind.  Firmware re-attaches the leading 0xCC and trailing bytes before sending the response over the
 * CDC port to the host PC.
 *
 * I2C-prox messages:   
 * - 0xCC                (byte) leading value = 0xCC
 * - r/w#                (byte) 0 = write, 1 = read
 * - number of data bytes(byte) 0 to 32 (size of declared buffers)
 * - index               (2 bytes) 12-bit VL6801X register offset, high byte first
 * - data                (n bytes) number of data bytes noted above
 * - end_mark            (byte) 0x7E
 * - dummy               (2 bytes) values are don't-care - fillers for RFID CRC bytes
 *
 * Multiple registers can be read or written with single prox_msg_rd() or prox_msg_wr().  Location address increments for each byte.
 * VL6180X registers are defined in the sensor datasheet.
 *
 * @param [in/out] i2c_buffer - messages to and from the i2c bus - see above
 *
 * @retval 0            No error
 * @retval 1            I2C bus has NAK'd / failure
 *
 * 
 */
int prox_msg_rd()
{
    int i2c_err;
    i2c_err = i2c.write(PROX, &i2c_buffer[3], 2, 1);                // I2C Address, pointer to buffer (just the index), index, number of bytes (2 for index), no stop at end.
    i2c_err |= i2c.read(PROX, &i2c_buffer[5], i2c_buffer[2], 0);    // I2C Address, pointer to buffer (just the data), number of data bytes, stop at end.
    return i2c_err;                                                 // 0 = ACK received, 1 = NAK/failure
}

/**
 * @name    gpio_rd
 * @brief   retrieves instantaneous value of GPIO pins
 *
 * GPIO signals are defined directly off of the KL25Z.  
 * The host PC sends the GPIO command over the COM port.  With a 0xDD leading byte in the message, the state of the GPIO signals are read and returned.
 * This allows a read-modify-write GPIO sequence.
 *
 * GPIO messages:       
 * - 0xDD                (byte) leading value = 0xDD
 * - r/w#                (byte) 0 = write, 1 = read
 * - data                (byte) see below
 * - end_mark            (byte) 0x7E
 * - dummy               (2 bytes) values are don't-care - fillers for RFID CRC bytes
 *
 * GPIO data bits:      
 * - 0 LED - Error           0 = on, 1 = off                  
 * - 1 LED - Comm state      0 = on, 1 = off
 * - 2 RFID interrupt input  0 = off, 1 = on (inverted in h/w)
 * - 3 RFID in-system-prog   0 = off, 1 = on (inverted in h/w)
 * - 4 RFID reset            0 = off, 1 = on (inverted in h/w)
 * - 5 RFID power enable     for first prototype, 0 = off, 1 = on / for production, 0 = on, 1 = off
 * - 6 RFID over-current     0 = overcurrent detected, 1 = OK
 * - 7 Proximity interrupt   0 = interrupt, 1 = idle (This pin may not return anything meaningful here.  The interrupt is edge triggered).
 *
 * @param [in/out] gpio_buffer - GPIO states
 *
 * @retval 0            No error
 * 
 */

int gpio_rd()
{
    gpio_buffer[2]  = ( led_err.read()        & 0x01);              // read all of the GPIO pins and store in a single byte
    gpio_buffer[2] |= ((led_com_state   << 1) & 0x02);              // use of led_com_state allows the led to be ON during this call, but send back the pre-call state.
    gpio_buffer[2] |= ((rfid_int.read() << 2) & 0x04);
    gpio_buffer[2] |= ((rfid_isp.read() << 3) & 0x08);
    gpio_buffer[2] |= ((rfid_rst.read() << 4) & 0x10);
    gpio_buffer[2] |= ((rfid_pwr.read() << 5) & 0x20);
    gpio_buffer[2] |= ((rfid_hot.read() << 6) & 0x40);
    gpio_buffer[2] |= ((prox_int.read() << 7) & 0x80);
    return ERR_NONE;
}


/**
 * @name    gpio_wr
 * @brief   sets value of GPIO pins
 *
 * GPIO signals are defined directly off of the KL25Z.  
 * The host PC sends the GPIO command over the COM port.  With a 0xDD leading byte in the message, the state of the GPIO signals are read and returned.
 * This allows a read-modify-write GPIO sequence.
 *
 * GPIO messages:       
 * - 0xDD                (byte) leading value = 0xDD
 * - r/w#                (byte) 0 = write, 1 = read
 * - data                (byte) see below
 * - end_mark            (byte) 0x7E
 * - dummy               (2 bytes) values are don't-care - fillers for RFID CRC bytes
 *
 * GPIO data bits:      
 * - 0 LED - Error           0 = on, 1 = off                  
 * - 1 LED - Comm state      0 = on, 1 = off
 * - 2 RFID interrupt input  0 = off, 1 = on (inverted in h/w)
 * - 3 RFID in-system-prog   0 = off, 1 = on (inverted in h/w)
 * - 4 RFID reset            0 = off, 1 = on (inverted in h/w)
 * - 5 RFID power enable     for first prototype, 0 = off, 1 = on / for production, 0 = on, 1 = off
 * - 6 RFID over-current     0 = overcurrent detected, 1 = OK
 * - 7 Proximity interrupt   0 = interrupt, 1 = idle (This pin may not return anything meaningful here.  The interrupt is edge triggered).
 *
 * @param [in/out] gpio_buffer - GPIO states
 *
 * @retval 0            No error
 * 
 */
int gpio_wr()
{
    if ((gpio_buffer[2] & 0x02) == 0x00) 
    {
        led_com_state = LEDON;
    }
    else 
    {
        led_com_state = LEDOFF;
    }
    led_err.write(gpio_buffer[2] & 0x01);                              
    led_com.write(led_com_state);                              
    rfid_int.write(gpio_buffer[2] & 0x04);                             
    rfid_isp.write(gpio_buffer[2] & 0x08);                             
    rfid_rst.write(gpio_buffer[2] & 0x10);                             
    rfid_pwr.write(gpio_buffer[2] & 0x20);                             
    return ERR_NONE;
}
    
    
/**
 * @name    eeprom_msg_wr
 * @brief   writes data to the I2C EEPROM
 * @note    *** UNTESTED with first prototype ***
 *
 * The EEPROM is connected to the KL25Z I2C interface.  
 * The host PC sends the sensor command over the COM port.  Messages destined for the EERPOM (0xEE leading byte) are 
 * forwarded to the EEPROM after removing the leading byte and trailing bytes (0x7E endmark plus 2 bytes).  
 * Firmware re-attaches the leading 0xFF and trailing bytes before sending the response over the
 * CDC port to the host PC.
 *
 * I2C-EEPROM messages:    
 * - 0xEE                (byte) leading value = 0xEE
 * - r/w#                (byte) 0 = write, 1 = read
 * - number of data bytes(byte) 0 to 32 (size of declared buffers)
 * - block               (byte) lower 3 bits are logically OR'd with the I2C address
 * - address             (byte) memory location within block
 * - data                (n bytes) number of data bytes noted above
 * - end_mark            (byte) 0x7E
 * - dummy               (2 bytes) values are don't-care - fillers for RFID CRC bytes
 *
 * Multiple memory locations can be read or written with single eeprom_msg_rd() or eeprom_msg_wr().  Location address increments for each byte.
 * Read/Write sequences are defined in the 24LC16B datasheet.
 *
 * This practically the the same as the proximity calls, except the index/location is only one byte and the block select is part of the I2C address byte.
 *
 * @param [in] i2c_buffer - messages to and from the VL6180X and EEPROM
 * 
 * @retval 0            No error
 * @retval 1            I2C bus has NAK'd / failure
 *
 * @param [in/out] i2c_buffer - messages to and from the i2c bus - see above
 * 
 */

int eeprom_msg_wr()                                                 // write proximity I2C register
{
    int i2c_err;
    i2c_err = i2c.write((EEPROM | i2c_buffer[3]), &i2c_buffer[4], i2c_buffer[2] + 1, 0);  
                                                                    // I2C Address & block select, pointer to buffer, number of bytes (for address + data), stop at end.
    while (!i2c.write(EEPROM | i2c_buffer[3]));                     // wait until write is done (EEPROM will ACK = 0 for single byte i2c.write)
    return i2c_err;                                                 // 0 = ACK received, 1 = NAK/failure
}
    
/**
 * @name    eeprom_msg_rd
 * @brief   read data from the I2C EEPROM
 * @note    *** UNTESTED with first prototype ***
 *
 * The EEPROM is connected to the KL25Z I2C interface.  
 * The host PC sends the sensor command over the COM port.  Messages destined for the EERPOM (0xEE leading byte) are 
 * forwarded to the EEPROM after removing the leading byte and trailing bytes (0x7E endmark plus 2 bytes).  
 * Firmware re-attaches the leading 0xFF and trailing bytes before sending the response over the
 * CDC port to the host PC.
 *
 * I2C-EEPROM messages:    
 * - 0xEE                (byte) leading value = 0xEE
 * - r/w#                (byte) 0 = write, 1 = read
 * - number of data bytes(byte) 0 to 32 (size of declared buffers)
 * - block               (byte) lower 3 bits are logically OR'd with the I2C address
 * - address             (byte) memory location within block
 * - data                (n bytes) number of data bytes noted above
 * - end_mark            (byte) 0x7E
 * - dummy               (2 bytes) values are don't-care - fillers for RFID CRC bytes
 *
 * Multiple memory locations can be read or written with single eeprom_msg_rd() or eeprom_msg_wr().  Location address increments for each byte.
 * Read/Write sequences are defined in the 24LC16B datasheet.
 *
 * This practically the the same as the proximity calls, except the index/location is only one byte and the block select is part of the I2C address byte.
 *
 * @param [in/out] i2c_buffer - messages to and from the VL6180X and EEPROM
 * 
 * @retval [none]0            No error
 * @retval 1            I2C bus has NAK'd / failure
 *
 * @param [in/out] i2c_buffer - messages to and from the i2c bus - see above
 * 
 */
 int eeprom_msg_rd()
{
    int i2c_err;
    i2c_err = i2c.write((EEPROM | i2c_buffer[3]), &i2c_buffer[4], 1, 1); 
                                                                    // I2C Address & block select, pointer to buffer (just the index), index, number of bytes (for address + data), no stop at end.
    i2c_err |= i2c.read((EEPROM || i2c_buffer[3]), &i2c_buffer[5], i2c_buffer[2], 0);   
                                                                    // I2C Address & block select, pointer to buffer (just the data), number of data bytes, stop at end.
    return i2c_err;                                                 // 0 = ACK received, 1 = NAK/failure
}


/**
 * @name    main
 * @brief   main firmware loop
 *
 * @returns [none]
 */
int main(void) 
{
    int em_pos = 0;                                                 // end of message count - allows multiple 0x7e in message.

    //wait(5.0);                                                    // gives a chance to connect the COM port - this can be removed for production

    init_periph();                                                  // initialize everything
    
    while(1)
    {
        led_com.write(led_com_state);                               // turn off communication LED unless it was specifically turned on by GPIO command

        if (prox_irq_state == 1)                                    // process the proximity interrupt 
        {
            prox_irq_state = 0;
            cdc_buffer_tx[0] = 0xFF;                                // send message to PC
            cdc_buffer_tx[1] = 0x7E;
            cdc_buffer_tx[2] = 0x0F;
            cdc_buffer_tx[3] = 0xF0;
            cdc.writeBlock(cdc_buffer_tx, 4);
        }

        if (uart.readable())                                        // message availalbe from rfid
        {
            rfid_rd();
            em_pos = 0;
            for (i = 0; i < sizeof(cdc_buffer_tx); i++)
            {
                cdc_buffer_tx[i] = uart_buffer_rx[i];               // copy RFID response back to USB buffer
                if (cdc_buffer_tx[i] == 0x7E) 
                {
                    em_pos = (i + 1);                               // allows 0x7E to appear in the data payload - uses last one for end-mark
                }
            }
            if (em_pos == 0) 
            {
                led_err.write(LEDON);                               // end mark never reached
                break;
            }
            cdc.writeBlock(cdc_buffer_tx, (em_pos + 2));
        }                                         
        
        if (usb_irq_state == 1)                                     // message available from PC
        {
            led_com.write(LEDON);                                   // Message received - turn on LED
            usb_irq_state = 0;

            for (i = 0; i < sizeof(cdc_buffer_rx); i++)
            {
                if (cdc.readable()) cdc_buffer_rx[i] = cdc._getc(); // read data from USB side
            }
            for (i = 0; i < sizeof(cdc_buffer_rx); i++)
            {
                if (cdc_buffer_rx[i] == 0x7E)                       // check for rfid end mark in outbound message
                {
                    em_pos = (i + 1);
                }
            }
            if (em_pos == 0)                                        // end mark never reached
            {
                led_err.write(LEDON);
                break;
            }
    
            switch(cdc_buffer_rx[0])                                // check first byte for "destination"
            {
                case 0xBB:                                          // RFID-FE
                    for (i = 0; i < sizeof(cdc_buffer_rx); i++)
                    {
                        uart_buffer_tx[i] = cdc_buffer_rx[i];       // copy USB message to UART for RFID
                    }
                    
                    status = rfid_wr();                             // send buffer to RFID and get response according to RFID board
                    break;
            
                case 0xCC:                                          // Proximity Sensor
                    led_com.write(LEDON);
                    for (i = 0; i < sizeof(cdc_buffer_rx); i++)
                    {
                        i2c_buffer[i] = cdc_buffer_rx[i];           // copy USB message to buffer for I2C
                    }

                    if (i2c_buffer[1] == 1)                         // I2C read = 1
                        status = prox_msg_rd();                     // read the requested data
                    else if (i2c_buffer[1] == 0)                    // I2C write = 0
                        status = prox_msg_wr();                     // send buffer to proximity sensor and get response

                    if (!status) led_err.write(LEDON);
            
                    em_pos = 0;
                    for (i = 0; i < sizeof(cdc_buffer_tx); i++)
                    {
                        cdc_buffer_tx[i] = i2c_buffer[i];           // copy RFID response back to USB buffer
                        if (cdc_buffer_tx[i] == 0x7E) 
                        {
                            em_pos = (i + 1);                       // allows 0x7E to appear in the data payload - uses last one for end-mark
                        }
                    }
                    if (em_pos == 0) 
                    {
                        led_err.write(LEDON);                       // end mark never reached
                        break;
                    }

                    cdc.writeBlock(cdc_buffer_tx, (em_pos + 2));
                    led_com.write(LEDOFF);
                    break;
            
                case 0xDD:                                          // GPIO (LEDs and RFID-FE control)

                    led_com.write(LEDON);
                    for (i = 0; i < sizeof(cdc_buffer_rx); i++)
                    {
                        gpio_buffer[i] = cdc_buffer_rx[i];          // copy USB message to buffer for I2C
                    }
                
                    if (gpio_buffer[1] == 1)                        // GPIO read = 1
                        status = gpio_rd();                         // read the requested data
                    else if (gpio_buffer[1] == 0)                   // GPIO write = 0
                        status = gpio_wr();                         // send GPIO pin data
            
                    em_pos = 0;
                    for (i = 0; i < sizeof(cdc_buffer_tx); i++)
                    {
                        cdc_buffer_tx[i] = gpio_buffer[i];          // copy RFID response back to USB buffer
                        if (cdc_buffer_tx[i] == 0x7E) 
                        {
                            em_pos = (i + 1);                       // allows 0x7E to appear in the data payload - uses last one for end-mark
                        }
                    }
                    if (em_pos == 0) 
                    {
                        led_err.write(LEDON);                       // end mark never reached
                        break;
                    }

                    cdc.writeBlock(cdc_buffer_tx, (em_pos + 2));
                    led_com.write(LEDOFF);

                    break;            
                
                case 0xEE:                                          // Read/write EEPROM
                   led_com.write(LEDON);
                    for (i = 0; i < sizeof(cdc_buffer_rx); i++)
                    {
                        i2c_buffer[i] = cdc_buffer_rx[i];           // copy USB message to buffer for I2C
                    }

                    if (i2c_buffer[1] == 1)                         // I2C read = 1
                        status = eeprom_msg_rd();                   // read the requested data
                    else if (i2c_buffer[1] == 0)                    // I2C write = 0
                        status = eeprom_msg_wr();                   // send buffer to proximity sensor and get response

                    if (!status) led_err.write(LEDON);
            
                    em_pos = 0;
                    for (i = 0; i < sizeof(cdc_buffer_tx); i++)
                    {
                        cdc_buffer_tx[i] = i2c_buffer[i];           // copy RFID response back to USB buffer
                        if (cdc_buffer_tx[i] == 0x7E) 
                        {
                            em_pos = (i + 1);                       // allows 0x7E to appear in the data payload - uses last one for end-mark
                        }
                    }
                    if (em_pos == 0) 
                    {
                        led_err.write(LEDON);                       // end mark never reached
                        break;
                    }

                    cdc.writeBlock(cdc_buffer_tx, (em_pos + 2));
                    led_com.write(LEDOFF);
                    break;
                default:
                    led_err.write(LEDON);
                    while(1);
            }
        }
        led_com.write(LEDOFF);
    }
}
//EOF