USB-UART: New GUI (#826)

* USB-UART: new gui
* Furi: use furi_console for logging instead of printf.
* CDC: calling open/close callbacks on interface change
* fix vcp_tx block on disconnect
* USB mode set by struct pointer
* FuriHal: proper event sequence on vcp reconnect
* disable debug prints
* HAL: add context to UART IRQ's
* Context usage in UART IRQ and CDC callbacks
* USB-UART: geting rid of baudrate limitations
* FuriHal: remove struct pollutant in usb api.

Co-authored-by: あく <alleteam@gmail.com>
Co-authored-by: DrZlo13 <who.just.the.doctor@gmail.com>
This commit is contained in:
Nikolay Minaylov
2021-11-21 18:17:43 +03:00
committed by GitHub
parent a5052a0375
commit efded63bcb
37 changed files with 1444 additions and 961 deletions

View File

@@ -1,5 +1,6 @@
#include "furi-hal-version.h"
#include "furi-hal-usb_i.h"
#include "furi-hal-usb.h"
#include "furi-hal-usb-cdc_i.h"
#include <furi.h>
@@ -347,7 +348,7 @@ static const struct CdcConfigDescriptorDual cdc_cfg_desc_dual = {
static struct usb_cdc_line_coding cdc_config[IF_NUM_MAX] = {};
static uint8_t cdc_ctrl_line_state[IF_NUM_MAX];
static void cdc_init(usbd_device* dev, struct UsbInterface* intf);
static void cdc_init(usbd_device* dev, UsbInterface* intf);
static void cdc_deinit(usbd_device *dev);
static void cdc_on_wakeup(usbd_device *dev);
static void cdc_on_suspend(usbd_device *dev);
@@ -355,10 +356,12 @@ static void cdc_on_suspend(usbd_device *dev);
static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg);
static usbd_respond cdc_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback);
static usbd_device* usb_dev;
static struct UsbInterface* cdc_if_cur = NULL;
static UsbInterface* cdc_if_cur = NULL;
static bool connected = false;
static CdcCallbacks* callbacks[IF_NUM_MAX] = {NULL};
static void* cb_ctx[IF_NUM_MAX];
struct UsbInterface usb_cdc_single = {
UsbInterface usb_cdc_single = {
.init = cdc_init,
.deinit = cdc_deinit,
.wakeup = cdc_on_wakeup,
@@ -373,7 +376,7 @@ struct UsbInterface usb_cdc_single = {
.cfg_descr = (void*)&cdc_cfg_desc_single,
};
struct UsbInterface usb_cdc_dual = {
UsbInterface usb_cdc_dual = {
.init = cdc_init,
.deinit = cdc_deinit,
.wakeup = cdc_on_wakeup,
@@ -388,7 +391,7 @@ struct UsbInterface usb_cdc_dual = {
.cfg_descr = (void*)&cdc_cfg_desc_dual,
};
static void cdc_init(usbd_device* dev, struct UsbInterface* intf) {
static void cdc_init(usbd_device* dev, UsbInterface* intf) {
usb_dev = dev;
cdc_if_cur = intf;
@@ -428,21 +431,35 @@ static void cdc_deinit(usbd_device *dev) {
cdc_if_cur = NULL;
}
void furi_hal_cdc_set_callbacks(uint8_t if_num, CdcCallbacks* cb) {
if (if_num < 2)
callbacks[if_num] = cb;
void furi_hal_cdc_set_callbacks(uint8_t if_num, CdcCallbacks* cb, void* context) {
furi_assert(if_num < IF_NUM_MAX);
if (callbacks[if_num] != NULL) {
if (callbacks[if_num]->state_callback != NULL) {
if (connected == true)
callbacks[if_num]->state_callback(cb_ctx[if_num], 0);
}
}
callbacks[if_num] = cb;
cb_ctx[if_num] = context;
if (callbacks[if_num] != NULL) {
if (callbacks[if_num]->state_callback != NULL) {
if (connected == true)
callbacks[if_num]->state_callback(cb_ctx[if_num], 1);
}
}
}
struct usb_cdc_line_coding* furi_hal_cdc_get_port_settings(uint8_t if_num) {
if (if_num < 2)
return &cdc_config[if_num];
return NULL;
furi_assert(if_num < IF_NUM_MAX);
return &cdc_config[if_num];
}
uint8_t furi_hal_cdc_get_ctrl_line_state(uint8_t if_num) {
if (if_num < 2)
return cdc_ctrl_line_state[if_num];
return 0;
furi_assert(if_num < IF_NUM_MAX);
return cdc_ctrl_line_state[if_num];
}
void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len) {
@@ -462,20 +479,22 @@ int32_t furi_hal_cdc_receive(uint8_t if_num, uint8_t* buf, uint16_t max_len) {
}
static void cdc_on_wakeup(usbd_device *dev) {
connected = true;
for (uint8_t i = 0; i < IF_NUM_MAX; i++) {
if (callbacks[i] != NULL) {
if (callbacks[i]->state_callback != NULL)
callbacks[i]->state_callback(1);
callbacks[i]->state_callback(cb_ctx[i], 1);
}
}
}
static void cdc_on_suspend(usbd_device *dev) {
connected = false;
for (uint8_t i = 0; i < IF_NUM_MAX; i++) {
cdc_ctrl_line_state[i] = 0;
if (callbacks[i] != NULL) {
if (callbacks[i]->state_callback != NULL)
callbacks[i]->state_callback(0);
callbacks[i]->state_callback(cb_ctx[i], 0);
}
}
}
@@ -489,7 +508,7 @@ static void cdc_rx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
if (callbacks[if_num] != NULL) {
if (callbacks[if_num]->rx_ep_callback != NULL)
callbacks[if_num]->rx_ep_callback();
callbacks[if_num]->rx_ep_callback(cb_ctx[if_num]);
}
}
@@ -502,7 +521,7 @@ static void cdc_tx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
if (callbacks[if_num] != NULL) {
if (callbacks[if_num]->tx_ep_callback != NULL)
callbacks[if_num]->tx_ep_callback();
callbacks[if_num]->tx_ep_callback(cb_ctx[if_num]);
}
}
@@ -590,14 +609,14 @@ static usbd_respond cdc_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_cal
if (callbacks[if_num] != NULL) {
cdc_ctrl_line_state[if_num] = req->wValue;
if (callbacks[if_num]->ctrl_line_callback != NULL)
callbacks[if_num]->ctrl_line_callback(cdc_ctrl_line_state[if_num]);
callbacks[if_num]->ctrl_line_callback(cb_ctx[if_num], cdc_ctrl_line_state[if_num]);
}
return usbd_ack;
case USB_CDC_SET_LINE_CODING:
memcpy(&cdc_config[if_num], req->data, sizeof(cdc_config[0]));
if (callbacks[if_num] != NULL) {
if (callbacks[if_num]->config_callback != NULL)
callbacks[if_num]->config_callback(&cdc_config[if_num]);
callbacks[if_num]->config_callback(cb_ctx[if_num], &cdc_config[if_num]);
}
return usbd_ack;
case USB_CDC_GET_LINE_CODING:

View File

@@ -6,14 +6,14 @@
#define CDC_DATA_SZ 64
typedef struct {
void (*tx_ep_callback)(void);
void (*rx_ep_callback)(void);
void (*state_callback)(uint8_t state);
void (*ctrl_line_callback)(uint8_t state);
void (*config_callback)(struct usb_cdc_line_coding* config);
void (*tx_ep_callback)(void* context);
void (*rx_ep_callback)(void* context);
void (*state_callback)(void* context, uint8_t state);
void (*ctrl_line_callback)(void* context, uint8_t state);
void (*config_callback)(void* context, struct usb_cdc_line_coding* config);
} CdcCallbacks;
void furi_hal_cdc_set_callbacks(uint8_t if_num, CdcCallbacks* cb);
void furi_hal_cdc_set_callbacks(uint8_t if_num, CdcCallbacks* cb, void* context);
struct usb_cdc_line_coding* furi_hal_cdc_get_port_settings(uint8_t if_num);

View File

@@ -1,5 +1,6 @@
#include "furi-hal-version.h"
#include "furi-hal-usb_i.h"
#include "furi-hal-usb.h"
#include <furi.h>
#include "usb.h"
@@ -182,7 +183,7 @@ static struct HidReport {
struct HidReportMouse mouse;
} __attribute__((packed)) hid_report;
static void hid_init(usbd_device* dev, struct UsbInterface* intf);
static void hid_init(usbd_device* dev, UsbInterface* intf);
static void hid_deinit(usbd_device *dev);
static void hid_on_wakeup(usbd_device *dev);
static void hid_on_suspend(usbd_device *dev);
@@ -254,7 +255,7 @@ bool furi_hal_hid_mouse_scroll(int8_t delta) {
return state;
}
struct UsbInterface usb_hid = {
UsbInterface usb_hid = {
.init = hid_init,
.deinit = hid_deinit,
.wakeup = hid_on_wakeup,
@@ -269,7 +270,7 @@ struct UsbInterface usb_hid = {
.cfg_descr = (void*)&hid_cfg_desc,
};
static void hid_init(usbd_device* dev, struct UsbInterface* intf) {
static void hid_init(usbd_device* dev, UsbInterface* intf) {
if (hid_semaphore == NULL)
hid_semaphore = osSemaphoreNew(1, 1, NULL);
usb_dev = dev;

View File

@@ -9,17 +9,8 @@
#define USB_RECONNECT_DELAY 500
extern struct UsbInterface usb_cdc_single;
extern struct UsbInterface usb_cdc_dual;
extern struct UsbInterface usb_hid;
static struct UsbInterface* const usb_if_modes[UsbModesNum] = {
NULL,
&usb_cdc_single,
&usb_cdc_dual,
&usb_hid,
NULL,//&usb_hid_u2f,
};
static UsbInterface* usb_if_cur;
static UsbInterface* usb_if_next;
static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US);
@@ -32,8 +23,6 @@ static void wkup_evt(usbd_device *dev, uint8_t event, uint8_t ep);
struct UsbCfg{
osTimerId_t reconnect_tmr;
UsbMode mode_cur;
UsbMode mode_next;
bool enabled;
bool connected;
} usb_config;
@@ -69,30 +58,30 @@ void furi_hal_usb_init(void) {
FURI_LOG_I(TAG, "Init OK");
}
void furi_hal_usb_set_config(UsbMode new_mode) {
if (new_mode != usb_config.mode_cur) {
void furi_hal_usb_set_config(UsbInterface* new_if) {
if (new_if != usb_if_cur) {
if (usb_config.enabled) {
usb_config.mode_next = new_mode;
usb_if_next = new_if;
if (usb_config.reconnect_tmr == NULL)
usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL);
furi_hal_usb_disable();
osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY);
}
else {
if (usb_if_modes[usb_config.mode_cur] != NULL)
usb_if_modes[usb_config.mode_cur]->deinit(&udev);
if (usb_if_modes[new_mode] != NULL) {
usb_if_modes[new_mode]->init(&udev, usb_if_modes[new_mode]);
FURI_LOG_I(TAG, "USB mode change %u -> %u", usb_config.mode_cur, new_mode);
if (usb_if_cur != NULL)
usb_if_cur->deinit(&udev);
if (new_if != NULL) {
new_if->init(&udev, new_if);
FURI_LOG_I(TAG, "USB mode change");
usb_config.enabled = true;
usb_config.mode_cur = new_mode;
usb_if_cur = new_if;
}
}
}
}
UsbMode furi_hal_usb_get_config() {
return usb_config.mode_cur;
UsbInterface* furi_hal_usb_get_config() {
return usb_if_cur;
}
void furi_hal_usb_disable() {
@@ -105,7 +94,7 @@ void furi_hal_usb_disable() {
}
void furi_hal_usb_enable() {
if ((!usb_config.enabled) && (usb_if_modes[usb_config.mode_cur] != NULL)) {
if ((!usb_config.enabled) && (usb_if_cur != NULL)) {
usbd_connect(&udev, true);
usb_config.enabled = true;
FURI_LOG_I(TAG, "USB Enable");
@@ -113,35 +102,35 @@ void furi_hal_usb_enable() {
}
static void furi_hal_usb_tmr_cb(void* context) {
furi_hal_usb_set_config(usb_config.mode_next);
furi_hal_usb_set_config(usb_if_next);
}
/* Get device / configuration descriptors */
static usbd_respond usb_descriptor_get (usbd_ctlreq *req, void **address, uint16_t *length) {
static usbd_respond usb_descriptor_get(usbd_ctlreq *req, void **address, uint16_t *length) {
const uint8_t dtype = req->wValue >> 8;
const uint8_t dnumber = req->wValue & 0xFF;
const void* desc;
uint16_t len = 0;
if (usb_if_modes[usb_config.mode_cur] == NULL)
if (usb_if_cur == NULL)
return usbd_fail;
switch (dtype) {
case USB_DTYPE_DEVICE:
desc = usb_if_modes[usb_config.mode_cur]->dev_descr;
desc = usb_if_cur->dev_descr;
break;
case USB_DTYPE_CONFIGURATION:
desc = usb_if_modes[usb_config.mode_cur]->cfg_descr;
len = ((struct usb_string_descriptor*)(usb_if_modes[usb_config.mode_cur]->cfg_descr))->wString[0];
desc = usb_if_cur->cfg_descr;
len = ((struct usb_string_descriptor*)(usb_if_cur->cfg_descr))->wString[0];
break;
case USB_DTYPE_STRING:
if (dnumber == UsbDevLang) {
desc = &dev_lang_desc;
} else if (dnumber == UsbDevManuf) {
desc = usb_if_modes[usb_config.mode_cur]->str_manuf_descr;
desc = usb_if_cur->str_manuf_descr;
} else if (dnumber == UsbDevProduct) {
desc = usb_if_modes[usb_config.mode_cur]->str_prod_descr;
desc = usb_if_cur->str_prod_descr;
} else if (dnumber == UsbDevSerial) {
desc = usb_if_modes[usb_config.mode_cur]->str_serial_descr;
desc = usb_if_cur->str_serial_descr;
} else
return usbd_fail;
break;
@@ -160,15 +149,15 @@ static usbd_respond usb_descriptor_get (usbd_ctlreq *req, void **address, uint16
}
static void susp_evt(usbd_device *dev, uint8_t event, uint8_t ep) {
if ((usb_if_modes[usb_config.mode_cur] != NULL) && (usb_config.connected == true)) {
if ((usb_if_cur != NULL) && (usb_config.connected == true)) {
usb_config.connected = false;
usb_if_modes[usb_config.mode_cur]->suspend(&udev);
usb_if_cur->suspend(&udev);
}
}
static void wkup_evt(usbd_device *dev, uint8_t event, uint8_t ep) {
if ((usb_if_modes[usb_config.mode_cur] != NULL) && (usb_config.connected == false)) {
if ((usb_if_cur != NULL) && (usb_config.connected == false)) {
usb_config.connected = true;
usb_if_modes[usb_config.mode_cur]->wakeup(&udev);
usb_if_cur->wakeup(&udev);
}
}

View File

@@ -11,18 +11,3 @@ enum UsbDevDescStr{
UsbDevProduct = 2,
UsbDevSerial = 3,
};
struct UsbInterface {
void (*init)(usbd_device *dev, struct UsbInterface* intf);
void (*deinit)(usbd_device *dev);
void (*wakeup)(usbd_device *dev);
void (*suspend)(usbd_device *dev);
struct usb_device_descriptor* dev_descr;
void* str_manuf_descr;
void* str_prod_descr;
void* str_serial_descr;
void* cfg_descr;
};

View File

@@ -13,17 +13,17 @@
typedef enum {
VcpEvtReserved = (1 << 0), // Reserved for StreamBuffer internal event
VcpEvtConnect = (1 << 1),
VcpEvtDisconnect = (1 << 2),
VcpEvtEnable = (1 << 3),
VcpEvtDisable = (1 << 4),
VcpEvtRx = (1 << 5),
VcpEvtTx = (1 << 6),
VcpEvtStreamRx = (1 << 7),
VcpEvtStreamTx = (1 << 8),
VcpEvtEnable = (1 << 1),
VcpEvtDisable = (1 << 2),
VcpEvtConnect = (1 << 3),
VcpEvtDisconnect = (1 << 4),
VcpEvtStreamRx = (1 << 5),
VcpEvtRx = (1 << 6),
VcpEvtStreamTx = (1 << 7),
VcpEvtTx = (1 << 8),
} WorkerEvtFlags;
#define VCP_THREAD_FLAG_ALL (VcpEvtConnect | VcpEvtDisconnect | VcpEvtEnable | VcpEvtDisable | VcpEvtRx | VcpEvtTx | VcpEvtStreamRx | VcpEvtStreamTx)
#define VCP_THREAD_FLAG_ALL (VcpEvtEnable | VcpEvtDisable | VcpEvtConnect | VcpEvtDisconnect | VcpEvtRx | VcpEvtTx | VcpEvtStreamRx | VcpEvtStreamTx)
typedef struct {
FuriThread* thread;
@@ -37,10 +37,10 @@ typedef struct {
} FuriHalVcp;
static int32_t vcp_worker(void* context);
static void vcp_on_cdc_tx_complete();
static void vcp_on_cdc_rx();
static void vcp_state_callback(uint8_t state);
static void vcp_on_cdc_control_line(uint8_t state);
static void vcp_on_cdc_tx_complete(void* context);
static void vcp_on_cdc_rx(void* context);
static void vcp_state_callback(void* context, uint8_t state);
static void vcp_on_cdc_control_line(void* context, uint8_t state);
static CdcCallbacks cdc_cb = {
vcp_on_cdc_tx_complete,
@@ -76,93 +76,19 @@ static int32_t vcp_worker(void* context) {
bool tx_idle = false;
size_t missed_rx = 0;
furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb);
furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL);
while (1) {
uint32_t flags = osThreadFlagsWait(VCP_THREAD_FLAG_ALL, osFlagsWaitAny, osWaitForever);
furi_assert((flags & osFlagsError) == 0);
// New data received
if((flags & VcpEvtStreamRx) && enabled && missed_rx > 0) {
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_puts("VCP StreamRx\r\n");
#endif
if (xStreamBufferSpacesAvailable(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
flags |= VcpEvtRx;
missed_rx--;
}
}
// Rx buffer was read, maybe there is enough space for new data?
if((flags & VcpEvtRx)) {
if (xStreamBufferSpacesAvailable(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
int32_t len = furi_hal_cdc_receive(VCP_IF_NUM, vcp->data_buffer, USB_CDC_PKT_LEN);
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_printf("VCP Rx %d\r\n", len);
#endif
if (len > 0) {
furi_check(xStreamBufferSend(vcp->rx_stream, vcp->data_buffer, len, osWaitForever) == len);
}
} else {
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_puts("VCP Rx missed\r\n");
#endif
missed_rx++;
}
}
// New data in Tx buffer
if((flags & VcpEvtStreamTx) && enabled) {
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_puts("VCP StreamTx\r\n");
#endif
if (tx_idle) {
flags |= VcpEvtTx;
}
}
// CDC write transfer done
if((flags & VcpEvtTx) && enabled) {
size_t len = xStreamBufferReceive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_printf("VCP Tx %d\r\n", len);
#endif
if (len > 0) { // Some data left in Tx buffer. Sending it now
tx_idle = false;
furi_hal_cdc_send(VCP_IF_NUM, vcp->data_buffer, len);
} else { // There is nothing to send. Set flag to start next transfer instantly
tx_idle = true;
}
}
// VCP session opened
if((flags & VcpEvtConnect) && enabled) {
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_puts("VCP Connect\r\n");
#endif
if (vcp->connected == false) {
vcp->connected = true;
xStreamBufferSend(vcp->rx_stream, &ascii_soh, 1, osWaitForever);
}
}
// VCP session closed
if((flags & VcpEvtDisconnect) && enabled) {
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_puts("VCP Disconnect\r\n");
#endif
if (vcp->connected == true) {
vcp->connected = false;
xStreamBufferSend(vcp->rx_stream, &ascii_eot, 1, osWaitForever);
}
}
// VCP enabled
if((flags & VcpEvtEnable) && !enabled){
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_puts("VCP Enable\r\n");
#endif
furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb);
FURI_LOG_D(TAG, "Enable");
#endif
flags |= VcpEvtTx;
furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL);
enabled = true;
furi_hal_cdc_receive(VCP_IF_NUM, vcp->data_buffer, USB_CDC_PKT_LEN); // flush Rx buffer
if (furi_hal_cdc_get_ctrl_line_state(VCP_IF_NUM) & (1 << 0)) {
@@ -173,13 +99,90 @@ static int32_t vcp_worker(void* context) {
// VCP disabled
if((flags & VcpEvtDisable) && enabled) {
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_puts("VCP Disable\r\n");
#endif
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "Disable");
#endif
enabled = false;
vcp->connected = false;
xStreamBufferReceive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
xStreamBufferSend(vcp->rx_stream, &ascii_eot, 1, osWaitForever);
}
// VCP session opened
if((flags & VcpEvtConnect) && enabled) {
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "Connect");
#endif
if (vcp->connected == false) {
vcp->connected = true;
xStreamBufferSend(vcp->rx_stream, &ascii_soh, 1, osWaitForever);
}
}
// VCP session closed
if((flags & VcpEvtDisconnect) && enabled) {
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "Disconnect");
#endif
if (vcp->connected == true) {
vcp->connected = false;
xStreamBufferReceive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
xStreamBufferSend(vcp->rx_stream, &ascii_eot, 1, osWaitForever);
}
}
// Rx buffer was read, maybe there is enough space for new data?
if((flags & VcpEvtStreamRx) && enabled && missed_rx > 0) {
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "StreamRx");
#endif
if (xStreamBufferSpacesAvailable(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
flags |= VcpEvtRx;
missed_rx--;
}
}
// New data received
if((flags & VcpEvtRx)) {
if (xStreamBufferSpacesAvailable(vcp->rx_stream) >= USB_CDC_PKT_LEN) {
int32_t len = furi_hal_cdc_receive(VCP_IF_NUM, vcp->data_buffer, USB_CDC_PKT_LEN);
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "Rx %d", len);
#endif
if (len > 0) {
furi_check(xStreamBufferSend(vcp->rx_stream, vcp->data_buffer, len, osWaitForever) == len);
}
} else {
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "Rx missed");
#endif
missed_rx++;
}
}
// New data in Tx buffer
if((flags & VcpEvtStreamTx) && enabled) {
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "StreamTx");
#endif
if (tx_idle) {
flags |= VcpEvtTx;
}
}
// CDC write transfer done
if((flags & VcpEvtTx) && enabled) {
size_t len = xStreamBufferReceive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0);
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "Tx %d", len);
#endif
if (len > 0) { // Some data left in Tx buffer. Sending it now
tx_idle = false;
furi_hal_cdc_send(VCP_IF_NUM, vcp->data_buffer, len);
} else { // There is nothing to send. Set flag to start next transfer instantly
tx_idle = true;
}
}
}
return 0;
}
@@ -196,6 +199,10 @@ size_t furi_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeo
furi_assert(vcp);
furi_assert(buffer);
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "rx %u start", size);
#endif
size_t rx_cnt = 0;
while (size > 0) {
@@ -204,6 +211,9 @@ size_t furi_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeo
batch_size = VCP_RX_BUF_SIZE;
size_t len = xStreamBufferReceive(vcp->rx_stream, buffer, batch_size, timeout);
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "%u ", batch_size);
#endif
if (len == 0)
break;
osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStreamRx);
@@ -211,6 +221,10 @@ size_t furi_hal_vcp_rx_with_timeout(uint8_t* buffer, size_t size, uint32_t timeo
buffer += len;
rx_cnt += len;
}
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "rx %u end", size);
#endif
return rx_cnt;
}
@@ -223,34 +237,40 @@ void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) {
furi_assert(vcp);
furi_assert(buffer);
while (size > 0) {
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "tx %u start", size);
#endif
while (size > 0 && vcp->connected) {
size_t batch_size = size;
if (batch_size > VCP_TX_BUF_SIZE)
batch_size = VCP_TX_BUF_SIZE;
if (batch_size > USB_CDC_PKT_LEN)
batch_size = USB_CDC_PKT_LEN;
xStreamBufferSend(vcp->tx_stream, buffer, batch_size, osWaitForever);
osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtStreamTx);
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "%u ", batch_size);
#endif
size -= batch_size;
buffer += batch_size;
}
#ifdef FURI_HAL_USB_VCP_DEBUG
FURI_LOG_D(TAG, "tx %u end", size);
#endif
}
static void vcp_state_callback(uint8_t state) {
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_puts("VCP State\r\n");
#endif
static void vcp_state_callback(void* context, uint8_t state) {
if (state == 0) {
osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtDisconnect);
}
}
static void vcp_on_cdc_control_line(uint8_t state) {
static void vcp_on_cdc_control_line(void* context, uint8_t state) {
// bit 0: DTR state, bit 1: RTS state
bool dtr = state & (1 << 0);
#ifdef FURI_HAL_USB_VCP_DEBUG
furi_hal_console_puts("VCP CtrlLine\r\n");
#endif
if (dtr == true) {
osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtConnect);
} else {
@@ -258,12 +278,12 @@ static void vcp_on_cdc_control_line(uint8_t state) {
}
}
static void vcp_on_cdc_rx() {
static void vcp_on_cdc_rx(void* context) {
uint32_t ret = osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtRx);
furi_assert((ret & osFlagsError) == 0);
}
static void vcp_on_cdc_tx_complete() {
static void vcp_on_cdc_tx_complete(void* context) {
osThreadFlagsSet(furi_thread_get_thread_id(vcp->thread), VcpEvtTx);
}
@@ -271,4 +291,3 @@ bool furi_hal_vcp_is_connected(void) {
furi_assert(vcp);
return vcp->connected;
}

View File

@@ -40,7 +40,7 @@ void furi_hal_init() {
// VCP + USB
furi_hal_usb_init();
furi_hal_usb_set_config(UsbModeVcpSingle);
furi_hal_usb_set_config(&usb_cdc_single);
furi_hal_vcp_init();
FURI_LOG_I(TAG, "USB OK");