Update USBHID and USBCDC for new AsyncOp

Update USB classes to use the new AsyncOp API.
feature-hal-spec-usb-device
Russ Butler 2018-05-07 14:43:35 -05:00
parent bfa9992c7d
commit 6984060b9f
4 changed files with 224 additions and 252 deletions

View File

@ -21,24 +21,91 @@
class USBHID::AsyncSend: public AsyncOp {
public:
AsyncSend(const HID_REPORT *report): AsyncOp(NULL), report(report), result(false)
AsyncSend(USBHID *hid, const HID_REPORT *report): hid(hid), report(report), result(false)
{
}
~AsyncSend()
{
}
virtual bool process()
{
if (!hid->configured()) {
result = false;
return true;
}
if (hid->send_nb(report)) {
result = true;
return true;
}
return false;
}
USBHID *hid;
const HID_REPORT *report;
bool result;
};
class USBHID::AsyncRead: public AsyncOp {
public:
AsyncRead(HID_REPORT *report): AsyncOp(NULL), report(report), result(false)
AsyncRead(USBHID *hid, HID_REPORT *report): hid(hid), report(report), result(false)
{
}
~AsyncRead()
{
}
virtual bool process()
{
if (!hid->configured()) {
result = false;
return true;
}
if (hid->read_nb(report)) {
result = true;
return true;
}
return false;
}
USBHID *hid;
HID_REPORT *report;
bool result;
};
class USBHID::AsyncWait: public AsyncOp {
public:
AsyncWait(USBHID *hid): hid(hid)
{
}
~AsyncWait()
{
}
virtual bool process()
{
if (hid->configured()) {
return true;
}
return false;
}
USBHID *hid;
};
USBHID::USBHID(bool connect_blocking, uint8_t output_report_length, uint8_t input_report_length, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
: USBDevice(get_usb_phy(), vendor_id, product_id, product_release)
@ -88,15 +155,12 @@ void USBHID::wait_ready()
{
lock();
AsyncOp wait_op(NULL);
wait_op.start(&_connect_list);
if (configured()) {
wait_op.complete();
}
AsyncWait wait_op(this);
_connect_list.add(&wait_op);
unlock();
wait_op.wait();
wait_op.wait(NULL);
}
@ -104,23 +168,12 @@ bool USBHID::send(const HID_REPORT *report)
{
lock();
if (!configured()) {
unlock();
return false;
}
if (send_nb(report)) {
unlock();
return true;
}
AsyncSend send_op(report);
send_op.start(&_send_list);
AsyncSend send_op(this, report);
_send_list.add(&send_op);
unlock();
send_op.wait();
send_op.wait(NULL);
return send_op.result;
}
@ -149,23 +202,12 @@ bool USBHID::read(HID_REPORT *report)
{
lock();
if (!configured()) {
unlock();
return false;
}
if (read_nb(report)) {
unlock();
return true;
}
AsyncRead read_op(report);
read_op.start(&_read_list);
AsyncRead read_op(this, report);
_read_list.add(&read_op);
unlock();
read_op.wait();
read_op.wait(NULL);
return read_op.result;
}
@ -198,13 +240,8 @@ void USBHID::_send_isr(usb_ep_t endpoint)
write_finish(_int_in);
_send_idle = true;
AsyncSend *send_op = _send_list.head();
if (send_op != NULL) {
if (send_nb(send_op->report)) {
send_op->result = true;
send_op->complete();
}
} else {
_send_list.process();
if (_send_idle) {
report_tx();
}
@ -217,60 +254,12 @@ void USBHID::_read_isr(usb_ep_t endpoint)
_output_report.length = read_finish(_int_out);
_read_idle = true;
AsyncRead *read_op = _read_list.head();
if (read_op != NULL) {
if (read_nb(read_op->report)) {
read_op->result = true;
read_op->complete();
}
} else {
_read_list.process();
if (_read_idle) {
report_rx();
}
}
void USBHID::_connect_wake_all()
{
assert_locked();
AsyncOp *wait_op = _connect_list.head();
while (wait_op != NULL) {
wait_op->complete();
wait_op = _connect_list.head();
}
}
void USBHID::_send_abort_all()
{
assert_locked();
if (!_send_idle) {
endpoint_abort(_int_in);
_send_idle = true;
}
AsyncSend *tx_cur = _send_list.head();
while (tx_cur != NULL) {
tx_cur->result = false;
tx_cur->complete();
tx_cur = _send_list.head();
}
}
void USBHID::_read_abort_all()
{
assert_locked();
if (!_read_idle) {
endpoint_abort(_int_out);
_read_idle = true;
}
AsyncRead *rx_cur = _read_list.head();
while (rx_cur != NULL) {
rx_cur->result = false;
rx_cur->complete();
rx_cur = _read_list.head();
}
}
uint16_t USBHID::report_desc_length()
{
report_desc();
@ -280,12 +269,19 @@ uint16_t USBHID::report_desc_length()
void USBHID::callback_state_change(DeviceState new_state)
{
if (new_state == Configured) {
_connect_wake_all();
} else {
_send_abort_all();
_read_abort_all();
if (new_state != Configured) {
if (!_send_idle) {
endpoint_abort(_int_in);
_send_idle = true;
}
if (!_read_idle) {
endpoint_abort(_int_out);
_read_idle = true;
}
}
_send_list.process();
_read_list.process();
_connect_list.process();
}
//

View File

@ -22,8 +22,7 @@
#include "USBDevice.h"
#include "USBHID_Types.h"
#include "AsyncOp.h"
#include "LinkedList.h"
#include "OperationList.h"
@ -249,17 +248,14 @@ private:
void _send_isr(usb_ep_t endpoint);
void _read_isr(usb_ep_t endpoint);
void _connect_wake_all();
void _send_abort_all();
void _read_abort_all();
class AsyncSend;
class AsyncRead;
class AsyncWait;
LinkedList<AsyncOp> _connect_list;
LinkedList<AsyncSend> _send_list;
OperationList<AsyncWait> _connect_list;
OperationList<AsyncSend> _send_list;
bool _send_idle;
LinkedList<AsyncRead> _read_list;
OperationList<AsyncRead> _read_list;
bool _read_idle;
uint8_t _configuration_descriptor[41];

View File

@ -36,10 +36,39 @@ static const uint8_t cdc_line_coding_default[7] = {0x80, 0x25, 0x00, 0x00, 0x00,
class USBCDC::AsyncWrite: public AsyncOp {
public:
AsyncWrite(uint8_t *buf, uint32_t size): AsyncOp(NULL), tx_buf(buf), tx_size(size), result(false)
AsyncWrite(USBCDC *serial, uint8_t *buf, uint32_t size):
serial(serial), tx_buf(buf), tx_size(size), result(false)
{
}
virtual ~AsyncWrite()
{
}
virtual bool process()
{
if (!serial->_terminal_connected) {
result = false;
return true;
}
uint32_t actual_size = 0;
serial->send_nb(tx_buf, tx_size, &actual_size, true);
tx_size -= actual_size;
tx_buf += actual_size;
if (tx_size == 0) {
result = true;
return true;
}
// Start transfer if it hasn't been
serial->_send_isr_start();
return false;
}
USBCDC *serial;
uint8_t *tx_buf;
uint32_t tx_size;
bool result;
@ -47,11 +76,40 @@ public:
class USBCDC::AsyncRead: public AsyncOp {
public:
AsyncRead(uint8_t *buf, uint32_t size, uint32_t *size_read, bool read_all)
: AsyncOp(NULL), rx_buf(buf), rx_size(size), rx_actual(size_read), all(read_all), result(false)
AsyncRead(USBCDC *serial, uint8_t *buf, uint32_t size, uint32_t *size_read, bool read_all)
: serial(serial), rx_buf(buf), rx_size(size), rx_actual(size_read), all(read_all), result(false)
{
}
virtual ~AsyncRead()
{
}
virtual bool process()
{
if (!serial->_terminal_connected) {
result = false;
return true;
}
uint32_t actual_size = 0;
serial->receive_nb(rx_buf, rx_size, &actual_size);
rx_buf += actual_size;
*rx_actual += actual_size;
rx_size -= actual_size;
if ((!all && *rx_actual > 0) || (rx_size == 0)) {
// Wake thread if request is done
result = true;
return true;
}
serial->_receive_isr_start();
return false;
}
USBCDC *serial;
uint8_t *rx_buf;
uint32_t rx_size;
uint32_t *rx_actual;
@ -59,6 +117,31 @@ public:
bool result;
};
class USBCDC::AsyncWait: public AsyncOp {
public:
AsyncWait(USBCDC *serial)
: serial(serial)
{
}
virtual ~AsyncWait()
{
}
virtual bool process()
{
if (serial->_terminal_connected) {
return true;
}
return false;
}
USBCDC *serial;
};
USBCDC::USBCDC(bool connect_blocking, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
: USBDevice(get_usb_phy(), vendor_id, product_id, product_release)
@ -230,13 +313,30 @@ void USBCDC::_change_terminal_connected(bool connected)
{
assert_locked();
if (connected) {
_connect_wake_all();
} else {
_send_abort_all();
_receive_abort_all();
}
_terminal_connected = connected;
if (!_terminal_connected) {
// Abort TX
if (_tx_in_progress) {
endpoint_abort(_bulk_in);
_tx_in_progress = false;
}
_tx_buf = _tx_buffer;
_tx_size = 0;
_tx_list.process();
MBED_ASSERT(_tx_list.empty());
// Abort RX
if (_rx_in_progress) {
endpoint_abort(_bulk_in);
_rx_in_progress = false;
}
_rx_buf = _rx_buffer;
_rx_size = 0;
_rx_list.process();
MBED_ASSERT(_rx_list.empty());
}
_connected_list.process();
}
bool USBCDC::ready()
@ -253,89 +353,27 @@ void USBCDC::wait_ready()
{
lock();
AsyncOp wait_op(NULL);
wait_op.start(&_connected_list);
if (_terminal_connected) {
wait_op.complete();
}
AsyncWait wait_op(this);
_connected_list.add(&wait_op);
unlock();
wait_op.wait();
}
void USBCDC::_connect_wake_all()
{
AsyncOp *wait_op = _connected_list.head();
while (wait_op != NULL) {
wait_op->complete();
wait_op = _connected_list.head();
}
wait_op.wait(NULL);
}
bool USBCDC::send(uint8_t *buffer, uint32_t size)
{
lock();
if (!_terminal_connected) {
unlock();
return false;
}
AsyncWrite write_op(buffer, size);
write_op.start(&_tx_list);
_send_next();
AsyncWrite write_op(this, buffer, size);
_tx_list.add(&write_op);
unlock();
write_op.wait();
write_op.wait(NULL);
return write_op.result;
}
void USBCDC::_send_next()
{
assert_locked();
uint32_t actual_size;
do {
// Set current TX operation or return if there are none left
AsyncWrite *tx_cur = _tx_list.head();
if (tx_cur == NULL) {
break;
}
actual_size = 0;
send_nb(tx_cur->tx_buf, tx_cur->tx_size, &actual_size, false);
tx_cur->tx_size -= actual_size;
tx_cur->tx_buf += actual_size;
if (tx_cur->tx_size == 0) {
tx_cur->result = true;
tx_cur->complete();
}
} while (actual_size > 0);
// Start transfer if it hasn't been
_send_isr_start();
}
void USBCDC::_send_abort_all()
{
assert_locked();
if (_tx_in_progress) {
endpoint_abort(_bulk_in);
_tx_in_progress = false;
}
_tx_buf = _tx_buffer;
_tx_size = 0;
AsyncWrite *tx_cur = _tx_list.head();
while (tx_cur != NULL) {
tx_cur->result = false;
tx_cur->complete();
tx_cur = _tx_list.head();
}
}
void USBCDC::send_nb(uint8_t *buffer, uint32_t size, uint32_t *actual, bool now)
{
lock();
@ -357,7 +395,6 @@ void USBCDC::send_nb(uint8_t *buffer, uint32_t size, uint32_t *actual, bool now)
unlock();
}
void USBCDC::_send_isr_start()
{
assert_locked();
@ -382,7 +419,7 @@ void USBCDC::_send_isr(usb_ep_t endpoint)
_tx_size = 0;
_tx_in_progress = false;
_send_next();
_tx_list.process();
if (!_tx_in_progress) {
data_tx();
}
@ -392,72 +429,19 @@ bool USBCDC::receive(uint8_t *buffer, uint32_t size, uint32_t *size_read)
{
lock();
if (!_terminal_connected) {
unlock();
return false;
}
bool read_all = size_read == NULL;
uint32_t size_read_dummy;
uint32_t *size_read_ptr = read_all ? &size_read_dummy : size_read;
*size_read_ptr = 0;
AsyncRead read_op(buffer, size, size_read_ptr, read_all);
read_op.start(&_rx_list);
_receive_next();
AsyncRead read_op(this, buffer, size, size_read_ptr, read_all);
_rx_list.add(&read_op);
unlock();
read_op.wait();
read_op.wait(NULL);
return read_op.result;
}
void USBCDC::_receive_next()
{
assert_locked();
uint32_t actual_size;
do {
// Set current RX operation or return if there are none left
AsyncRead *rx_cur = _rx_list.head();
if (rx_cur == NULL) {
break;
}
actual_size = 0;
receive_nb(rx_cur->rx_buf, rx_cur->rx_size, &actual_size);
rx_cur->rx_buf += actual_size;
*rx_cur->rx_actual += actual_size;
rx_cur->rx_size -= actual_size;
if ((!rx_cur->all && *rx_cur->rx_actual > 0) || (rx_cur->rx_size == 0)) {
// Wake thread if request is done
rx_cur->result = true;
rx_cur->complete();
rx_cur = NULL;
}
} while (actual_size > 0);
_receive_isr_start();
}
void USBCDC::_receive_abort_all()
{
assert_locked();
if (_rx_in_progress) {
endpoint_abort(_bulk_in);
_rx_in_progress = false;
}
_rx_buf = _rx_buffer;
_rx_size = 0;
AsyncRead *rx_cur = _rx_list.head();
while (rx_cur != NULL) {
rx_cur->result = false;
rx_cur->complete();
rx_cur = _rx_list.head();
}
}
void USBCDC::receive_nb(uint8_t *buffer, uint32_t size, uint32_t *size_read)
{
@ -496,7 +480,7 @@ void USBCDC::_receive_isr(usb_ep_t endpoint)
_rx_buf = _rx_buffer;
_rx_size = read_finish(_bulk_out);
_rx_in_progress = false;
_receive_next();
_rx_list.process();
if (!_rx_in_progress) {
data_rx();
}

View File

@ -22,7 +22,7 @@
#include "USBDevice_Types.h"
#include "USBDevice.h"
#include "LinkedList.h"
#include "OperationList.h"
class AsyncOp;
@ -180,6 +180,7 @@ protected:
class AsyncWrite;
class AsyncRead;
class AsyncWait;
virtual void callback_reset();
virtual void callback_state_change(DeviceState new_state);
@ -191,15 +192,10 @@ protected:
void _init();
void _change_terminal_connected(bool connected);
void _connect_wake_all();
void _send_next();
void _send_abort_all();
void _send_isr_start();
void _send_isr(usb_ep_t endpoint);
void _receive_next();
void _receive_abort_all();
void _receive_isr_start();
void _receive_isr(usb_ep_t endpoint);
@ -211,16 +207,16 @@ protected:
uint8_t _cdc_new_line_coding[7];
uint8_t _config_descriptor[75];
LinkedList<AsyncOp> _connected_list;
OperationList<AsyncWait> _connected_list;
bool _terminal_connected;
LinkedList<AsyncWrite> _tx_list;
OperationList<AsyncWrite> _tx_list;
bool _tx_in_progress;
uint8_t _tx_buffer[64];
uint8_t *_tx_buf;
uint32_t _tx_size;
LinkedList<AsyncRead> _rx_list;
OperationList<AsyncRead> _rx_list;
bool _rx_in_progress;
uint8_t _rx_buffer[64];
uint8_t *_rx_buf;