//****************************************************************************
//
// This function will print out to the console UART and not the echo UART.
//
//****************************************************************************
void
CommandPrint(const char *pcStr)
{
    int iIdx;
    const char cCR = 0xd;

    iIdx = 0;

    while(pcStr[iIdx] != 0)
    {
        //
        // Wait for space for two bytes in case there is a need to send out
        // the line feed plus the carriage return.
        //
        while(USBBufferSpaceAvailable(&g_sTxBuffer) < 2)
        {
        }

        //
        // Print the next character.
        //
        USBBufferWrite(&g_sTxBuffer, (const unsigned char *)&pcStr[iIdx], 1);

        //
        // If this is a line feed then send a carriage return as well.
        //
        if(pcStr[iIdx] == 0xa)
        {
            USBBufferWrite(&g_sTxBuffer, (const unsigned char *)&cCR, 1);
        }

        iIdx++;
    }
}
示例#2
0
/*
 *  ======== txData ========
 */
static uint32_t txData(const uint8_t *pStr, uint32_t length)
{
    unsigned long buffAvailSize;
    uint32_t bufferedCount = 0;
    uint32_t sendCount = 0;
    uint8_t *sendPtr;

    while (bufferedCount != length) {
        /* Determine the buffer size available */
        buffAvailSize = USBBufferSpaceAvailable(&txBuffer);

        /* Determine how much needs to be sent */
        if ((length - bufferedCount) > buffAvailSize) {
            sendCount = buffAvailSize;
        }
        else {
            sendCount = length - bufferedCount;
        }

        /* Adjust the pointer to the data */
        sendPtr = (uint8_t *)pStr + bufferedCount;

        /* Place the contents into the USB BUffer */
        bufferedCount += USBBufferWrite(&txBuffer, sendPtr, sendCount);
    }

    return (bufferedCount);
}
示例#3
0
/******************************************************************************
*																			  *
* \brief  Read as many characters from the UART FIFO as we can and move the   *
*         into the CDC transmit buffer.\n                                     *
*                                                                             *
* \param none.																  *
*																		      *
* \return UART error flags read during data reception.                        *
*                                                                             *
******************************************************************************/
static int ReadUARTData(void)
{
    int lChar, lErrors;
    unsigned char ucChar;
    unsigned int ulSpace;

    
    /* Clear our error indicator. */
    
    lErrors = 0;

    
    /* How much space do we have in the buffer? */
    
    ulSpace = USBBufferSpaceAvailable((tUSBBuffer *)&g_sTxBuffer);

    
    /* Read data from the UART FIFO until there is none left or we run
       out of space in our receive buffer.
    */
    while(ulSpace && UARTCharsAvail(USB_UART_BASE))
    {
        
        /* Read a character from the UART FIFO into the ring buffer if no
           errors are reported.
        */
        lChar = UARTCharGetNonBlocking(USB_UART_BASE);

        
        /* If the character did not contain any error notifications,
           copy it to the output buffer.
        */
        if(!(lChar & ~0xFF))
        {
            ucChar = (unsigned char)(lChar & 0xFF);
            USBBufferWrite((tUSBBuffer *)&g_sTxBuffer,
                           (unsigned char *)&ucChar, 1);

            
            /* Decrement the number of bytes we know the buffer can accept. */
            
            ulSpace--;
        }
        else
        {
            
           /* Update our error accumulator. */
            
           lErrors |= lChar;
        }

        /* Update our count of bytes received via the UART. */
        
        g_ulUARTRxCount++;
    }

    /* Pass back the accumulated error indicators. */
    
    return(lErrors);
}
//*****************************************************************************
//
// Read as many characters from the UART FIFO as possible and move them into
// the CDC transmit buffer.
//
// \return Returns UART error flags read during data reception.
//
//*****************************************************************************
static long
ReadUARTData(void)
{
    long lChar, lErrors;
    unsigned char ucChar;
    unsigned long ulSpace;

    //
    // Clear the error indicator.
    //
    lErrors = 0;

    //
    // How much space is available in the buffer?
    //
    ulSpace = USBBufferSpaceAvailable(&g_sTxBuffer);

    //
    // Read data from the UART FIFO until there is none left or there is no
    // more space in the receive buffer.
    //
    while(ulSpace && ROM_UARTCharsAvail(UART0_BASE))
    {
        //
        // Read a character from the UART FIFO into the ring buffer if no
        // errors are reported.
        //
        lChar = ROM_UARTCharGetNonBlocking(UART0_BASE);

        //
        // If the character did not contain any error notifications,
        // copy it to the output buffer.
        //
        if(!(lChar & ~0xFF))
        {
            ucChar = (unsigned char)(lChar & 0xFF);
            USBBufferWrite(&g_sTxBuffer, &ucChar, 1);

            //
            // Decrement the number of bytes the buffer can accept.
            //
            ulSpace--;
        }
        else
        {
            //
            // Update the error accumulator.
            //
            lErrors |= lChar;
        }
    }

    //
    // Pass back the accumulated error indicators.
    //
    return(lErrors);
}
示例#5
0
void platform_s_uart_send( unsigned id, u8 data )
{
#ifdef BUILD_USB_CDC
  if( id == CDC_UART_ID )
    USBBufferWrite( &g_sTxBuffer, &data, 1 );
  else
#endif
    MAP_UARTCharPut( uart_base[ id ], data );
}
示例#6
0
文件: superv_cmd.c 项目: lnls-elp/ARM
/**********************************************************************************************************************
 *
 * Subrotina destinada a enviar dados para o display via UART2
 *
 **********************************************************************************************************************/
