mirror of https://github.com/ArduPilot/ardupilot
796 lines
19 KiB
C
796 lines
19 KiB
C
/*
|
|
(c) 2017 night_ghost@ykoctpa.ru
|
|
|
|
*/
|
|
|
|
#include <usb.h>
|
|
#include <hal.h>
|
|
#include <systick.h>
|
|
#include <exti.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <boards.h>
|
|
|
|
// bugfixes to ST USB stack - https://github.com/olegv142/stm32tivc_usb_cdc
|
|
// register description - http://mcu.goodboard.ru/viewtopic.php?id=40
|
|
|
|
|
|
/*
|
|
на поржать - https://kincajou.livejournal.com/4206484.html
|
|
товарисч копает USB :)
|
|
|
|
*/
|
|
|
|
|
|
//#define USB_DEBUG
|
|
|
|
typedef uint8_t U8;
|
|
typedef uint32_t U32;
|
|
typedef uint16_t U16;
|
|
|
|
|
|
extern USB_OTG_CORE_HANDLE USB_OTG_dev;
|
|
extern uint32_t USBD_OTG_ISR_Handler (const USB_OTG_CORE_HANDLE *pdev);
|
|
|
|
__ALIGN_BEGIN USB_OTG_CORE_HANDLE USB_OTG_dev __ALIGN_END;
|
|
|
|
static usb_attr_t *usb_attr;
|
|
static volatile U8 VCP_DTRHIGH = 0;
|
|
static volatile U8 VCP_RTSHIGH = 0;
|
|
|
|
enum reset_state_t {
|
|
DTR_UNSET,
|
|
DTR_HIGH,
|
|
DTR_NEGEDGE,
|
|
DTR_LOW
|
|
};
|
|
|
|
static enum reset_state_t reset_state = DTR_UNSET;
|
|
|
|
static const U16 rxfifo_size = USB_RXFIFO_SIZE;
|
|
//static const U16 txfifo_size = USB_TXFIFO_SIZE;
|
|
|
|
static ring_buffer _rxfifo IN_CCM;
|
|
//static ring_buffer _txfifo;
|
|
|
|
static ring_buffer *rxfifo = &_rxfifo; /* Rx FIFO */
|
|
//static ring_buffer *txfifo = &_txfifo; /* Rx FIFO */
|
|
|
|
static uint8_t rx_buf[USB_RXFIFO_SIZE]; // USB can work via DMA so no CCM!
|
|
//static uint8_t tx_buf[USB_TXFIFO_SIZE];
|
|
|
|
static U8 preempt_prio, sub_prio;
|
|
static U8 usb_ready;
|
|
|
|
static U8 UsbTXBlock = 1;
|
|
|
|
|
|
LINE_CODING linecoding = // not const!
|
|
{
|
|
115200, /* baud rate*/
|
|
0x00, /* stop bits-1*/
|
|
0x00, /* parity - none*/
|
|
0x08 /* nb. of bits 8*/
|
|
};
|
|
|
|
/* These are external variables imported from CDC core to be used for IN
|
|
transfer management. */
|
|
extern U8 APP_Rx_Buffer []; /* Write CDC received data in this buffer.
|
|
These data will be sent over USB IN endpoint
|
|
in the CDC core functions. */
|
|
extern U32 APP_Rx_ptr_in; /* Increment this pointer or roll it back to
|
|
start address when writing received data
|
|
in the buffer APP_Rx_Buffer. */
|
|
|
|
/* Private function prototypes -----------------------------------------------*/
|
|
static U16 VCP_Init (void);
|
|
static U16 VCP_DeInit (void);
|
|
static U16 VCP_Ctrl (uint32_t Cmd, uint8_t* Buf, uint32_t Len);
|
|
static U16 VCP_DataTx (const uint8_t* Buf, uint32_t Len);
|
|
static U16 VCP_DataRx (uint8_t* Buf, uint32_t Len);
|
|
|
|
// direct usage from usbd_cdc_core.c
|
|
const CDC_IF_Prop_TypeDef VCP_fops =
|
|
{
|
|
VCP_Init,
|
|
VCP_DeInit,
|
|
VCP_Ctrl,
|
|
VCP_DataTx,
|
|
VCP_DataRx
|
|
};
|
|
|
|
const USBD_Usr_cb_TypeDef USR_cb =
|
|
{
|
|
USBD_USR_Init,
|
|
USBD_USR_DeviceReset,
|
|
USBD_USR_DeviceConfigured,
|
|
USBD_USR_DeviceSuspended,
|
|
USBD_USR_DeviceResumed,
|
|
USBD_USR_DeviceConnected,
|
|
USBD_USR_DeviceDisconnected,
|
|
};
|
|
|
|
|
|
|
|
static const USBD_DEVICE USR_CDC_desc =
|
|
{
|
|
USBD_USR_DeviceDescriptor,
|
|
USBD_USR_LangIDStrDescriptor,
|
|
USBD_USR_ManufacturerStrDescriptor,
|
|
USBD_USR_ProductStrDescriptor,
|
|
USBD_USR_SerialStrDescriptor,
|
|
USBD_USR_ConfigStrDescriptor,
|
|
USBD_USR_InterfaceStrDescriptor,
|
|
|
|
};
|
|
|
|
/* USB Standard Device Descriptor */
|
|
__ALIGN_BEGIN U8 const USBD_DeviceDesc[USB_SIZ_DEVICE_DESC] __ALIGN_END =
|
|
{
|
|
0x12, /*bLength */
|
|
USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
|
|
0x00, /*bcdUSB */
|
|
0x02,
|
|
0x00, /*bDeviceClass*/
|
|
0x00, /*bDeviceSubClass*/
|
|
0x00, /*bDeviceProtocol*/
|
|
USB_OTG_MAX_EP0_SIZE, /*bMaxPacketSize*/
|
|
LOBYTE(USBD_VID), /*idVendor*/
|
|
HIBYTE(USBD_VID), /*idVendor*/
|
|
LOBYTE(USBD_PID), /*idVendor*/
|
|
HIBYTE(USBD_PID), /*idVendor*/
|
|
0x00, /*bcdDevice rel. 2.00*/
|
|
0x02,
|
|
USBD_IDX_MFC_STR, /*Index of manufacturer string*/
|
|
USBD_IDX_PRODUCT_STR, /*Index of product string*/
|
|
USBD_IDX_SERIAL_STR, /*Index of serial number string*/
|
|
USBD_CFG_MAX_NUM /*bNumConfigurations*/
|
|
} ; /* USB_DeviceDescriptor */
|
|
|
|
/* USB Standard Device Descriptor */
|
|
const __ALIGN_BEGIN U8 USBD_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
|
|
{
|
|
USB_LEN_DEV_QUALIFIER_DESC,
|
|
USB_DESC_TYPE_DEVICE_QUALIFIER,
|
|
0x00,
|
|
0x02,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x40,
|
|
0x01,
|
|
0x00,
|
|
};
|
|
|
|
|
|
// handler for hardware ISR
|
|
void OTG_FS_IRQHandler(void)
|
|
{
|
|
USBD_OTG_ISR_Handler(&USB_OTG_dev);
|
|
}
|
|
|
|
|
|
/* USB Standard Device Descriptor */
|
|
const __ALIGN_BEGIN U8 USBD_LangIDDesc[USB_SIZ_STRING_LANGID] __ALIGN_END =
|
|
{
|
|
USB_SIZ_STRING_LANGID,
|
|
USB_DESC_TYPE_STRING,
|
|
LOBYTE(USBD_LANGID_STRING),
|
|
HIBYTE(USBD_LANGID_STRING),
|
|
};
|
|
|
|
|
|
static U8 usb_connected =0;
|
|
static U8 usb_opened =0;
|
|
|
|
/* Return the device descriptor */
|
|
U8 * USBD_USR_DeviceDescriptor(U8 speed, U16 *length)
|
|
{
|
|
*length = sizeof(USBD_DeviceDesc);
|
|
return (U8 *)USBD_DeviceDesc;
|
|
}
|
|
|
|
/* return the LangID string descriptor */
|
|
U8 * USBD_USR_LangIDStrDescriptor(U8 speed, U16 *length)
|
|
{
|
|
*length = sizeof(USBD_LangIDDesc);
|
|
return (U8 *)USBD_LangIDDesc;
|
|
}
|
|
|
|
|
|
|
|
/* return the product string descriptor */
|
|
U8 * USBD_USR_ProductStrDescriptor(U8 speed, U16 *length)
|
|
{
|
|
USBD_GetString ((U8 *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);
|
|
|
|
return USBD_StrDesc;
|
|
}
|
|
|
|
/* return the manufacturer string descriptor */
|
|
U8 * USBD_USR_ManufacturerStrDescriptor(U8 speed, U16 *length)
|
|
{
|
|
USBD_GetString ((U8 *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
|
|
return USBD_StrDesc;
|
|
}
|
|
|
|
/* return the serial number string descriptor */
|
|
U8 * USBD_USR_SerialStrDescriptor(U8 speed, U16 *length)
|
|
{
|
|
USBD_GetString ((U8 *)USBD_SERIALNUMBER_FS_STRING, USBD_StrDesc, length);
|
|
return USBD_StrDesc;
|
|
}
|
|
|
|
/* return the configuration string descriptor */
|
|
U8 * USBD_USR_ConfigStrDescriptor(U8 speed , U16 *length)
|
|
{
|
|
USBD_GetString ((U8 *)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length);
|
|
return USBD_StrDesc;
|
|
}
|
|
|
|
|
|
/* return the interface string descriptor */
|
|
U8 * USBD_USR_InterfaceStrDescriptor( U8 speed , U16 *length)
|
|
{
|
|
USBD_GetString ((U8 *)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length);
|
|
return USBD_StrDesc;
|
|
}
|
|
|
|
void USBD_USR_Init(void)
|
|
{
|
|
usb_connected = 0;
|
|
usb_opened = 0;
|
|
}
|
|
|
|
void USBD_USR_DeviceReset(uint8_t speed )
|
|
{
|
|
switch (speed) {
|
|
case USB_OTG_SPEED_HIGH:
|
|
break;
|
|
case USB_OTG_SPEED_FULL:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void USBD_USR_DeviceConfigured (void)
|
|
{
|
|
usb_connected = 1;
|
|
usb_opened = 1; // just for case
|
|
}
|
|
|
|
void USBD_USR_DeviceSuspended(void)
|
|
{
|
|
usb_connected = 0;
|
|
usb_opened = 0;
|
|
}
|
|
|
|
|
|
void USBD_USR_DeviceResumed(void)
|
|
{
|
|
usb_connected = 1;
|
|
usb_opened = 1; // just for case
|
|
}
|
|
|
|
|
|
void USBD_USR_DeviceConnected (void)
|
|
{
|
|
usb_connected = 1;
|
|
usb_opened = 1; // just for case
|
|
}
|
|
|
|
|
|
void USBD_USR_DeviceDisconnected (void)
|
|
{
|
|
usb_connected = 0;
|
|
usb_opened = 0;
|
|
|
|
extern void usb_mass_mal_USBdisconnect();
|
|
usb_mass_mal_USBdisconnect(); //reset connection state for mass-storage
|
|
}
|
|
|
|
/*------------------------- usb_default_attr -------------------------------*/
|
|
|
|
void usb_default_attr(usb_attr_t *attr)
|
|
{
|
|
attr->preempt_prio = 0;
|
|
attr->sub_prio = 0;
|
|
attr->use_present_pin = 0;
|
|
// attr->description = NULL;
|
|
// attr->manufacturer = NULL;
|
|
// attr->serial_number = NULL;
|
|
// attr->configuration = NULL;
|
|
// attr->interface = NULL;
|
|
}
|
|
|
|
/*--------------------------- usb_periphcfg -------------------------------*/
|
|
|
|
void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev){ // callback for hardware init
|
|
return;
|
|
}
|
|
|
|
int usb_periphcfg(FunctionalState state)
|
|
{
|
|
USB_OTG_BSP_DisableInterrupt(); // disable IRQ
|
|
|
|
if (state == ENABLE) {
|
|
|
|
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA , ENABLE); // USB on GPIO_A
|
|
|
|
/* Configure USB D-/D+ (DM/DP) pins */
|
|
GPIO_InitTypeDef GPIO_InitStructure;
|
|
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; // sometimes touching of GPIO_Pin_12 causes interrupt which will not be served
|
|
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
|
|
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
|
|
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
|
|
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
|
|
GPIO_Init(GPIOA, &GPIO_InitStructure);
|
|
|
|
gpio_set_af_mode(_GPIOA, GPIO_PinSource11, GPIO_AF_OTG1_FS);
|
|
gpio_set_af_mode(_GPIOA, GPIO_PinSource12, GPIO_AF_OTG1_FS);
|
|
|
|
|
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
|
|
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE) ;
|
|
} else {
|
|
gpio_set_mode(DM_PIN_PORT, DM_PIN_PIN, GPIO_INPUT_FLOATING);
|
|
gpio_set_mode(DP_PIN_PORT, DP_PIN_PIN, GPIO_INPUT_FLOATING);
|
|
// we should not disable sysfg clock..
|
|
}
|
|
|
|
RCC_AHB2PeriphClockCmd(USB_CLOCK, state);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------- usb_configure -------------------------------*/
|
|
|
|
int usb_configure(usb_attr_t * attr)
|
|
{
|
|
if (attr == NULL)
|
|
return 0;
|
|
|
|
usb_setParams(attr);
|
|
|
|
// USB Device Initialize
|
|
USBD_Init(&USB_OTG_dev, USB_OTG_FS_CORE_ID, &USR_CDC_desc, &USBD_CDC_cb, &USR_cb);
|
|
|
|
usb_ready = 1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void usb_setParams(usb_attr_t * attr)
|
|
{
|
|
if (attr == NULL)
|
|
return;
|
|
|
|
if (attr->use_present_pin) {
|
|
if (!IS_GPIO_ALL_PERIPH(attr->present_port->GPIOx) || !IS_GPIO_PIN_SOURCE(attr->present_pin))
|
|
return;
|
|
gpio_set_mode(attr->present_port, attr->present_pin, GPIO_INPUT_FLOATING);
|
|
}
|
|
|
|
preempt_prio = attr->preempt_prio;
|
|
sub_prio = attr->sub_prio;
|
|
}
|
|
|
|
|
|
|
|
|
|
void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev)
|
|
{
|
|
enable_nvic_irq(OTG_FS_IRQn, preempt_prio);
|
|
}
|
|
|
|
void USB_OTG_BSP_DisableInterrupt()
|
|
{
|
|
NVIC_DisableIRQ(OTG_FS_IRQn);
|
|
}
|
|
|
|
void USB_OTG_BSP_mDelay (const uint32_t msec)
|
|
{
|
|
uint32_t start = hal_micros(), ms = msec;
|
|
|
|
while (ms > 0) {
|
|
while ((hal_micros() - start) >= 1000) {
|
|
ms--;
|
|
if (ms == 0) break;
|
|
start += 1000;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* VCP_Init
|
|
* Initializes the Media on the STM32
|
|
* @param None
|
|
* @retval Result of the opeartion (USBD_OK in all cases)
|
|
*/
|
|
static U16 VCP_Init(void)
|
|
{
|
|
rb_init(rxfifo, rxfifo_size, rx_buf);
|
|
// rb_init(txfifo, txfifo_size, tx_buf);
|
|
return USBD_OK;
|
|
}
|
|
|
|
/* VCP_DeInit
|
|
* DeInitializes the Media on the STM32
|
|
* @param None
|
|
* @retval Result of the opeartion (USBD_OK in all cases)
|
|
*/
|
|
static U16 VCP_DeInit(void)
|
|
{
|
|
return USBD_OK;
|
|
}
|
|
|
|
|
|
/* VCP_Ctrl
|
|
* Manage the CDC class requests
|
|
* @param Cmd: Command code
|
|
* @param Buf: Buffer containing command data (request parameters)
|
|
* @param Len: Number of data to be sent (in bytes)
|
|
* @retval Result of the opeartion (USBD_OK in all cases)
|
|
*/
|
|
static U16 VCP_Ctrl (U32 Cmd, U8 *Buf, U32 Len)
|
|
{
|
|
switch (Cmd) {
|
|
case SEND_ENCAPSULATED_COMMAND:
|
|
/* Not needed for this driver */
|
|
break;
|
|
|
|
case GET_ENCAPSULATED_RESPONSE:
|
|
/* Not needed for this driver */
|
|
break;
|
|
|
|
case SET_COMM_FEATURE:
|
|
/* Not needed for this driver */
|
|
break;
|
|
|
|
case GET_COMM_FEATURE:
|
|
/* Not needed for this driver */
|
|
break;
|
|
|
|
case CLEAR_COMM_FEATURE:
|
|
/* Not needed for this driver */
|
|
break;
|
|
|
|
case SET_LINE_CODING:
|
|
linecoding.bitrate = (uint32_t)(Buf[0] | (Buf[1] << 8) | (Buf[2] << 16) | (Buf[3] << 24));
|
|
linecoding.format = Buf[4];
|
|
linecoding.paritytype = Buf[5];
|
|
linecoding.datatype = Buf[6];
|
|
/* Set the new configuration */
|
|
break;
|
|
|
|
case GET_LINE_CODING:
|
|
Buf[0] = (uint8_t)(linecoding.bitrate);
|
|
Buf[1] = (uint8_t)(linecoding.bitrate >> 8);
|
|
Buf[2] = (uint8_t)(linecoding.bitrate >> 16);
|
|
Buf[3] = (uint8_t)(linecoding.bitrate >> 24);
|
|
Buf[4] = linecoding.format;
|
|
Buf[5] = linecoding.paritytype;
|
|
Buf[6] = linecoding.datatype;
|
|
break;
|
|
|
|
|
|
#define USB_CDCACM_CONTROL_LINE_DTR (0x01)
|
|
#define USB_CDCACM_CONTROL_LINE_RTS (0x02)
|
|
|
|
|
|
case SET_CONTROL_LINE_STATE:
|
|
linecoding.bitrate = (uint32_t)(Buf[0] | (Buf[1] << 8));
|
|
|
|
VCP_DTRHIGH = (Buf[0] & USB_CDCACM_CONTROL_LINE_DTR);
|
|
VCP_RTSHIGH = (Buf[0] & USB_CDCACM_CONTROL_LINE_RTS);
|
|
|
|
#ifdef DEBUG_BUILD
|
|
// { from Arduino32
|
|
// We need to see a negative edge on DTR before we start looking
|
|
// for the in-band magic reset byte sequence.
|
|
uint8_t dtr = VCP_DTRHIGH;
|
|
switch (reset_state) {
|
|
case DTR_UNSET:
|
|
reset_state = dtr ? DTR_HIGH : DTR_LOW;
|
|
break;
|
|
case DTR_HIGH:
|
|
reset_state = dtr ? DTR_HIGH : DTR_NEGEDGE;
|
|
break;
|
|
case DTR_NEGEDGE:
|
|
reset_state = dtr ? DTR_HIGH : DTR_LOW;
|
|
break;
|
|
case DTR_LOW:
|
|
reset_state = dtr ? DTR_HIGH : DTR_LOW;
|
|
break;
|
|
}
|
|
|
|
// as Arduino - reset on DTR negative edge
|
|
if ((linecoding.bitrate == 1200) && (reset_state == DTR_NEGEDGE)) {
|
|
// iwdg_init(IWDG_PRE_4, 10);
|
|
NVIC_SystemReset();
|
|
while (1);
|
|
}
|
|
//}
|
|
#endif
|
|
|
|
break;
|
|
|
|
case SEND_BREAK:
|
|
/* Not needed for this driver */
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
usb_opened = 1; // set active state only on VCP opening
|
|
usb_connected = 1; // just for case
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
/* VCP_DataTx
|
|
* CDC received data to be send over USB IN endpoint are managed in
|
|
* this function.
|
|
* @param Buf: Buffer of data to be sent
|
|
* @param Len: Number of data to be sent (in bytes)
|
|
* @retval Result of the opeartion: USBD_OK if all operations are OK else VCP_FAIL
|
|
*/
|
|
|
|
void VCP_MarkWritten(unsigned sz)
|
|
{
|
|
noInterrupts();
|
|
USB_Tx_buff_head = ring_wrap(USB_TX_BUFF_SIZE, USB_Tx_buff_head + sz);
|
|
interrupts();
|
|
}
|
|
|
|
unsigned VCP_SpaceAvailContig(void)
|
|
{
|
|
noInterrupts();
|
|
unsigned sz = ring_space_contig(USB_TX_BUFF_SIZE, USB_Tx_buff_head, USB_Tx_buff_tail);
|
|
interrupts();
|
|
return sz;
|
|
}
|
|
|
|
unsigned VCP_PutContig(void const* buff, unsigned len)
|
|
{
|
|
unsigned avail = VCP_SpaceAvailContig();
|
|
unsigned sz = MIN_(avail, len);
|
|
if (sz) {
|
|
memcpy(VCP_SpacePtr(), buff, sz);
|
|
VCP_MarkWritten(sz);
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
unsigned VCP_SpaceAvail(void)
|
|
{
|
|
noInterrupts();
|
|
unsigned sz = ring_space_avail(USB_TX_BUFF_SIZE, USB_Tx_buff_head, USB_Tx_buff_tail);
|
|
interrupts();
|
|
return sz;
|
|
}
|
|
|
|
U16 VCP_DataTx(const U8 *buffer, U32 nbytes)
|
|
{
|
|
|
|
unsigned sz = VCP_PutContig(buffer, nbytes);
|
|
if (sz && (nbytes -= sz))
|
|
sz += VCP_PutContig((uint8_t*)buffer + sz, nbytes);
|
|
return sz;
|
|
}
|
|
|
|
|
|
|
|
/* VCP_DataRx
|
|
* Data received over USB OUT endpoint are sent over CDC interface
|
|
* through this function.
|
|
*
|
|
* Note
|
|
* This function will block any OUT packet reception on USB endpoint
|
|
* untill exiting this function. If you exit this function before transfer
|
|
* is complete on CDC interface (ie. using DMA controller) it will result
|
|
* in receiving more data while previous ones are still not sent.
|
|
*
|
|
* @param Buf: Buffer of data to be received
|
|
* @param Len: Number of data received (in bytes)
|
|
* @retval Result of the opeartion: USBD_OK if all operations are OK else VCP_FAIL
|
|
*/
|
|
|
|
unsigned VCP_DataAvail(void)
|
|
{
|
|
noInterrupts();
|
|
unsigned sz = ring_data_avail(USB_Rx_buff_size, USB_Rx_buff_head, USB_Rx_buff_tail);
|
|
interrupts();
|
|
return sz;
|
|
}
|
|
|
|
|
|
void VCP_MarkRead(unsigned sz)
|
|
{
|
|
noInterrupts();
|
|
USB_Rx_buff_tail = ring_wrap(USB_Rx_buff_size, USB_Rx_buff_tail + sz);
|
|
interrupts();
|
|
}
|
|
|
|
unsigned VCP_GetContig(void* buff, unsigned max_len)
|
|
{
|
|
unsigned avail = VCP_DataAvailContig();
|
|
unsigned sz = MIN_(avail, max_len);
|
|
if (sz) {
|
|
memcpy(buff, VCP_DataPtr(), sz);
|
|
VCP_MarkRead(sz);
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
unsigned VCP_DataAvailContig(void)
|
|
{
|
|
noInterrupts();
|
|
unsigned sz = ring_data_contig(USB_Rx_buff_size, USB_Rx_buff_head, USB_Rx_buff_tail);
|
|
interrupts();
|
|
return sz;
|
|
}
|
|
|
|
static U16 VCP_DataRx(U8 *buffer, U32 nbytes)
|
|
{
|
|
usb_opened = 1; // data from other side
|
|
|
|
#ifdef DEBUG_BUILD
|
|
if(VCP_DTRHIGH) {
|
|
if(nbytes >= 4) {
|
|
if(buffer[0] == '1' && buffer[1] == 'E' && buffer[2] == 'A' && buffer[3] == 'F') {
|
|
nbytes = 0;
|
|
if(is_bare_metal()) // bare metal build without bootloader should reboot to DFU on this reset
|
|
board_set_rtc_register(DFU_RTC_SIGNATURE, RTC_SIGNATURE_REG);
|
|
|
|
NVIC_SystemReset();
|
|
}
|
|
}
|
|
}
|
|
VCP_DTRHIGH =0;
|
|
#endif
|
|
unsigned sz = VCP_GetContig(buffer, nbytes);
|
|
if (sz && (nbytes -= sz))
|
|
sz += VCP_GetContig((uint8_t*)buffer + sz, nbytes);
|
|
return sz;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*---------------------------- usb_open ---------------------------------*/
|
|
|
|
int usb_open(void)
|
|
{
|
|
usb_periphcfg(ENABLE);
|
|
|
|
usb_connected = 0;
|
|
preempt_prio = 0;
|
|
sub_prio = 0;
|
|
usb_ready = 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------- usb_close --------------------------------*/
|
|
|
|
int usb_close(void)
|
|
{
|
|
usb_periphcfg(DISABLE);
|
|
|
|
if (usb_ready == 1) {
|
|
DCD_DevDisconnect(&USB_OTG_dev);
|
|
USBD_DeInit(&USB_OTG_dev);
|
|
USB_OTG_StopDevice(&USB_OTG_dev);
|
|
usb_ready = 0;
|
|
}
|
|
|
|
if (usb_attr->use_present_pin){
|
|
gpio_set_mode(usb_attr->present_port, usb_attr->present_pin, GPIO_INPUT_FLOATING);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
uint8_t is_usb_connected(usb_attr_t *attr)
|
|
{
|
|
if (usb_attr == NULL || (usb_attr && usb_attr->use_present_pin == 0))
|
|
return usb_connected;
|
|
else
|
|
return gpio_read_bit(usb_attr->present_port, usb_attr->present_pin);
|
|
}
|
|
|
|
|
|
/*---------------------------- usb_ioctl --------------------------------*/
|
|
|
|
int usb_ioctl(int request, void *ctl)
|
|
{
|
|
switch(request) {
|
|
case I_USB_CLEAR:
|
|
if (!rxfifo) {
|
|
return 0;
|
|
}
|
|
rb_reset(rxfifo);
|
|
return 1;
|
|
|
|
case I_USB_CONNECTED:
|
|
*((U8 *)ctl) = is_usb_connected(usb_attr);
|
|
break;
|
|
|
|
case I_USB_GETATTR:
|
|
if (usb_attr) {
|
|
*((usb_attr_t **)ctl) = usb_attr;
|
|
} else {
|
|
return 0;
|
|
}
|
|
break;
|
|
case I_USB_SETATTR:
|
|
if (ctl == NULL) {
|
|
return 0;
|
|
}
|
|
usb_attr = (usb_attr_t *)ctl;
|
|
return usb_configure(usb_attr);
|
|
default:
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
// following functions can't be inline!
|
|
void USB_OTG_BSP_uDelay (const uint32_t usec) {
|
|
//stopwatch_delay_us(usec);
|
|
hal_delay_microseconds(usec);
|
|
}
|
|
|
|
int usb_write(const uint8_t *buf, unsigned int nbytes) {
|
|
return VCP_DataTx(buf, nbytes);
|
|
}
|
|
|
|
int usb_read(void * buf, unsigned int nbytes){
|
|
return VCP_DataRx(buf, nbytes);
|
|
}
|
|
|
|
uint32_t usb_data_available(void){
|
|
return VCP_DataAvail();
|
|
}
|
|
|
|
bool usb_get_dtr(){
|
|
return VCP_DTRHIGH;
|
|
}
|
|
|
|
void usb_reset_rx(){
|
|
rb_reset(rxfifo);
|
|
}
|
|
|
|
void usb_reset_tx(){
|
|
APP_Rx_ptr_in = 0;
|
|
}
|
|
|
|
uint16_t usb_tx_pending(void){
|
|
return USB_TX_BUFF_SIZE-VCP_SpaceAvail();
|
|
}
|
|
|
|
uint16_t usb_tx_space(void){
|
|
return VCP_SpaceAvail();
|
|
}
|
|
|
|
|
|
void VCP_SetUSBTxBlocking(uint8_t Mode) {
|
|
UsbTXBlock = Mode;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
|
|
uint8_t is_usb_opened() { return usb_opened; }
|
|
void reset_usb_opened() { usb_opened=0; }
|