core: add helper state machine for control read/write
Signed-off-by: Amir Hammad <amir.hammad@hotmail.com>
This commit is contained in:
parent
6d9ee8e9a6
commit
c4e6f3b55b
2 changed files with 122 additions and 24 deletions
|
|
@ -26,6 +26,7 @@
|
|||
#include "usbh_config.h"
|
||||
#include "usbh_core.h"
|
||||
|
||||
#include <libopencm3/usb/usbstd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
BEGIN_DECLS
|
||||
|
|
@ -64,8 +65,6 @@ enum USBH_CONTROL_TYPE {
|
|||
enum USBH_ENUM_STATE {
|
||||
USBH_ENUM_STATE_SET_ADDRESS,
|
||||
USBH_ENUM_STATE_FIRST = USBH_ENUM_STATE_SET_ADDRESS,
|
||||
USBH_ENUM_STATE_SET_ADDRESS_EMPTY_READ,
|
||||
USBH_ENUM_STATE_SET_ADDRESS_EMPTY_READ_COMPLETE,
|
||||
USBH_ENUM_STATE_DEVICE_DT_READ_SETUP,
|
||||
USBH_ENUM_STATE_DEVICE_DT_READ,
|
||||
USBH_ENUM_STATE_DEVICE_DT_READ_COMPLETE,
|
||||
|
|
@ -81,6 +80,38 @@ enum USBH_ENUM_STATE {
|
|||
USBH_ENUM_STATE_FIND_DRIVER,
|
||||
};
|
||||
|
||||
enum USBH_CONTROL_STATE {
|
||||
USBH_CONTROL_STATE_NONE,
|
||||
USBH_CONTROL_STATE_SETUP,
|
||||
USBH_CONTROL_STATE_DATA,
|
||||
USBH_CONTROL_STATE_STATUS,
|
||||
};
|
||||
|
||||
typedef struct _usbh_device usbh_device_t;
|
||||
|
||||
struct _usbh_packet_callback_data {
|
||||
/// status - it is used for reporting of the errors
|
||||
enum USBH_PACKET_CALLBACK_STATUS status;
|
||||
|
||||
/// count of bytes that has been actually transferred
|
||||
uint32_t transferred_length;
|
||||
};
|
||||
typedef struct _usbh_packet_callback_data usbh_packet_callback_data_t;
|
||||
|
||||
typedef void (*usbh_packet_callback_t)(usbh_device_t *dev, usbh_packet_callback_data_t status);
|
||||
|
||||
struct _usbh_control {
|
||||
enum USBH_CONTROL_STATE state;
|
||||
usbh_packet_callback_t callback;
|
||||
union {
|
||||
const void *out;
|
||||
void *in;
|
||||
} data;
|
||||
uint16_t data_length;
|
||||
struct usb_setup_data setup_data;
|
||||
};
|
||||
typedef struct _usbh_control usbh_control_t;
|
||||
|
||||
/**
|
||||
* @brief The _usbh_device struct
|
||||
*
|
||||
|
|
@ -98,6 +129,7 @@ struct _usbh_device {
|
|||
|
||||
/// state used for enumeration purposes
|
||||
enum USBH_ENUM_STATE state;
|
||||
usbh_control_t control;
|
||||
|
||||
/// toggle bit
|
||||
uint8_t toggle0;
|
||||
|
|
@ -119,17 +151,6 @@ struct _usbh_device {
|
|||
};
|
||||
typedef struct _usbh_device usbh_device_t;
|
||||
|
||||
struct _usbh_packet_callback_data {
|
||||
/// status - it is used for reporting of the errors
|
||||
enum USBH_PACKET_CALLBACK_STATUS status;
|
||||
|
||||
/// count of bytes that has been actually transferred
|
||||
uint32_t transferred_length;
|
||||
};
|
||||
typedef struct _usbh_packet_callback_data usbh_packet_callback_data_t;
|
||||
|
||||
typedef void (*usbh_packet_callback_t)(usbh_device_t *dev, usbh_packet_callback_data_t status);
|
||||
|
||||
struct _usbh_packet {
|
||||
/// pointer to data
|
||||
union {
|
||||
|
|
@ -239,9 +260,7 @@ void usbh_read(usbh_device_t *dev, usbh_packet_t *packet);
|
|||
void usbh_write(usbh_device_t *dev, const usbh_packet_t *packet);
|
||||
|
||||
/* Helper functions used by device drivers */
|
||||
void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
|
||||
void device_xfer_control_write_setup(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
|
||||
void device_xfer_control_write_data(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
|
||||
void device_control(usbh_device_t *dev, usbh_packet_callback_t callback, const struct usb_setup_data *setup_data, void *data);
|
||||
|
||||
END_DECLS
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
#include <libopencm3/stm32/gpio.h>
|
||||
#include <libopencm3/usb/usbstd.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
static struct {
|
||||
bool enumeration_run;
|
||||
const usbh_low_level_driver_t * const *lld_drivers;
|
||||
|
|
@ -204,11 +206,7 @@ void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* NEW ENUMERATE
|
||||
*
|
||||
*/
|
||||
void device_xfer_control_write_setup(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
static void device_xfer_control_write_setup(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
{
|
||||
usbh_packet_t packet;
|
||||
|
||||
|
|
@ -228,7 +226,7 @@ void device_xfer_control_write_setup(const void *data, uint16_t datalen, usbh_pa
|
|||
LOG_PRINTF("WR-setup@device...%d \n", dev->address);
|
||||
}
|
||||
|
||||
void device_xfer_control_write_data(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
static void device_xfer_control_write_data(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
{
|
||||
usbh_packet_t packet;
|
||||
|
||||
|
|
@ -248,7 +246,7 @@ void device_xfer_control_write_data(const void *data, uint16_t datalen, usbh_pac
|
|||
LOG_PRINTF("WR-data@device...%d \n", dev->address);
|
||||
}
|
||||
|
||||
void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
static void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
{
|
||||
usbh_packet_t packet;
|
||||
|
||||
|
|
@ -268,6 +266,85 @@ void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback
|
|||
}
|
||||
|
||||
|
||||
static void control_state_machine(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
||||
{
|
||||
switch (dev->control.state) {
|
||||
case USBH_CONTROL_STATE_SETUP:
|
||||
if (cb_data.status != USBH_PACKET_CALLBACK_STATUS_OK) {
|
||||
dev->control.state = USBH_CONTROL_STATE_NONE;
|
||||
// Unable to deliver setup control packet - this is a fatal error
|
||||
usbh_packet_callback_data_t ret_data;
|
||||
ret_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
|
||||
ret_data.transferred_length = 0;
|
||||
dev->control.callback(dev, ret_data);
|
||||
break;
|
||||
}
|
||||
if (dev->control.setup_data.bmRequestType & USB_REQ_TYPE_IN) {
|
||||
dev->control.state = USBH_CONTROL_STATE_DATA;
|
||||
device_xfer_control_read(dev->control.data.in, dev->control.data_length, control_state_machine, dev);
|
||||
} else {
|
||||
if (dev->control.data_length == 0) {
|
||||
dev->control.state = USBH_CONTROL_STATE_STATUS;
|
||||
device_xfer_control_read(0, 0, control_state_machine, dev);
|
||||
} else {
|
||||
dev->control.state = USBH_CONTROL_STATE_DATA;
|
||||
device_xfer_control_write_data(dev->control.data.out, dev->control.data_length, control_state_machine, dev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_CONTROL_STATE_DATA:
|
||||
if (dev->control.setup_data.bmRequestType & USB_REQ_TYPE_IN) {
|
||||
dev->control.state = USBH_CONTROL_STATE_NONE;
|
||||
dev->control.callback(dev, cb_data);
|
||||
} else {
|
||||
if (cb_data.status != USBH_PACKET_CALLBACK_STATUS_OK) {
|
||||
dev->control.state = USBH_CONTROL_STATE_NONE;
|
||||
// Unable to deliver data control packet - this is a fatal error
|
||||
usbh_packet_callback_data_t ret_data;
|
||||
ret_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
|
||||
ret_data.transferred_length = 0;
|
||||
dev->control.callback(dev, ret_data);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dev->control.data_length == 0) {
|
||||
// we should be in status state when the length of data is zero
|
||||
LOG_PRINTF("Control logic error\n");
|
||||
dev->control.state = USBH_CONTROL_STATE_NONE;
|
||||
dev->control.callback(dev, cb_data);
|
||||
} else {
|
||||
dev->control.state = USBH_CONTROL_STATE_STATUS;
|
||||
device_xfer_control_read(0, 0, control_state_machine, dev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_CONTROL_STATE_STATUS:
|
||||
dev->control.state = USBH_CONTROL_STATE_NONE;
|
||||
dev->control.callback(dev, cb_data);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void device_control(usbh_device_t *dev, usbh_packet_callback_t callback, const struct usb_setup_data *setup_data, void *data)
|
||||
{
|
||||
if (dev->control.state != USBH_CONTROL_STATE_NONE) {
|
||||
LOG_PRINTF("ERROR: Use of control state machine while not idle\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dev->control.state = USBH_CONTROL_STATE_SETUP;
|
||||
dev->control.callback = callback;
|
||||
dev->control.data.out = data;
|
||||
dev->control.data_length = setup_data->wLength;
|
||||
dev->control.setup_data = *setup_data;
|
||||
device_xfer_control_write_setup(&dev->control.setup_data, sizeof(dev->control.setup_data), control_state_machine, dev);
|
||||
}
|
||||
|
||||
|
||||
bool usbh_enum_available(void)
|
||||
{
|
||||
|
|
@ -689,12 +766,14 @@ void usbh_poll(uint32_t time_curr_us)
|
|||
usbh_device[0].lld = usbh_data.lld_drivers[k];
|
||||
usbh_device[0].speed = usbh_data.lld_drivers[k]->root_speed(lld_data);
|
||||
usbh_device[0].address = 1;
|
||||
usbh_device[0].control.state = USBH_CONTROL_STATE_NONE;
|
||||
|
||||
device_enumeration_start(&usbh_device[0]);
|
||||
break;
|
||||
|
||||
case USBH_POLL_STATUS_DEVICE_DISCONNECTED:
|
||||
{
|
||||
usbh_device[0].control.state = USBH_CONTROL_STATE_NONE;
|
||||
uint32_t i;
|
||||
for (i = 0; i < USBH_MAX_DEVICES; i++) {
|
||||
device_remove(&usbh_device[i]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue