Hey Martin,
As I noted elsewhere, I'm using a modified form of the USB device demo code.
To detect a connection/disconnection I have added code to notify my (FreeRTOS) command task that there has been a USB "disconnect" by the modifications to the "virtual_USB" code segements (int red). I've put in the whole "case" code so you can find where the locations are more easily.
Here:
case kUSB_DeviceCdcEventRecvResponse:
{
uint32_t i;
if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions)) {
s_recvSize = epCbParam->length;
if ((0 != s_recvSize) && (0xFFFFFFFF != s_recvSize)) {
for (i = 0; (s_recvSize + 0) > i; ++i) {
if (0 != usbBlockCountDown) {
usbCMDMsg.msg[usbCMDMsgSize++] = s_currRecvBuf[i];
--usbBlockCountDown;
}
else if (usbBlockFlag) {
usbBlockCountDown = (uint32_t)(usbCMDMsg.msg[usbCMDMsgSize++] = s_currRecvBuf[i]);
usbBlockFlag = FALSE;
}
else {
// myke packet receive code here/Modified from the original
mykeUSBBuffer[usbBufferSize++] = s_currRecvBuf[i];
}
}
s_recvSize = 0;
error = USB_DeviceCdcAcmRecv(handle
, USB_CDC_VCOM_BULK_OUT_ENDPOINT
, s_currRecvBuf
, g_UsbDeviceCdcVcomDicEndpoints[0].maxPacketSize);
}
else {
usbCMDMsg.header = CMD_REQUEST_DISCONNECT;
CMDMSGISR(usbCMDMsg)
}
}
}
break;
and here (I marked where I detect the "connection" in blue):
case kUSB_DeviceCdcEventSetControlLineState:
{
s_usbCdcAcmInfo.dteStatus = acmReqParam->setupValue;
/* activate/deactivate Tx carrier */
if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION)
{
acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_TX_CARRIER;
}
else
{
acmInfo->uartState &= (uint16_t)~USB_DEVICE_CDC_UART_STATE_TX_CARRIER;
}
/* activate carrier and DTE */
if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE)
{
acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_RX_CARRIER;
}
else
{
acmInfo->uartState &= (uint16_t)~USB_DEVICE_CDC_UART_STATE_RX_CARRIER;
}
/* Indicates to DCE if DTE is present or not */
acmInfo->dtePresent = (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) ? true : false;
/* Initialize the serial state buffer */
acmInfo->serialStateBuf[0] = NOTIF_REQUEST_TYPE; /* bmRequestType */
acmInfo->serialStateBuf[1] = USB_DEVICE_CDC_NOTIF_SERIAL_STATE; /* bNotification */
acmInfo->serialStateBuf[2] = 0x00; /* wValue */
acmInfo->serialStateBuf[3] = 0x00;
acmInfo->serialStateBuf[4] = 0x00; /* wIndex */
acmInfo->serialStateBuf[5] = 0x00;
acmInfo->serialStateBuf[6] = UART_BITMAP_SIZE; /* wLength */
acmInfo->serialStateBuf[7] = 0x00;
/* Notifiy to host the line state */
acmInfo->serialStateBuf[4] = acmReqParam->interfaceIndex;
/* Lower byte of UART BITMAP */
uartBitmap = (uint8_t *)&acmInfo->serialStateBuf[NOTIF_PACKET_SIZE + UART_BITMAP_SIZE - 2];
uartBitmap[0] = acmInfo->uartState & 0xFFu;
uartBitmap[1] = (acmInfo->uartState >> 8) & 0xFFu;
len = (uint32_t)(NOTIF_PACKET_SIZE + UART_BITMAP_SIZE);
if (0 == ((usb_device_cdc_acm_struct_t *)handle)->hasSentState)
{
error = USB_DeviceCdcAcmSend(handle, USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT, acmInfo->serialStateBuf, len);
if (kStatus_USB_Success != error)
{
usb_echo("kUSB_DeviceCdcEventSetControlLineState error!");
}
((usb_device_cdc_acm_struct_t *)handle)->hasSentState = 1;
}
/* Update status */
if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION) {
/* To do: CARRIER_ACTIVATED */
}
else {
/* To do: CARRIER_DEACTIVATED */
}
if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE)
{
/* DTE_ACTIVATED */
if (1 == s_cdcVcom.attach)
{
usbCMDMsg.header = CMD_REQUEST_CONNECT;
CMDMSGISR(usbCMDMsg)
s_cdcVcom.startTransactions = 1;
#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \
defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \
defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U)
s_waitForDataReceive = 1;
USB0->INTEN &= ~USB_INTEN_SOFTOKEN_MASK;
s_comOpen = 1;
usb_echo("USB_APP_CDC_DTE_ACTIVATED\r\n");
#endif
}
}
else
{
/* DTE_DEACTIVATED */
if (1 == s_cdcVcom.attach)
{
usbCMDMsg.header = CMD_REQUEST_DISCONNECT;
CMDMSGISR(usbCMDMsg)
s_cdcVcom.startTransactions = 0;
}
}
}
break;
I don't if you would call these modifications "elegant" but they do the job. I have the two "disconnect" locations as I have found that different apps and situations (ie unplugging the cable) will result in different code locations executing - but there are no observed conditions where there is something like "disconnect" - "connect" - "disconnect".
Note that as this code is executing in the USB callback, I'm treating it like an ISR (and using the ISR Message Send APIs).
If there's a better way of detecting connections/disconnections I'm interested in seeing it.
myke