title: STM32 USB CDC Will Not Return Data
body: <p>I am trying to use the STM32F303 Discovery Board to send back data via USB, but am running into some issues. Here is the code where the problem is happening:</p>
  
  <pre><code>void CDC_Receive_Callback(uint8_t *_buff, uint16_t _len) {
    uint8_t *sub_buff;            // Buffer to store sub strings (extracted data)
    uint8_t outputMsg[256] = "";  // Buffer for output message
    uint8_t command;              // Command
    uint8_t value;                // Command value
  
    // Extract the command
    sub_buff = (uint8_t *) strtok((char *) _buff, " ");
    command = (uint8_t) atoi((char *) sub_buff);
  
    // Extract the command value
    sub_buff = (uint8_t *) strtok(NULL, " ");
    value = (uint8_t) atoi((char *) sub_buff);
  
    // Check for extraneous data
    if (strtok(NULL, " ") != NULL) {
      command = 0;
    }
  
    // Perform command
    switch(command) {
  
      /* ...Command Options... */
  
      case CMD_LED_ON:
        //Acknowledge command
        CDC_Transmit_FS((uint8_t *) MSG_LED_ON, 
         strlen(MSG_LED_ON));
  
        //Turn on LED
        HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_RESET);
  
        break;
  
      case CMD_RETURN_DATA:
        //Acknowledge command
        CDC_Transmit_FS((uint8_t *) MSG_RETURN_DATA, 
         strlen(MSG_RETURN_DATA));
  
        calculateData();
  
        //Build return message
        strcat((char *) outputMsg, "Calculation Results: \n");
        uint8_t value_as_string[100];
  
        sprintf((char *)value_as_string, "Data: %u\n", getData());
        strcat((char *) outputMsg, (char *)value_as_string);
  
        CDC_Transmit_FS((uint8_t *) outputMsg, 
        strlen((char *)outputMsg));
  
        break;
  </code></pre>
  
  <p>The CMD_LED_ON command completely works (the LED turns on and MSG_LED_ON is returned). The CMD_RETURN_DATA command, however, only sends MSG_RETURN_DATA over USB, but nothing else. I've tried simply sending MSG_RETURN_DATA twice:</p>
  
  <pre><code>case CMD_RETURN_DATA:
        //Acknowledge command
        CDC_Transmit_FS((uint8_t *) MSG_RETURN_DATA, 
         strlen(MSG_RETURN_DATA));
  
        CDC_Transmit_FS((uint8_t *) MSG_RETURN_DATA, 
         strlen(MSG_RETURN_DATA));
  
        break;
  </code></pre>
  
  <p>but MSG_RETURN_DATA is only displayed once. I thought the issue was calling CDC_Transmit_FS() twice, so I tried including MSG_RETURN_DATA in outputMsg to only call CDC_Transmit_FS() once:</p>
  
  <pre><code>case CMD_RETURN_DATA:
    calculateData();
  
    //Build return message
    strcat((char *) outputMsg, MSG_RETURN_DATA);
    strcat((char *) outputMsg, "Calculation Results: \n");
    uint8_t value_as_string[100];
  
    sprintf((char *)value_as_string, "Data: %u\n", getData());
    strcat((char *) outputMsg, (char *)value_as_string);
  
    CDC_Transmit_FS((uint8_t *) outputMsg, 
    strlen((char *)outputMsg));
  
    break;
  </code></pre>
  
  <p>and nothing is displayed in RealTerm. Here is my code for CDC_Transmit_FS():</p>
  
  <pre><code>uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
  {
    uint8_t result = USBD_OK;
    USBD_CDC_HandleTypeDef *hcdc = 
    (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  
    if(hcdc-&gt;TxState != 0) {
      return USBD_BUSY;
    }
  
    USBD_CDC_SetTxBuffer(&amp;hUsbDeviceFS, Buf, Len);
    result = USBD_CDC_TransmitPacket(&amp;hUsbDeviceFS);
  
    return result;
  }
  </code></pre>
  
  <p>When I try to debug, it seems that when given the CMD_RETURN_DATA command,  CDC_Transmit_FS() always returns USBD_BUSY, at which point the code jumps to CDC_Receive_FS(), for reasons that I don't understand. Here is the code for CDC_Receive_FS():</p>
  
  <pre><code>static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
  {
    USBD_CDC_SetRxBuffer(&amp;hUsbDeviceFS, &amp;Buf[0]);
    USBD_CDC_ReceivePacket(&amp;hUsbDeviceFS);
    CDC_Receive_Callback(Buf, *Len);
    return (USBD_OK);
  }
  </code></pre>
  
  <p>I'm at a loss as to how to get CMD_RETURN_DATA to successfully return the data. Any help would be greatly appreciated.</p>
  
  <p><strong>Edit:</strong> To expand on my question, after one transfer is made it seems that TxState never becomes 0. I modified CDC_Transmit_FS() to wait on TxState:</p>
  
  <pre><code>uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
  {
    uint8_t result = USBD_OK;
    USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  
    if(hcdc-&gt;TxState != 0) {
      return USBD_BUSY;
    }
  
    USBD_CDC_SetTxBuffer(&amp;hUsbDeviceFS, Buf, Len);
    result = USBD_CDC_TransmitPacket(&amp;hUsbDeviceFS);
  
    //Wait for transmission to finish
    while(hcdc-&gt;TxState) ;
  
    return result;
  }
  </code></pre>
  
  <p>and the program hangs inside the while loop. I've tried sending CMD_LED_ON, and the computer receives the message like it's supposed to, so I know the transmission has completed, but the program remains stuck inside the loop. My expectation is that the PCD_EP_ISR_Handler() should call HAL_PCD_DataInStageCallback(), which calls USBD_LL_DataInStage(), which calls pdev->pClass->DataIn(), which is another name for USBD_CDC_DataIn(). This USBD_CDC_DataIn() is what sets TxState back to 0. For some reason this function doesn't seem to be getting called.</p>