From 643208f4898400fb04bf0773c388551f58b0b5bf Mon Sep 17 00:00:00 2001 From: Matthias Hannig Date: Fri, 13 Jul 2018 16:13:00 +0200 Subject: added bluefnorf skeleton --- bluefnorf/usb.c | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) create mode 100644 bluefnorf/usb.c (limited to 'bluefnorf/usb.c') diff --git a/bluefnorf/usb.c b/bluefnorf/usb.c new file mode 100644 index 0000000..7894b81 --- /dev/null +++ b/bluefnorf/usb.c @@ -0,0 +1,331 @@ + + +/* + * Initialize USB ACM serial device, provide convenience + * function for serial communication. + * + * Mostly plucked together from some opencm3 example code. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "usb.h" + +#define STATUS_LED_PORT GPIOC +#define STATUS_LED_PIN GPIO13 + +#define USBD_PORT GPIOA +#define USBDM GPIO11 +#define USBDP GPIO12 + +#define RX_ECHO 1 +#define RX_BUF_LEN 256 + +static char _rx_tmp[RX_BUF_LEN]; +static char _rx_buf[RX_BUF_LEN]; + +static size_t _rx_tmp_len; +static uint8_t _rx_buf_ready; + +/* Buffer to be used for control requests. */ +uint8_t usbd_control_buffer[128]; + +static usbd_device* __USBDEV; + +static const struct usb_device_descriptor device_descriptor = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0xfe, // USB_CLASS_CDC, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x1209, + .idProduct = 0x4001, + .bcdDevice = 0x0200, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + + +static const struct usb_endpoint_descriptor comm_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x83, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 16, + .bInterval = 255, +}}; + + +static const struct usb_endpoint_descriptor data_endp[] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + + +static const struct usb_interface_descriptor comm_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 1, + .bInterfaceClass = 0xfe, // USB_CLASS_CDC, + .bInterfaceSubClass = 0x00, // USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = 0x00, // USB_CDC_PROTOCOL_AT, + .iInterface = 0, + + .endpoint = comm_endp, + + .extra = NULL, // &cdcacm_functional_descriptors, + .extralen = 0, +}}; + +static const struct usb_interface_descriptor data_iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_DATA, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = data_endp, +}}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = comm_iface, +}, { + .num_altsetting = 1, + .altsetting = data_iface, +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 2, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + + .interface = ifaces, +}; + + +static const char *usb_strings[] = { + "Chaos Computer Club Berlin e.V.", + "bluefnorf", + "bf1", +}; + + + +/* + * Initialize GPIO for D+ and status LED + */ +void usb_gpio_init() +{ + // Clock + rcc_periph_clock_enable(RCC_GPIOA); + rcc_periph_clock_enable(RCC_GPIOC); + + // D+ + gpio_set_mode(USBD_PORT, + GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, + USBDP); + + // LED + gpio_set_mode(STATUS_LED_PORT, + GPIO_MODE_OUTPUT_2_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, + STATUS_LED_PIN); + +} + +/* + * Switch status led on / off + */ +inline void usb_status_led_toggle() +{ + gpio_toggle(STATUS_LED_PORT, STATUS_LED_PIN); +} + + +/* + * Poll usb interface using TIM4 + */ +void usb_timer_init() +{ + // Enable clock + rcc_periph_clock_enable(RCC_TIM4); + + // Enable interrupts + nvic_enable_irq(NVIC_TIM4_IRQ); + nvic_set_priority(NVIC_TIM4_IRQ, 1); + + timer_reset(TIM4); + + // Edge aligned + TIM4_CR1 |= TIM_CR1_CKD_CK_INT | + TIM_CR1_CMS_EDGE | + TIM_CR1_DIR_UP; + + TIM4_PSC = 32; + TIM4_ARR = 65535; + + // Interrupts: + // - Update / Overflow Event (UIE) + TIM4_DIER |= TIM_DIER_UIE; +} + +void usb_timer_start() +{ + TIM4_CR1 |= TIM_CR1_CEN; +} + + +void tim4_isr() +{ + // Poll USBDEV + usbd_poll(__USBDEV); + + // Blink status LED + usb_status_led_toggle(); + TIM4_SR &= ~TIM_SR_UIF; // Clear flag +} + + + +static void usb_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) +{ + char buf[64]; + + int len = usbd_ep_read_packet(usbd_dev, 0x01, buf, 64); + + if (len) { + // We received data, let's handle it + + usbd_ep_write_packet(usbd_dev, 0x82, "fnorf", 6); + } +} + + +static int usb_control_request_cb(usbd_device *usbd_dev, + struct usb_setup_data *req, + uint8_t **buf, + uint16_t *len, + usbd_control_complete_callback *complete) +{ + return 0; +} + +static void usb_set_config_cb(usbd_device *usbd_dev, uint16_t wValue) +{ + usbd_ep_setup(usbd_dev, 0x01, USB_ENDPOINT_ATTR_BULK, 64, usb_data_rx_cb); + usbd_ep_setup(usbd_dev, 0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL); + usbd_ep_setup(usbd_dev, 0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL); + + usbd_register_control_callback( + usbd_dev, + USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE, + USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, + usb_control_request_cb + ); +} + + +usbd_device *usb_serial_init() +{ + usbd_device *usbd_dev; + + // Initialize GPIO + usb_gpio_init(); + + // Initialize timers + usb_timer_init(); + + // Initialize buffers + memset(_rx_tmp, 0, RX_BUF_LEN); + memset(_rx_buf, 0, RX_BUF_LEN); + + _rx_tmp_len = 0; + _rx_buf_ready = 0; + + // Pull down D+ + gpio_clear(USBD_PORT, USBDP); + for (int i = 0; i < 0x10000; i++) { + __asm__("nop"); + } + gpio_set(USBD_PORT, USBDP); + + // Initialize usb device + usbd_dev = usbd_init(&st_usbfs_v1_usb_driver, + &device_descriptor, + &config, + usb_strings, 3, + usbd_control_buffer, sizeof(usbd_control_buffer)); + + usbd_register_set_config_callback(usbd_dev, usb_set_config_cb); + + // Make available + __USBDEV = usbd_dev; + + // Pull down + gpio_clear(USBD_PORT, USBDP); + + // Poll a bit + for (int i = 0; i < 0x80000; i++) { + usbd_poll(usbd_dev); + } + + // Start polling + usb_timer_start(); + + return usbd_dev; +} + + +/* + * Override _write and redirect stdout to usb + */ + /* +int _write(int file, char* data, int len) +{ + if (file < 2) { + return usb_serial_tx(data, len); + } + + // Set error and return failure + errno = EIO; + return -1; +} +*/ -- cgit