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:
@@ -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:
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
};
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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");
|
||||
|
||||
|
Reference in New Issue
Block a user