You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
795 lines
19 KiB
795 lines
19 KiB
/* |
|
(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; }
|
|
|