I'm using a K64 with SDK 2.4.2 and FreeRTOS. I'd like to extend the example code to provide read and write functions that block with a timeout. For example:
count = virtual_com_read(buffer, 8, timeout);
Would return after either timeout milliseconds or 8 bytes was read from the bus. It would return the actual number of bytes read.
I have experience using the RTOS. My questions are more about interpreting the existing code. Here are my questions:
This routine looks promising:
extern usb_status_t USB_DeviceCdcAcmSend(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length);
May I pass a buffer of any length? Will it block? Is there a way to specify a timeout?
Elsewhere in USB_DeviceCdcVcomCallback when kUSB_DeviceCdcEventSendResponse is handled there is the following (sorry the source code formatting is not working in Chrome ):
else if ((1 == _cdcvc.attach) && (1 == _cdcvc.startTransactions))
{
if ((epCbParam->buffer != NULL) ||((epCbParam->buffer == NULL) && (epCbParam->length == 0)))
{
/* User: add your own code for send complete event */
/* Schedule buffer for next receive event */
error = USB_DeviceCdcAcmRecv(handle,USB_CDC_VCOM_BULK_OUT_ENDPOINT, _receive_buffer,
g_UsbDeviceCdcVcomDicEndpoints[0].maxPacketSize);
I can see how I might use this in combination with USB_DeviceCdcAcmSend to create my virtual_com_send routine by adding an RTOS primitive.
Why though is this code called when the callback buffer is not null? What is in this buffer?
If I were to add a timeout how may I return the number of bytes actually written to the host?
What are some suggestions for implementing my read function?
Finally, there is a macro USB_DEVICE_CONFIG_USE_TASK which ultimately allows a task to periodically call:
void USB_DeviceTaskFunction(void *deviceHandle)
{
usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle;
static usb_device_callback_message_struct_t message;if (deviceHandle)
{/* Get the message from the queue */
if (kStatus_USB_OSA_Success == USB_OsaMsgqRecv(handle->notificationQueue,
(uint32_t *)&message, 0U))
{
/* Handle the message */
USB_DeviceNotification(handle, &message);
}
}
}
This function is ultimately calling FreeRTOS's xQueueReceive with a timeout of zero. It would be nice to support a timeout as that task will return immediately whether or not a message is in the queue. So this task will starve other tasks at lower priority. I can sleep a bit in the calling task but that will always add that latency rather than only when a message is unavailable (if I understand this correctly).
Thanks for reading.
Solved! Go to Solution.
I believe I've worked this out and I'm attaching a replacement virtual_com.h/.c along with a Python test script.
Note that I'm using the helper task so USB_DEVICE_CONFIG_USE_TASK must be defined to be nonzero. Also configSUPPORT_STATIC_ALLOCATION must be set in FreeRTOSConfig.h. I'm probably missing some other details.
I believe I've worked this out and I'm attaching a replacement virtual_com.h/.c along with a Python test script.
Note that I'm using the helper task so USB_DEVICE_CONFIG_USE_TASK must be defined to be nonzero. Also configSUPPORT_STATIC_ALLOCATION must be set in FreeRTOSConfig.h. I'm probably missing some other details.
FYI: I found a bug where "ready" was not cleared when "attached" is set to zero. In my testing if I physically disconnected the device from the bus, "attached" was cleared but "ready" remained set. When plugging the device back in both "ready" and "attached" were set which is an incorrect state. "ready" is set when the device file is opened in Linux or MacOS (likely similar in Windows).
Anyway, find where "attached" is cleared and also clear "ready".