void send_usb(void){

   uint8_t count;

   checksum_calc_usb();            // Rotina de calculo de CheckSum

   USBBufferWrite(&g_sTxBuffer, &MensagemUsb.CMD, 1);
   USBBufferWrite(&g_sTxBuffer, &MensagemUsb.NDADO, 1);

   if(MensagemUsb.NDADO > 0)
   {
	   for(count = 0; count < MensagemUsb.NDADO; count++)
	   {
		  USBBufferWrite(&g_sTxBuffer, &MensagemUsb.DADO[count], 1);
	   }
   }

   USBBufferWrite(&g_sTxBuffer, &MensagemUsb.CKS, 1);

}
示例#7
0
// * USBChalkBusSendException *************************************************
// * Sends an exception to the master.                                        *
// *                                                                          *
// * offending_function should be the function code that caused the exception *
// * code should be the exception code that should be sent to the master,     *
// *      it's value should be one of CBUS_EX_CODE_*.                         *
// ****************************************************************************
void USBChalkBusSendException(unsigned char offending_function, unsigned char code)
{
  cbus_slave_exception_t* cbus_exception;                   // will use this to build an exception
  cbus_exception = (cbus_slave_exception_t*)ChalkBusBuff;   // use ChalkBusBuff to build the exception
  cbus_exception->function_code = offending_function | CBUS_FN_CODE_EXCEPTION;
                                                            // exception signaled by setting msb of offending function code
  cbus_exception->exception_code = code;                    // load the exception code
  if(g_bUSBDevConnected)                                    // send exception if there is a device to listen
  {
    USBBufferWrite((tUSBBuffer *)&g_sTxBuffer,(unsigned char*)ChalkBusBuff, sizeof(cbus_slave_exception_t));
                                                            // queue the exception to send
  }
}
/*
 *  ======== USBCDCD_LoggerIdle_sendData ========
 */
