mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-02-10 11:58:37 -05:00
1181 lines
59 KiB
C
1181 lines
59 KiB
C
/********************************** (C) COPYRIGHT *******************************
|
|
* File Name : CDC.C
|
|
* Author : WCH
|
|
* Version : V1.0
|
|
* Date : 2017/03/01
|
|
* Description : CH554 as CDC device to serial port, select serial port 1
|
|
*******************************************************************************/
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <ch554.h>
|
|
#include <ch554_usb.h>
|
|
|
|
#include "debug.h"
|
|
#include "mem.h"
|
|
#include "print.h"
|
|
#include "usb_strings.h"
|
|
|
|
XDATA AT0000 uint8_t Ep0Buffer[DEFAULT_EP0_SIZE] = { 0 }; // Endpoint 0, Default endpoint, OUT & IN buffer, must be an even address
|
|
XDATA AT0008 uint8_t Ep1Buffer[DEFAULT_EP1_SIZE] = { 0 }; // Endpoint 1, CDC Ctrl, IN[8] buffer
|
|
XDATA AT0010 uint8_t Ep2Buffer[2*MAX_PACKET_SIZE] = { 0 }; // Endpoint 2, CDC Data, buffer OUT[64]+IN[64], must be an even address
|
|
XDATA AT0090 uint8_t Ep3Buffer[2*MAX_PACKET_SIZE] = { 0 }; // Endpoint 3, HID, buffer OUT[64]+IN[64], must be an even address
|
|
|
|
uint16_t SetupLen = 0;
|
|
uint8_t SetupReq = 0;
|
|
uint8_t UsbConfig = 0;
|
|
const uint8_t *pDescr = NULL; // USB configuration flag
|
|
USB_SETUP_REQ SetupReqBuf = { 0 }; // Temporary Setup package
|
|
|
|
#define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer)
|
|
|
|
#define CDC_CTRL_EPIN_ADDR 0x81 // CDC Ctrl Endpoint IN Address
|
|
#define CDC_CTRL_EPIN_SIZE DEFAULT_EP1_SIZE // CDC Ctrl Endpoint IN Size
|
|
|
|
#define CDC_DATA_EPOUT_ADDR 0x02 // CDC Data Endpoint OUT Address
|
|
#define CDC_DATA_EPOUT_SIZE MAX_PACKET_SIZE // CDC Data Endpoint OUT Size
|
|
|
|
#define CDC_DATA_EPIN_ADDR 0x82 // CDC Data Endpoint IN Address
|
|
#define CDC_DATA_EPIN_SIZE MAX_PACKET_SIZE // CDC Data Endpoint IN Size
|
|
|
|
#define HID_EPOUT_ADDR 0x03 // HID Endpoint OUT Address
|
|
#define HID_EPOUT_SIZE MAX_PACKET_SIZE // HID Endpoint OUT Size
|
|
|
|
#define HID_EPIN_ADDR 0x83 // HID Endpoint IN Address
|
|
#define HID_EPIN_SIZE MAX_PACKET_SIZE // HID Endpoint IN Size
|
|
|
|
#define CDC_CTRL_FS_BINTERVAL 0xFF // 255 ms polling interval at Full Speed
|
|
#define CDC_DATA_FS_BINTERVAL 1 /* was: 0 */ // 1 ms polling interval at Full Speed
|
|
#define HID_FS_BINTERVAL 1 // 1 ms polling interval at Full Speed
|
|
|
|
#define HID_REPORT_DESC_SIZE 47 // HID Report Descriptor size
|
|
|
|
#define LOBYTE(x) ((uint8_t)( (x) & 0x00FFU))
|
|
#define HIBYTE(x) ((uint8_t)(((x) & 0xFF00U) >> 8U))
|
|
|
|
// Device Descriptor
|
|
FLASH uint8_t DevDesc[] = {
|
|
0x12, /* bLength */
|
|
USB_DESC_TYPE_DEVICE, /* bDescriptorType: Device */
|
|
0x10, /* bcdUSB (low byte), USB Specification Release Number in Binary-Coded Decimal (1.10 is 110h) */
|
|
0x01, /* bcdUSB (high byte) USB Specification Release Number in Binary-Coded Decimal (1.10 is 110h) */
|
|
0x00, /* bDeviceClass */ // Each configuration has its own class
|
|
0x00, /* bDeviceSubClass */ // Each configuration has its own sub-class
|
|
0x00, /* bDeviceProtocol */ // Each configuration has its own protocol
|
|
DEFAULT_EP0_SIZE, /* bMaxPacketSize */
|
|
0x07, /* idVendor */ // VID LOBYTE
|
|
0x12, /* idVendor */ // VID HIBYTE
|
|
0x87, /* idProduct */ // PID LOBYTE
|
|
0x88, /* idProduct */ // PID HIBYTE
|
|
0x00, /* bcdDevice (low byte, i.e. YY) rel. XX.YY */
|
|
0x01, /* bcdDevice (high byte, i.e. XX) rel. XX.YY */ // Orig: 0x02
|
|
0x01, /* Index of manufacturer string */
|
|
0x02, /* Index of product string */
|
|
0x03, /* Index of serial number string */
|
|
0x01, /* bNumConfigurations */
|
|
};
|
|
|
|
// Configuration Descriptor
|
|
FLASH uint8_t CfgDesc[] = {
|
|
/******************** Configuration Descriptor ********************/
|
|
0x09, /* bLength: Configuration Descriptor size */
|
|
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
99U, /* wTotalLength (low byte): Bytes returned */
|
|
0x00, /* wTotalLength (high byte): Bytes returned */
|
|
0x03, /* bNumInterfaces: 3 interfaces (1 CDC Ctrl, 1 CDC Data, 1 HID) */
|
|
0x01, /* bConfigurationValue: Configuration value */
|
|
0x00, /* iConfiguration: Index of string descriptor describing the configuration */
|
|
0xA0, /*Mouse:0xE0,whatis:0xC0?*/ /* bmAttributes: Bus powered and Support Remote Wake-up */
|
|
0x32, /* MaxPower 100 mA: this current is used for detecting Vbus */
|
|
/******************** Interface 0, CDC Ctrl Descriptor (one endpoint) ********************/
|
|
/* 9 */
|
|
0x09, /* bLength: Interface Descriptor size */
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
|
|
0x00, /* bInterfaceNumber: Number of Interface */
|
|
0x00, /* bAlternateSetting: Alternate setting */
|
|
0x01, /* bNumEndpoints */
|
|
USB_DEV_CLASS_CDC_CONTROL, /* bInterfaceClass: Communications and CDC Control */
|
|
0x02, /* bInterfaceSubClass : Abstract Control Model */
|
|
0x01, /* bInterfaceProtocol : AT Commands: V.250 etc */
|
|
0x00, /* iInterface: Index of string descriptor */
|
|
/******************** Header Functional Descriptor ********************/
|
|
/* 18 */
|
|
0x05, /* bFunctionLength: Size of this descriptor in bytes */
|
|
USB_DESC_TYPE_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE (24h) */
|
|
0x00, /* bDescriptorSubtype: Header Functional Descriptor */
|
|
0x10, /* bcdCDC (low byte): CDC version 1.10 */
|
|
0x01, /* bcdCDC (high byte): CDC version 1.10 */
|
|
/******************** Call Management Functional Descriptor (no data interface, bmCapabilities=03, bDataInterface=01) ********************/
|
|
/* 23 */
|
|
0x05, /* bFunctionLength: Size of this descriptor */
|
|
USB_DESC_TYPE_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE (24h) */
|
|
0x01, /* bDescriptorSubtype: Call Management Functional Descriptor */
|
|
0x00, /* bmCapabilities:
|
|
D7..2: 0x00 (RESERVED,
|
|
D1 : 0x00 (0 - Device sends/receives call management information only over the Communications Class interface
|
|
1 - Device can send/receive call management information over a Data Class interface)
|
|
D0 : 0x00 (0 - Device does not handle call management itself
|
|
1 - Device handles call management itself) */
|
|
0x00, /* bDataInterface: Interface number of Data Class interface optionally used for call management */
|
|
/******************** Abstract Control Management Functional Descriptor ********************/
|
|
/* 28 */
|
|
0x04, /* bLength */
|
|
0x24, /* bDescriptorType: CS_INTERFACE (24h) */
|
|
0x02, /* bDescriptorSubtype: Abstract Control Management Functional Descriptor */
|
|
0x02, /* bmCapabilities:
|
|
D7..4: 0x00 (RESERVED, Reset to zero)
|
|
D3 : 0x00 (1 - Device supports the notification Network_Connection)
|
|
D2 : 0x00 (1 - Device supports the request Send_Break)
|
|
D1 : 0x01 (1 - Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State)
|
|
D0 : 0x00 (1 - Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature) */
|
|
/******************** Union Functional Descriptor. CDC Ctrl interface numbered 0; CDC Data interface numbered 1 ********************/
|
|
/* 32 */
|
|
0x05, /* bLength */
|
|
0x24, /* bDescriptorType: CS_INTERFACE (24h) */
|
|
0x06, /* bDescriptorSubtype: Union Functional Descriptor */
|
|
0x00, /* bControlInterface: Interface number 0 (Control interface) */
|
|
0x01, /* bSubordinateInterface0: Interface number 1 (Data interface) */
|
|
/******************** CDC Ctrl Endpoint descriptor (IN) ********************/
|
|
/* 37 */
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_CTRL_EPIN_ADDR, /* bEndpointAddress: Endpoint Address (IN) */
|
|
USB_EP_TYPE_INTERRUPT, /* bmAttributes: Interrupt Endpoint */
|
|
LOBYTE(CDC_CTRL_EPIN_SIZE), /* wMaxPacketSize (low byte): 8 Byte max */
|
|
HIBYTE(CDC_CTRL_EPIN_SIZE), /* wMaxPacketSize (high byte): 8 Byte max */
|
|
CDC_CTRL_FS_BINTERVAL, /* bInterval: Polling Interval */
|
|
/******************** Interface 1, CDC Data Descriptor (two endpoints) ********************/
|
|
/* 44 */
|
|
0x09, /* bLength: Interface Descriptor size */
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
|
|
0x01, /* bInterfaceNumber: Number of Interface */
|
|
0x00, /* bAlternateSetting: Alternate setting */
|
|
0x02, /* bNumEndpoints */
|
|
USB_DEV_CLASS_CDC_DATA, /* bInterfaceClass: CDC Data */
|
|
0x00, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
|
0x00, /* bInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
|
|
0x00, /* iInterface: Index of string descriptor */
|
|
/******************** CDC Data Endpoint descriptor (OUT) ********************/
|
|
/* 53 */
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_DATA_EPOUT_ADDR, /* bEndpointAddress: Endpoint Address (OUT) */
|
|
USB_EP_TYPE_BULK, /* bmAttributes: Bulk Endpoint */
|
|
LOBYTE(CDC_DATA_EPOUT_SIZE), /* wMaxPacketSize (low byte): 64 Byte max */
|
|
HIBYTE(CDC_DATA_EPOUT_SIZE), /* wMaxPacketSize (high byte): 64 Byte max */
|
|
CDC_DATA_FS_BINTERVAL, /* bInterval: Polling Interval */
|
|
/******************** CDC Data Endpoint descriptor (IN) ********************/
|
|
/* 60 */
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_DATA_EPIN_ADDR, /* bEndpointAddress: Endpoint Address (IN) */
|
|
USB_EP_TYPE_BULK, /* bmAttributes: Bulk Endpoint */
|
|
LOBYTE(CDC_DATA_EPIN_SIZE), /* wMaxPacketSize (low byte): 64 Byte max */
|
|
HIBYTE(CDC_DATA_EPIN_SIZE), /* wMaxPacketSize (high byte): 64 Byte max */
|
|
CDC_DATA_FS_BINTERVAL, /* bInterval: Polling Interval */
|
|
/******************** Interface 2, HID Descriptor (two endpoints) ********************/
|
|
/* 67 */
|
|
0x09, /* bLength: Interface Descriptor size */
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface */
|
|
0x02, /* bInterfaceNumber: Number of Interface */
|
|
0x00, /* bAlternateSetting: Alternate setting */
|
|
0x02, /* bNumEndpoints: 2 */
|
|
USB_DEV_CLASS_HID, /* bInterfaceClass: Human Interface Device */
|
|
0x00, /* bInterfaceSubClass : 1=BOOT, 0=no boot */
|
|
0x00, /* bInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
|
|
0x00, /* iInterface: Index of string descriptor */
|
|
/******************** HID Device Descriptor ********************/
|
|
/* 76 */
|
|
0x09, /* bLength: HID Descriptor size */
|
|
USB_DESC_TYPE_HID, /* bDescriptorType: HID */
|
|
0x11, /* bcdHID (low byte): HID Class Spec release number */
|
|
0x01, /* bcdHID (high byte): HID Class Spec release number */
|
|
0x00, /* bCountryCode: Hardware target country */
|
|
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
|
|
USB_DESC_TYPE_REPORT, /* bDescriptorType: Report */
|
|
LOBYTE(HID_REPORT_DESC_SIZE), /* wDescriptorLength (low byte): Total length of Report descriptor */
|
|
HIBYTE(HID_REPORT_DESC_SIZE), /* wDescriptorLength (high byte): Total length of Report descriptor */
|
|
/******************** HID Endpoint Descriptor (OUT) ********************/
|
|
/* 85 */
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
HID_EPOUT_ADDR, /* bEndpointAddress: Endpoint Address (OUT) */
|
|
USB_EP_TYPE_INTERRUPT, /* bmAttributes: Interrupt endpoint */
|
|
LOBYTE(HID_EPOUT_SIZE), /* wMaxPacketSize (low byte): 64 Byte max */
|
|
HIBYTE(HID_EPOUT_SIZE), /* wMaxPacketSize (high byte): 64 Byte max */
|
|
HID_FS_BINTERVAL, /* bInterval: Polling Interval */
|
|
/******************** HID Endpoint Descriptor (IN) ********************/
|
|
/* 92 */
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
HID_EPIN_ADDR, /* bEndpointAddress: Endpoint Address (IN) */
|
|
USB_EP_TYPE_INTERRUPT, /* bmAttributes: Interrupt endpoint */
|
|
LOBYTE(HID_EPIN_SIZE), /* wMaxPacketSize (low byte): 64 Byte max */
|
|
HIBYTE(HID_EPIN_SIZE), /* wMaxPacketSize (high byte): 64 Byte max */
|
|
HID_FS_BINTERVAL, /* bInterval: Polling Interval */
|
|
/* 99 */
|
|
};
|
|
|
|
// HID Device Descriptor (copy from CfgDesc)
|
|
FLASH uint8_t HID_CfgDesc[] = {
|
|
0x09, /* bLength: HID Descriptor size */
|
|
USB_DESC_TYPE_HID, /* bDescriptorType: HID */
|
|
0x11, /* bcdHID (low byte): HID Class Spec release number */
|
|
0x01, /* bcdHID (high byte): HID Class Spec release number */
|
|
0x00, /* bCountryCode: Hardware target country */
|
|
0x01, /* bNumDescriptors: Number of HID class descriptors to follow */
|
|
USB_DESC_TYPE_REPORT, /* bDescriptorType: Report */
|
|
LOBYTE(HID_REPORT_DESC_SIZE), /* wDescriptorLength (low byte): Total length of Report descriptor */
|
|
HIBYTE(HID_REPORT_DESC_SIZE), /* wDescriptorLength (high byte): Total length of Report descriptor */
|
|
};
|
|
|
|
FLASH uint8_t HID_ReportDesc[] ={
|
|
0x06, 0xD0, 0xF1, /* Usage Page (FIDO Alliance Page) */
|
|
0x09, 0x01, /* Usage (U2F Authenticator Device) */
|
|
0xA1, 0x01, /* Collection (Application) */
|
|
|
|
0x09, 0x20, /* Usage (Input Report Data) */
|
|
0x15, 0x00, /* Logical Minimum (0) */
|
|
0x26, 0xFF, 0x00, /* Logical Maximum (255) */
|
|
0x75, 0x08, /* Report Size (8) */
|
|
0x95, MAX_PACKET_SIZE, /* Report Count (64) */
|
|
0x81, 0x02, /* Input (Data, Variable, Absolute); */
|
|
|
|
0x09, 0x21, /* Usage (Output Report Data) */
|
|
0x15, 0x00, /* Logical Minimum (0) */
|
|
0x26, 0xFF, 0x00, /* Logical Maximum (255) */
|
|
0x75, 0x08, /* Report Size (8) */
|
|
0x95, MAX_PACKET_SIZE, /* Report Count (64) */
|
|
0x91, 0x02, /* Output (Data, Variable, Absolute); */
|
|
|
|
0x09, 0x07, /* Usage (7, Reserved) */
|
|
0x15, 0x00, /* Logical Minimum (0) */
|
|
0x26, 0xFF, 0x00, /* Logical Maximum (255) */
|
|
0x75, 0x08, /* Report Size (8) */
|
|
0x95, 0x08, /* Report Count (8) */
|
|
0xB1, 0x02, /* Feature (2) (???) */
|
|
|
|
0xC0 /* End Collection */
|
|
};
|
|
|
|
// String Descriptor (Language descriptor )
|
|
FLASH uint8_t LangDesc[] = {
|
|
0x04, 0x03, 0x09, 0x04
|
|
};
|
|
|
|
// CDC Parameters: The initial baud rate is 500000, 1 stop bit, no parity, 8 data bits.
|
|
XDATA uint8_t LineCoding[7] = { 0x20, 0xA1, 0x07, 0x00, /* Data terminal rate, in bits per second: 500000 */
|
|
0x00, /* Stop bits: 0 - 1 Stop bit, 1 - 1.5 Stop bits, 2 - 2 Stop bits */
|
|
0x00, /* Parity: 0 - None, 1 - Odd, 2 - Even, 3 - Mark, 4 - Space */
|
|
0x08, /* Data bits (5, 6, 7, 8 or 16) */
|
|
};
|
|
|
|
#define HID_FRAME_SIZE 64
|
|
#define MAX_CDC_FRAME_SIZE 32
|
|
|
|
#define UART_TX_BUF_SIZE 64 // Serial transmit buffer
|
|
#define UART_RX_BUF_SIZE ((HID_FRAME_SIZE*2)+4) // Serial receive buffer
|
|
|
|
/** Communication UART */
|
|
XDATA uint8_t UartTxBuf[UART_TX_BUF_SIZE] = { 0 }; // Serial transmit buffer
|
|
volatile IDATA uint8_t byte_len;
|
|
|
|
XDATA uint8_t UartRxBuf[UART_RX_BUF_SIZE] = { 0 }; // Serial receive buffer
|
|
volatile IDATA uint8_t UartRxBufInputPointer = 0; // Circular buffer write pointer, bus reset needs to be initialized to 0
|
|
volatile IDATA uint8_t UartRxBufOutputPointer = 0; // Take pointer out of circular buffer, bus reset needs to be initialized to 0
|
|
volatile IDATA uint8_t UartRxBufByteCount = 0; // Number of unprocessed bytes remaining in the buffer
|
|
volatile IDATA uint8_t UartRxBufOverflow = 0;
|
|
|
|
/** Debug UART */
|
|
#define DEBUG_UART_RX_BUF_SIZE 8
|
|
XDATA uint8_t DebugUartRxBuf[DEBUG_UART_RX_BUF_SIZE] = { 0 };
|
|
volatile IDATA uint8_t DebugUartRxBufInputPointer = 0;
|
|
volatile IDATA uint8_t DebugUartRxBufOutputPointer = 0;
|
|
volatile IDATA uint8_t DebugUartRxBufByteCount = 0;
|
|
|
|
/** Endpoint handling */
|
|
volatile IDATA uint8_t UsbEp2ByteCount = 0; // Represents the data received by USB endpoint 2 (CDC)
|
|
volatile IDATA uint8_t UsbEp3ByteCount = 0; // Represents the data received by USB endpoint 3 (HID)
|
|
volatile IDATA uint8_t Endpoint2UploadBusy = 0; // Whether the upload endpoint 2 (CDC) is busy
|
|
volatile IDATA uint8_t Endpoint3UploadBusy = 0; // Whether the upload endpoint 3 (HID) is busy
|
|
|
|
/** CDC and HID variables */
|
|
volatile IDATA uint32_t LoopCounter = 0;
|
|
volatile IDATA uint32_t LastReceiveCounter = 0;
|
|
|
|
XDATA uint8_t CdcRxBuf[MAX_CDC_FRAME_SIZE] = { 0 };
|
|
IDATA uint8_t CdcRxBufLength = 0;
|
|
IDATA uint8_t CdcDataAvailable = 0;
|
|
IDATA uint32_t CdcLoopCount = 0;
|
|
|
|
XDATA uint8_t HidRxBuf[HID_FRAME_SIZE] = { 0 };
|
|
IDATA uint8_t HidRxBufLength;
|
|
IDATA uint8_t HidDataAvailable;
|
|
|
|
/** Frame data */
|
|
#define FRAME_TIMEOUT 10000 // Timeout in number of main loop iterations
|
|
|
|
#define MODE_CDC 0x40
|
|
#define MODE_HID 0x80
|
|
#define MODE_MASK 0xC0
|
|
#define NUM_MASK 0x3F
|
|
|
|
volatile IDATA uint8_t FrameMode = 0;
|
|
volatile IDATA uint8_t FrameLength = 0;
|
|
volatile IDATA uint8_t FrameStarted = 0;
|
|
volatile IDATA uint8_t Halted = 0;
|
|
|
|
/*******************************************************************************
|
|
* Function Name : USBDeviceCfg()
|
|
* Description : USB device mode configuration
|
|
* Input : None
|
|
* Output : None
|
|
* Return : None
|
|
*******************************************************************************/
|
|
void USBDeviceCfg()
|
|
{
|
|
USB_CTRL = 0x00; // Clear USB control register
|
|
USB_CTRL &= ~bUC_HOST_MODE; // This bit selects the device mode
|
|
USB_CTRL |= bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; // USB device and internal pull-up enable, automatically return to NAK before interrupt flag is cleared
|
|
USB_DEV_AD = 0x00; // Device address initialization
|
|
#if 0
|
|
// USB_CTRL |= bUC_LOW_SPEED;
|
|
// UDEV_CTRL |= bUD_LOW_SPEED; // Select low speed 1.5M mode
|
|
#else
|
|
USB_CTRL &= ~bUC_LOW_SPEED;
|
|
UDEV_CTRL &= ~bUD_LOW_SPEED; // Select full speed 12M mode, the default mode
|
|
#endif
|
|
UDEV_CTRL = bUD_PD_DIS; // Disable DP / DM pull-down resistor
|
|
UDEV_CTRL |= bUD_PORT_EN; // Enable physical port
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Function Name : USBDeviceIntCfg()
|
|
* Description : USB device mode interrupt initialization
|
|
* Input : None
|
|
* Output : None
|
|
* Return : None
|
|
*******************************************************************************/
|
|
void USBDeviceIntCfg()
|
|
{
|
|
USB_INT_EN |= bUIE_SUSPEND; // Enable device suspend interrupt
|
|
USB_INT_EN |= bUIE_TRANSFER; // Enable USB transfer completion interrupt
|
|
USB_INT_EN |= bUIE_BUS_RST; // Enable device mode USB bus reset interrupt
|
|
USB_INT_FG |= (UIF_FIFO_OV | UIF_HST_SOF | UIF_SUSPEND | UIF_TRANSFER | UIF_BUS_RST ); // Clear interrupt flag
|
|
IE_USB = 1; // Enable USB interrupt
|
|
EA = 1; // Allow microcontroller interrupt
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Function Name : USBDeviceEndPointCfg()
|
|
* Description : USB device mode endpoint configuration, simulation compatible
|
|
* HID device, in addition to endpoint 0 control transmission,
|
|
* also includes endpoint 2 batch upload
|
|
* Input : None
|
|
* Output : None
|
|
* Return : None
|
|
*******************************************************************************/
|
|
void USBDeviceEndPointCfg()
|
|
{
|
|
// TODO: Is casting the right thing here? What about endianness?
|
|
UEP0_DMA = (uint16_t) Ep0Buffer; // Endpoint 0 data transfer address
|
|
UEP1_DMA = (uint16_t) Ep1Buffer; // Endpoint 1 sends data transfer address
|
|
UEP2_DMA = (uint16_t) Ep2Buffer; // Endpoint 2 IN data transfer address
|
|
UEP3_DMA = (uint16_t) Ep3Buffer; // Endpoint 3 IN data transfer address
|
|
|
|
UEP4_1_MOD = bUEP1_TX_EN; // Endpoint 1, transmit enable; Endpoint 0 single 8-byte send and receive buffer
|
|
UEP2_3_MOD = bUEP2_TX_EN | bUEP2_RX_EN | bUEP3_TX_EN | bUEP3_RX_EN; // Endpoint 2/3, single buffer, transmit+receive enable
|
|
|
|
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; // Manual flip, OUT transaction returns ACK, IN transaction returns NAK
|
|
UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK; // Endpoint 1 automatically flips the synchronization flag, IN transaction returns NAK
|
|
UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK; // Endpoint 2 automatically flips the synchronization flag, IN transaction returns NAK, OUT returns ACK
|
|
UEP3_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK; // Endpoint 3 automatically flips the synchronization flag, IN transaction returns NAK, OUT returns ACK
|
|
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Function Name : Config_Uart1(uint8_t *cfg_uart)
|
|
* Description : Configure serial port 1 parameters
|
|
* Input : Serial port configuration parameters Four bit baud rate, stop bit, parity, data bit
|
|
* Output : None
|
|
* Return : None
|
|
*******************************************************************************/
|
|
void Config_Uart1(uint8_t *cfg_uart)
|
|
{
|
|
uint32_t uart1_buad = 0;
|
|
*((uint8_t*) &uart1_buad) = cfg_uart[0];
|
|
*((uint8_t*) &uart1_buad + 1) = cfg_uart[1];
|
|
*((uint8_t*) &uart1_buad + 2) = cfg_uart[2];
|
|
*((uint8_t*) &uart1_buad + 3) = cfg_uart[3];
|
|
SBAUD1 = 256 - FREQ_SYS / 16 / uart1_buad; // SBAUD1 = 256 - Fsys / 16 / baud rate
|
|
IE_UART1 = 1; // Enable UART1 interrupt
|
|
}
|
|
|
|
void usb_irq_setup_handler(void)
|
|
{
|
|
uint16_t len = USB_RX_LEN;
|
|
printStrSetup("Setup ");
|
|
|
|
if (len == (sizeof(USB_SETUP_REQ))) {
|
|
SetupLen = ((uint16_t) UsbSetupBuf->wLengthH << 8) | (UsbSetupBuf->wLengthL);
|
|
len = 0; // Defaults to success and uploading 0 length
|
|
SetupReq = UsbSetupBuf->bRequest;
|
|
|
|
// Class-Specific Requests, i.e. HID request, CDC request etc.
|
|
if ((UsbSetupBuf->bmRequestType & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD) {
|
|
printStrSetup("Class-Specific ");
|
|
printStrSetup("SetupReq=");
|
|
printStrSetup("0x");
|
|
printNumHexSetup(SetupReq);
|
|
printStrSetup(" ");
|
|
switch(SetupReq) {
|
|
case USB_HID_REQ_TYPE_GET_REPORT:
|
|
printStrSetup("HID Get Report\n");
|
|
break;
|
|
case USB_HID_REQ_TYPE_GET_IDLE:
|
|
printStrSetup("HID Get Idle\n");
|
|
break;
|
|
case USB_HID_REQ_TYPE_GET_PROTOCOL:
|
|
printStrSetup("HID Get Protocol\n");
|
|
break;
|
|
case USB_HID_REQ_TYPE_SET_REPORT:
|
|
printStrSetup("HID Set Report\n");
|
|
break;
|
|
case USB_HID_REQ_TYPE_SET_IDLE:
|
|
printStrSetup("HID Set Idle\n");
|
|
break;
|
|
case USB_HID_REQ_TYPE_SET_PROTOCOL:
|
|
printStrSetup("HID Set Protocol\n");
|
|
break;
|
|
case USB_CDC_REQ_TYPE_SET_LINE_CODING:
|
|
printStrSetup("CDC Set Line Coding\n");
|
|
break;
|
|
case USB_CDC_REQ_TYPE_GET_LINE_CODING:
|
|
printStrSetup("CDC Get Line Coding\n");
|
|
pDescr = LineCoding;
|
|
len = sizeof(LineCoding);
|
|
len = SetupLen >= DEFAULT_EP0_SIZE ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
|
|
memcpy(Ep0Buffer, pDescr, len);
|
|
SetupLen -= len;
|
|
pDescr += len;
|
|
break;
|
|
case USB_CDC_REQ_TYPE_SET_CONTROL_LINE_STATE: // Generates RS-232/V.24 style control signals
|
|
printStrSetup("CDC Set Control Line State\n");
|
|
break;
|
|
default:
|
|
len = 0xFF; // Command not supported
|
|
printStrSetup("Unsupported\n");
|
|
break;
|
|
}
|
|
} // END Non-standard request
|
|
|
|
else { // Standard Requests
|
|
// Request code
|
|
switch (SetupReq) {
|
|
case USB_GET_DESCRIPTOR: {
|
|
switch (UsbSetupBuf->wValueH) {
|
|
case USB_DESC_TYPE_DEVICE: // Device descriptor
|
|
pDescr = DevDesc; // Send the device descriptor to the buffer to be sent
|
|
len = sizeof(DevDesc);
|
|
printStrSetup("DevDesc\n");
|
|
break;
|
|
case USB_DESC_TYPE_CONFIGURATION: // Configuration descriptor
|
|
pDescr = CfgDesc; // Send the configuration descriptor to the buffer to be sent
|
|
len = sizeof(CfgDesc);
|
|
printStrSetup("CfgDesc\n");
|
|
break;
|
|
case USB_DESC_TYPE_STRING: // String descriptors
|
|
if (UsbSetupBuf->wValueL == USB_IDX_LANGID_STR) {
|
|
pDescr = LangDesc;
|
|
len = sizeof(LangDesc);
|
|
printStrSetup("LangDesc\n");
|
|
} else if (UsbSetupBuf->wValueL == USB_IDX_MFC_STR) {
|
|
pDescr = ManufDesc;
|
|
len = sizeof(ManufDesc);
|
|
printStrSetup("ManufDesc\n");
|
|
} else if (UsbSetupBuf->wValueL == USB_IDX_PRODUCT_STR) {
|
|
pDescr = ProdDesc;
|
|
len = sizeof(ProdDesc);
|
|
printStrSetup("ProdDesc\n");
|
|
} else if (UsbSetupBuf->wValueL == USB_IDX_SERIAL_STR) {
|
|
pDescr = SerialDesc;
|
|
len = sizeof(SerialDesc);
|
|
printStrSetup("SerialDesc\n");
|
|
} else {
|
|
printStrSetup("Error: USB_DESC_TYPE_STRING\n");
|
|
}
|
|
break;
|
|
case USB_DESC_TYPE_HID:
|
|
pDescr = HID_CfgDesc;
|
|
len = sizeof(HID_CfgDesc);
|
|
printStrSetup("HID_CfgDesc\n");
|
|
break;
|
|
case USB_DESC_TYPE_REPORT:
|
|
pDescr = HID_ReportDesc;
|
|
len = sizeof(HID_ReportDesc);
|
|
printStrSetup("HID_ReportDesc\n");
|
|
break;
|
|
default:
|
|
len = 0xFF; // Unsupported command or error
|
|
printStrSetup("Unsupported\n");
|
|
break;
|
|
}
|
|
|
|
if (SetupLen > len) {
|
|
SetupLen = len; // Limit total length
|
|
}
|
|
|
|
len = SetupLen >= DEFAULT_EP0_SIZE ? DEFAULT_EP0_SIZE : SetupLen; // This transmission length
|
|
memcpy(Ep0Buffer, pDescr, len); // Copy upload data
|
|
SetupLen -= len;
|
|
pDescr += len;
|
|
}
|
|
break;
|
|
|
|
case USB_SET_ADDRESS:
|
|
SetupLen = UsbSetupBuf->wValueL; // Temporary storage of USB device address
|
|
printStrSetup("SetAddress\n");
|
|
break;
|
|
|
|
case USB_GET_CONFIGURATION:
|
|
Ep0Buffer[0] = UsbConfig;
|
|
if (SetupLen >= 1) {
|
|
len = 1;
|
|
}
|
|
printStrSetup("GetConfig\n");
|
|
break;
|
|
|
|
case USB_SET_CONFIGURATION:
|
|
UsbConfig = UsbSetupBuf->wValueL;
|
|
printStrSetup("SetConfig\n");
|
|
break;
|
|
|
|
case USB_GET_INTERFACE:
|
|
printStrSetup("GetInterface\n");
|
|
break;
|
|
|
|
case USB_CLEAR_FEATURE: // Clear Feature
|
|
printStrSetup("ClearFeature\n");
|
|
if ((UsbSetupBuf->bmRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { // Remove device
|
|
if ((((uint16_t) UsbSetupBuf->wValueH << 8) | UsbSetupBuf->wValueL) == 0x01) {
|
|
if (CfgDesc[7] & 0x20) {
|
|
// Wake
|
|
} else {
|
|
len = 0xFF; // Operation failed
|
|
printStrSetup("Unsupported\n");
|
|
}
|
|
} else {
|
|
len = 0xFF; // Operation failed
|
|
printStrSetup("Unsupported\n");
|
|
}
|
|
} else if ((UsbSetupBuf->bmRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) { // Endpoint
|
|
switch (UsbSetupBuf->wIndexL) {
|
|
case 0x83:
|
|
UEP3_CTRL = (UEP3_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; // Set endpoint 3 IN (TX) NAK
|
|
break;
|
|
case 0x03:
|
|
UEP3_CTRL = (UEP3_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; // Set endpoint 3 OUT (RX) ACK
|
|
break;
|
|
case 0x82:
|
|
UEP2_CTRL = (UEP2_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; // Set endpoint 2 IN (TX) NACK
|
|
break;
|
|
case 0x02:
|
|
UEP2_CTRL = (UEP2_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; // Set endpoint 2 OUT (RX) ACK
|
|
break;
|
|
case 0x81:
|
|
UEP1_CTRL = (UEP1_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; // Set endpoint 1 IN (TX) NACK
|
|
break;
|
|
case 0x01:
|
|
UEP1_CTRL = (UEP1_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; // Set endpoint 1 OUT (RX) ACK
|
|
break;
|
|
default:
|
|
len = 0xFF; // Unsupported endpoint
|
|
printStrSetup("Unsupported\n");
|
|
break;
|
|
}
|
|
} else {
|
|
len = 0xFF; // It's not that the endpoint doesn't support it
|
|
printStrSetup("Unsupported\n");
|
|
}
|
|
break;
|
|
|
|
case USB_SET_FEATURE: // Set Feature
|
|
printStrSetup("SetFeature\n");
|
|
if (( UsbSetupBuf->bmRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { // Set up the device
|
|
if ((((uint16_t) UsbSetupBuf->wValueH << 8) | UsbSetupBuf->wValueL) == 0x01) {
|
|
if (CfgDesc[7] & 0x20) {
|
|
printStrSetup("Suspend\n");
|
|
while (XBUS_AUX & bUART0_TX) {
|
|
; // Wait for sending to complete
|
|
}
|
|
SAFE_MOD = 0x55;
|
|
SAFE_MOD = 0xAA;
|
|
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO | bWAK_RXD1_LO; // USB or RXD0/1 can be woken up when there is a signal
|
|
PCON |= PD; // Sleep
|
|
SAFE_MOD = 0x55;
|
|
SAFE_MOD = 0xAA;
|
|
WAKE_CTRL = 0x00;
|
|
} else {
|
|
len = 0xFF; // Operation failed
|
|
}
|
|
} else {
|
|
len = 0xFF; // Operation failed
|
|
}
|
|
} else if (( UsbSetupBuf->bmRequestType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) { // Set endpoint
|
|
if ((((uint16_t) UsbSetupBuf->wValueH << 8) | UsbSetupBuf->wValueL) == 0x00) {
|
|
switch (((uint16_t) UsbSetupBuf->wIndexH << 8) | UsbSetupBuf->wIndexL) {
|
|
case 0x83:
|
|
UEP3_CTRL = (UEP3_CTRL & ~bUEP_T_TOG) | UEP_T_RES_STALL; // Set endpoint 3 IN (TX) Stall (error)
|
|
break;
|
|
case 0x03:
|
|
UEP3_CTRL = (UEP3_CTRL & ~bUEP_R_TOG) | UEP_R_RES_STALL; // Set endpoint 3 OUT (RX) Stall (error)
|
|
break;
|
|
case 0x82:
|
|
UEP2_CTRL = (UEP2_CTRL & ~bUEP_T_TOG) | UEP_T_RES_STALL; // Set endpoint 2 IN (TX) Stall (error)
|
|
break;
|
|
case 0x02:
|
|
UEP2_CTRL = (UEP2_CTRL & ~bUEP_R_TOG) | UEP_R_RES_STALL; // Set endpoint 2 OUT (RX) Stall (error)
|
|
break;
|
|
case 0x81:
|
|
UEP1_CTRL = (UEP1_CTRL & ~bUEP_T_TOG) | UEP_T_RES_STALL; // Set endpoint 1 IN (TX) Stall (error)
|
|
break;
|
|
case 0x01:
|
|
UEP1_CTRL = (UEP1_CTRL & ~bUEP_R_TOG) | UEP_R_RES_STALL; // Set endpoint 1 OUT (RX) Stall (error)
|
|
default:
|
|
len = 0xFF; // Operation failed
|
|
break;
|
|
}
|
|
} else {
|
|
len = 0xFF; // Operation failed
|
|
printStrSetup("Unsupported\n");
|
|
}
|
|
} else {
|
|
len = 0xFF; // Operation failed
|
|
printStrSetup("Unsupported\n");
|
|
}
|
|
break;
|
|
|
|
case USB_GET_STATUS:
|
|
printStrSetup("GetStatus\n");
|
|
Ep0Buffer[0] = 0x00;
|
|
Ep0Buffer[1] = 0x00;
|
|
if (SetupLen >= 2) {
|
|
len = 2;
|
|
} else {
|
|
len = SetupLen;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
len = 0xFF; // Operation failed
|
|
printStrSetup("Unsupported\n");
|
|
break;
|
|
|
|
} // END switch (SetupReq)
|
|
} // END Standard request
|
|
} else {
|
|
len = 0xFF; // Packet length error
|
|
}
|
|
|
|
if (len == 0xFF) {
|
|
SetupReq = 0xFF;
|
|
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL; // STALL
|
|
} else if (len <= DEFAULT_EP0_SIZE) { // Upload data or status phase returns 0 length packet
|
|
UEP0_T_LEN = len;
|
|
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; // The default packet is DATA1, Return response ACK
|
|
} else {
|
|
UEP0_T_LEN = 0; // Although it has not yet reached the status stage, it is preset to upload 0-length data packets in advance to prevent the host from entering the status stage early.
|
|
UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; // The default data packet is DATA1, and the response ACK is returned
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Function Name : DeviceInterrupt()
|
|
* Description : CH559USB interrupt processing function
|
|
*******************************************************************************/
|
|
#ifdef BUILD_CODE
|
|
#define IRQ_USB __interrupt(INT_NO_USB)
|
|
#else
|
|
#define IRQ_USB
|
|
#endif
|
|
|
|
void DeviceInterrupt(void)IRQ_USB // USB interrupt service routine, using register set 1
|
|
{
|
|
uint16_t len;
|
|
|
|
if (UIF_TRANSFER) { // Check USB transfer complete flag
|
|
switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP)) {
|
|
|
|
case UIS_TOKEN_SETUP | 0: // SETUP routine
|
|
usb_irq_setup_handler();
|
|
break;
|
|
|
|
case UIS_TOKEN_IN | 0: // Endpoint 0 IN (TX)
|
|
switch (SetupReq) {
|
|
case USB_GET_DESCRIPTOR:
|
|
len = SetupLen >= DEFAULT_EP0_SIZE ? DEFAULT_EP0_SIZE : SetupLen; // The length of this transmission
|
|
memcpy(Ep0Buffer, pDescr, len); // Load upload data
|
|
SetupLen -= len;
|
|
pDescr += len;
|
|
UEP0_T_LEN = len;
|
|
UEP0_CTRL ^= bUEP_T_TOG; // Sync flag flip
|
|
break;
|
|
case USB_SET_ADDRESS:
|
|
USB_DEV_AD = (USB_DEV_AD & bUDA_GP_BIT) | SetupLen;
|
|
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
|
break;
|
|
default:
|
|
UEP0_T_LEN = 0; // The status phase is completed and interrupted or the 0-length data packet is forced to be uploaded to end the control transmission.
|
|
UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case UIS_TOKEN_IN | 1: // Endpoint 1 IN (TX), Endpoint interrupts upload
|
|
UEP1_T_LEN = 0; // Transmit length must be cleared (Endpoint 1)
|
|
UEP1_CTRL = (UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; // Default answer NAK
|
|
break;
|
|
|
|
case UIS_TOKEN_IN | 2: // Endpoint 2 IN (TX), Endpoint bulk upload
|
|
UEP2_T_LEN = 0; // Transmit length must be cleared (Endpoint 2)
|
|
UEP2_CTRL = (UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; // Default answer NAK
|
|
Endpoint2UploadBusy = 0; // Clear busy flag
|
|
break;
|
|
|
|
case UIS_TOKEN_IN | 3: // Endpoint 3 IN (TX), Endpoint bulk upload
|
|
UEP3_T_LEN = 0; // Transmit length must be cleared (Endpoint 3)
|
|
UEP3_CTRL = (UEP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; // Default answer NAK
|
|
Endpoint3UploadBusy = 0; // Clear busy flag
|
|
break;
|
|
|
|
case UIS_TOKEN_OUT | 0: // Endpoint 0 OUT (RX)
|
|
switch (SetupReq) {
|
|
case USB_CDC_REQ_TYPE_SET_LINE_CODING: // We ignore line coding here because baudrate to the FPGA should not change
|
|
if (U_TOG_OK) {
|
|
UEP0_T_LEN = 0;
|
|
UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_ACK; // Prepare to upload 0 packages
|
|
}
|
|
break;
|
|
default:
|
|
UEP0_T_LEN = 0;
|
|
UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_NAK; // Status phase, responds to IN with NAK
|
|
}
|
|
break;
|
|
|
|
case UIS_TOKEN_OUT | 1: // Endpoint 1 OUT (RX), Disabled for now.
|
|
// Out-of-sync packets will be dropped
|
|
if (U_TOG_OK) {
|
|
//UsbEpXByteCount = USB_RX_LEN; // Length of received data
|
|
//UEP1_CTRL = (UEP1_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_NAK; // NAK after receiving a packet of data, the main function finishes processing, and the main function modifies the response mode
|
|
}
|
|
break;
|
|
|
|
case UIS_TOKEN_OUT | 2: // Endpoint 2 OUT (RX), Endpoint batch download
|
|
// Out-of-sync packets will be dropped
|
|
if (U_TOG_OK) {
|
|
UsbEp2ByteCount = USB_RX_LEN; // Length of received data
|
|
UEP2_CTRL = (UEP2_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_NAK; // NAK after receiving a packet of data, the main function finishes processing, and the main function modifies the response mode
|
|
}
|
|
break;
|
|
|
|
case UIS_TOKEN_OUT | 3: // Endpoint 3 OUT (RX), Endpoint batch download
|
|
// Out-of-sync packets will be dropped
|
|
if (U_TOG_OK) {
|
|
UsbEp3ByteCount = USB_RX_LEN; // Length of received data
|
|
UEP3_CTRL = (UEP3_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_NAK; // NAK after receiving a packet of data, the main function finishes processing, and the main function modifies the response mode
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
UIF_TRANSFER = 0; // Writing 0 clears the interrupt
|
|
|
|
} else if (UIF_BUS_RST) { // Check device mode USB bus reset interrupt
|
|
|
|
printStr("Reset\n");
|
|
|
|
UEP0_CTRL = UEP_T_RES_NAK | UEP_R_RES_ACK;
|
|
UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;
|
|
UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;
|
|
UEP3_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;
|
|
USB_DEV_AD = 0x00;
|
|
UIF_SUSPEND = 0;
|
|
UIF_TRANSFER = 0; // Writing 0 clears the interrupt
|
|
UIF_BUS_RST = 0; // Clear interrupt flag
|
|
|
|
UartRxBufInputPointer = 0; // Circular buffer input pointer
|
|
UartRxBufOutputPointer = 0; // Circular buffer read pointer
|
|
UartRxBufByteCount = 0; // The number of bytes remaining in the current buffer to be fetched
|
|
UsbEp2ByteCount = 0; // USB endpoint 2 (CDC) received length
|
|
UsbEp3ByteCount = 0; // USB endpoint 3 (HID) received length
|
|
Endpoint2UploadBusy = 0; // Clear busy flag
|
|
Endpoint3UploadBusy = 0; // Clear busy flag
|
|
|
|
FrameMode = 0;
|
|
|
|
UsbConfig = 0; // Clear configuration values
|
|
|
|
} else if (UIF_SUSPEND) { // Check USB bus suspend/wake completed
|
|
|
|
UIF_SUSPEND = 0;
|
|
|
|
if (USB_MIS_ST & bUMS_SUSPEND) { // Hang
|
|
|
|
printStr("Suspend\n");
|
|
|
|
while (XBUS_AUX & bUART0_TX) {
|
|
; // Wait for sending to complete
|
|
}
|
|
|
|
SAFE_MOD = 0x55;
|
|
SAFE_MOD = 0xAA;
|
|
WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO | bWAK_RXD1_LO; // Can be woken up when there is a signal from USB or RXD0/1
|
|
PCON |= PD; // Sleep
|
|
SAFE_MOD = 0x55;
|
|
SAFE_MOD = 0xAA;
|
|
WAKE_CTRL = 0x00;
|
|
|
|
}
|
|
} else { // Unexpected IRQ, should not happen
|
|
printStr("Unexpected IRQ\n");
|
|
USB_INT_FG = 0xFF; // Clear interrupt flag
|
|
}
|
|
}
|
|
|
|
/*******************************************************************************
|
|
* Function Name : Uart0_ISR()
|
|
* Description : Serial debug port receiving interrupt function to realize circular buffer receiving
|
|
*******************************************************************************/
|
|
#if 1
|
|
#ifdef BUILD_CODE
|
|
#define IRQ_UART0 __interrupt(INT_NO_UART0)
|
|
#else
|
|
#define IRQ_UART0
|
|
#endif
|
|
|
|
void Uart0_ISR(void)IRQ_UART0
|
|
{
|
|
// Check if data has been received
|
|
if (RI) {
|
|
DebugUartRxBuf[DebugUartRxBufInputPointer++] = SBUF;
|
|
if (DebugUartRxBufInputPointer >= DEBUG_UART_RX_BUF_SIZE) {
|
|
DebugUartRxBufInputPointer = 0; // Reset write pointer
|
|
}
|
|
RI = 0;
|
|
}
|
|
}
|
|
|
|
uint8_t debug_uart_byte_count()
|
|
{
|
|
uint8_t in = DebugUartRxBufInputPointer;
|
|
uint8_t out = DebugUartRxBufOutputPointer;
|
|
|
|
if (in < out) {
|
|
in = in + DEBUG_UART_RX_BUF_SIZE;
|
|
}
|
|
return in - out;
|
|
}
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
* Function Name : Uart1_ISR()
|
|
* Description : Serial port receiving interrupt function to realize circular buffer receiving
|
|
*******************************************************************************/
|
|
#ifdef BUILD_CODE
|
|
#define IRQ_UART1 __interrupt(INT_NO_UART1)
|
|
#else
|
|
#define IRQ_UART1
|
|
#endif
|
|
|
|
void Uart1_ISR(void)IRQ_UART1
|
|
{
|
|
// Check if data has been received
|
|
if (U1RI) {
|
|
UartRxBuf[UartRxBufInputPointer++] = SBUF1;
|
|
LastReceiveCounter = LoopCounter; // Update the counter when a byte is received
|
|
if (UartRxBufInputPointer == UartRxBufOutputPointer) {
|
|
UartRxBufOverflow = 1;
|
|
}
|
|
if (UartRxBufInputPointer >= UART_RX_BUF_SIZE) {
|
|
UartRxBufInputPointer = 0; // Reset write pointer
|
|
}
|
|
U1RI = 0;
|
|
}
|
|
}
|
|
|
|
uint8_t uart_byte_count()
|
|
{
|
|
uint8_t in = UartRxBufInputPointer;
|
|
uint8_t out = UartRxBufOutputPointer;
|
|
|
|
if (in < out) {
|
|
in = in + UART_RX_BUF_SIZE;
|
|
}
|
|
return in - out;
|
|
}
|
|
|
|
// Copy data from a circular buffer
|
|
void circular_copy(uint8_t *dest, uint8_t *src, uint32_t src_size, uint32_t start_pos, uint32_t length) {
|
|
|
|
// Calculate the remaining space from start_pos to end of buffer
|
|
uint32_t remaining_space = src_size - start_pos;
|
|
|
|
if (length <= remaining_space) {
|
|
// If the length to copy doesn't exceed the remaining space, do a single memcpy
|
|
memcpy(dest, src + start_pos, length);
|
|
} else {
|
|
// If the length to copy exceeds the remaining space, split the copy
|
|
memcpy(dest, src + start_pos, remaining_space); // Copy from start_pos to end of buffer
|
|
memcpy(dest + remaining_space, src, length - remaining_space); // Copy the rest from the beginning of buffer
|
|
}
|
|
}
|
|
|
|
|
|
// Function to increment a pointer and wrap around the buffer
|
|
uint32_t increment_pointer(uint32_t pointer, uint32_t increment, uint32_t buffer_size)
|
|
{
|
|
return (pointer + increment) % buffer_size;
|
|
}
|
|
|
|
void main()
|
|
{
|
|
CfgFsys(); // CH559 clock selection configuration
|
|
mDelaymS(5); // Modify the main frequency and wait for the internal crystal to stabilize, which must be added
|
|
mInitSTDIO(); // Serial port 0, can be used for debugging
|
|
UART1Setup(); // For communication with FPGA
|
|
UART1Clean(); // Clean register from spurious data
|
|
|
|
printStr("\n\nStartup...\n");
|
|
|
|
USBDeviceCfg();
|
|
USBDeviceEndPointCfg(); // Endpoint configuration
|
|
USBDeviceIntCfg(); // Interrupt initialization
|
|
|
|
UEP0_T_LEN = 0; // Transmit length must be cleared (Endpoint 0)
|
|
UEP1_T_LEN = 0; // Transmit length must be cleared (Endpoint 1)
|
|
UEP2_T_LEN = 0; // Transmit length must be cleared (Endpoint 2)
|
|
UEP3_T_LEN = 0; // Transmit length must be cleared (Endpoint 3)
|
|
|
|
// Enable GPIO debugging on p1.4 and p1.5
|
|
// gpio_init();
|
|
// gpio_unset(0x10);
|
|
// gpio_unset(0x20);
|
|
|
|
while (1) {
|
|
if (UsbConfig) {
|
|
|
|
// Check if Endpoint 2 (CDC) has received data
|
|
if (UsbEp2ByteCount) {
|
|
byte_len = UsbEp2ByteCount;
|
|
memcpy(UartTxBuf, Ep2Buffer, byte_len);
|
|
|
|
UsbEp2ByteCount = 0;
|
|
CH554UART1SendByte(MODE_CDC); // Send CDC mode header
|
|
CH554UART1SendByte(byte_len); // Send length
|
|
CH554UART1SendBuffer(UartTxBuf, byte_len);
|
|
UEP2_CTRL = (UEP2_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK; // Enable Endpoint 2 to ACK again
|
|
}
|
|
|
|
// Check if Endpoint 3 (HID) has received data
|
|
if (UsbEp3ByteCount) {
|
|
byte_len = UsbEp3ByteCount;
|
|
memcpy(UartTxBuf, Ep3Buffer, byte_len);
|
|
|
|
UsbEp3ByteCount = 0;
|
|
CH554UART1SendByte(MODE_HID); // Send HID mode header
|
|
CH554UART1SendByte(byte_len); // Send length (always 64 bytes)
|
|
CH554UART1SendBuffer(UartTxBuf, byte_len);
|
|
UEP3_CTRL = (UEP3_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK; // Enable Endpoint 3 to ACK again
|
|
}
|
|
|
|
UartRxBufByteCount = uart_byte_count(); // Check amount of data in buffer
|
|
|
|
if ((UartRxBufByteCount >= 2) && !FrameStarted) { // If we have data and the header in not yet validated
|
|
FrameMode = UartRxBuf[UartRxBufOutputPointer]; // Extract frame mode
|
|
if ((FrameMode == MODE_CDC) ||
|
|
(FrameMode == MODE_HID)) {
|
|
FrameLength = UartRxBuf[increment_pointer(UartRxBufOutputPointer, 1, UART_RX_BUF_SIZE)]; // Extract frame length
|
|
FrameStarted = 1;
|
|
} else { // Invalid mode
|
|
if (!Halted) {
|
|
printStr("Invalid header: 0x");
|
|
printNumHex(FrameMode);
|
|
printStr(", len = ");
|
|
printNumU32(UartRxBuf[increment_pointer(UartRxBufOutputPointer, 1, UART_RX_BUF_SIZE)]);
|
|
printStr("\n");
|
|
uint16_t i;
|
|
uint8_t print_char_count_out = 0;
|
|
for (i=0; i<UART_RX_BUF_SIZE; i++) {
|
|
printNumHex(UartRxBuf[increment_pointer(UartRxBufOutputPointer, i, UART_RX_BUF_SIZE)]);
|
|
print_char_count_out++;
|
|
if (print_char_count_out >= 16) {
|
|
printStr("\n");
|
|
print_char_count_out = 0;
|
|
}
|
|
}
|
|
if (print_char_count_out != 0) {
|
|
printStr("\n");
|
|
}
|
|
printStr("Halting!\n");
|
|
Halted = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FrameStarted && (LoopCounter - LastReceiveCounter > FRAME_TIMEOUT)) {
|
|
// Timeout, reset frame reception
|
|
FrameMode = 0;
|
|
FrameLength = 0;
|
|
FrameStarted = 0;
|
|
printStr("Frame timeout, reset\n");
|
|
if (FrameMode == MODE_CDC) {
|
|
CdcRxBufLength = 0;
|
|
CdcLoopCount = 0;
|
|
}
|
|
}
|
|
|
|
if (FrameStarted) {
|
|
// Check if a complete frame has been received, include one mode byte and and one length byte
|
|
if (UartRxBufByteCount >= (FrameLength + 2)) {
|
|
UartRxBufOutputPointer = increment_pointer(UartRxBufOutputPointer, 2, UART_RX_BUF_SIZE); // Start at valid data so skip the mode and length byte
|
|
if (FrameMode == MODE_CDC) {
|
|
circular_copy(CdcRxBuf + CdcRxBufLength,
|
|
UartRxBuf,
|
|
UART_RX_BUF_SIZE,
|
|
UartRxBufOutputPointer,
|
|
FrameLength);
|
|
CdcRxBufLength += FrameLength;
|
|
CdcDataAvailable = 1;
|
|
} else if (FrameMode == MODE_HID) {
|
|
circular_copy(HidRxBuf,
|
|
UartRxBuf,
|
|
UART_RX_BUF_SIZE,
|
|
UartRxBufOutputPointer,
|
|
FrameLength);
|
|
HidRxBufLength = MAX_PACKET_SIZE;
|
|
HidDataAvailable = 1;
|
|
}
|
|
// Update output pointer
|
|
UartRxBufOutputPointer = increment_pointer(UartRxBufOutputPointer, FrameLength, UART_RX_BUF_SIZE);
|
|
|
|
// Get next header and data
|
|
FrameStarted = 0;
|
|
}
|
|
}
|
|
|
|
// Check if we should upload data to Endpoint 2 (CDC)
|
|
if (CdcDataAvailable && !Endpoint2UploadBusy && ((CdcLoopCount >= 100) || CdcRxBufLength >= MAX_CDC_FRAME_SIZE)) {
|
|
|
|
// Write upload endpoint
|
|
memcpy(Ep2Buffer + MAX_PACKET_SIZE, /* Copy to IN buffer of Endpoint 2 */
|
|
CdcRxBuf,
|
|
CdcRxBufLength);
|
|
|
|
UEP2_T_LEN = CdcRxBufLength; // Set the number of data bytes that Endpoint 2 is ready to send
|
|
UEP2_CTRL = (UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; // Answer ACK
|
|
Endpoint2UploadBusy = 1; // Set busy flag
|
|
CdcDataAvailable = 0;
|
|
CdcRxBufLength = 0;
|
|
CdcLoopCount = 0;
|
|
} else {
|
|
CdcLoopCount++;
|
|
}
|
|
|
|
// Check if we should upload data to Endpoint 3 (HID)
|
|
if (HidDataAvailable && !Endpoint3UploadBusy) {
|
|
|
|
// Write upload endpoint
|
|
memcpy(Ep3Buffer + MAX_PACKET_SIZE, /* Copy to IN buffer of Endpoint 3 */
|
|
HidRxBuf,
|
|
HidRxBufLength);
|
|
|
|
UEP3_T_LEN = MAX_PACKET_SIZE; // Set the number of data bytes that Endpoint 3 is ready to send
|
|
UEP3_CTRL = (UEP3_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; // Answer ACK
|
|
Endpoint3UploadBusy = 1; // Set busy flag
|
|
HidDataAvailable = 0;
|
|
}
|
|
|
|
#if 1
|
|
DebugUartRxBufByteCount = debug_uart_byte_count();
|
|
if (DebugUartRxBufByteCount) {
|
|
switch(DebugUartRxBuf[DebugUartRxBufOutputPointer]) {
|
|
case 'h':
|
|
printStr("h Show help\n");
|
|
printStr("r Reset UART1\n");
|
|
printStr("s Show status\n");
|
|
break;
|
|
|
|
case 'r':
|
|
/** UART */
|
|
UartRxBufInputPointer = 0;
|
|
UartRxBufOutputPointer = 0;
|
|
UartRxBufOverflow = 0;
|
|
/** Frame */
|
|
FrameMode = 0;
|
|
FrameLength = 0;
|
|
FrameStarted = 0;
|
|
/** CDC */
|
|
CdcDataAvailable = 0;
|
|
CdcRxBufLength = 0;
|
|
CdcLoopCount = 0;
|
|
/** HID */
|
|
HidDataAvailable = 0;
|
|
/** Timeout */
|
|
LoopCounter = 0;
|
|
LastReceiveCounter = 0;
|
|
/** Endpoints */
|
|
UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;
|
|
UEP3_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK;
|
|
UIF_TRANSFER = 0; // Writing 0 clears the interrupt
|
|
UIF_BUS_RST = 0; // Clear interrupt flag
|
|
|
|
Endpoint2UploadBusy = 0;
|
|
Endpoint3UploadBusy = 0;
|
|
UsbEp2ByteCount = 0; // USB endpoint 2 (CDC) received length
|
|
UsbEp3ByteCount = 0; // USB endpoint 3 (HID) received length
|
|
|
|
/** Misc */
|
|
Halted = 0;
|
|
printStr("Reset done!\n");
|
|
break;
|
|
|
|
case 's':
|
|
printStr("Endpoint2UploadBusy = "); printNumU32(Endpoint2UploadBusy); printStr("\n");
|
|
printStr("UsbEp2ByteCount = "); printNumU32(UsbEp2ByteCount); printStr("\n");
|
|
printStr("UEP2_CTRL = 0x"); printNumHex(UEP2_CTRL); printStr("\n");
|
|
|
|
printStr("Endpoint3UploadBusy = "); printNumU32(Endpoint3UploadBusy); printStr("\n");
|
|
printStr("UsbEp3ByteCount = "); printNumU32(UsbEp3ByteCount); printStr("\n");
|
|
printStr("UEP3_CTRL = 0x"); printNumHex(UEP3_CTRL); printStr("\n");
|
|
|
|
printStr("UartRxBufInputPointer = "); printNumU32(UartRxBufInputPointer); printStr("\n");
|
|
printStr("UartRxBufOutputPointer = "); printNumU32(UartRxBufOutputPointer); printStr("\n");
|
|
printStr("UartRxBufOverflow = "); printNumU32(UartRxBufOverflow); printStr("\n");
|
|
|
|
printStr("UartRxBufByteCount = "); printNumU32(UartRxBufByteCount); printStr("\n");
|
|
printStr("FrameMode = 0x"); printNumHex(FrameMode); printStr("\n");
|
|
printStr("FrameLength = "); printNumU32(FrameLength); printStr("\n");
|
|
printStr("FrameStarted = "); printNumU32(FrameStarted); printStr("\n");
|
|
|
|
printStr("CdcDataAvailable = "); printNumU32(CdcDataAvailable); printStr("\n");
|
|
printStr("HidDataAvailable = "); printNumU32(HidDataAvailable); printStr("\n");
|
|
|
|
printStr("Halted = "); printNumU32(Halted); printStr("\n");
|
|
break;
|
|
|
|
default:
|
|
printStr("\n");
|
|
break;
|
|
}
|
|
|
|
// Update out pointer
|
|
DebugUartRxBufOutputPointer = increment_pointer(DebugUartRxBufOutputPointer, DebugUartRxBufByteCount, DEBUG_UART_RX_BUF_SIZE);
|
|
}
|
|
#endif
|
|
} /* END if (UsbConfig) */
|
|
} /* END while (1) */
|
|
}
|