reset device when USB CDC ACM data with is set to 5 bits, to restart DFU bootloader

This commit is contained in:
King Kévin 2016-01-21 10:59:53 +01:00
parent f7d0b5610c
commit 57f3b45f83
1 changed files with 16 additions and 14 deletions

View File

@ -24,6 +24,7 @@
#include <libopencm3/stm32/rcc.h> // real-time control clock library
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/cm3/nvic.h> // interrupt handler
#include <libopencm3/cm3/scb.h> // reset utilities
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
#include <libopencm3/usb/usbd.h> // USB library
#include <libopencm3/usb/cdc.h> // USB CDC library
@ -206,28 +207,30 @@ static int cdcacm_control_request(usbd_device *usbd_dev, struct usb_setup_data *
switch (req->bRequest) {
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
/*
* This Linux cdc_acm driver requires this to be implemented
bool dtr = (req->wValue & (1 << 0)) ? true : false;
bool rts = (req->wValue & (1 << 1)) ? true : false;
*/
/* 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(usbd_dev, 0x83, local_buf, 10);
return 1;
}
case USB_CDC_REQ_SET_LINE_CODING:
// ignore if length is wrong
if (*len < sizeof(struct usb_cdc_line_coding)) {
return 0;
}
// get the line coding
struct usb_cdc_line_coding *coding = (struct usb_cdc_line_coding *)*buf;
/* reset device is the data bits is set to 5
* this is used to allowing rebooting the device in DFU mode for reflashing
* to reset the device from the host you can use stty --file /dev/ttyACM0 115200 raw cs5
*/
if (coding->bDataBits==5) {
scb_reset_system(); // reset device
while (true); // wait for the reset to happen
}
return 1;
default:
return 0;
@ -273,7 +276,6 @@ static void cdcacm_data_tx_cb(usbd_device *usbd_dev, uint8_t ep)
uint8_t transmitted = usbd_ep_write_packet(usb_device, 0x82, usb_data, usb_length); // try to transmit data
tx_i = (tx_i+transmitted)%sizeof(rx_buffer); // update location on buffer
tx_used -= transmitted; // update used size
}
}