diff --git a/lib/usb_cdcacm.c b/lib/usb_cdcacm.c
new file mode 100644
index 0000000..27f3859
--- /dev/null
+++ b/lib/usb_cdcacm.c
@@ -0,0 +1,302 @@
+/* This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+/* Copyright (c) 2016 King Kévin */
+/* this library handles the USB CDC ACM */
+
+/* standard libraries */
+#include // standard integer types
+#include // standard I/O facilities
+#include // general utilities
+
+/* STM32 (including CM3) libraries */
+#include // real-time control clock library
+#include // general purpose input output library
+#include // interrupt handler
+#include // Cortex M3 utilities
+#include // USB library
+#include // USB CDC library
+
+#include "usb_cdcacm.h" // USB CDC ACM header and definitions
+
+/* USB descriptor */
+static const struct usb_device_descriptor device_descriptor = {
+ .bLength = USB_DT_DEVICE_SIZE, // the size of this header in bytes, 18
+ .bDescriptorType = USB_DT_DEVICE, // a value of 1 indicates that this is a device descriptor
+ .bcdUSB = 0x0200, // this device supports USB 2.0
+ .bDeviceClass = USB_CLASS_CDC, // use the CDC device class
+ .bDeviceSubClass = USB_CDC_SUBCLASS_ACM, // use the ACM sub-class
+ .bDeviceProtocol = USB_CDC_PROTOCOL_NONE, // use no specific protocol
+ .bMaxPacketSize0 = 64, // packet size for endpoint zero in bytes
+ .idVendor = 0xc440, // Vendor ID (CuVo...)
+ .idProduct = 0x0d00, // product ID within the Vendor ID space (...odoo)
+ .bcdDevice = 0x0100, // version number for the device
+ .iManufacturer = 1, // the index of the string in the string table that represents the name of the manufacturer of this device.
+ .iProduct = 2, // the index of the string in the string table that represents the name of the product
+ .iSerialNumber = 3, // the index of the string in the string table that represents the serial number of this item in string form.
+ .bNumConfigurations = 1, // the number of possible configurations this device has
+};
+
+static const struct usb_endpoint_descriptor data_endpoints[] = {{
+ .bLength = USB_DT_ENDPOINT_SIZE, // the size of the endpoint descriptor in bytes
+ .bDescriptorType = USB_DT_ENDPOINT, // a value of 5 indicates that this describes an endpoint
+ .bEndpointAddress = 0x01, // OUT (from host) direction (0<<7), endpoint 1
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK, // bulk mode
+ .wMaxPacketSize = 64, // maximum packet size
+ .bInterval = 1, // the frequency, in number of frames, that we're going to be sending data
+},{
+ .bLength = USB_DT_ENDPOINT_SIZE, // the size of the endpoint descriptor in bytes
+ .bDescriptorType = USB_DT_ENDPOINT, // a value of 5 indicates that this describes an endpoint
+ .bEndpointAddress = 0x82, // IN (to host) direction (1<<7), endpoint 2
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK, // bulk mode
+ .wMaxPacketSize = 64, // maximum packet size
+ .bInterval = 1, // the frequency, in number of frames, that we're going to be sending data
+}};
+
+/* This notification endpoint isn't implemented. According to CDC spec its
+ * optional, but its absence causes a NULL pointer dereference in Linux
+ * cdc_acm driver.
+ */
+static const struct usb_endpoint_descriptor communication_endpoints[] = {{
+ .bLength = USB_DT_ENDPOINT_SIZE, // the size of the endpoint descriptor in bytes
+ .bDescriptorType = USB_DT_ENDPOINT, // a value of 5 indicates that this describes an endpoint
+ .bEndpointAddress = 0x83, // IN (to host) direction (1<<7), endpoint 3
+ .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, // interrupt mode
+ .wMaxPacketSize = 16, // maximum packet size
+ .bInterval = 255, // the frequency, in number of frames, that we're going to be sending data
+}};
+
+static const struct {
+ struct usb_cdc_header_descriptor header;
+ struct usb_cdc_call_management_descriptor call_mgmt;
+ struct usb_cdc_acm_descriptor acm;
+ struct usb_cdc_union_descriptor cdc_union;
+} __attribute__((packed)) cdcacm_functional_descriptors = {
+ .header = {
+ .bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
+ .bcdCDC = 0x0110,
+ },
+ .call_mgmt = {
+ .bFunctionLength =
+ sizeof(struct usb_cdc_call_management_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
+ .bmCapabilities = 0,
+ .bDataInterface = 1,
+ },
+ .acm = {
+ .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_CDC_TYPE_ACM,
+ .bmCapabilities = 0,
+ },
+ .cdc_union = {
+ .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_CDC_TYPE_UNION,
+ .bControlInterface = 0,
+ .bSubordinateInterface0 = 1,
+ },
+};
+
+static const struct usb_interface_descriptor communication_interface[] = {{
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_CDC,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
+ .bInterfaceProtocol = USB_CDC_PROTOCOL_NONE,
+ .iInterface = 0,
+
+ .endpoint = communication_endpoints,
+
+ .extra = &cdcacm_functional_descriptors,
+ .extralen = sizeof(cdcacm_functional_descriptors),
+}};
+
+static const struct usb_interface_descriptor data_interface[] = {{
+ .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_endpoints,
+}};
+
+static const struct usb_interface interfaces[] = {{
+ .num_altsetting = 1,
+ .altsetting = communication_interface,
+}, {
+ .num_altsetting = 1,
+ .altsetting = data_interface,
+}};
+
+static const struct usb_config_descriptor config = {
+ .bLength = USB_DT_CONFIGURATION_SIZE, // the length of this header in bytes
+ .bDescriptorType = USB_DT_CONFIGURATION, // a value of 2 indicates that this is a configuration descriptor
+ .wTotalLength = 0, // this should hold the total size of the configuration descriptor including all sub interfaces. it is automatically filled in by the USB stack in libopencm3
+ .bNumInterfaces = 2, // the number of interfaces in this configuration
+ .bConfigurationValue = 1, // the index of this configuration
+ .iConfiguration = 0, // a string index describing this configuration (zero means not provided)
+ .bmAttributes = 0x80, // self powered (0<<6), supports remote wakeup (5<<0)
+ .bMaxPower = 0x32, // the maximum amount of current that this device will draw in 2mA units
+ // end of header
+ .interface = interfaces, // pointer to an array of interfaces
+};
+
+/* string table (starting with index 1) */
+const char *usb_strings[] = {
+ "CuVoodoo",
+ "CDC-ACM",
+ "STM32F1",
+};
+
+/* buffer to be used for control requests */
+static uint8_t usbd_control_buffer[128];
+
+/* structure holding all the info related to the USB device */
+static usbd_device *usb_device;
+
+/* input and output ring buffer, indexes, and available memory */
+static uint8_t rx_buffer[CDCACM_BUFFER] = {0};
+static volatile uint8_t rx_i = 0;
+static volatile uint8_t rx_used = 0;
+/* show the user how much data received over USB is ready */
+volatile uint8_t cdcacm_received = 0; // same as rx_used, but since the user can write this variable we don't rely on it
+
+static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
+{
+ (void)complete;
+ (void)buf;
+ (void)usbd_dev;
+
+ switch (req->bRequest) {
+ case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
+ /*
+ * This Linux cdc_acm driver requires this to be implemented
+ * even though it's optional in the CDC spec, and we don't
+ * advertise it in the ACM functional descriptor.
+ */
+ char local_buf[10];
+ struct usb_cdc_notification *notif = (void *)local_buf;
+
+ /* We echo signals back to host as notification. */
+ notif->bmRequestType = 0xA1;
+ notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
+ notif->wValue = 0;
+ notif->wIndex = 0;
+ notif->wLength = 2;
+ local_buf[8] = req->wValue & 3;
+ local_buf[9] = 0;
+ // usbd_ep_write_packet(0x83, buf, 10);
+ return 1;
+ }
+ case USB_CDC_REQ_SET_LINE_CODING:
+ if (*len < sizeof(struct usb_cdc_line_coding))
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static void cdcacm_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
+{
+ (void)ep;
+ (void)usbd_dev;
+
+ char usb_data[64] = {0}; // buffer to read data
+ uint16_t usb_length = 0; // length of incoming data
+
+ /* receive data */
+ usb_length = usbd_ep_read_packet(usbd_dev, 0x01, usb_data, sizeof(usb_data));
+ if (usb_length) { // copy received data
+ for (uint16_t i=0; i.
+ *
+ */
+/* Copyright (c) 2016 King Kévin */
+/* this library handles the USB CDC ACM */
+
+
+/* RX buffer size */
+#define CDCACM_BUFFER 128
+/* show the user how much received is available */
+extern volatile uint8_t cdcacm_received;
+
+/* setup USB CDC ACM */
+void cdcacm_setup(void);
+/* get character from USB CDC ACM (blocking) */
+char cdcacm_getchar(void);
+/* put character on USB CDC ACM (blocking) */
+void cdcacm_putchar(char c);