Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/flipperzero-firmware.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile23
-rw-r--r--applications/debug_tools/bad_usb.c2
-rw-r--r--[-rwxr-xr-x]applications/gpio/gpio_app.c6
-rw-r--r--applications/gpio/gpio_app_i.h3
-rw-r--r--applications/gpio/scenes/gpio_scene_config.h1
-rw-r--r--[-rwxr-xr-x]applications/gpio/scenes/gpio_scene_start.c8
-rw-r--r--applications/gpio/scenes/gpio_scene_usb_uart.c352
-rwxr-xr-xapplications/gui/modules/variable-item-list.c2
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-console.c66
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-console.h18
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-lpuart.c105
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-lpuart.h24
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c92
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-usb-cdc_i.h17
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-usb.c10
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-vcp.c78
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal-vcp_i.h13
-rw-r--r--firmware/targets/f6/furi-hal/furi-hal.c2
-rw-r--r--firmware/targets/f6/target.mk1
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-console.c66
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-console.h18
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-lpuart.c105
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-lpuart.h24
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c92
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h17
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-usb.c10
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-vcp.c78
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal-vcp_i.h13
-rw-r--r--firmware/targets/f7/furi-hal/furi-hal.c2
-rw-r--r--firmware/targets/f7/target.mk1
-rw-r--r--firmware/targets/furi-hal-include/furi-hal-vcp.h8
-rw-r--r--firmware/targets/furi-hal-include/furi-hal.h1
32 files changed, 1097 insertions, 161 deletions
diff --git a/Makefile b/Makefile
index bc9c5be7..0091c292 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,15 @@
PROJECT_ROOT := $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST)))))
COPRO_DIR := $(PROJECT_ROOT)/lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
+NPROCS := 1
+OS := $(shell uname -s)
+
+ifeq ($(OS), Linux)
+NPROCS := $(shell grep -c ^processor /proc/cpuinfo)
+else ifeq ($(OS), Darwin)
+NPROCS := $(shell sysctl -n hw.ncpu)
+endif
+
.PHONY: all
all: bootloader_all firmware_all
@@ -15,7 +24,7 @@ flash: bootloader_flash firmware_flash
.PHONY: debug
debug:
- $(MAKE) -C firmware -j9 debug
+ $(MAKE) -C firmware -j$(NPROCS) debug
.PHONY: wipe
wipe:
@@ -24,29 +33,29 @@ wipe:
.PHONY: bootloader_all
bootloader_all:
- $(MAKE) -C $(PROJECT_ROOT)/bootloader -j9 all
+ $(MAKE) -C $(PROJECT_ROOT)/bootloader -j$(NPROCS) all
.PHONY: firmware_all
firmware_all:
- $(MAKE) -C $(PROJECT_ROOT)/firmware -j9 all
+ $(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) all
.PHONY: bootloader_clean
bootloader_clean:
- $(MAKE) -C $(PROJECT_ROOT)/bootloader -j9 clean
+ $(MAKE) -C $(PROJECT_ROOT)/bootloader -j$(NPROCS) clean
.PHONY: firmware_clean
firmware_clean:
- $(MAKE) -C $(PROJECT_ROOT)/firmware -j9 clean
+ $(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) clean
.PHONY: bootloader_flash
bootloader_flash:
rm $(PROJECT_ROOT)/bootloader/.obj/f*/flash || true
- $(MAKE) -C $(PROJECT_ROOT)/bootloader -j9 flash
+ $(MAKE) -C $(PROJECT_ROOT)/bootloader -j$(NPROCS) flash
.PHONY: firmware_flash
firmware_flash:
rm $(PROJECT_ROOT)/firmware/.obj/f*/flash || true
- $(MAKE) -C $(PROJECT_ROOT)/firmware -j9 flash
+ $(MAKE) -C $(PROJECT_ROOT)/firmware -j$(NPROCS) flash
.PHONY: flash_radio
flash_radio:
diff --git a/applications/debug_tools/bad_usb.c b/applications/debug_tools/bad_usb.c
index 1bd35d59..ad20e26e 100644
--- a/applications/debug_tools/bad_usb.c
+++ b/applications/debug_tools/bad_usb.c
@@ -248,6 +248,8 @@ static void badusb_worker(void* context) {
evt.worker.state = WorkerStateDone;
osMessageQueuePut(app->event_queue, &evt, 0, osWaitForever);
+ furi_hal_hid_kb_release_all();
+
osThreadExit();
}
diff --git a/applications/gpio/gpio_app.c b/applications/gpio/gpio_app.c
index 32d92af0..8cd27bc1 100755..100644
--- a/applications/gpio/gpio_app.c
+++ b/applications/gpio/gpio_app.c
@@ -42,6 +42,9 @@ GpioApp* gpio_app_alloc() {
view_dispatcher_add_view(
app->view_dispatcher, GpioAppViewGpioTest, gpio_test_get_view(app->gpio_test));
+ view_dispatcher_add_view(
+ app->view_dispatcher, GpioAppViewUsbUart, variable_item_list_get_view(app->var_item_list));
+
scene_manager_next_scene(app->scene_manager, GpioSceneStart);
return app;
@@ -54,10 +57,13 @@ void gpio_app_free(GpioApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewVarItemList);
variable_item_list_free(app->var_item_list);
view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewGpioTest);
+ view_dispatcher_remove_view(app->view_dispatcher, GpioAppViewUsbUart);
gpio_test_free(app->gpio_test);
+
// View dispatcher
view_dispatcher_free(app->view_dispatcher);
scene_manager_free(app->scene_manager);
+
// Close records
furi_record_close("gui");
furi_record_close("notification");
diff --git a/applications/gpio/gpio_app_i.h b/applications/gpio/gpio_app_i.h
index 590bedc3..bfeab404 100644
--- a/applications/gpio/gpio_app_i.h
+++ b/applications/gpio/gpio_app_i.h
@@ -7,8 +7,8 @@
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
+#include <gui/modules/submenu.h>
#include <notification/notification-messages.h>
-
#include <gui/modules/variable-item-list.h>
#include "views/gpio_test.h"
@@ -25,4 +25,5 @@ struct GpioApp {
typedef enum {
GpioAppViewVarItemList,
GpioAppViewGpioTest,
+ GpioAppViewUsbUart,
} GpioAppView;
diff --git a/applications/gpio/scenes/gpio_scene_config.h b/applications/gpio/scenes/gpio_scene_config.h
index 5f7f78ba..263df2d1 100644
--- a/applications/gpio/scenes/gpio_scene_config.h
+++ b/applications/gpio/scenes/gpio_scene_config.h
@@ -1,2 +1,3 @@
ADD_SCENE(gpio, start, Start)
ADD_SCENE(gpio, test, Test)
+ADD_SCENE(gpio, usb_uart, UsbUart)
diff --git a/applications/gpio/scenes/gpio_scene_start.c b/applications/gpio/scenes/gpio_scene_start.c
index 946d8e1b..b3ed40fd 100755..100644
--- a/applications/gpio/scenes/gpio_scene_start.c
+++ b/applications/gpio/scenes/gpio_scene_start.c
@@ -4,10 +4,12 @@
#define GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF (0UL)
#define GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON (1UL)
#define GPIO_SCENE_START_CUSTOM_EVENT_TEST (2UL)
+#define GPIO_SCENE_START_CUSTOM_EVENT_USB_UART (3UL)
enum GpioItem {
GpioItemOtg,
GpioItemTest,
+ GpioItemUsbUart,
};
enum GpioOtg {
@@ -27,6 +29,9 @@ static void gpio_scene_start_var_list_enter_callback(void* context, uint32_t ind
if(index == GpioItemTest) {
view_dispatcher_send_custom_event(
app->view_dispatcher, GPIO_SCENE_START_CUSTOM_EVENT_TEST);
+ } else if(index == GpioItemUsbUart) {
+ view_dispatcher_send_custom_event(
+ app->view_dispatcher, GPIO_SCENE_START_CUSTOM_EVENT_USB_UART);
}
}
@@ -65,6 +70,7 @@ void gpio_scene_start_on_enter(void* context) {
variable_item_set_current_value_text(item, gpio_otg_text[GpioOtgOff]);
}
variable_item_list_add(var_item_list, "GPIO tester", 0, NULL, NULL);
+ variable_item_list_add(var_item_list, "USB-UART bridge", 0, NULL, NULL);
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewVarItemList);
}
@@ -80,6 +86,8 @@ bool gpio_scene_start_on_event(void* context, SceneManagerEvent event) {
furi_hal_power_disable_otg();
} else if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_TEST) {
scene_manager_next_scene(app->scene_manager, GpioSceneTest);
+ } else if(event.event == GPIO_SCENE_START_CUSTOM_EVENT_USB_UART) {
+ scene_manager_next_scene(app->scene_manager, GpioSceneUsbUart);
}
consumed = true;
}
diff --git a/applications/gpio/scenes/gpio_scene_usb_uart.c b/applications/gpio/scenes/gpio_scene_usb_uart.c
new file mode 100644
index 00000000..05de8e7b
--- /dev/null
+++ b/applications/gpio/scenes/gpio_scene_usb_uart.c
@@ -0,0 +1,352 @@
+#include "../gpio_app_i.h"
+#include "furi-hal.h"
+#include <stream_buffer.h>
+#include <furi-hal-usb-cdc_i.h>
+#include "usb_cdc.h"
+
+#define USB_PKT_LEN CDC_DATA_SZ
+#define USB_UART_RX_BUF_SIZE (USB_PKT_LEN * 3)
+#define USB_UART_TX_BUF_SIZE (USB_PKT_LEN * 3)
+
+typedef enum {
+ WorkerCmdStop = (1 << 0),
+
+} WorkerCommandFlags;
+
+typedef enum {
+ UsbUartLineIndexVcp,
+ UsbUartLineIndexUart,
+ UsbUartLineIndexBaudrate,
+ UsbUartLineIndexEnable,
+ UsbUartLineIndexDisable,
+} LineIndex;
+
+typedef enum {
+ UsbUartPortUSART1 = 0,
+ UsbUartPortLPUART1 = 1,
+} PortIdx;
+
+typedef struct {
+ uint8_t vcp_ch;
+ PortIdx uart_ch;
+ uint32_t baudrate;
+} UsbUartConfig;
+
+typedef struct {
+ UsbUartConfig cfg_cur;
+ UsbUartConfig cfg_set;
+ char br_text[8];
+
+ bool running;
+ osThreadId_t parent_thread;
+
+ osThreadAttr_t thread_attr;
+ osThreadId_t thread;
+
+ osThreadAttr_t tx_thread_attr;
+ osThreadId_t tx_thread;
+
+ StreamBufferHandle_t rx_stream;
+ osSemaphoreId_t rx_done_sem;
+ osSemaphoreId_t usb_sof_sem;
+
+ StreamBufferHandle_t tx_stream;
+
+ uint8_t rx_buf[USB_PKT_LEN];
+ uint8_t tx_buf[USB_PKT_LEN];
+} UsbUartParams;
+
+static UsbUartParams* usb_uart;
+
+static const char* vcp_ch[] = {"0 (CLI)", "1"};
+static const char* uart_ch[] = {"USART1", "LPUART1"};
+static const char* baudrate_mode[] = {"Host"};
+static const uint32_t baudrate_list[] = {
+ 2400,
+ 9600,
+ 19200,
+ 38400,
+ 57600,
+ 115200,
+ 230400,
+ 460800,
+ 921600,
+};
+
+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_line_config(struct usb_cdc_line_coding* config);
+
+static CdcCallbacks cdc_cb = {
+ vcp_on_cdc_tx_complete,
+ vcp_on_cdc_rx,
+ vcp_state_callback,
+ vcp_on_cdc_control_line,
+ vcp_on_line_config,
+};
+
+/* USB UART worker */
+
+static void usb_uart_tx_thread(void* context);
+
+static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data) {
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+
+ if(ev == UartIrqEventRXNE) {
+ size_t ret =
+ xStreamBufferSendFromISR(usb_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken);
+ furi_check(ret == 1);
+ ret = xStreamBufferBytesAvailable(usb_uart->rx_stream);
+ if(ret > USB_PKT_LEN) osSemaphoreRelease(usb_uart->rx_done_sem);
+ } else if(ev == UartIrqEventIDLE) {
+ osSemaphoreRelease(usb_uart->rx_done_sem);
+ }
+
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+}
+
+static void usb_uart_worker(void* context) {
+ memcpy(&usb_uart->cfg_cur, &usb_uart->cfg_set, sizeof(UsbUartConfig));
+
+ usb_uart->rx_stream = xStreamBufferCreate(USB_UART_RX_BUF_SIZE, 1);
+ usb_uart->rx_done_sem = osSemaphoreNew(1, 1, NULL);
+ usb_uart->usb_sof_sem = osSemaphoreNew(1, 1, NULL);
+
+ usb_uart->tx_stream = xStreamBufferCreate(USB_UART_TX_BUF_SIZE, 1);
+
+ usb_uart->tx_thread = NULL;
+ usb_uart->tx_thread_attr.name = "usb_uart_tx";
+ usb_uart->tx_thread_attr.stack_size = 512;
+
+ UsbMode usb_mode_prev = furi_hal_usb_get_config();
+ if(usb_uart->cfg_cur.vcp_ch == 0) {
+ furi_hal_usb_set_config(UsbModeVcpSingle);
+ furi_hal_vcp_disable();
+ } else {
+ furi_hal_usb_set_config(UsbModeVcpDual);
+ }
+
+ if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1) {
+ furi_hal_usart_init();
+ furi_hal_usart_set_irq_cb(usb_uart_on_irq_cb);
+ if(usb_uart->cfg_cur.baudrate != 0)
+ furi_hal_usart_set_br(usb_uart->cfg_cur.baudrate);
+ else
+ vcp_on_line_config(furi_hal_cdc_get_port_settings(usb_uart->cfg_cur.vcp_ch));
+ } else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1) {
+ furi_hal_lpuart_init();
+ furi_hal_lpuart_set_irq_cb(usb_uart_on_irq_cb);
+ if(usb_uart->cfg_cur.baudrate != 0)
+ furi_hal_lpuart_set_br(usb_uart->cfg_cur.baudrate);
+ else
+ vcp_on_line_config(furi_hal_cdc_get_port_settings(usb_uart->cfg_cur.vcp_ch));
+ }
+
+ furi_hal_cdc_set_callbacks(usb_uart->cfg_cur.vcp_ch, &cdc_cb);
+ usb_uart->tx_thread = osThreadNew(usb_uart_tx_thread, NULL, &usb_uart->tx_thread_attr);
+
+ while(1) {
+ furi_check(osSemaphoreAcquire(usb_uart->rx_done_sem, osWaitForever) == osOK);
+ if(osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny, 0) == WorkerCmdStop) break;
+ size_t len = 0;
+ do {
+ len = xStreamBufferReceive(usb_uart->rx_stream, usb_uart->rx_buf, USB_PKT_LEN, 0);
+ if(len > 0) {
+ if(osSemaphoreAcquire(usb_uart->usb_sof_sem, 100) == osOK)
+ furi_hal_cdc_send(usb_uart->cfg_cur.vcp_ch, usb_uart->rx_buf, len);
+ else
+ xStreamBufferReset(usb_uart->rx_stream);
+ }
+ } while(len > 0);
+ }
+
+ osThreadTerminate(usb_uart->tx_thread);
+
+ if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1)
+ furi_hal_usart_deinit();
+ else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1)
+ furi_hal_lpuart_deinit();
+
+ furi_hal_cdc_set_callbacks(usb_uart->cfg_cur.vcp_ch, NULL);
+ furi_hal_usb_set_config(usb_mode_prev);
+ if(usb_uart->cfg_cur.vcp_ch == 0) furi_hal_vcp_enable();
+
+ vStreamBufferDelete(usb_uart->rx_stream);
+ osSemaphoreDelete(usb_uart->rx_done_sem);
+ osSemaphoreDelete(usb_uart->usb_sof_sem);
+
+ vStreamBufferDelete(usb_uart->tx_stream);
+ osThreadFlagsSet(usb_uart->parent_thread, WorkerCmdStop);
+ osThreadExit();
+}
+
+static void usb_uart_tx_thread(void* context) {
+ uint8_t data = 0;
+ while(1) {
+ size_t len = xStreamBufferReceive(usb_uart->tx_stream, &data, 1, osWaitForever);
+ if(len > 0) {
+ if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1)
+ furi_hal_usart_tx(&data, len);
+ else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1)
+ furi_hal_lpuart_tx(&data, len);
+ }
+ }
+ osThreadExit();
+}
+
+/* VCP callbacks */
+
+static void vcp_on_cdc_tx_complete() {
+ osSemaphoreRelease(usb_uart->usb_sof_sem);
+}
+
+static void vcp_on_cdc_rx() {
+ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
+
+ uint16_t max_len = xStreamBufferSpacesAvailable(usb_uart->tx_stream);
+ if(max_len > 0) {
+ if(max_len > USB_PKT_LEN) max_len = USB_PKT_LEN;
+ int32_t size = furi_hal_cdc_receive(usb_uart->cfg_cur.vcp_ch, usb_uart->tx_buf, max_len);
+
+ if(size > 0) {
+ size_t ret = xStreamBufferSendFromISR(
+ usb_uart->tx_stream, usb_uart->tx_buf, size, &xHigherPriorityTaskWoken);
+ furi_check(ret == size);
+ }
+ }
+ portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
+}
+
+static void vcp_state_callback(uint8_t state) {
+}
+
+static void vcp_on_cdc_control_line(uint8_t state) {
+}
+
+static void vcp_on_line_config(struct usb_cdc_line_coding* config) {
+ if((usb_uart->cfg_cur.baudrate == 0) && (config->dwDTERate != 0)) {
+ if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1)
+ furi_hal_usart_set_br(config->dwDTERate);
+ else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1)
+ furi_hal_lpuart_set_br(config->dwDTERate);
+ }
+}
+
+/* USB UART app */
+
+static void usb_uart_enable() {
+ if(usb_uart->running == false) {
+ usb_uart->thread = NULL;
+ usb_uart->thread_attr.name = "usb_uart";
+ usb_uart->thread_attr.stack_size = 1024;
+ usb_uart->parent_thread = osThreadGetId();
+ usb_uart->running = true;
+ usb_uart->thread = osThreadNew(usb_uart_worker, NULL, &usb_uart->thread_attr);
+ }
+}
+
+static void usb_uart_disable() {
+ if(usb_uart->running == true) {
+ osThreadFlagsSet(usb_uart->thread, WorkerCmdStop);
+ osSemaphoreRelease(usb_uart->rx_done_sem);
+ osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny, osWaitForever);
+ usb_uart->running = false;
+ }
+}
+
+bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) {
+ //GpioApp* app = context;
+ bool consumed = false;
+
+ if(event.type == SceneManagerEventTypeCustom) {
+ if(event.event == UsbUartLineIndexEnable) {
+ usb_uart_enable();
+ } else if(event.event == UsbUartLineIndexDisable) {
+ usb_uart_disable();
+ }
+ consumed = true;
+ }
+ return consumed;
+}
+
+/* Scene callbacks */
+
+static void line_vcp_cb(VariableItem* item) {
+ //GpioApp* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+
+ variable_item_set_current_value_text(item, vcp_ch[index]);
+
+ usb_uart->cfg_set.vcp_ch = index;
+}
+
+static void line_port_cb(VariableItem* item) {
+ //GpioApp* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+
+ variable_item_set_current_value_text(item, uart_ch[index]);
+
+ usb_uart->cfg_set.uart_ch = index;
+}
+
+static void line_baudrate_cb(VariableItem* item) {
+ //GpioApp* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+
+ if(index > 0) {
+ snprintf(usb_uart->br_text, 7, "%lu", baudrate_list[index - 1]);
+ variable_item_set_current_value_text(item, usb_uart->br_text);
+ usb_uart->cfg_set.baudrate = baudrate_list[index - 1];
+ } else {
+ variable_item_set_current_value_text(item, baudrate_mode[index]);
+ usb_uart->cfg_set.baudrate = 0;
+ }
+}
+
+static void gpio_scene_usb_uart_enter_callback(void* context, uint32_t index) {
+ furi_assert(context);
+ GpioApp* app = context;
+ view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void gpio_scene_usb_uart_on_enter(void* context) {
+ GpioApp* app = context;
+ VariableItemList* var_item_list = app->var_item_list;
+
+ usb_uart = furi_alloc(sizeof(UsbUartParams));
+
+ VariableItem* item;
+
+ variable_item_list_set_enter_callback(var_item_list, gpio_scene_usb_uart_enter_callback, app);
+
+ item = variable_item_list_add(var_item_list, "VCP Channel", 2, line_vcp_cb, app);
+ variable_item_set_current_value_index(item, 0);
+ variable_item_set_current_value_text(item, vcp_ch[0]);
+
+ item = variable_item_list_add(var_item_list, "UART Port", 2, line_port_cb, app);
+ variable_item_set_current_value_index(item, 0);
+ variable_item_set_current_value_text(item, uart_ch[0]);
+
+ item = variable_item_list_add(
+ var_item_list,
+ "Baudrate",
+ sizeof(baudrate_list) / sizeof(baudrate_list[0]) + 1,
+ line_baudrate_cb,
+ app);
+ variable_item_set_current_value_index(item, 0);
+ variable_item_set_current_value_text(item, baudrate_mode[0]);
+
+ item = variable_item_list_add(var_item_list, "Enable", 0, NULL, NULL);
+ item = variable_item_list_add(var_item_list, "Disable", 0, NULL, NULL);
+
+ view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUart);
+}
+
+void gpio_scene_usb_uart_on_exit(void* context) {
+ GpioApp* app = context;
+ usb_uart_disable();
+ variable_item_list_clean(app->var_item_list);
+ free(usb_uart);
+} \ No newline at end of file
diff --git a/applications/gui/modules/variable-item-list.c b/applications/gui/modules/variable-item-list.c
index fccfd84a..800e0602 100755
--- a/applications/gui/modules/variable-item-list.c
+++ b/applications/gui/modules/variable-item-list.c
@@ -259,7 +259,7 @@ void variable_item_list_clean(VariableItemList* variable_item_list) {
VariableItemArray_it_t it;
for(VariableItemArray_it(it, model->items); !VariableItemArray_end_p(it);
VariableItemArray_next(it)) {
- string_clean(VariableItemArray_ref(it)->current_value_text);
+ string_clear(VariableItemArray_ref(it)->current_value_text);
}
VariableItemArray_clean(model->items);
return false;
diff --git a/firmware/targets/f6/furi-hal/furi-hal-console.c b/firmware/targets/f6/furi-hal/furi-hal-console.c
index b04a17a1..552f9e77 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-console.c
+++ b/firmware/targets/f6/furi-hal/furi-hal-console.c
@@ -1,4 +1,5 @@
#include <furi-hal-console.h>
+#include <furi-hal-lpuart.h>
#include <stdbool.h>
#include <stm32wbxx_ll_gpio.h>
@@ -7,8 +8,12 @@
#include <furi.h>
+#define CONSOLE_BAUDRATE 230400
+
volatile bool furi_hal_console_alive = false;
+static void (*irq_cb)(uint8_t ev, uint8_t data);
+
void furi_hal_console_init() {
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7;
@@ -21,11 +26,11 @@ void furi_hal_console_init() {
LL_USART_InitTypeDef USART_InitStruct = {0};
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
- USART_InitStruct.BaudRate = 230400;
+ USART_InitStruct.BaudRate = CONSOLE_BAUDRATE;
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
- USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX;
+ USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
LL_USART_Init(USART1, &USART_InitStruct);
@@ -36,12 +41,41 @@ void furi_hal_console_init() {
LL_USART_Enable(USART1);
while(!LL_USART_IsActiveFlag_TEACK(USART1)) ;
+
+ LL_USART_EnableIT_RXNE_RXFNE(USART1);
+ LL_USART_EnableIT_IDLE(USART1);
+ HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
+
furi_hal_console_alive = true;
FURI_LOG_I("FuriHalConsole", "Init OK");
}
-static void furi_hal_console_uart_tx(const uint8_t* buffer, size_t buffer_size) {
+void furi_hal_usart_init() {
+ furi_hal_console_alive = false;
+}
+
+void furi_hal_usart_set_br(uint32_t baud) {
+ if (LL_USART_IsEnabled(USART1)) {
+ // Wait for transfer complete flag
+ while (!LL_USART_IsActiveFlag_TC(USART1));
+ LL_USART_Disable(USART1);
+ uint32_t uartclk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE);
+ LL_USART_SetBaudRate(USART1, uartclk, LL_USART_PRESCALER_DIV1, LL_USART_OVERSAMPLING_16, baud);
+ LL_USART_Enable(USART1);
+ }
+}
+
+void furi_hal_usart_deinit() {
+ while (!LL_USART_IsActiveFlag_TC(USART1));
+ furi_hal_usart_set_br(CONSOLE_BAUDRATE);
+ furi_hal_console_alive = true;
+}
+
+void furi_hal_usart_tx(const uint8_t* buffer, size_t buffer_size) {
+ if (LL_USART_IsEnabled(USART1) == 0)
+ return;
+
while(buffer_size > 0) {
while (!LL_USART_IsActiveFlag_TXE(USART1));
@@ -52,12 +86,32 @@ static void furi_hal_console_uart_tx(const uint8_t* buffer, size_t buffer_size)
}
}
+void furi_hal_usart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)) {
+ irq_cb = cb;
+ if (irq_cb == NULL)
+ NVIC_DisableIRQ(USART1_IRQn);
+ else
+ NVIC_EnableIRQ(USART1_IRQn);
+}
+
+void USART1_IRQHandler(void) {
+ if (LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) {
+ uint8_t data = LL_USART_ReceiveData8(USART1);
+ irq_cb(UartIrqEventRXNE, data);
+ } else if (LL_USART_IsActiveFlag_IDLE(USART1)) {
+ irq_cb(UartIrqEventIDLE, 0);
+ LL_USART_ClearFlag_IDLE(USART1);
+ }
+
+ //TODO: more events
+}
+
void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) {
if (!furi_hal_console_alive)
return;
// Transmit data
- furi_hal_console_uart_tx(buffer, buffer_size);
+ furi_hal_usart_tx(buffer, buffer_size);
// Wait for TC flag to be raised for last char
while (!LL_USART_IsActiveFlag_TC(USART1));
}
@@ -67,9 +121,9 @@ void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t buffer_size
return;
// Transmit data
- furi_hal_console_uart_tx(buffer, buffer_size);
+ furi_hal_usart_tx(buffer, buffer_size);
// Transmit new line symbols
- furi_hal_console_uart_tx((const uint8_t*)"\r\n", 2);
+ furi_hal_usart_tx((const uint8_t*)"\r\n", 2);
// Wait for TC flag to be raised for last char
while (!LL_USART_IsActiveFlag_TC(USART1));
}
diff --git a/firmware/targets/f6/furi-hal/furi-hal-console.h b/firmware/targets/f6/furi-hal/furi-hal-console.h
index cd7ccae8..013653ba 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-console.h
+++ b/firmware/targets/f6/furi-hal/furi-hal-console.h
@@ -7,6 +7,12 @@
extern "C" {
#endif
+typedef enum {
+ UartIrqEventRXNE,
+ UartIrqEventIDLE,
+ //TODO: more events
+} UartIrqEvent;
+
void furi_hal_console_init();
void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size);
@@ -23,6 +29,18 @@ void furi_hal_console_printf(const char format[], ...);
void furi_hal_console_puts(const char* data);
+
+void furi_hal_usart_init();
+
+void furi_hal_usart_deinit();
+
+void furi_hal_usart_set_br(uint32_t baud);
+
+void furi_hal_usart_tx(const uint8_t* buffer, size_t buffer_size);
+
+void furi_hal_usart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data));
+
+
#ifdef __cplusplus
}
#endif
diff --git a/firmware/targets/f6/furi-hal/furi-hal-lpuart.c b/firmware/targets/f6/furi-hal/furi-hal-lpuart.c
new file mode 100644
index 00000000..31aa8b86
--- /dev/null
+++ b/firmware/targets/f6/furi-hal/furi-hal-lpuart.c
@@ -0,0 +1,105 @@
+#include <furi-hal-lpuart.h>
+#include <stdbool.h>
+#include <stm32wbxx_ll_gpio.h>
+#include <stm32wbxx_ll_lpuart.h>
+
+#include <furi.h>
+
+static void (*irq_cb)(uint8_t ev, uint8_t data);
+
+void furi_hal_lpuart_init() {
+ LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
+ GPIO_InitStruct.Pin = PC0_Pin|PC1_Pin;
+ GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
+ GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
+ GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
+ GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
+ LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+
+ LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1);
+ LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
+
+ LL_LPUART_InitTypeDef LPUART_InitStruct = {0};
+ LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;
+ LPUART_InitStruct.BaudRate = 115200;
+ LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
+ LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
+ LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
+ LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
+ LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
+ LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
+ LL_LPUART_SetTXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8);
+ LL_LPUART_SetRXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8);
+ LL_LPUART_EnableFIFO(LPUART1);
+
+ LL_LPUART_Enable(LPUART1);
+
+ while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1))));
+
+ LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);
+ LL_LPUART_EnableIT_IDLE(LPUART1);
+ HAL_NVIC_SetPriority(LPUART1_IRQn, 5, 0);
+
+ FURI_LOG_I("FuriHalLpUart", "Init OK");
+}
+
+void furi_hal_lpuart_set_br(uint32_t baud) {
+ if (LL_LPUART_IsEnabled(LPUART1)) {
+ // Wait for transfer complete flag
+ while (!LL_LPUART_IsActiveFlag_TC(LPUART1));
+ LL_LPUART_Disable(LPUART1);
+ uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_GetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1));
+ if (uartclk/baud > 4095) {
+ LL_LPUART_SetPrescaler(LPUART1, LL_LPUART_PRESCALER_DIV32);
+ LL_LPUART_SetBaudRate(LPUART1, uartclk, LL_LPUART_PRESCALER_DIV32, baud);
+ } else {
+ LL_LPUART_SetPrescaler(LPUART1, LL_LPUART_PRESCALER_DIV1);
+ LL_LPUART_SetBaudRate(LPUART1, uartclk, LL_LPUART_PRESCALER_DIV1, baud);
+ }
+
+ LL_LPUART_Enable(LPUART1);
+ }
+}
+
+void furi_hal_lpuart_deinit() {
+ furi_hal_lpuart_set_irq_cb(NULL);
+ LL_GPIO_SetPinMode(GPIOC, PC0_Pin, LL_GPIO_MODE_ANALOG);
+ LL_GPIO_SetPinMode(GPIOC, PC1_Pin, LL_GPIO_MODE_ANALOG);
+ LL_LPUART_Disable(LPUART1);
+ LL_APB1_GRP2_DisableClock(LL_APB1_GRP2_PERIPH_LPUART1);
+}
+
+void furi_hal_lpuart_tx(const uint8_t* buffer, size_t buffer_size) {
+ if (LL_LPUART_IsEnabled(LPUART1) == 0)
+ return;
+
+ while(buffer_size > 0) {
+ while (!LL_LPUART_IsActiveFlag_TXE(LPUART1));
+
+ LL_LPUART_TransmitData8(LPUART1, *buffer);
+
+ buffer++;
+ buffer_size--;
+ }
+}
+
+void furi_hal_lpuart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)) {
+ irq_cb = cb;
+ if (irq_cb == NULL)
+ NVIC_DisableIRQ(LPUART1_IRQn);
+ else
+ NVIC_EnableIRQ(LPUART1_IRQn);
+}
+
+void LPUART1_IRQHandler(void) {
+ if (LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) {
+ uint8_t data = LL_LPUART_ReceiveData8(LPUART1);
+ irq_cb(UartIrqEventRXNE, data);
+ } else if (LL_LPUART_IsActiveFlag_IDLE(LPUART1)) {
+ irq_cb(UartIrqEventIDLE, 0);
+ LL_LPUART_ClearFlag_IDLE(LPUART1);
+ }
+
+ //TODO: more events
+}
diff --git a/firmware/targets/f6/furi-hal/furi-hal-lpuart.h b/firmware/targets/f6/furi-hal/furi-hal-lpuart.h
new file mode 100644
index 00000000..118a9a9c
--- /dev/null
+++ b/firmware/targets/f6/furi-hal/furi-hal-lpuart.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+#include "furi-hal-console.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void furi_hal_lpuart_init();
+
+void furi_hal_lpuart_deinit();
+
+void furi_hal_lpuart_set_br(uint32_t baud);
+
+void furi_hal_lpuart_tx(const uint8_t* buffer, size_t buffer_size);
+
+void furi_hal_lpuart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data));
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c b/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c
index 09efbec3..e643fe57 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c
+++ b/firmware/targets/f6/furi-hal/furi-hal-usb-cdc.c
@@ -1,6 +1,5 @@
#include "furi-hal-version.h"
#include "furi-hal-usb_i.h"
-#include "furi-hal-vcp_i.h"
#include "furi-hal-usb-cdc_i.h"
#include <furi.h>
@@ -17,6 +16,8 @@
#define CDC_NTF_SZ 0x08
+#define IF_NUM_MAX 2
+
struct CdcIadDescriptor {
struct usb_iad_descriptor comm_iad;
struct usb_interface_descriptor comm;
@@ -343,12 +344,8 @@ static const struct CdcConfigDescriptorDual cdc_cfg_desc_dual = {
},
};
-static struct usb_cdc_line_coding cdc_line = {
- .dwDTERate = 38400,
- .bCharFormat = USB_CDC_1_STOP_BITS,
- .bParityType = USB_CDC_NO_PARITY,
- .bDataBits = 8,
-};
+static struct usb_cdc_line_coding cdc_config[IF_NUM_MAX] = {};
+
static void cdc_init(usbd_device* dev, struct UsbInterface* intf);
static void cdc_deinit(usbd_device *dev);
static void cdc_on_wakeup(usbd_device *dev);
@@ -358,6 +355,7 @@ 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 CdcCallbacks* callbacks[IF_NUM_MAX] = {NULL};
struct UsbInterface usb_cdc_single = {
.init = cdc_init,
@@ -429,6 +427,17 @@ 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;
+}
+
+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;
+}
+
void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len) {
if (if_num == 0)
usbd_ep_write(usb_dev, CDC0_TXD_EP, buf, len);
@@ -444,25 +453,47 @@ 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) {
- furi_hal_vcp_on_usb_resume();
+ 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);
+ }
+ }
}
static void cdc_on_suspend(usbd_device *dev) {
- furi_hal_vcp_on_usb_suspend();
+ for (uint8_t i = 0; i < IF_NUM_MAX; i++) {
+ if (callbacks[i] != NULL) {
+ if (callbacks[i]->state_callback != NULL)
+ callbacks[i]->state_callback(0);
+ }
+ }
}
static void cdc_rx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
+ uint8_t if_num = 0;
if (ep == CDC0_RXD_EP)
- furi_hal_vcp_on_cdc_rx(0);
+ if_num = 0;
else
- furi_hal_vcp_on_cdc_rx(1);
+ if_num = 1;
+
+ if (callbacks[if_num] != NULL) {
+ if (callbacks[if_num]->rx_ep_callback != NULL)
+ callbacks[if_num]->rx_ep_callback();
+ }
}
static void cdc_tx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
+ uint8_t if_num = 0;
if (ep == CDC0_TXD_EP)
- furi_hal_vcp_on_cdc_tx_complete(0);
+ if_num = 0;
else
- furi_hal_vcp_on_cdc_tx_complete(1);
+ if_num = 1;
+
+ if (callbacks[if_num] != NULL) {
+ if (callbacks[if_num]->tx_ep_callback != NULL)
+ callbacks[if_num]->tx_ep_callback();
+ }
}
static void cdc_txrx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
@@ -494,13 +525,15 @@ static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg) {
return usbd_ack;
case 1:
/* configuring device */
- if ((CDC0_TXD_EP & 0x7F) != (CDC0_RXD_EP & 0x7F)) {
+ if ((CDC0_TXD_EP & 0x7F) != (CDC0_RXD_EP & 0x7F)) {
+ // 2x unidirectional endpoint mode with dualbuf
usbd_ep_config(dev, CDC0_RXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ);
usbd_ep_config(dev, CDC0_TXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ);
usbd_ep_config(dev, CDC0_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ);
usbd_reg_endpoint(dev, CDC0_RXD_EP, cdc_rx_ep_callback);
usbd_reg_endpoint(dev, CDC0_TXD_EP, cdc_tx_ep_callback);
- } else {
+ } else {
+ // 1x bidirectional endpoint mode
usbd_ep_config(dev, CDC0_RXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ);
usbd_ep_config(dev, CDC0_TXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ);
usbd_ep_config(dev, CDC0_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ);
@@ -532,20 +565,33 @@ static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg) {
}
/* Control requests handler */
-static usbd_respond cdc_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) {
+static usbd_respond cdc_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) {
/* CDC control requests */
- if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS)
- && req->wIndex == 0 ) {
- switch (req->bRequest) {
+ uint8_t if_num = 0;
+ if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS)
+ && (req->wIndex == 0 || req->wIndex == 2)) {
+ if (req->wIndex == 0)
+ if_num = 0;
+ else
+ if_num = 1;
+
+ switch(req->bRequest) {
case USB_CDC_SET_CONTROL_LINE_STATE:
- furi_hal_vcp_on_cdc_control_line(req->wValue);
+ if (callbacks[if_num] != NULL) {
+ if (callbacks[if_num]->ctrl_line_callback != NULL)
+ callbacks[if_num]->ctrl_line_callback(req->wValue);
+ }
return usbd_ack;
case USB_CDC_SET_LINE_CODING:
- memcpy(&cdc_line, req->data, sizeof(cdc_line));
+ 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]);
+ }
return usbd_ack;
case USB_CDC_GET_LINE_CODING:
- dev->status.data_ptr = &cdc_line;
- dev->status.data_count = sizeof(cdc_line);
+ dev->status.data_ptr = &cdc_config[if_num];
+ dev->status.data_count = sizeof(cdc_config[0]);
return usbd_ack;
default:
return usbd_fail;
diff --git a/firmware/targets/f6/furi-hal/furi-hal-usb-cdc_i.h b/firmware/targets/f6/furi-hal/furi-hal-usb-cdc_i.h
index 636b3c04..3b181582 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-usb-cdc_i.h
+++ b/firmware/targets/f6/furi-hal/furi-hal-usb-cdc_i.h
@@ -1,6 +1,21 @@
#pragma once
-#define CDC_DATA_SZ 0x40
+#include <stdint.h>
+#include "usb_cdc.h"
+
+#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);
+} CdcCallbacks;
+
+void furi_hal_cdc_set_callbacks(uint8_t if_num, CdcCallbacks* cb);
+
+struct usb_cdc_line_coding* furi_hal_cdc_get_port_settings(uint8_t if_num);
void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len);
diff --git a/firmware/targets/f6/furi-hal/furi-hal-usb.c b/firmware/targets/f6/furi-hal/furi-hal-usb.c
index 5442975f..8c78eb8b 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-usb.c
+++ b/firmware/targets/f6/furi-hal/furi-hal-usb.c
@@ -1,7 +1,6 @@
#include "furi-hal-version.h"
#include "furi-hal-usb_i.h"
#include "furi-hal-usb.h"
-#include "furi-hal-vcp_i.h"
#include <furi.h>
#include "usb.h"
@@ -34,6 +33,7 @@ struct UsbCfg{
UsbMode mode_cur;
UsbMode mode_next;
bool enabled;
+ bool connected;
} usb_config;
static void furi_hal_usb_tmr_cb(void* context);
@@ -158,11 +158,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)
+ if ((usb_if_modes[usb_config.mode_cur] != NULL) && (usb_config.connected == true)) {
+ usb_config.connected = false;
usb_if_modes[usb_config.mode_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)
+ if ((usb_if_modes[usb_config.mode_cur] != NULL) && (usb_config.connected == false)) {
+ usb_config.connected = true;
usb_if_modes[usb_config.mode_cur]->wakeup(&udev);
+ }
}
diff --git a/firmware/targets/f6/furi-hal/furi-hal-vcp.c b/firmware/targets/f6/furi-hal/furi-hal-vcp.c
index e276c4a3..b975495d 100644
--- a/firmware/targets/f6/furi-hal/furi-hal-vcp.c
+++ b/firmware/targets/f6/furi-hal/furi-hal-vcp.c
@@ -1,4 +1,3 @@
-#include <furi-hal-vcp_i.h>
#include <furi-hal-usb-cdc_i.h>
#include <furi.h>
@@ -7,6 +6,7 @@
#define APP_RX_DATA_SIZE CDC_DATA_SZ
#define APP_TX_DATA_SIZE CDC_DATA_SZ
#define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 16)
+#define VCP_IF_NUM 0
typedef struct {
volatile bool connected;
@@ -17,6 +17,19 @@ typedef struct {
osSemaphoreId_t tx_semaphore;
} FuriHalVcp;
+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 CdcCallbacks cdc_cb = {
+ vcp_on_cdc_tx_complete,
+ vcp_on_cdc_rx,
+ vcp_state_callback,
+ vcp_on_cdc_control_line,
+ NULL,
+};
+
static FuriHalVcp* furi_hal_vcp = NULL;
static const uint8_t ascii_soh = 0x01;
@@ -34,9 +47,22 @@ void furi_hal_vcp_init() {
furi_hal_vcp->tx_semaphore = osSemaphoreNew(1, 1, NULL);
+ furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb);
+
FURI_LOG_I("FuriHalVcp", "Init OK");
}
+void furi_hal_vcp_enable() {
+ furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb);
+ furi_hal_vcp->connected = true;
+}
+
+void furi_hal_vcp_disable() {
+ furi_hal_cdc_set_callbacks(VCP_IF_NUM, NULL);
+ furi_hal_vcp->connected = false;
+ osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
+}
+
size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size) {
furi_assert(furi_hal_vcp);
@@ -68,24 +94,22 @@ void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) {
batch_size = APP_TX_DATA_SIZE;
}
- furi_hal_cdc_send(0, (uint8_t*)buffer, batch_size);
+ furi_hal_cdc_send(VCP_IF_NUM, (uint8_t*)buffer, batch_size);
size -= batch_size;
buffer += batch_size;
}
}
-void furi_hal_vcp_on_usb_resume() {
- osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
-}
-
-void furi_hal_vcp_on_usb_suspend() {
- if (furi_hal_vcp->connected) {
+static void vcp_state_callback(uint8_t state) {
+ if (state == 1)
+ osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
+ else if (furi_hal_vcp->connected) {
furi_hal_vcp->connected = false;
osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
}
}
-void furi_hal_vcp_on_cdc_control_line(uint8_t state) {
+static void vcp_on_cdc_control_line(uint8_t state) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// bit 0: DTR state, bit 1: RTS state
@@ -110,30 +134,26 @@ void furi_hal_vcp_on_cdc_control_line(uint8_t state) {
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
-void furi_hal_vcp_on_cdc_rx(uint8_t if_num) {
+static void vcp_on_cdc_rx() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
- if (if_num == 0) {
- uint16_t max_len = xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream);
- if (max_len > 0) {
- if (max_len > APP_RX_DATA_SIZE)
- max_len = APP_RX_DATA_SIZE;
- int32_t size = furi_hal_cdc_receive(0, vcp_rx_buf, max_len);
-
- if (size > 0) {
- size_t ret = xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, vcp_rx_buf, size, &xHigherPriorityTaskWoken);
- furi_check(ret == size);
- }
- } else {
- furi_hal_vcp->rx_stream_full = true;
- };
- }
+ uint16_t max_len = xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream);
+ if (max_len > 0) {
+ if (max_len > APP_RX_DATA_SIZE)
+ max_len = APP_RX_DATA_SIZE;
+ int32_t size = furi_hal_cdc_receive(VCP_IF_NUM, vcp_rx_buf, max_len);
+
+ if (size > 0) {
+ size_t ret = xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, vcp_rx_buf, size, &xHigherPriorityTaskWoken);
+ furi_check(ret == size);
+ }
+ } else {
+ furi_hal_vcp->rx_stream_full = true;
+ };
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
-void furi_hal_vcp_on_cdc_tx_complete(uint8_t if_num) {
- if (if_num == 0)
- osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
+static void vcp_on_cdc_tx_complete() {
+ osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
}
-
diff --git a/firmware/targets/f6/furi-hal/furi-hal-vcp_i.h b/firmware/targets/f6/furi-hal/furi-hal-vcp_i.h
deleted file mode 100644
index 9c8ccd73..00000000
--- a/firmware/targets/f6/furi-hal/furi-hal-vcp_i.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-#include <furi-hal-vcp.h>
-
-void furi_hal_vcp_on_usb_resume();
-
-void furi_hal_vcp_on_usb_suspend();
-
-void furi_hal_vcp_on_cdc_control_line(uint8_t state);
-
-void furi_hal_vcp_on_cdc_rx(uint8_t if_num);
-
-void furi_hal_vcp_on_cdc_tx_complete(uint8_t if_num);
diff --git a/firmware/targets/f6/furi-hal/furi-hal.c b/firmware/targets/f6/furi-hal/furi-hal.c
index 8f680385..bcddc6e0 100644
--- a/firmware/targets/f6/furi-hal/furi-hal.c
+++ b/firmware/targets/f6/furi-hal/furi-hal.c
@@ -33,9 +33,9 @@ void furi_hal_init() {
furi_hal_crypto_init();
// VCP + USB
- furi_hal_vcp_init();
furi_hal_usb_init();
furi_hal_usb_set_config(UsbModeVcpSingle);
+ furi_hal_vcp_init();
FURI_LOG_I("HAL", "USB OK");
furi_hal_i2c_init();
diff --git a/firmware/targets/f6/target.mk b/firmware/targets/f6/target.mk
index 298182ef..f942ba0f 100644
--- a/firmware/targets/f6/target.mk
+++ b/firmware/targets/f6/target.mk
@@ -72,6 +72,7 @@ C_SOURCES += \
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_spi.c \
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \
+ $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lpuart.c \
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c
# FreeRTOS
diff --git a/firmware/targets/f7/furi-hal/furi-hal-console.c b/firmware/targets/f7/furi-hal/furi-hal-console.c
index b04a17a1..552f9e77 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-console.c
+++ b/firmware/targets/f7/furi-hal/furi-hal-console.c
@@ -1,4 +1,5 @@
#include <furi-hal-console.h>
+#include <furi-hal-lpuart.h>
#include <stdbool.h>
#include <stm32wbxx_ll_gpio.h>
@@ -7,8 +8,12 @@
#include <furi.h>
+#define CONSOLE_BAUDRATE 230400
+
volatile bool furi_hal_console_alive = false;
+static void (*irq_cb)(uint8_t ev, uint8_t data);
+
void furi_hal_console_init() {
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7;
@@ -21,11 +26,11 @@ void furi_hal_console_init() {
LL_USART_InitTypeDef USART_InitStruct = {0};
USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
- USART_InitStruct.BaudRate = 230400;
+ USART_InitStruct.BaudRate = CONSOLE_BAUDRATE;
USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
USART_InitStruct.Parity = LL_USART_PARITY_NONE;
- USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX;
+ USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
LL_USART_Init(USART1, &USART_InitStruct);
@@ -36,12 +41,41 @@ void furi_hal_console_init() {
LL_USART_Enable(USART1);
while(!LL_USART_IsActiveFlag_TEACK(USART1)) ;
+
+ LL_USART_EnableIT_RXNE_RXFNE(USART1);
+ LL_USART_EnableIT_IDLE(USART1);
+ HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
+
furi_hal_console_alive = true;
FURI_LOG_I("FuriHalConsole", "Init OK");
}
-static void furi_hal_console_uart_tx(const uint8_t* buffer, size_t buffer_size) {
+void furi_hal_usart_init() {
+ furi_hal_console_alive = false;
+}
+
+void furi_hal_usart_set_br(uint32_t baud) {
+ if (LL_USART_IsEnabled(USART1)) {
+ // Wait for transfer complete flag
+ while (!LL_USART_IsActiveFlag_TC(USART1));
+ LL_USART_Disable(USART1);
+ uint32_t uartclk = LL_RCC_GetUSARTClockFreq(LL_RCC_USART1_CLKSOURCE);
+ LL_USART_SetBaudRate(USART1, uartclk, LL_USART_PRESCALER_DIV1, LL_USART_OVERSAMPLING_16, baud);
+ LL_USART_Enable(USART1);
+ }
+}
+
+void furi_hal_usart_deinit() {
+ while (!LL_USART_IsActiveFlag_TC(USART1));
+ furi_hal_usart_set_br(CONSOLE_BAUDRATE);
+ furi_hal_console_alive = true;
+}
+
+void furi_hal_usart_tx(const uint8_t* buffer, size_t buffer_size) {
+ if (LL_USART_IsEnabled(USART1) == 0)
+ return;
+
while(buffer_size > 0) {
while (!LL_USART_IsActiveFlag_TXE(USART1));
@@ -52,12 +86,32 @@ static void furi_hal_console_uart_tx(const uint8_t* buffer, size_t buffer_size)
}
}
+void furi_hal_usart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)) {
+ irq_cb = cb;
+ if (irq_cb == NULL)
+ NVIC_DisableIRQ(USART1_IRQn);
+ else
+ NVIC_EnableIRQ(USART1_IRQn);
+}
+
+void USART1_IRQHandler(void) {
+ if (LL_USART_IsActiveFlag_RXNE_RXFNE(USART1)) {
+ uint8_t data = LL_USART_ReceiveData8(USART1);
+ irq_cb(UartIrqEventRXNE, data);
+ } else if (LL_USART_IsActiveFlag_IDLE(USART1)) {
+ irq_cb(UartIrqEventIDLE, 0);
+ LL_USART_ClearFlag_IDLE(USART1);
+ }
+
+ //TODO: more events
+}
+
void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size) {
if (!furi_hal_console_alive)
return;
// Transmit data
- furi_hal_console_uart_tx(buffer, buffer_size);
+ furi_hal_usart_tx(buffer, buffer_size);
// Wait for TC flag to be raised for last char
while (!LL_USART_IsActiveFlag_TC(USART1));
}
@@ -67,9 +121,9 @@ void furi_hal_console_tx_with_new_line(const uint8_t* buffer, size_t buffer_size
return;
// Transmit data
- furi_hal_console_uart_tx(buffer, buffer_size);
+ furi_hal_usart_tx(buffer, buffer_size);
// Transmit new line symbols
- furi_hal_console_uart_tx((const uint8_t*)"\r\n", 2);
+ furi_hal_usart_tx((const uint8_t*)"\r\n", 2);
// Wait for TC flag to be raised for last char
while (!LL_USART_IsActiveFlag_TC(USART1));
}
diff --git a/firmware/targets/f7/furi-hal/furi-hal-console.h b/firmware/targets/f7/furi-hal/furi-hal-console.h
index cd7ccae8..013653ba 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-console.h
+++ b/firmware/targets/f7/furi-hal/furi-hal-console.h
@@ -7,6 +7,12 @@
extern "C" {
#endif
+typedef enum {
+ UartIrqEventRXNE,
+ UartIrqEventIDLE,
+ //TODO: more events
+} UartIrqEvent;
+
void furi_hal_console_init();
void furi_hal_console_tx(const uint8_t* buffer, size_t buffer_size);
@@ -23,6 +29,18 @@ void furi_hal_console_printf(const char format[], ...);
void furi_hal_console_puts(const char* data);
+
+void furi_hal_usart_init();
+
+void furi_hal_usart_deinit();
+
+void furi_hal_usart_set_br(uint32_t baud);
+
+void furi_hal_usart_tx(const uint8_t* buffer, size_t buffer_size);
+
+void furi_hal_usart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data));
+
+
#ifdef __cplusplus
}
#endif
diff --git a/firmware/targets/f7/furi-hal/furi-hal-lpuart.c b/firmware/targets/f7/furi-hal/furi-hal-lpuart.c
new file mode 100644
index 00000000..31aa8b86
--- /dev/null
+++ b/firmware/targets/f7/furi-hal/furi-hal-lpuart.c
@@ -0,0 +1,105 @@
+#include <furi-hal-lpuart.h>
+#include <stdbool.h>
+#include <stm32wbxx_ll_gpio.h>
+#include <stm32wbxx_ll_lpuart.h>
+
+#include <furi.h>
+
+static void (*irq_cb)(uint8_t ev, uint8_t data);
+
+void furi_hal_lpuart_init() {
+ LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
+ GPIO_InitStruct.Pin = PC0_Pin|PC1_Pin;
+ GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
+ GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
+ GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
+ GPIO_InitStruct.Alternate = LL_GPIO_AF_8;
+ LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
+
+ LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1);
+ LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
+
+ LL_LPUART_InitTypeDef LPUART_InitStruct = {0};
+ LPUART_InitStruct.PrescalerValue = LL_LPUART_PRESCALER_DIV1;
+ LPUART_InitStruct.BaudRate = 115200;
+ LPUART_InitStruct.DataWidth = LL_LPUART_DATAWIDTH_8B;
+ LPUART_InitStruct.StopBits = LL_LPUART_STOPBITS_1;
+ LPUART_InitStruct.Parity = LL_LPUART_PARITY_NONE;
+ LPUART_InitStruct.TransferDirection = LL_LPUART_DIRECTION_TX_RX;
+ LPUART_InitStruct.HardwareFlowControl = LL_LPUART_HWCONTROL_NONE;
+ LL_LPUART_Init(LPUART1, &LPUART_InitStruct);
+ LL_LPUART_SetTXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8);
+ LL_LPUART_SetRXFIFOThreshold(LPUART1, LL_LPUART_FIFOTHRESHOLD_1_8);
+ LL_LPUART_EnableFIFO(LPUART1);
+
+ LL_LPUART_Enable(LPUART1);
+
+ while((!(LL_LPUART_IsActiveFlag_TEACK(LPUART1))) || (!(LL_LPUART_IsActiveFlag_REACK(LPUART1))));
+
+ LL_LPUART_EnableIT_RXNE_RXFNE(LPUART1);
+ LL_LPUART_EnableIT_IDLE(LPUART1);
+ HAL_NVIC_SetPriority(LPUART1_IRQn, 5, 0);
+
+ FURI_LOG_I("FuriHalLpUart", "Init OK");
+}
+
+void furi_hal_lpuart_set_br(uint32_t baud) {
+ if (LL_LPUART_IsEnabled(LPUART1)) {
+ // Wait for transfer complete flag
+ while (!LL_LPUART_IsActiveFlag_TC(LPUART1));
+ LL_LPUART_Disable(LPUART1);
+ uint32_t uartclk = LL_RCC_GetLPUARTClockFreq(LL_RCC_GetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1));
+ if (uartclk/baud > 4095) {
+ LL_LPUART_SetPrescaler(LPUART1, LL_LPUART_PRESCALER_DIV32);
+ LL_LPUART_SetBaudRate(LPUART1, uartclk, LL_LPUART_PRESCALER_DIV32, baud);
+ } else {
+ LL_LPUART_SetPrescaler(LPUART1, LL_LPUART_PRESCALER_DIV1);
+ LL_LPUART_SetBaudRate(LPUART1, uartclk, LL_LPUART_PRESCALER_DIV1, baud);
+ }
+
+ LL_LPUART_Enable(LPUART1);
+ }
+}
+
+void furi_hal_lpuart_deinit() {
+ furi_hal_lpuart_set_irq_cb(NULL);
+ LL_GPIO_SetPinMode(GPIOC, PC0_Pin, LL_GPIO_MODE_ANALOG);
+ LL_GPIO_SetPinMode(GPIOC, PC1_Pin, LL_GPIO_MODE_ANALOG);
+ LL_LPUART_Disable(LPUART1);
+ LL_APB1_GRP2_DisableClock(LL_APB1_GRP2_PERIPH_LPUART1);
+}
+
+void furi_hal_lpuart_tx(const uint8_t* buffer, size_t buffer_size) {
+ if (LL_LPUART_IsEnabled(LPUART1) == 0)
+ return;
+
+ while(buffer_size > 0) {
+ while (!LL_LPUART_IsActiveFlag_TXE(LPUART1));
+
+ LL_LPUART_TransmitData8(LPUART1, *buffer);
+
+ buffer++;
+ buffer_size--;
+ }
+}
+
+void furi_hal_lpuart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data)) {
+ irq_cb = cb;
+ if (irq_cb == NULL)
+ NVIC_DisableIRQ(LPUART1_IRQn);
+ else
+ NVIC_EnableIRQ(LPUART1_IRQn);
+}
+
+void LPUART1_IRQHandler(void) {
+ if (LL_LPUART_IsActiveFlag_RXNE_RXFNE(LPUART1)) {
+ uint8_t data = LL_LPUART_ReceiveData8(LPUART1);
+ irq_cb(UartIrqEventRXNE, data);
+ } else if (LL_LPUART_IsActiveFlag_IDLE(LPUART1)) {
+ irq_cb(UartIrqEventIDLE, 0);
+ LL_LPUART_ClearFlag_IDLE(LPUART1);
+ }
+
+ //TODO: more events
+}
diff --git a/firmware/targets/f7/furi-hal/furi-hal-lpuart.h b/firmware/targets/f7/furi-hal/furi-hal-lpuart.h
new file mode 100644
index 00000000..118a9a9c
--- /dev/null
+++ b/firmware/targets/f7/furi-hal/furi-hal-lpuart.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+#include "furi-hal-console.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void furi_hal_lpuart_init();
+
+void furi_hal_lpuart_deinit();
+
+void furi_hal_lpuart_set_br(uint32_t baud);
+
+void furi_hal_lpuart_tx(const uint8_t* buffer, size_t buffer_size);
+
+void furi_hal_lpuart_set_irq_cb(void (*cb)(UartIrqEvent ev, uint8_t data));
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c b/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c
index 09efbec3..e643fe57 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c
+++ b/firmware/targets/f7/furi-hal/furi-hal-usb-cdc.c
@@ -1,6 +1,5 @@
#include "furi-hal-version.h"
#include "furi-hal-usb_i.h"
-#include "furi-hal-vcp_i.h"
#include "furi-hal-usb-cdc_i.h"
#include <furi.h>
@@ -17,6 +16,8 @@
#define CDC_NTF_SZ 0x08
+#define IF_NUM_MAX 2
+
struct CdcIadDescriptor {
struct usb_iad_descriptor comm_iad;
struct usb_interface_descriptor comm;
@@ -343,12 +344,8 @@ static const struct CdcConfigDescriptorDual cdc_cfg_desc_dual = {
},
};
-static struct usb_cdc_line_coding cdc_line = {
- .dwDTERate = 38400,
- .bCharFormat = USB_CDC_1_STOP_BITS,
- .bParityType = USB_CDC_NO_PARITY,
- .bDataBits = 8,
-};
+static struct usb_cdc_line_coding cdc_config[IF_NUM_MAX] = {};
+
static void cdc_init(usbd_device* dev, struct UsbInterface* intf);
static void cdc_deinit(usbd_device *dev);
static void cdc_on_wakeup(usbd_device *dev);
@@ -358,6 +355,7 @@ 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 CdcCallbacks* callbacks[IF_NUM_MAX] = {NULL};
struct UsbInterface usb_cdc_single = {
.init = cdc_init,
@@ -429,6 +427,17 @@ 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;
+}
+
+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;
+}
+
void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len) {
if (if_num == 0)
usbd_ep_write(usb_dev, CDC0_TXD_EP, buf, len);
@@ -444,25 +453,47 @@ 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) {
- furi_hal_vcp_on_usb_resume();
+ 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);
+ }
+ }
}
static void cdc_on_suspend(usbd_device *dev) {
- furi_hal_vcp_on_usb_suspend();
+ for (uint8_t i = 0; i < IF_NUM_MAX; i++) {
+ if (callbacks[i] != NULL) {
+ if (callbacks[i]->state_callback != NULL)
+ callbacks[i]->state_callback(0);
+ }
+ }
}
static void cdc_rx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
+ uint8_t if_num = 0;
if (ep == CDC0_RXD_EP)
- furi_hal_vcp_on_cdc_rx(0);
+ if_num = 0;
else
- furi_hal_vcp_on_cdc_rx(1);
+ if_num = 1;
+
+ if (callbacks[if_num] != NULL) {
+ if (callbacks[if_num]->rx_ep_callback != NULL)
+ callbacks[if_num]->rx_ep_callback();
+ }
}
static void cdc_tx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
+ uint8_t if_num = 0;
if (ep == CDC0_TXD_EP)
- furi_hal_vcp_on_cdc_tx_complete(0);
+ if_num = 0;
else
- furi_hal_vcp_on_cdc_tx_complete(1);
+ if_num = 1;
+
+ if (callbacks[if_num] != NULL) {
+ if (callbacks[if_num]->tx_ep_callback != NULL)
+ callbacks[if_num]->tx_ep_callback();
+ }
}
static void cdc_txrx_ep_callback (usbd_device *dev, uint8_t event, uint8_t ep) {
@@ -494,13 +525,15 @@ static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg) {
return usbd_ack;
case 1:
/* configuring device */
- if ((CDC0_TXD_EP & 0x7F) != (CDC0_RXD_EP & 0x7F)) {
+ if ((CDC0_TXD_EP & 0x7F) != (CDC0_RXD_EP & 0x7F)) {
+ // 2x unidirectional endpoint mode with dualbuf
usbd_ep_config(dev, CDC0_RXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ);
usbd_ep_config(dev, CDC0_TXD_EP, USB_EPTYPE_BULK | USB_EPTYPE_DBLBUF, CDC_DATA_SZ);
usbd_ep_config(dev, CDC0_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ);
usbd_reg_endpoint(dev, CDC0_RXD_EP, cdc_rx_ep_callback);
usbd_reg_endpoint(dev, CDC0_TXD_EP, cdc_tx_ep_callback);
- } else {
+ } else {
+ // 1x bidirectional endpoint mode
usbd_ep_config(dev, CDC0_RXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ);
usbd_ep_config(dev, CDC0_TXD_EP, USB_EPTYPE_BULK, CDC_DATA_SZ);
usbd_ep_config(dev, CDC0_NTF_EP, USB_EPTYPE_INTERRUPT, CDC_NTF_SZ);
@@ -532,20 +565,33 @@ static usbd_respond cdc_ep_config (usbd_device *dev, uint8_t cfg) {
}
/* Control requests handler */
-static usbd_respond cdc_control (usbd_device *dev, usbd_ctlreq *req, usbd_rqc_callback *callback) {
+static usbd_respond cdc_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) {
/* CDC control requests */
- if (((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS)
- && req->wIndex == 0 ) {
- switch (req->bRequest) {
+ uint8_t if_num = 0;
+ if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) == (USB_REQ_INTERFACE | USB_REQ_CLASS)
+ && (req->wIndex == 0 || req->wIndex == 2)) {
+ if (req->wIndex == 0)
+ if_num = 0;
+ else
+ if_num = 1;
+
+ switch(req->bRequest) {
case USB_CDC_SET_CONTROL_LINE_STATE:
- furi_hal_vcp_on_cdc_control_line(req->wValue);
+ if (callbacks[if_num] != NULL) {
+ if (callbacks[if_num]->ctrl_line_callback != NULL)
+ callbacks[if_num]->ctrl_line_callback(req->wValue);
+ }
return usbd_ack;
case USB_CDC_SET_LINE_CODING:
- memcpy(&cdc_line, req->data, sizeof(cdc_line));
+ 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]);
+ }
return usbd_ack;
case USB_CDC_GET_LINE_CODING:
- dev->status.data_ptr = &cdc_line;
- dev->status.data_count = sizeof(cdc_line);
+ dev->status.data_ptr = &cdc_config[if_num];
+ dev->status.data_count = sizeof(cdc_config[0]);
return usbd_ack;
default:
return usbd_fail;
diff --git a/firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h b/firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h
index 636b3c04..3b181582 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h
+++ b/firmware/targets/f7/furi-hal/furi-hal-usb-cdc_i.h
@@ -1,6 +1,21 @@
#pragma once
-#define CDC_DATA_SZ 0x40
+#include <stdint.h>
+#include "usb_cdc.h"
+
+#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);
+} CdcCallbacks;
+
+void furi_hal_cdc_set_callbacks(uint8_t if_num, CdcCallbacks* cb);
+
+struct usb_cdc_line_coding* furi_hal_cdc_get_port_settings(uint8_t if_num);
void furi_hal_cdc_send(uint8_t if_num, uint8_t* buf, uint16_t len);
diff --git a/firmware/targets/f7/furi-hal/furi-hal-usb.c b/firmware/targets/f7/furi-hal/furi-hal-usb.c
index 5442975f..8c78eb8b 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-usb.c
+++ b/firmware/targets/f7/furi-hal/furi-hal-usb.c
@@ -1,7 +1,6 @@
#include "furi-hal-version.h"
#include "furi-hal-usb_i.h"
#include "furi-hal-usb.h"
-#include "furi-hal-vcp_i.h"
#include <furi.h>
#include "usb.h"
@@ -34,6 +33,7 @@ struct UsbCfg{
UsbMode mode_cur;
UsbMode mode_next;
bool enabled;
+ bool connected;
} usb_config;
static void furi_hal_usb_tmr_cb(void* context);
@@ -158,11 +158,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)
+ if ((usb_if_modes[usb_config.mode_cur] != NULL) && (usb_config.connected == true)) {
+ usb_config.connected = false;
usb_if_modes[usb_config.mode_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)
+ if ((usb_if_modes[usb_config.mode_cur] != NULL) && (usb_config.connected == false)) {
+ usb_config.connected = true;
usb_if_modes[usb_config.mode_cur]->wakeup(&udev);
+ }
}
diff --git a/firmware/targets/f7/furi-hal/furi-hal-vcp.c b/firmware/targets/f7/furi-hal/furi-hal-vcp.c
index e276c4a3..b975495d 100644
--- a/firmware/targets/f7/furi-hal/furi-hal-vcp.c
+++ b/firmware/targets/f7/furi-hal/furi-hal-vcp.c
@@ -1,4 +1,3 @@
-#include <furi-hal-vcp_i.h>
#include <furi-hal-usb-cdc_i.h>
#include <furi.h>
@@ -7,6 +6,7 @@
#define APP_RX_DATA_SIZE CDC_DATA_SZ
#define APP_TX_DATA_SIZE CDC_DATA_SZ
#define FURI_HAL_VCP_RX_BUFFER_SIZE (APP_RX_DATA_SIZE * 16)
+#define VCP_IF_NUM 0
typedef struct {
volatile bool connected;
@@ -17,6 +17,19 @@ typedef struct {
osSemaphoreId_t tx_semaphore;
} FuriHalVcp;
+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 CdcCallbacks cdc_cb = {
+ vcp_on_cdc_tx_complete,
+ vcp_on_cdc_rx,
+ vcp_state_callback,
+ vcp_on_cdc_control_line,
+ NULL,
+};
+
static FuriHalVcp* furi_hal_vcp = NULL;
static const uint8_t ascii_soh = 0x01;
@@ -34,9 +47,22 @@ void furi_hal_vcp_init() {
furi_hal_vcp->tx_semaphore = osSemaphoreNew(1, 1, NULL);
+ furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb);
+
FURI_LOG_I("FuriHalVcp", "Init OK");
}
+void furi_hal_vcp_enable() {
+ furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb);
+ furi_hal_vcp->connected = true;
+}
+
+void furi_hal_vcp_disable() {
+ furi_hal_cdc_set_callbacks(VCP_IF_NUM, NULL);
+ furi_hal_vcp->connected = false;
+ osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
+}
+
size_t furi_hal_vcp_rx(uint8_t* buffer, size_t size) {
furi_assert(furi_hal_vcp);
@@ -68,24 +94,22 @@ void furi_hal_vcp_tx(const uint8_t* buffer, size_t size) {
batch_size = APP_TX_DATA_SIZE;
}
- furi_hal_cdc_send(0, (uint8_t*)buffer, batch_size);
+ furi_hal_cdc_send(VCP_IF_NUM, (uint8_t*)buffer, batch_size);
size -= batch_size;
buffer += batch_size;
}
}
-void furi_hal_vcp_on_usb_resume() {
- osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
-}
-
-void furi_hal_vcp_on_usb_suspend() {
- if (furi_hal_vcp->connected) {
+static void vcp_state_callback(uint8_t state) {
+ if (state == 1)
+ osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
+ else if (furi_hal_vcp->connected) {
furi_hal_vcp->connected = false;
osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
}
}
-void furi_hal_vcp_on_cdc_control_line(uint8_t state) {
+static void vcp_on_cdc_control_line(uint8_t state) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// bit 0: DTR state, bit 1: RTS state
@@ -110,30 +134,26 @@ void furi_hal_vcp_on_cdc_control_line(uint8_t state) {
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
-void furi_hal_vcp_on_cdc_rx(uint8_t if_num) {
+static void vcp_on_cdc_rx() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
- if (if_num == 0) {
- uint16_t max_len = xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream);
- if (max_len > 0) {
- if (max_len > APP_RX_DATA_SIZE)
- max_len = APP_RX_DATA_SIZE;
- int32_t size = furi_hal_cdc_receive(0, vcp_rx_buf, max_len);
-
- if (size > 0) {
- size_t ret = xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, vcp_rx_buf, size, &xHigherPriorityTaskWoken);
- furi_check(ret == size);
- }
- } else {
- furi_hal_vcp->rx_stream_full = true;
- };
- }
+ uint16_t max_len = xStreamBufferSpacesAvailable(furi_hal_vcp->rx_stream);
+ if (max_len > 0) {
+ if (max_len > APP_RX_DATA_SIZE)
+ max_len = APP_RX_DATA_SIZE;
+ int32_t size = furi_hal_cdc_receive(VCP_IF_NUM, vcp_rx_buf, max_len);
+
+ if (size > 0) {
+ size_t ret = xStreamBufferSendFromISR(furi_hal_vcp->rx_stream, vcp_rx_buf, size, &xHigherPriorityTaskWoken);
+ furi_check(ret == size);
+ }
+ } else {
+ furi_hal_vcp->rx_stream_full = true;
+ };
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
-void furi_hal_vcp_on_cdc_tx_complete(uint8_t if_num) {
- if (if_num == 0)
- osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
+static void vcp_on_cdc_tx_complete() {
+ osSemaphoreRelease(furi_hal_vcp->tx_semaphore);
}
-
diff --git a/firmware/targets/f7/furi-hal/furi-hal-vcp_i.h b/firmware/targets/f7/furi-hal/furi-hal-vcp_i.h
deleted file mode 100644
index 9c8ccd73..00000000
--- a/firmware/targets/f7/furi-hal/furi-hal-vcp_i.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-#include <furi-hal-vcp.h>
-
-void furi_hal_vcp_on_usb_resume();
-
-void furi_hal_vcp_on_usb_suspend();
-
-void furi_hal_vcp_on_cdc_control_line(uint8_t state);
-
-void furi_hal_vcp_on_cdc_rx(uint8_t if_num);
-
-void furi_hal_vcp_on_cdc_tx_complete(uint8_t if_num);
diff --git a/firmware/targets/f7/furi-hal/furi-hal.c b/firmware/targets/f7/furi-hal/furi-hal.c
index 8f680385..bcddc6e0 100644
--- a/firmware/targets/f7/furi-hal/furi-hal.c
+++ b/firmware/targets/f7/furi-hal/furi-hal.c
@@ -33,9 +33,9 @@ void furi_hal_init() {
furi_hal_crypto_init();
// VCP + USB
- furi_hal_vcp_init();
furi_hal_usb_init();
furi_hal_usb_set_config(UsbModeVcpSingle);
+ furi_hal_vcp_init();
FURI_LOG_I("HAL", "USB OK");
furi_hal_i2c_init();
diff --git a/firmware/targets/f7/target.mk b/firmware/targets/f7/target.mk
index c1f2e82d..be91cee9 100644
--- a/firmware/targets/f7/target.mk
+++ b/firmware/targets/f7/target.mk
@@ -72,6 +72,7 @@ C_SOURCES += \
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_spi.c \
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \
+ $(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lpuart.c \
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_utils.c
# FreeRTOS
diff --git a/firmware/targets/furi-hal-include/furi-hal-vcp.h b/firmware/targets/furi-hal-include/furi-hal-vcp.h
index 7d4803ae..996232cf 100644
--- a/firmware/targets/furi-hal-include/furi-hal-vcp.h
+++ b/firmware/targets/furi-hal-include/furi-hal-vcp.h
@@ -17,6 +17,14 @@ extern "C" {
*/
void furi_hal_vcp_init();
+/** Disable VCP to make CDC interface usable by other application
+ */
+void furi_hal_vcp_disable();
+
+/** Enable VCP
+ */
+void furi_hal_vcp_enable();
+
/** Recieve data from VCP Waits till some data arrives, never returns 0
*
* @param buffer pointer to buffer
diff --git a/firmware/targets/furi-hal-include/furi-hal.h b/firmware/targets/furi-hal-include/furi-hal.h
index 01d38e1e..757dd121 100644
--- a/firmware/targets/furi-hal-include/furi-hal.h
+++ b/firmware/targets/furi-hal-include/furi-hal.h
@@ -36,6 +36,7 @@ template <unsigned int N> struct STOP_EXTERNING_ME {};
#include "furi-hal-usb.h"
#include "furi-hal-usb-hid.h"
#include "furi-hal-compress.h"
+#include "furi-hal-lpuart.h"
/** Init furi-hal */
void furi_hal_init();