int USBCDCD_LoggerIdle_sendData(unsigned char *pStr, int length)
{
    unsigned int bufAvailSize;

    /* Determine the buffer size available  and length to send */
    bufAvailSize = USBBufferSpaceAvailable(&txBuffer);

    if (!bufAvailSize || state != USBCDCD_STATE_IDLE) {
        return (0);
    }
    else if (bufAvailSize < length) {
        /* Write largest multiple of 4 bytes */
        length =  bufAvailSize - (bufAvailSize % 4);
    }

    /* Place the contents into the USB BUffer */
    return (USBBufferWrite(&txBuffer, pStr, length));
}
示例#9
0
//*****************************************************************************
//
// Writes a character to the USB interface.
//
//*****************************************************************************
void
USBIFWrite(unsigned char ucChar)
{
    //
    // Delay until there is some space in the output buffer.
    //
    while(g_bUSBConnected)
    {
        if(USBBufferSpaceAvailable(&g_sTxBuffer) != 0)
        {
            break;
        }
    }

    //
    // If there is still a USB connection, write this character into the output
    // buffer.
    //
    if(g_bUSBConnected)
    {
        USBBufferWrite(&g_sTxBuffer, &ucChar, 1);
    }
}
示例#10
0
//*****************************************************************************
//
// Read as many characters from the UART FIFO as we can and move them into
// the CDC transmit buffer.
//
// \return Returns UART error flags read during data reception.
//
//*****************************************************************************
static int32_t
ReadUARTData(void)
{
    int32_t i32Char, i32Errors;
    uint8_t ui8Char;
    uint32_t ui32Space;

    //
    // Clear our error indicator.
    //
    i32Errors = 0;

    //
    // How much space do we have in the buffer?
    //
    ui32Space = USBBufferSpaceAvailable((tUSBBuffer *)&g_sTxBuffer);

    //
    // Read data from the UART FIFO until there is none left or we run
    // out of space in our receive buffer.
    //
    while(ui32Space && ROM_UARTCharsAvail(USB_UART_BASE))
    {
        //
        // Read a character from the UART FIFO into the ring buffer if no
        // errors are reported.
        //
        i32Char = ROM_UARTCharGetNonBlocking(USB_UART_BASE);

        //
        // If the character did not contain any error notifications,
        // copy it to the output buffer.
        //
        if(!(i32Char & ~0xFF))
        {
            ui8Char = (uint8_t)(i32Char & 0xFF);
            USBBufferWrite((tUSBBuffer *)&g_sTxBuffer,
                           (uint8_t *)&ui8Char, 1);

            //
            // Decrement the number of bytes we know the buffer can accept.
            //
            ui32Space--;
        }
        else
        {
#ifdef DEBUG
            //
            // Increment our receive error counter.
            //
            g_ui32UARTRxErrors++;
#endif
            //
            // Update our error accumulator.
            //
            i32Errors |= i32Char;
        }

        //
        // Update our count of bytes received via the UART.
        //
        g_ui32UARTRxCount++;
    }

    //
    // Pass back the accumulated error indicators.
    //
    return(i32Errors);
}
//****************************************************************************
//
// Handles CDC driver notifications related to the receive channel (data from
// the USB host).
//
// \param pvCBData is the client-supplied callback data value for this
// channel.
// \param ulEvent identifies the event we are being notified about.
// \param ulMsgValue is an event-specific value.
// \param pvMsgData is an event-specific pointer.
//
// This function is called by the CDC driver to notify us of any events
// related to operation of the receive data channel (the OUT channel carrying
// data from the USB host).
//
// \return The return value is event-specific.
//
//****************************************************************************
unsigned long
RxHandler(void *pvCBData, unsigned long ulEvent, unsigned long ulMsgValue,
          void *pvMsgData)
{
    unsigned char ucChar;
    const tUSBDCDCDevice *psCDCDevice;
    const tUSBBuffer *pBufferRx;
    const tUSBBuffer *pBufferTx;

    //
    // Which event are we being sent?
    //
    switch(ulEvent)
    {
        //
        // A new packet has been received.
        //
        case USB_EVENT_RX_AVAILABLE:
        {
            //
            // Create a device pointer.
            //
            psCDCDevice = (const tUSBDCDCDevice *)pvCBData;
            pBufferRx = (const tUSBBuffer *)psCDCDevice->pvRxCBData;
            pBufferTx = (const tUSBBuffer *)psCDCDevice->pvTxCBData;

            //
            // Keep reading and processing characters as long as there are new
            // ones in the buffer.
            //
            while(USBBufferRead(pBufferRx,
                                (unsigned char *)&g_pcCmdBuf[ulCmdIdx], 1))
            {
                //
                // If this is a backspace character, erase the last thing typed
                // assuming there's something there to type.
                //
                if(g_pcCmdBuf[ulCmdIdx] == 0x08)
                {
                    //
                    // If our current command buffer has any characters in it,
                    // erase the last one.
                    //
                    if(ulCmdIdx)
                    {
                        //
                        // Delete the last character.
                        //
                        ulCmdIdx--;

                        //
                        // Send a backspace, a space and a further backspace so
                        // that the character is erased from the terminal too.
                        //
                        USBBufferWrite(pBufferTx, (unsigned char *)g_pcBackspace,
                                       3);
                    }
                }
                else
                {
                    //
                    // Feed some the new character into the UART TX FIFO.
                    //
                    USBBufferWrite(pBufferTx,
                                   (unsigned char *)&g_pcCmdBuf[ulCmdIdx], 1);

                    //
                    // If this was a line feed then put out a carriage return
                    // as well.
                    //
                    if(g_pcCmdBuf[ulCmdIdx] == 0xd)
                    {
                        //
                        // Set a line feed.
                        //
                        ucChar = 0xa;
                        USBBufferWrite(pBufferTx, &ucChar, 1);

                        //
                        // Indicate that a command has been received.
                        //
                        HWREGBITW(&g_ulFlags, FLAG_COMMAND_RECEIVED) = 1;

                        g_pcCmdBuf[ulCmdIdx] = 0;

                        ulCmdIdx = 0;
                    }
                    //
                    // Only increment if the index has not reached the end of
                    // the buffer and continually overwrite the last value if
                    // the buffer does attempt to overflow.
                    //
                    else if(ulCmdIdx < CMD_BUF_SIZE)
                    {
                        ulCmdIdx++;
                    }
                }
            }
            break;
        }

        //
        // We are being asked how much unprocessed data we have still to
        // process. We return 0 if the UART is currently idle or 1 if it is
        // in the process of transmitting something. The actual number of
        // bytes in the UART FIFO is not important here, merely whether or
        // not everything previously sent to us has been transmitted.
        //
        case USB_EVENT_DATA_REMAINING:
        {
            //
            // Get the number of bytes in the buffer and add 1 if some data
            // still has to clear the transmitter.
            //
            return(0);
        }

        //
        // We are being asked to provide a buffer into which the next packet
        // can be read. We do not support this mode of receiving data so let
        // the driver know by returning 0. The CDC driver should not be
        // sending this message but this is included just for illustration and
        // completeness.
        //
        case USB_EVENT_REQUEST_BUFFER:
        {
            return(0);
        }

        //
        // We don't expect to receive any other events.  Ignore any that show
        // up in a release build or hang in a debug build.
        //
        default:
        {
            break;
        }
    }

    return(0);
}
示例#12
0
//*****************************************************************************
//
// Handles CDC driver notifications related to the receive channel (data from
// the USB host).
//
// \param ulCBData is the client-supplied callback data value for this channel.
// \param ulEvent identifies the notification event.
// \param ulMsgValue is an event-specific value.
// \param pvMsgData is an event-specific pointer.
//
// This function is called by the CDC driver to notify us of any events
// related to operation of the receive data channel (the OUT channel carrying
// data from the USB host).
//
// \return The return value is event-specific.
//
//*****************************************************************************
static unsigned long
RxHandler(void *pvCBData, unsigned long ulEvent, unsigned long ulMsgValue,
          void *pvMsgData)
{
    //
    // Which event was sent?
    //
    switch(ulEvent)
    {
        //
        // A new packet has been received.
        //
        case USB_EVENT_RX_AVAILABLE:
        {
            //
            // Since data has been received, see if the game is already being
            // played.
            //
            if(g_ulGameIF == GAME_IF_NONE)
            {
                //
                // The game is not being played, so select the USB interface.
                //
                g_ulGameIF = GAME_IF_USB;

                //
                // Read and discard the character used to activate the game.
                //
                USBBufferRead(&g_sRxBuffer, (unsigned char *)&ulEvent, 1);
            }

            //
            // Otherwise, see if the game is being played on an interface other
            // than USB.
            //
            else if(g_ulGameIF != GAME_IF_USB)
            {
                //
                // Write the error message to the USB interface.
                //
                USBBufferWrite(&g_sTxBuffer, g_pucErrorMessage,
                               sizeof(g_pucErrorMessage));

                //
                // Read and discard all data that was received over USB.
                //
                while(USBBufferDataAvailable(&g_sRxBuffer) != 0)
                {
                    USBBufferRead(&g_sRxBuffer, (unsigned char *)&ulEvent, 1);
                }
            }

            break;
        }

        //
        // This is a request for how much unprocessed data is still waiting to
        // be processed.  Return 0 if the UART is currently idle or 1 if it is
        // in the process of transmitting something.  The actual number of
        // bytes in the UART FIFO is not important here, merely whether or
        // not everything previously sent to us has been transmitted.
        //
        case USB_EVENT_DATA_REMAINING:
        {
            //
            // Get the number of bytes in the buffer and add 1 if some data
            // still has to clear the transmitter.
            //
            return(0);
        }

        //
        // This is a request for a buffer into which the next packet can be
        // read.  This mode of receiving data is not supported so let the
        // driver know by returning 0.  The CDC driver should not be sending
        // this message but this is included just for illustration and
        // completeness.
        //
        case USB_EVENT_REQUEST_BUFFER:
        {
            return(0);
        }

        //
        // Other events can be safely ignored.
        //
        default:
        {
            break;
        }
    }

    return(0);
}
示例#13
0
// * USBChalkBusPoll **********************************************************
// * Handle communication requests from ChalkBus master.                      *
// *                                                                          *
// * Communication protocol based off of a subset of the Modicon Modbus RTU   *
// * protocol developed by Modicon, Inc.                                      *
// *                                                                          *
// * Note: Among other changes, multi-byte value endianness has been changed  *
// *       to little endian in the ChalkBus implementation for efficient      *
// *       compatibility with the Cortex-M4 core's native little-endian byte  *
// *       order.                                                             *
// *                                                                          *
// * See structures above (cbus_*_t) for definition of packet structures for  *
// * different functions.                                                     *
// *                                                                          *
// * Function codes:                                                          *
// * 0x03: read registers (pc reading from lm4f)                              *
// * 0x10: multiple register set (pc writing to lm4f)                         *
// *                                                                          *
// * Exception signaling:                                                     *
// * Offending function code or-ed with 0x80 (msb set), see structure above   *
// * (cbus_slave_exception_t) for return format.                              *
// *                                                                          *
// * Register read/write from ChalkBusRegs[].                                 *
// * Note: This driver is not written to handle multi-packet transmissions,   *
// *       overall package size (header, data) must fit within a 64B USB bulk *
// *       transmission.                                                      *
// ****************************************************************************
void USBChalkBusPoll(void)
{
  unsigned long buffer_bytes;                               // bytes received from/accepted by buffer
  cbus_function_read_write_t* cbus_rw_header;               // header for reading/writing a 
  if(!g_bUSBRxAvailable)                                    // if no Rx is available 
  {
    return;                                                 // exit now (we only send solicited responses)
  }
                                                            // else new Rx is in the buffer, let's handle it
  buffer_bytes = USBBufferRead((tUSBBuffer *)&g_sRxBuffer, (unsigned char*)ChalkBusBuff, CBUS_BUFFER_SIZE);
  //buffer_bytes = USBDCDCPacketRead(&g_sCDCDevice,unsigned char *pcData,unsigned long ulLength,tBoolean bLast)
                                                            // read data in from the receive buffer
  g_bUSBRxAvailable = false;                                // we have read the new Rx, no more available
  if(buffer_bytes == 0)                                     // cancel, there wasn't actually any data
  {
    return;
  }
                                                            // find out what kind of packet this is, validate it
  cbus_rw_header = (cbus_function_read_write_t*)ChalkBusBuff;
                                                            // guess that this function is either read or write to save doing this cast in both cases
  switch(*((unsigned char*)ChalkBusBuff))                   // read function code
  {
    case CBUS_FN_CODE_READ:                                 // function read
    case CBUS_FN_CODE_WRITE:                                // function write, same validation steps
      {
        if((CBUS_FN_HDR_SIZE_RD_WR > buffer_bytes) ||
           (CBUS_FN_HDR_SIZE_RD_WR + cbus_rw_header->data_bytes != buffer_bytes))
        {
          USBChalkBusSendException(cbus_rw_header->function_code, CBUS_EX_CODE_NAK);
                                                            // throw exception, too few bytes even for header or bytes expected != bytes received
          return;
        }
        if(cbus_rw_header->reg_count > CBUS_MAX_REG_COUNT)  // more registers requested than are allowed in a single request
        {
          USBChalkBusSendException(cbus_rw_header->function_code, CBUS_EX_CODE_NAK);
                                                            // throw exception, more registers requested than are allowed
          return;
        }
        if((cbus_rw_header->function_code == CBUS_FN_CODE_WRITE) &&
           (cbus_rw_header->reg_count * CBUS_DATA_WORD_SIZE != cbus_rw_header->data_bytes))
        {
          USBChalkBusSendException(cbus_rw_header->function_code, CBUS_EX_CODE_NAK);
                                                            // throw exception, register count not consistent with data bytes count
          return;
        }
        if( (cbus_rw_header->starting_reg >= CBUS_REG_COUNT) ||
           ((cbus_rw_header->starting_reg + cbus_rw_header->reg_count) > CBUS_REG_COUNT))
        {                                                   // if starting register or ending register beyond last register
          USBChalkBusSendException(cbus_rw_header->function_code, CBUS_EX_CODE_ADDRESS);
                                                            // throw exception, an address is out of range
          return;
        }
      }
      break;
    default:                                                // function unknown
      {
        USBChalkBusSendException(*((unsigned char*)ChalkBusBuff), CBUS_EX_CODE_FUNCTION);
                                                            // throw exception, this function code is unknown
        return;                                             // done
      }
  }
                                                            // handle now validated function
  switch(*((unsigned char*)ChalkBusBuff))                   // read function code
  {
    case CBUS_FN_CODE_READ:                                 // function read
      {
        unsigned short count;                               // used to copy data
        unsigned long* read_ptr;                            // source pointer (holding registers)
        read_ptr = ChalkBusRegs + (cbus_rw_header->starting_reg);
                                                            // initialize starting read pointer
        for(count = 0; count < (cbus_rw_header->reg_count); count++)
        {                                                   // copy regs a register at a time
          cbus_rw_header->data[count] = *read_ptr;          // copy data at read_ptr into outgoing packet
          read_ptr++;                                       // increment read_ptr to next register
        }
        cbus_rw_header->data_bytes = cbus_rw_header->reg_count * CBUS_DATA_WORD_SIZE;
                                                            // load number of bytes written into header before returning
        buffer_bytes = CBUS_FN_HDR_SIZE_RD_WR + cbus_rw_header->data_bytes;
                                                            // load count of bytes to be queued for tx to host below
      }
      break;
    case CBUS_FN_CODE_WRITE:                                // function write
      {
        unsigned short count;                               // used to copy data
        unsigned long* write_ptr;                           // destination pointer (holding registers)
        write_ptr = ChalkBusRegs + (cbus_rw_header->starting_reg);
                                                            // initialize starting write pointer
        for(count = 0; count < (cbus_rw_header->reg_count); count++)
        {                                                   // copy regs a register at a time
          *write_ptr = cbus_rw_header->data[count];         // copy data from incoming packet to write_ptr
          write_ptr++;                                      // increment write_ptr to next register
        }
        cbus_rw_header->data_bytes = 0;                     // returning zero data in response
        buffer_bytes = CBUS_FN_HDR_SIZE_RD_WR;              // acknowledge packet's only bytes to return is header with 0 data byte count
      }
      break;
    default:                                                // function unknown
      {
        return;                                             // unknown functions should never get here
      }
  } 
  if(g_bUSBDevConnected)                                    // send response if there is a device to listen
  {
    USBBufferWrite((tUSBBuffer *)&g_sTxBuffer,(unsigned char*)ChalkBusBuff, buffer_bytes);
                                                            // queue the data to send
  }
}
示例#14
0
//*****************************************************************************
//
// Write a data record to the serial port.  An acquired data record is passed
// in and is composed into a binary packet and sent on the serial port.  The
// host PC, if connected will receive this packet via the virtual serial port,
// and can decode and display the data.
//
// The binary packet has the following format:
// - 16-bit header, value 0x5351
// - 32-bit seconds time stamp
// - 16-bit fractional seconds time stamp (1/32768 resolution)
// - 16-bit data item selection mask (which items are included in the record)
// - multiple 16-bit data item values, per selection mask
// - 16-bit checksum which when added to the 16-bit sum of the entire packet
// will result in 0.
//
// The entire packet is transmitted bytewise over the virtual serial port,
// little-endian format.
//
//*****************************************************************************
int
USBSerialWriteRecord(tLogRecord *pRecord)
{
    unsigned long ulIdx;
    unsigned short usChecksum;
    unsigned long ulItemCount;
    unsigned short *pusBuf;

    //
    // Check the arguments
    //
    ASSERT(pRecord);
    if(!pRecord)
    {
        return(1);
    }

    //
    // Check state for ready device
    //
    if(!g_bUSBDevConnected)
    {
        return(1);
    }

    //
    // Determine how many channels are to be logged
    //
    ulIdx = pRecord->usItemMask;
    ulItemCount = 0;
    while(ulIdx)
    {
        if(ulIdx & 1)
        {
            ulItemCount++;
        }
        ulIdx >>= 1;
    }

    //
    // Add to item count the equivalent number of 16-bit words for timestamp
    // and selection mask.
    //
    ulItemCount += 4;

    //
    // Put the header word in the USB buffer
    //
    usChecksum = 0x5351;
    USBBufferWrite((tUSBBuffer *)&g_sTxBuffer,
                   (unsigned char *)&usChecksum, 2);

    //
    // Compute the checksum over the entire record
    //
    pusBuf = (unsigned short *)pRecord;
    for(ulIdx = 0; ulIdx < ulItemCount; ulIdx++)
    {
        usChecksum += pusBuf[ulIdx];
    }

    //
    // Convert item count to bytes.  This now represents the entire record
    // size in bytes, not including the checksum.  The header has already
    // been sent
    //
    ulItemCount *= 2;

    //
    // Transmit the record, which includes the time stamp, selection mask
    // and all selected data item, to the USB buffer
    //
    USBBufferWrite((tUSBBuffer *)&g_sTxBuffer,
                   (unsigned char *)pusBuf, ulItemCount);

    //
    // Adjust the checksum so that when added (as unsigned short) to the
    // sum of the rest of the packet, the result will be 0
    //
    usChecksum = (unsigned short)(0x10000L - (unsigned long)usChecksum);

    //
    // Transmit the checksum which is the end of the packet
    //
    USBBufferWrite((tUSBBuffer *)&g_sTxBuffer,
                   (unsigned char *)&usChecksum, 2);

    //
    // Return success to the caller
    //
    return(0);
}