2.5.2.4.3 Sending Data

The application may need to send data or serial state notification to the USB CDC Host. This is done by using the USB_DEVICE_CDC_Write and USB_DEVICE_CDC_SerialStateNotificationSend functions, respectively.

Sending Data to the USB Host

The application can send data to the Host by using the USB_DEVICE_CDC_Write function. This function returns a transfer handle that allows the application to track the write request. The request is completed when the Host has requested the data. The completion of the write transfer is indicated by a USB_DEVICE_CDC_EVENT_WRITE_COMPLETE event. A write request could fail if the function driver instance transfer queue is full.

The USB_DEVICE_CDC_Write function also allows the application to send data to the host without ending the transfer. This is done by specifying the USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_PENDING flag. The application can use this option when the data to be sent is not readily available or when the application is memory constrained. The combination of the transfer flag and the transfer size affects how the function driver sends the data to the host:

  • If size is a multiple of maxPacketSize (the IN endpoint size), and the flag is set as USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE, the write function will append a Zero Length Packet (ZLP) to complete the transfer.
  • If size is a multiple of maxPacketSize, and the flag is set as USB_DEVICE_CDC_TRANSFER_FLAGS_MORE_DATA_PENDING, the write function will not append a ZLP and therefore, will not complete the transfer.
  • If size is greater than but not a multiple of maxPacketSize, and the flag is set as USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE, the write function schedules (length/maxPacketSize) packets and one packet for the residual data.
  • If size if greater than but not a multiple of maxPacketSize, and the flag is set as USB_DEVICE_CDC_TRANSFER_FLAGS_MORE_DATA_PENDING, the write function returns an error code and sets the transferHandle parameter to USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID.
  • If size is less than maxPacketSize, and the flag is set as USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE, the write function schedules one packet.
  • If size is less than maxPacketSize, and the flag is set as USB_DEVICE_CDC_TRANSFER_FLAGS_MORE_DATA_PENDING, the write function returns an error code and sets the transferHandle parameter to USB_DEVICE_CDC_TRANSFER_HANDLE_INVALID.

The following code shows a set of examples of various conditions attempting to send data with the USB_DEVICE_CDC_Write command.

Example 1

// This example assume that the maxPacketSize is 64.
USB_DEVICE_CDC_TRANSFER_HANDLE transferHandle;
USB_DEVICE_CDC_INDEX instance;
USB_DEVICE_CDC_RESULT writeRequestResult;
uint8_t data[34];

// In this example we want to send 34 bytes only.
writeRequestResult = USB_DEVICE_CDC_Write(instance,&transferHandle, data, 34,
                                            USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE);
if(USB_DEVICE_CDC_RESULT_OK != writeRequestResult)
{
    //Do Error handling here
}

Example 2

//-------------------------------------------------------
// In this example we want to send 64 bytes only.
// This will cause a ZLP to be sent.

USB_DEVICE_CDC_TRANSFER_HANDLE transferHandle;
USB_DEVICE_CDC_INDEX instance;
USB_DEVICE_CDC_RESULT writeRequestResult;
uint8_t data[64];


writeRequestResult = USB_DEVICE_CDC_Write(instance,&transferHandle, data, 64,
                                            USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE);
if(USB_DEVICE_CDC_RESULT_OK != writeRequestResult)
{
//Do Error handling here
}

Example 3

//-------------------------------------------------------
// This example will return an error because size is less
// than maxPacketSize and the flag indicates that more
// data is pending.

USB_DEVICE_CDC_TRANSFER_HANDLE transferHandle;
USB_DEVICE_CDC_INDEX instance;
USB_DEVICE_CDC_RESULT writeRequestResult;
uint8_t data[64];

writeRequestResult = USB_DEVICE_CDC_Write(instance,&transferHandle, data, 32,
                                       USB_DEVICE_CDC_TRANSFER_FLAGS_MORE_DATA_PENDING);

Example 4

//-------------------------------------------------------
// In this example we want to place a request for a 70 byte transfer.
// The 70 bytes will be sent out in a 64 byte transaction and a 6 byte
// transaction completing the transfer.

USB_DEVICE_CDC_TRANSFER_HANDLE transferHandle;
USB_DEVICE_CDC_INDEX instance;
USB_DEVICE_CDC_RESULT writeRequestResult;
uint8_t data[70];

writeRequestResult = USB_DEVICE_CDC_Write(instance,&transferHandle, data, 70,
                                            USB_DEVICE_CDC_TRANSFER_FLAGS_DATA_COMPLETE);

if(USB_DEVICE_CDC_RESULT_OK != writeRequestResult)
{
//Do Error handling here
}

Example 5

//-------------------------------------------------------
// In this example we want to place a request for a 70 bytes to be sent
// but that we don't end the transfer as more data is coming. 64 bytes
// of the 70 will be sent out and the USB_DEVICE_CDC_EVENT_WRITE_COMPLETE
// with 64 bytes. This indicates that the extra 6 bytes weren't
// sent because it would cause the end of the transfer. Thus the
// user needs to add these 6 bytes back to the buffer for the next group
// of data that needs to be sent out.

USB_DEVICE_CDC_TRANSFER_HANDLE transferHandle;
USB_DEVICE_CDC_INDEX instance;
USB_DEVICE_CDC_RESULT writeRequestResult;
uint8_t data[70];

writeRequestResult = USB_DEVICE_CDC_Write(instance,&transferHandle, data, 70,
                                            USB_DEVICE_CDC_TRANSFER_FLAGS_MORE_DATA_PENDING);

if(USB_DEVICE_CDC_RESULT_OK != writeRequestResult)
{
//Do Error handling here
}
// The completion of the write request will be indicated by the
// USB_DEVICE_CDC_EVENT_WRITE_COMPLETE event.

Sending a Serial State Notification

The application can send a Serial State Notification by using the USB_DEVICE_CDC_SerialStateSend function. This function returns a transfer handle that allows the application to track the read request. The request is completed when the Host has requested the data. The completion of the transfer is indicated by a USB_DEVICE_CDC_EVENT_SERIAL_STATE_NOTIFICATION_COMPLETE event. The transfer request could fail if the function driver transfer queue is full. The following code shows an example of how this can be done.
USB_DEVICE_CDC_INDEX instanceIndex;
USB_DEVICE_CDC_TRANSFER_HANDLE transferHandle;
USB_DEVICE_CDC_SERIAL_STATE_NOTIFICATION_DATA notificationData;

// This application function could possibly update the notificationData
// data structure.

APP_UpdateNotificationData(&notificationData);

// Now send the updated notification data to the host.

result = USB_DEVICE_CDC_SerialStateDataSend(instanceIndex, &transferHandle,
                                            &notificationData);

if(USB_DEVICE_CDC_RESULT_OK != result)
{
    // Error handling here
}