USB VCP Cli (#237)

* Core: ring buffer.
* Api: usb vcp. F3: vcp glue code.
* Applications: cli draft version.
* Cli: basic working version, includes help and version commands
* HAL: vcp on f2
* Makefile: update openocd conf
* F3: vcp rx with freertos stream
* Cli: help
* Cli: standard commands, api-hal-uid
* Power: cli poweroff.
This commit is contained in:
あく
2020-11-16 13:16:34 +03:00
committed by GitHub
parent 466ea087a0
commit 3749eb0eed
30 changed files with 837 additions and 242 deletions

View File

@@ -0,0 +1,10 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
/* Get platform UID size in bytes */
size_t api_hal_uid_size();
/* Get const pointer to UID */
const uint8_t* api_hal_uid();

View File

@@ -0,0 +1,24 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
/* Init VCP HAL
* Allocates ring buffer and initializes state
*/
void api_hal_vcp_init();
/* Recieve data from VCP
* Waits till some data arrives, never returns 0
* @param buffer - pointer to buffer
* @param size - buffer size
* @return items copied in buffer, 0 if channel closed
*/
size_t api_hal_vcp_rx(uint8_t* buffer, size_t size);
/* Transmit data to VCP
* @param buffer - pointer to buffer
* @param size - buffer size
*/
void api_hal_vcp_tx(uint8_t* buffer, size_t size);

View File

@@ -5,3 +5,6 @@
#include "api-hal-pwm.h"
#include "api-hal-task.h"
#include "api-hal-tim.h"
#include "api-hal-power.h"
#include "api-hal-vcp.h"
#include "api-hal-uid.h"

View File

@@ -51,8 +51,8 @@
/* USER CODE BEGIN EXPORTED_DEFINES */
/* Define size for the receive and transmit buffer over CDC */
/* It's up to user to redefine and/or remove those define */
#define APP_RX_DATA_SIZE 2048
#define APP_TX_DATA_SIZE 2048
#define APP_RX_DATA_SIZE CDC_DATA_HS_MAX_PACKET_SIZE
#define APP_TX_DATA_SIZE CDC_DATA_HS_MAX_PACKET_SIZE
/* USER CODE END EXPORTED_DEFINES */

View File

@@ -104,6 +104,7 @@ int main(void)
/* USER CODE BEGIN 2 */
MX_FATFS_Init();
delay_us_init_DWT();
api_hal_vcp_init();
/* USER CODE END 2 */
/* Init scheduler */

View File

@@ -51,6 +51,12 @@
/* USER CODE BEGIN PRIVATE_TYPES */
extern void _api_hal_vcp_init();
extern void _api_hal_vcp_deinit();
extern void _api_hal_vcp_control_line(uint8_t state);
extern void _api_hal_vcp_rx_callback(char* buffer, size_t size);
extern void _api_hal_vcp_tx_complete(size_t size);
/* USER CODE END PRIVATE_TYPES */
/**
@@ -156,6 +162,7 @@ static int8_t CDC_Init_FS(void)
/* Set Application Buffers */
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
_api_hal_vcp_init();
return (USBD_OK);
/* USER CODE END 3 */
}
@@ -167,6 +174,7 @@ static int8_t CDC_Init_FS(void)
static int8_t CDC_DeInit_FS(void)
{
/* USER CODE BEGIN 4 */
_api_hal_vcp_deinit();
return (USBD_OK);
/* USER CODE END 4 */
}
@@ -181,63 +189,34 @@ static int8_t CDC_DeInit_FS(void)
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
/* USER CODE BEGIN 5 */
switch(cmd)
{
case CDC_SEND_ENCAPSULATED_COMMAND:
break;
case CDC_GET_ENCAPSULATED_RESPONSE:
break;
case CDC_SET_COMM_FEATURE:
break;
case CDC_GET_COMM_FEATURE:
break;
case CDC_CLEAR_COMM_FEATURE:
break;
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
case CDC_SET_LINE_CODING:
break;
case CDC_GET_LINE_CODING:
break;
case CDC_SET_CONTROL_LINE_STATE:
break;
case CDC_SEND_BREAK:
break;
default:
break;
if (cmd == CDC_SEND_ENCAPSULATED_COMMAND) {
} else if (cmd == CDC_GET_ENCAPSULATED_RESPONSE) {
} else if (cmd == CDC_SET_COMM_FEATURE) {
} else if (cmd == CDC_GET_COMM_FEATURE) {
} else if (cmd == CDC_CLEAR_COMM_FEATURE) {
} else if (cmd == CDC_SET_LINE_CODING) {
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
} else if (cmd == CDC_GET_LINE_CODING) {
} else if (cmd == CDC_SET_CONTROL_LINE_STATE) {
_api_hal_vcp_control_line(((USBD_SetupReqTypedef*)pbuf)->wValue);
} else if (cmd == CDC_SEND_BREAK) {
} else {
}
return (USBD_OK);
@@ -262,7 +241,7 @@ static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
_api_hal_vcp_rx_callback((char*)Buf, *Len);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
@@ -287,7 +266,8 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
if (hcdc->TxState != 0){
return USBD_BUSY;
}
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
memcpy(UserTxBufferFS, Buf, Len);
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len);
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
/* USER CODE END 7 */
return result;
@@ -310,8 +290,8 @@ static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum)
uint8_t result = USBD_OK;
/* USER CODE BEGIN 13 */
UNUSED(Buf);
UNUSED(Len);
UNUSED(epnum);
_api_hal_vcp_tx_complete(*Len);
/* USER CODE END 13 */
return result;
}

