From 102d5f5a4c830b8be3b7dea1bf24005e4f65654c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 23 Mar 2018 18:54:25 +0100 Subject: [PATCH] implemented fallback to physical usart and basis for wireless support in the future --- TinyFrame/TF_Integration.c | 41 ++++++- USB/README.TXT | 12 +++ USB/usbd_storage_if.c | 2 +- comm/interfaces.c | 207 ++++++++++++++++++++++++++++++++++++ comm/interfaces.h | 35 ++++++ comm/messages.c | 2 +- framework/settings.c | 6 +- framework/system_settings.c | 110 ++++++++++++++++++- framework/system_settings.h | 13 ++- gex_hooks.c | 2 + platform/debug_uart.c | 36 +++++++ platform/debug_uart.h | 10 +- platform/hw_utils.c | 13 ++- platform/hw_utils.h | 2 + platform/plat_compat.h | 6 +- platform/platform.c | 5 +- tasks/task_main.c | 62 ++++++----- 17 files changed, 514 insertions(+), 50 deletions(-) create mode 100644 comm/interfaces.c create mode 100644 comm/interfaces.h diff --git a/TinyFrame/TF_Integration.c b/TinyFrame/TF_Integration.c index fb911df..0b660dc 100644 --- a/TinyFrame/TF_Integration.c +++ b/TinyFrame/TF_Integration.c @@ -6,6 +6,9 @@ #include "platform.h" #include "task_main.h" +#include "comm/messages.h" +#include "comm/interfaces.h" +#include "framework/system_settings.h" #include "USB/usbd_cdc_if.h" #include "USB/usb_device.h" @@ -14,13 +17,20 @@ extern osSemaphoreId semVcomTxReadyHandle; extern osMutexId mutTinyFrameTxHandle; -void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len) +/** + * USB transmit implementation + * + * @param tf - TF + * @param buff - buffer to send (can be longer than the buffers) + * @param len - buffer size + */ +static inline void _USB_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len) { #if 1 const uint32_t real_size = len; // Padding to a multiple of 64 bytes - this is supposed to maximize the bulk transfer speed - if (len&0x3F) { + if ((len&0x3F) && !SystemSettings.visible_vcom) { // this corrupts VCOM on Linux for some reason uint32_t pad = (64 - (len&0x3F)); memset((void *) (buff + len), 0, pad); len += pad; // padding to a multiple of 64 (size of the endpoint) @@ -32,8 +42,9 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len) // The buffer is the TF transmit buffer, we can't leave it to work asynchronously because // the next call could modify it before it's been transmitted (in the case of a chunked / multi-part frame) - // the assumption here is that all until the last chunk use the full buffer capacity + // If this is not the last chunk (assuming all but the last use full 512 bytes of the TF buffer), wait now for completion if (real_size == TF_SENDBUF_LEN) { + // TODO this seems wrong - investigate if (pdTRUE != xSemaphoreTake(semVcomTxReadyHandle, 100)) { TF_Error("Tx stalled in WriteImpl"); return; @@ -41,7 +52,7 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len) } #else (void) tf; -#define CHUNK 64 // same as TF_SENDBUF_LEN, so we should always have only one run of the loop +#define CHUNK 64 // size of the USB packet int32_t total = (int32_t) len; while (total > 0) { const int32_t mxStatus = osSemaphoreWait(semVcomTxReadyHandle, 100); @@ -64,11 +75,31 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len) #endif } +void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, uint32_t len) +{ + if (gActiveComport == COMPORT_USB) { + _USB_WriteImpl(tf, buff, len); + } + else if (gActiveComport == COMPORT_USART) { + // TODO rewrite this to use DMA, then wait for the DMA + for(uint32_t i=0;i +#include "platform.h" +#include "usbd_core.h" +#include "USB/usb_device.h" +#include "interfaces.h" +#include "framework/system_settings.h" +#include "framework/unit.h" +#include "framework/resources.h" +#include "platform/hw_utils.h" +#include "framework/unit_base.h" + +enum ComportSelection gActiveComport = COMPORT_USB; // start with USB so the handlers work correctly initially + +static uint32_t last_switch_time = 0; // started with USB +static bool xfer_verify_done = false; + +static void configure_interface(enum ComportSelection iface); + +/** Switch com transfer if the current one doesnt seem to work */ +void com_switch_transfer_if_needed(void) +{ + if (xfer_verify_done) return; + + const uint32_t now = HAL_GetTick(); + const uint32_t elapsed = now - last_switch_time; + + if (gActiveComport == COMPORT_USB) { + if (elapsed > 1000) { + // USB may or may not work, depending on whether the module is plugged - + // in or running from a battery/external supply remotely. + + // Check if USB is enumerated + + const uint32_t uadr = (USB->DADDR & USB_DADDR_ADD); + if (0 == uadr) { + dbg("Not enumerated, assuming USB is dead"); + + // Fallback to bare USART + if (SystemSettings.use_comm_uart) { + configure_interface(COMPORT_USART); + } + else if (SystemSettings.use_comm_nordic) { + configure_interface(COMPORT_NORDIC); // this fallbacks to LoRa if LoRa enabled + } + else if (SystemSettings.use_comm_lora) { + configure_interface(COMPORT_LORA); + } + else { + dbg("No alternate com interface configured, leaving USB enabled."); + } + } else { + dbg("USB got address 0x%02x - OK", (int)uadr); + } + + xfer_verify_done = true; + } + } +} + +/** Claim resources that may be needed for alternate transfers */ +void com_claim_resources_for_alt_transfers(void) +{ + if (SystemSettings.use_comm_uart) { + do { + if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_USART2)) { + SystemSettings.use_comm_uart = false; + break; + } + + if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_PA2)) { + SystemSettings.use_comm_uart = false; + rsc_free(&UNIT_SYSTEM, R_USART2); + break; + } + if (E_SUCCESS != rsc_claim(&UNIT_SYSTEM, R_PA3)) { + SystemSettings.use_comm_uart = false; + rsc_free(&UNIT_SYSTEM, R_USART2); + rsc_free(&UNIT_SYSTEM, R_PA2); + break; + } + } while (0); + } +} + +/** Release resources allocated for alternate transfers */ +void com_release_resources_for_alt_transfers(void) +{ + if (SystemSettings.use_comm_uart) { + rsc_free(&UNIT_SYSTEM, R_USART2); + rsc_free(&UNIT_SYSTEM, R_PA2); + rsc_free(&UNIT_SYSTEM, R_PA3); + } +} + +static uint32_t usart_rxi = 0; +static uint8_t usart_rx_buffer[MSG_QUE_SLOT_SIZE]; +static uint32_t last_rx_time = 0; + +/** Handler for the USART transport */ +static void com_UsartIrqHandler(void *arg) +{ + (void)arg; + if (LL_USART_IsActiveFlag_RXNE(USART2)) { + vPortEnterCritical(); + { + usart_rx_buffer[usart_rxi++] = LL_USART_ReceiveData8(USART2); + if (usart_rxi == MSG_QUE_SLOT_SIZE) { + rxQuePostMsg(usart_rx_buffer, MSG_QUE_SLOT_SIZE); // avoid it happening in the irq + usart_rxi = 0; + } + last_rx_time = HAL_GetTick(); + } + vPortExitCritical(); + } +} + +/** this is called from the hal tick irq */ +void com_iface_flush_buffer(void) +{ + if (usart_rxi > 0 && (HAL_GetTick()-last_rx_time)>=2) { + vPortEnterCritical(); + { + rxQuePostMsg(usart_rx_buffer, usart_rxi); + usart_rxi = 0; + } + vPortExitCritical(); + } +} + +static void configure_interface(enum ComportSelection iface) +{ + // Teardown + if (gActiveComport == COMPORT_USB) { + // simplest USB disabling (XXX needs porting) + HAL_PCD_DeInit(&hpcd_USB_FS); + __HAL_RCC_USB_CLK_DISABLE(); + } + else if (gActiveComport == COMPORT_USART) { + // this doesn't normally happen + hw_deinit_pin_rsc(R_PA2); + hw_deinit_pin_rsc(R_PA3); + __HAL_RCC_USART2_CLK_DISABLE(); + irqd_detach(USART2, com_UsartIrqHandler); + } + gActiveComport = COMPORT_NONE; + + // Init + if (iface == COMPORT_USB) { + trap("illegal"); // this never happens + } + else if (iface == COMPORT_USART) { + dbg("Setting up UART transfer"); + assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA2, LL_GPIO_AF_1)); + assert_param(E_SUCCESS == hw_configure_gpiorsc_af(R_PA3, LL_GPIO_AF_1)); + + __HAL_RCC_USART2_CLK_ENABLE(); + __HAL_RCC_USART2_FORCE_RESET(); + __HAL_RCC_USART2_RELEASE_RESET(); + + LL_USART_Disable(USART2); + + LL_USART_SetBaudRate(USART2, PLAT_APB1_HZ, LL_USART_OVERSAMPLING_16, SystemSettings.comm_uart_baud); + dbg("baud = %d", (int)SystemSettings.comm_uart_baud); + + irqd_attach(USART2, com_UsartIrqHandler, NULL); + LL_USART_EnableIT_RXNE(USART2); + LL_USART_SetTransferDirection(USART2, LL_USART_DIRECTION_TX_RX); + + LL_USART_Enable(USART2); + } + else { + if (iface == COMPORT_NORDIC) { + // Try to configure nordic + dbg("Setting up nRF transfer"); + + // TODO set up and check nRF transport + + // On failure, try setting up LoRa + dbg("nRF failed to init"); + if (SystemSettings.use_comm_lora) { + iface = COMPORT_LORA; + } else { + iface = COMPORT_NONE; // fail + } + } + + if (iface == COMPORT_LORA) { + // Try to configure nordic + dbg("Setting up LoRa transfer"); + + // TODO set up and check LoRa transport + + dbg("LoRa failed to init"); + iface = COMPORT_NONE; // fail + } + } + + if (iface == COMPORT_NONE) { + dbg("NO COM PORT AVAILABLE!"); + } + + gActiveComport = iface; +} diff --git a/comm/interfaces.h b/comm/interfaces.h new file mode 100644 index 0000000..5d65766 --- /dev/null +++ b/comm/interfaces.h @@ -0,0 +1,35 @@ +// +// Created by MightyPork on 2018/03/23. +// + +#ifndef GEX_F072_COM_INTERFACES_H +#define GEX_F072_COM_INTERFACES_H + +#include "platform.h" + +enum ComportSelection { + COMPORT_NONE = 0, + COMPORT_USB = 1, + COMPORT_USART = 2, + COMPORT_NORDIC = 3, + COMPORT_LORA = 4, +}; + +/** + * The currently active communication port + */ +extern enum ComportSelection gActiveComport; + +/** Switch com transfer if the current one doesnt seem to work */ +void com_switch_transfer_if_needed(void); + +/** Claim resources that may be needed for alternate transfers */ +void com_claim_resources_for_alt_transfers(void); + +/** Release resources allocated for alternate transfers */ +void com_release_resources_for_alt_transfers(void); + +/** Flush the rx buffer */ +void com_iface_flush_buffer(void); + +#endif //GEX_F072_COM_INTERFACES_H diff --git a/comm/messages.c b/comm/messages.c index 7675504..e1b679a 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -2,7 +2,6 @@ // Created by MightyPork on 2017/11/21. // -#include #include "platform.h" #include "framework/settings.h" #include "utils/ini_parser.h" @@ -11,6 +10,7 @@ #include "comm/messages.h" #include "framework/system_settings.h" #include "utils/malloc_safe.h" +#include "platform/status_led.h" static TinyFrame tf_; TinyFrame *comm = &tf_; diff --git a/framework/settings.c b/framework/settings.c index c1b6213..5abd366 100644 --- a/framework/settings.c +++ b/framework/settings.c @@ -2,6 +2,7 @@ // Created by MightyPork on 2017/11/26. // +#include #include "platform.h" #include "utils/hexdump.h" #include "settings.h" @@ -9,6 +10,7 @@ #include "system_settings.h" #include "utils/str_utils.h" #include "unit_base.h" +#include "platform/debug_uart.h" #include "utils/avrlibc.h" // pre-declarations @@ -311,7 +313,7 @@ void settings_load_ini_key(const char *restrict section, const char *restrict ke if (streq(section, "SYSTEM")) { if (SystemSettings.loading_inifile == 0) { SystemSettings.loading_inifile = 'S'; - systemsettings_mco_teardown(); + systemsettings_begin_load(); systemsettings_loadDefaults(); } @@ -358,6 +360,6 @@ void settings_load_ini_end(void) } if (SystemSettings.loading_inifile == 'S') { - systemsettings_mco_init(); + systemsettings_finalize_load(); } } diff --git a/framework/system_settings.c b/framework/system_settings.c index ec8c780..8e49142 100644 --- a/framework/system_settings.c +++ b/framework/system_settings.c @@ -2,6 +2,8 @@ // Created by MightyPork on 2017/12/02. // +#include +#include #include "platform.h" #include "system_settings.h" #include "utils/str_utils.h" @@ -10,6 +12,11 @@ #include "resources.h" #include "unit_base.h" +static void systemsettings_mco_teardown(void); +static void systemsettings_mco_init(void); +/** Init/deinit debug uart */ +static void systemsettings_debug_uart_init_deinit(void); + struct system_settings SystemSettings; /** Load defaults only */ @@ -19,6 +26,13 @@ void systemsettings_loadDefaults(void) SystemSettings.ini_comments = true; SystemSettings.enable_mco = false; SystemSettings.mco_prediv = 7; + + SystemSettings.use_comm_uart = false; // TODO configure those based on compile flags for a particular platform + SystemSettings.use_comm_lora = false; + SystemSettings.use_comm_nordic = false; + SystemSettings.comm_uart_baud = 115200; // TODO + + SystemSettings.enable_debug_uart = true; } /** Load defaults and init flags */ @@ -35,14 +49,20 @@ void systemsettings_init(void) void systemsettings_save(PayloadBuilder *pb) { pb_char(pb, 'S'); - pb_u8(pb, 1); // settings format version + pb_u8(pb, 2); // settings format version { // system settings pb_bool(pb, SystemSettings.visible_vcom); pb_bool(pb, SystemSettings.ini_comments); - + // 1 pb_bool(pb, SystemSettings.enable_mco); pb_u8(pb, SystemSettings.mco_prediv); + // 2 + pb_bool(pb, SystemSettings.use_comm_uart); + pb_bool(pb, SystemSettings.use_comm_nordic); + pb_bool(pb, SystemSettings.use_comm_lora); + pb_u32(pb, SystemSettings.comm_uart_baud); + pb_bool(pb, SystemSettings.enable_debug_uart); } // end system settings } @@ -67,12 +87,40 @@ void systemsettings_mco_init(void) } } +void systemsettings_debug_uart_init_deinit(void) +{ + if (SystemSettings.enable_debug_uart) { + DebugUart_Init(); + } else { + DebugUart_Teardown(); + } +} + +/** + * Begin load of system settings, releasing resources etc + */ +void systemsettings_begin_load(void) +{ + systemsettings_mco_teardown(); + com_release_resources_for_alt_transfers(); +} + +/** + * Claim resources and set up system components based on the loaded settings + */ +void systemsettings_finalize_load(void) +{ + systemsettings_mco_init(); + systemsettings_debug_uart_init_deinit(); + com_claim_resources_for_alt_transfers(); +} + // from binary bool systemsettings_load(PayloadParser *pp) { if (pp_char(pp) != 'S') return false; - systemsettings_mco_teardown(); + systemsettings_begin_load(); uint8_t version = pp_u8(pp); @@ -85,9 +133,16 @@ bool systemsettings_load(PayloadParser *pp) SystemSettings.enable_mco = pp_bool(pp); SystemSettings.mco_prediv = pp_u8(pp); } + if (version >= 2) { + SystemSettings.use_comm_uart = pp_bool(pp); + SystemSettings.use_comm_nordic = pp_bool(pp); + SystemSettings.use_comm_lora = pp_bool(pp); + SystemSettings.comm_uart_baud = pp_u32(pp); + SystemSettings.enable_debug_uart = pp_bool(pp); + } } // end system settings - systemsettings_mco_init(); + systemsettings_finalize_load(); return pp->ok; } @@ -106,11 +161,31 @@ void systemsettings_build_ini(IniWriter *iw) iw_comment(iw, "Show comments in INI files (Y, N)"); iw_entry_s(iw, "ini-comments", str_yn(SystemSettings.ini_comments)); + iw_comment(iw, "Enable debug UART-Tx on PA9 (Y, N)"); // TODO update if moved to a different pin + iw_entry_s(iw, "debug-uart", str_yn(SystemSettings.enable_debug_uart)); + iw_cmt_newline(iw); iw_comment(iw, "Output core clock on PA8 (Y, N)"); iw_entry_s(iw, "mco-enable", str_yn(SystemSettings.enable_mco)); iw_comment(iw, "Output clock prediv (1,2,...,128)"); iw_entry_d(iw, "mco-prediv", (1<resources, (Resource)rsc)) { - rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc)); - GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16]; - uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16]; - LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG); + hw_deinit_pin_rsc((Resource)rsc); } } } +void hw_deinit_pin_rsc(Resource rsc) +{ + rsc_dbg("Freeing pin %s", rsc_get_name((Resource)rsc)); + GPIO_TypeDef *port = GPIO_PERIPHS[(rsc-R_PA0) / 16]; + uint32_t ll_pin = LL_GPIO_PINS[(rsc-R_PA0)%16]; + LL_GPIO_SetPinMode(port, ll_pin, LL_GPIO_MODE_ANALOG); +} + /** Configure a pin to alternate function */ error_t hw_configure_gpio_af(char port_name, uint8_t pin_num, uint32_t ll_af) { diff --git a/platform/hw_utils.h b/platform/hw_utils.h index e91fa48..4ad843f 100644 --- a/platform/hw_utils.h +++ b/platform/hw_utils.h @@ -40,6 +40,8 @@ GPIO_TypeDef *hw_port2periph(char port_name, bool *suc); */ bool hw_pinrsc2ll(Resource rsc, GPIO_TypeDef **port, uint32_t *llpin) __attribute__((warn_unused_result)); +void hw_deinit_pin_rsc(Resource rsc); + /** * Spread packed port pins using a mask * diff --git a/platform/plat_compat.h b/platform/plat_compat.h index 7f0bd1c..729de04 100644 --- a/platform/plat_compat.h +++ b/platform/plat_compat.h @@ -56,9 +56,9 @@ #define IWBUFFER_LEN 80 // Ini writer buffer for sprintf // -------- Timeouts ------------ -#define TF_PARSER_TIMEOUT_TICKS 300 // Timeout for receiving & parsing a frame -#define BULK_LST_TIMEOUT_MS 500 // timeout for the bulk transaction to expire -#define MSG_QUE_POST_TIMEOUT 100 // Time to post to the messages / jobs queue +#define TF_PARSER_TIMEOUT_TICKS 100 // Timeout for receiving & parsing a frame +#define BULK_LST_TIMEOUT_MS 2000 // timeout for the bulk transaction to expire +#define MSG_QUE_POST_TIMEOUT 200 // Time to post to the messages / jobs queue // -------- Platform specific includes and defines --------- diff --git a/platform/platform.c b/platform/platform.c index 24692bb..4e1ebf3 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -2,7 +2,6 @@ // Created by MightyPork on 2017/11/26. // -#include #include "platform.h" #include "usbd_core.h" #include "USB/usb_device.h" @@ -22,6 +21,8 @@ #include "units/fcap/unit_fcap.h" #include "units/touch/unit_touch.h" #include "units/simple_pwm/unit_pwmdim.h" +#include "units/dac/unit_dac.h" +#include "comm/interfaces.h" #include "hw_utils.h" void plat_init_resources(void) @@ -258,6 +259,8 @@ void plat_init_resources(void) */ void plat_usb_reconnect(void) { + if (gActiveComport != COMPORT_USB) return; + // TODO add better reset methods available on different chips USBD_LL_Reset(&hUsbDeviceFS); diff --git a/tasks/task_main.c b/tasks/task_main.c index 342e51e..16b44d1 100644 --- a/tasks/task_main.c +++ b/tasks/task_main.c @@ -12,6 +12,7 @@ #include "usb_device.h" #include "usbd_msc.h" #include "task_main.h" +#include "comm/interfaces.h" /* TaskUsbEvent function */ void TaskMain(void const * argument) @@ -25,14 +26,16 @@ void TaskMain(void const * argument) Indicator_Effect(STATUS_WELCOME); - uint32_t startTime = xTaskGetTickCount(); + const uint32_t bootTime = HAL_GetTick(); + uint32_t startTime = bootTime; uint32_t cnt = 1; + bool waiting_for_usb = true; while(1) { uint32_t msg; xTaskNotifyWait(0, UINT32_MAX, &msg, 100); // time out if nothing happened // periodic updates to the VFS driver - uint32_t now = xTaskGetTickCount(); + uint32_t now = HAL_GetTick(); uint32_t elapsed = now - startTime; if (elapsed >= 100) { // interval 100ms or more - slow periodic @@ -48,6 +51,9 @@ void TaskMain(void const * argument) Indicator_Heartbeat(); wd_restart(); + + // If USB has no signal, set up alternate communication interface + com_switch_transfer_if_needed(); } // if no message and it just timed out, go wait some more... @@ -61,35 +67,39 @@ void TaskMain(void const * argument) continue; } - // Endpoint 0 - control messages for the different classes - if (msg & USBEVT_FLAG_EP0_RX_RDY) { - USBD_CDC_EP0_RxReady(&hUsbDeviceFS); - } + if (gActiveComport == COMPORT_USB) { + // Endpoint 0 - control messages for the different classes + if (msg & USBEVT_FLAG_EP0_RX_RDY) { + USBD_CDC_EP0_RxReady(&hUsbDeviceFS); + } - if (msg & USBEVT_FLAG_EP0_TX_SENT) { - // - } + if (msg & USBEVT_FLAG_EP0_TX_SENT) { + // + } #ifndef DISABLE_MSC - // MSC - read/write etc - if (msg & (USBEVT_FLAG_EPx_IN(MSC_EPIN_ADDR))) { - USBD_MSC_DataIn(&hUsbDeviceFS, MSC_EPIN_ADDR); - } - - if (msg & (USBEVT_FLAG_EPx_OUT(MSC_EPOUT_ADDR))) { - USBD_MSC_DataOut(&hUsbDeviceFS, MSC_EPOUT_ADDR); - } + // MSC - read/write etc + if (msg & (USBEVT_FLAG_EPx_IN(MSC_EPIN_ADDR))) { + USBD_MSC_DataIn(&hUsbDeviceFS, MSC_EPIN_ADDR); + } + + if (msg & (USBEVT_FLAG_EPx_OUT(MSC_EPOUT_ADDR))) { + USBD_MSC_DataOut(&hUsbDeviceFS, MSC_EPOUT_ADDR); + } #endif - // CDC - config packets and data in/out -// if (msg & (USBEVT_FLAG_EPx_IN(CDC_IN_EP))) { -// USBD_CDC_DataIn(&hUsbDeviceFS, CDC_IN_EP); -// } - if (msg & (USBEVT_FLAG_EPx_IN(CDC_CMD_EP))) { - USBD_CDC_DataIn(&hUsbDeviceFS, CDC_CMD_EP); - } - if (msg & (USBEVT_FLAG_EPx_OUT(CDC_OUT_EP))) { - USBD_CDC_DataOut(&hUsbDeviceFS, CDC_OUT_EP); + // CDC - config packets and data in/out +// if (msg & (USBEVT_FLAG_EPx_IN(CDC_IN_EP))) { +// USBD_CDC_DataIn(&hUsbDeviceFS, CDC_IN_EP); +// } + + if (msg & (USBEVT_FLAG_EPx_IN(CDC_CMD_EP))) { + USBD_CDC_DataIn(&hUsbDeviceFS, CDC_CMD_EP); + } + + if (msg & (USBEVT_FLAG_EPx_OUT(CDC_OUT_EP))) { + USBD_CDC_DataOut(&hUsbDeviceFS, CDC_OUT_EP); + } } } }