View File

@@ -0,0 +1,10 @@
#include <api-hal-uid.h>
#include <stm32l4xx.h>
size_t api_hal_uid_size() {
return 96/8;
}
const uint8_t* api_hal_uid() {
return (const uint8_t *)UID_BASE;
}

View File

@@ -0,0 +1,92 @@
#include <api-hal-vcp.h>
#include <usbd_cdc_if.h>
#include <flipper_v2.h>
#include <stream_buffer.h>
#define API_HAL_VCP_RX_BUFFER_SIZE 600
typedef struct {
StreamBufferHandle_t rx_stream;
osSemaphoreId_t tx_semaphore;
volatile bool alive;
volatile bool underrun;
} ApiHalVcp;
ApiHalVcp api_hal_vcp;
static const uint8_t ascii_soh = 0x01;
static const uint8_t ascii_eot = 0x04;
void _api_hal_vcp_init();
void _api_hal_vcp_deinit();
void _api_hal_vcp_control_line(uint8_t state);
void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size);
void _api_hal_vcp_tx_complete(size_t size);
void api_hal_vcp_init() {
api_hal_vcp.rx_stream = xStreamBufferCreate(API_HAL_VCP_RX_BUFFER_SIZE, 1);
api_hal_vcp.tx_semaphore = osSemaphoreNew(1, 1, NULL);
api_hal_vcp.alive = false;
api_hal_vcp.underrun = false;
}
void _api_hal_vcp_init() {
osSemaphoreRelease(api_hal_vcp.tx_semaphore);
}
void _api_hal_vcp_deinit() {
api_hal_vcp.alive = false;
osSemaphoreRelease(api_hal_vcp.tx_semaphore);
}
void _api_hal_vcp_control_line(uint8_t state) {
// bit 0: DTR state, bit 1: RTS state
// bool dtr = state & 0b01;
bool rts = state & 0b10;
if (rts) {
api_hal_vcp.alive = true;
_api_hal_vcp_rx_callback(&ascii_soh, 1); // SOH
} else {
api_hal_vcp.alive = false;
_api_hal_vcp_rx_callback(&ascii_eot, 1); // EOT
}
osSemaphoreRelease(api_hal_vcp.tx_semaphore);
}
void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
size_t ret = xStreamBufferSendFromISR(api_hal_vcp.rx_stream, buffer, size, &xHigherPriorityTaskWoken);
if (ret != size) {
api_hal_vcp.underrun = true;
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void _api_hal_vcp_tx_complete(size_t size) {
osSemaphoreRelease(api_hal_vcp.tx_semaphore);
}
size_t api_hal_vcp_rx(uint8_t* buffer, size_t size) {
return xStreamBufferReceive(api_hal_vcp.rx_stream, buffer, size, portMAX_DELAY);
}
void api_hal_vcp_tx(uint8_t* buffer, size_t size) {
while (size > 0 && api_hal_vcp.alive) {
furi_check(osSemaphoreAcquire(api_hal_vcp.tx_semaphore, osWaitForever) == osOK);
size_t batch_size = size;
if (batch_size > APP_TX_DATA_SIZE) {
batch_size = APP_TX_DATA_SIZE;
}
if (CDC_Transmit_FS(buffer, batch_size) == USBD_OK) {
size -= batch_size;
buffer += batch_size;
} else {
// Shouldn't be there
osDelay(100);
}
}
}

View File

@@ -1,6 +1,6 @@
TOOLCHAIN = arm
DEBUG_AGENT = set -m; st-util -n --semihosting
DEBUG_AGENT = openocd -f interface/stlink-v2.cfg -c "transport select hla_swd" -f target/stm32l4x.cfg -c "init"
BOOT_ADDRESS = 0x08000000
FW_ADDRESS = 0x08008000

View File

@@ -51,8 +51,8 @@
/* USER CODE BEGIN EXPORTED_DEFINES */
/* Define size for the receive and transmit buffer over CDC */
/* It's up to user to redefine and/or remove those define */
#define APP_RX_DATA_SIZE 2048
#define APP_TX_DATA_SIZE 2048
#define APP_RX_DATA_SIZE CDC_DATA_HS_MAX_PACKET_SIZE
#define APP_TX_DATA_SIZE CDC_DATA_HS_MAX_PACKET_SIZE
/* USER CODE END EXPORTED_DEFINES */

View File

@@ -111,6 +111,7 @@ int main(void)
/* USER CODE BEGIN 2 */
MX_FATFS_Init();
delay_us_init_DWT();
api_hal_vcp_init();
/* USER CODE END 2 */
/* Init scheduler */

View File

@@ -51,6 +51,12 @@
/* USER CODE BEGIN PRIVATE_TYPES */
extern void _api_hal_vcp_init();
extern void _api_hal_vcp_deinit();
extern void _api_hal_vcp_control_line(uint8_t state);
extern void _api_hal_vcp_rx_callback(char* buffer, size_t size);
extern void _api_hal_vcp_tx_complete(size_t size);
/* USER CODE END PRIVATE_TYPES */
/**
@@ -156,6 +162,7 @@ static int8_t CDC_Init_FS(void)
/* Set Application Buffers */
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
_api_hal_vcp_init();
return (USBD_OK);
/* USER CODE END 3 */
}
@@ -167,6 +174,7 @@ static int8_t CDC_Init_FS(void)
static int8_t CDC_DeInit_FS(void)
{
/* USER CODE BEGIN 4 */
_api_hal_vcp_deinit();
return (USBD_OK);
/* USER CODE END 4 */
}
@@ -181,63 +189,34 @@ static int8_t CDC_DeInit_FS(void)
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
/* USER CODE BEGIN 5 */
switch(cmd)
{
case CDC_SEND_ENCAPSULATED_COMMAND:
break;
case CDC_GET_ENCAPSULATED_RESPONSE:
break;
case CDC_SET_COMM_FEATURE:
break;
case CDC_GET_COMM_FEATURE:
break;
case CDC_CLEAR_COMM_FEATURE:
break;
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
case CDC_SET_LINE_CODING:
break;
case CDC_GET_LINE_CODING:
break;
case CDC_SET_CONTROL_LINE_STATE:
break;
case CDC_SEND_BREAK:
break;
default:
break;
if (cmd == CDC_SEND_ENCAPSULATED_COMMAND) {
} else if (cmd == CDC_GET_ENCAPSULATED_RESPONSE) {
} else if (cmd == CDC_SET_COMM_FEATURE) {
} else if (cmd == CDC_GET_COMM_FEATURE) {
} else if (cmd == CDC_CLEAR_COMM_FEATURE) {
} else if (cmd == CDC_SET_LINE_CODING) {
/*******************************************************************************/
/* Line Coding Structure */
/*-----------------------------------------------------------------------------*/
/* Offset | Field | Size | Value | Description */
/* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/
/* 4 | bCharFormat | 1 | Number | Stop bits */
/* 0 - 1 Stop bit */
/* 1 - 1.5 Stop bits */
/* 2 - 2 Stop bits */
/* 5 | bParityType | 1 | Number | Parity */
/* 0 - None */
/* 1 - Odd */
/* 2 - Even */
/* 3 - Mark */
/* 4 - Space */
/* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */
/*******************************************************************************/
} else if (cmd == CDC_GET_LINE_CODING) {
} else if (cmd == CDC_SET_CONTROL_LINE_STATE) {
_api_hal_vcp_control_line(((USBD_SetupReqTypedef*)pbuf)->wValue);
} else if (cmd == CDC_SEND_BREAK) {
} else {
}
return (USBD_OK);
@@ -262,7 +241,7 @@ static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
_api_hal_vcp_rx_callback((char*)Buf, *Len);
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return (USBD_OK);
/* USER CODE END 6 */
@@ -287,7 +266,8 @@ uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
if (hcdc->TxState != 0){
return USBD_BUSY;
}
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
memcpy(UserTxBufferFS, Buf, Len);
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, Len);
result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);
/* USER CODE END 7 */
return result;
@@ -310,8 +290,8 @@ static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum)
uint8_t result = USBD_OK;
/* USER CODE BEGIN 13 */
UNUSED(Buf);
UNUSED(Len);
UNUSED(epnum);
_api_hal_vcp_tx_complete(*Len);
/* USER CODE END 13 */
return result;
}

View File

@@ -0,0 +1,10 @@
#include <api-hal-uid.h>
#include <stm32wbxx.h>
size_t api_hal_uid_size() {
return 64/8;
}
const uint8_t* api_hal_uid() {
return (const uint8_t *)UID64_BASE;
}

View File

@@ -0,0 +1,92 @@
#include <api-hal-vcp.h>
#include <usbd_cdc_if.h>
#include <flipper_v2.h>
#include <stream_buffer.h>
#define API_HAL_VCP_RX_BUFFER_SIZE 600
typedef struct {
StreamBufferHandle_t rx_stream;
osSemaphoreId_t tx_semaphore;
volatile bool alive;
volatile bool underrun;
} ApiHalVcp;
ApiHalVcp api_hal_vcp;
static const uint8_t ascii_soh = 0x01;
static const uint8_t ascii_eot = 0x04;
void _api_hal_vcp_init();
void _api_hal_vcp_deinit();
void _api_hal_vcp_control_line(uint8_t state);
void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size);
void _api_hal_vcp_tx_complete(size_t size);
void api_hal_vcp_init() {
api_hal_vcp.rx_stream = xStreamBufferCreate(API_HAL_VCP_RX_BUFFER_SIZE, 1);
api_hal_vcp.tx_semaphore = osSemaphoreNew(1, 1, NULL);
api_hal_vcp.alive = false;
api_hal_vcp.underrun = false;
}
void _api_hal_vcp_init() {
osSemaphoreRelease(api_hal_vcp.tx_semaphore);
}
void _api_hal_vcp_deinit() {
api_hal_vcp.alive = false;
osSemaphoreRelease(api_hal_vcp.tx_semaphore);
}
void _api_hal_vcp_control_line(uint8_t state) {
// bit 0: DTR state, bit 1: RTS state
// bool dtr = state & 0b01;
bool rts = state & 0b10;
if (rts) {
api_hal_vcp.alive = true;
_api_hal_vcp_rx_callback(&ascii_soh, 1); // SOH
} else {
api_hal_vcp.alive = false;
_api_hal_vcp_rx_callback(&ascii_eot, 1); // EOT
}
osSemaphoreRelease(api_hal_vcp.tx_semaphore);
}
void _api_hal_vcp_rx_callback(const uint8_t* buffer, size_t size) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
size_t ret = xStreamBufferSendFromISR(api_hal_vcp.rx_stream, buffer, size, &xHigherPriorityTaskWoken);
if (ret != size) {
api_hal_vcp.underrun = true;
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void _api_hal_vcp_tx_complete(size_t size) {
osSemaphoreRelease(api_hal_vcp.tx_semaphore);
}
size_t api_hal_vcp_rx(uint8_t* buffer, size_t size) {
return xStreamBufferReceive(api_hal_vcp.rx_stream, buffer, size, portMAX_DELAY);
}
void api_hal_vcp_tx(uint8_t* buffer, size_t size) {
while (size > 0 && api_hal_vcp.alive) {
furi_check(osSemaphoreAcquire(api_hal_vcp.tx_semaphore, osWaitForever) == osOK);
size_t batch_size = size;
if (batch_size > APP_TX_DATA_SIZE) {
batch_size = APP_TX_DATA_SIZE;
}
if (CDC_Transmit_FS(buffer, batch_size) == USBD_OK) {
size -= batch_size;
buffer += batch_size;
} else {
// Shouldn't be there
osDelay(100);
}
}
}

View File

@@ -1,7 +0,0 @@
#pragma once
#include "api-hal-gpio.h"
#include "api-hal-delay.h"
#include "api-hal-pwm.h"
#include "api-hal-task.h"
#include "api-hal-tim.h"

View File

@@ -270,6 +270,7 @@ Mcu.Pin12=PA2
PD0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
Mcu.Pin10=PA0
SH.GPXTI10.ConfNb=1
USB_DEVICE.APP_RX_DATA_SIZE=512
TIM2.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
PC3.GPIO_Label=PC3
PA3.PinState=GPIO_PIN_SET
@@ -453,7 +454,7 @@ OSC_IN.GPIOParameters=GPIO_Label
PB12.Locked=true
ProjectManager.DeletePrevious=true
PB10.Locked=true
USB_DEVICE.IPParameters=VirtualMode,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING,PRODUCT_STRING_CDC_FS
USB_DEVICE.IPParameters=VirtualMode,VirtualModeFS,CLASS_NAME_FS,MANUFACTURER_STRING,PRODUCT_STRING_CDC_FS,APP_RX_DATA_SIZE,APP_TX_DATA_SIZE
TIM16.Channel=TIM_CHANNEL_1
RCC.AHB2CLKDivider=RCC_SYSCLK_DIV2
RCC.FamilyName=M
@@ -528,6 +529,7 @@ PA13.Locked=true
RF1.Mode=RF1_Activate
PB7.Mode=Asynchronous
NVIC.EXTI9_5_IRQn=true\:5\:0\:true\:false\:true\:false\:true\:true
USB_DEVICE.APP_TX_DATA_SIZE=512
PA14.Signal=SYS_JTCK-SWCLK
PB2.GPIO_Label=PB2
PC6.GPIOParameters=GPIO_Label

View File

@@ -1,6 +1,6 @@
TOOLCHAIN = arm
DEBUG_AGENT = openocd -f interface/stlink-v2.cfg -c "transport select hla_swd" -f ../debug/stm32wbx.cfg -c "init" -c "reset halt"
DEBUG_AGENT = openocd -f interface/stlink.cfg -c "transport select hla_swd" -f target/stm32wbx.cfg -c "init"
BOOT_ADDRESS = 0x08000000
FW_ADDRESS = 0x08008000