Skip to content

USBDevice HAL specification improvements #6276

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion TESTS/usb_device/basic/USBTester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,16 @@ USBTester::USBTester(uint16_t vendor_id, uint16_t product_id, uint16_t product_r

configuration_desc();

init();
USBDevice::connect(connect_blocking);

}

USBTester::~USBTester()
{
deinit();
}

void USBTester::callback_state_change(DeviceState new_state)
{
// Nothing to do
Expand Down Expand Up @@ -102,8 +108,13 @@ void USBTester::callback_request(const setup_packet_t *setup)

}

void USBTester::callback_request_xfer_done(const setup_packet_t *setup)
void USBTester::callback_request_xfer_done(const setup_packet_t *setup, bool aborted)
{
if (aborted) {
complete_request_xfer_done(false);
return;
}

bool result = false;
if (setup->bmRequestType.Type == VENDOR_TYPE) {
switch (setup->bRequest) {
Expand Down
4 changes: 3 additions & 1 deletion TESTS/usb_device/basic/USBTester.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class USBTester: public USBDevice {
*/
USBTester(uint16_t vendor_id, uint16_t product_id, uint16_t product_release, bool connect_blocking);

~USBTester();

protected:

/*
Expand Down Expand Up @@ -77,7 +79,7 @@ class USBTester: public USBDevice {

virtual void callback_state_change(DeviceState new_state);
virtual void callback_request(const setup_packet_t *setup);
virtual void callback_request_xfer_done(const setup_packet_t *setup);
virtual void callback_request_xfer_done(const setup_packet_t *setup, bool aborted);
virtual void callback_set_configuration(uint8_t configuration);
virtual void callback_set_interface(uint16_t interface, uint8_t alternate);
virtual void epbulk_out_callback(usb_ep_t endpoint);
Expand Down
162 changes: 38 additions & 124 deletions platform/USBPhy.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,147 +17,51 @@
#ifndef USBPHY_H
#define USBPHY_H

#include <stdint.h>
#include "USBPhyTypes.h"
#include "USBPhyEvents.h"

/**
* \defgroup hal_usb_device USB Device HAL
* Abstract interface to physical USB hardware
/** Abstract interface to physical USB hardware
*
* # Defined behavior
* * Any endpoint configurations which fit in the parameters of the table returned
* by USBPhy::endpointTable can be used.
* by USBPhy::endpoint_table can be used.
* * All endpoints in any valid endpoint configuration can be used concurrently
* * Device supports use of at least one control, bulk, interrupt and
* isochronous in each direction at the same time - at least 8 endpoints.
* * Device supports all standard endpoint sizes (wMaxPacketSize)
* * Device can handle an interrupt latency of at least 100ms if reset is not being performed and address is not being set
* * USBPhyEvents events are only sent when USBPhy is in the initialized state
* * When unpowered only the USBPhyEvents::power event can be sent
* * On USB reset all endpoints are removed except for endpoint 0
* * USBPhyEvents::out and USBPhyEvents::in events only occur for endpoints which have been added
* * A call to USBPhy::ep0_write results in USBPhyEvents::in getting called if not
* interrupted by a power loss or reset
* * A call to endpoint_read followed by endpoint_read_result results in USBPhyEvents::out getting called if not
* interrupted by a power loss or reset
* * Endpoint 0 naks all transactions aside from setup packets until one
* of ep0_read, ep0_write or ep0_stall has been called
* * Endpoint 0 stall is automatically cleared on reception of a setup packet
*
* # Undefined behavior
* * Calling USBPhy::endpoint_add or USBPhy::endpoint_remove outside of the control requests SetInterface or SetConfiguration
* * Devices behavior is undefined if latency is greater than 2ms when address is being set - see USB spec 9.2.6.3
* * Devices behavior is undefined if latency is greater than 10ms when a reset occurs - see USB spec 7.1.7.5
* * Calling any of the USBPhy::endpoint_* functions on endpoint 0
*
* # Potential bugs
* * Processing control packets in the wrong order when multiple packets are present
* * Back to back setup packets handled incorrectly
* * Signal corruption not handled correctly
* * USB race conditions
* # Notes
* * Make sure USB packets are processed in the correct order when multiple packets are present.
* Typically IN endpoints should be handled before OUT endpoints if both are pending.
* * Setup packets may be resent if there is noise on the USB line. The USBPhy should be able
* to gracefully handle this scenario and respond to the setup packet with an ACK.
* * Bi-directional protocols making use of alternating IN and OUT phases should not rely
* on the last ACK an IN transfer to indicate that the OUT phase should start. Instead,
* the OUT phase should be started at the same time the last IN transfer is started. This
* is because the ACK to the last in transfer may be dropped if there is noise on the USB
* line. If dropped it will only get re-sent on the next IN phase. More info on this can be
* found in section 8.5.3.3 of the USB spec.
*
* @ingroup usb_device_core
*/

typedef uint8_t usb_ep_t;

typedef enum {
USB_EP_TYPE_CTRL = 0,
USB_EP_TYPE_ISO = 1,
USB_EP_TYPE_BULK = 2,
USB_EP_TYPE_INT = 3
} usb_ep_type_t;

enum {
USB_EP_ATTR_ALLOW_CTRL = 1 << USB_EP_TYPE_CTRL,
USB_EP_ATTR_ALLOW_BULK = 1 << USB_EP_TYPE_BULK,
USB_EP_ATTR_ALLOW_INT = 1 << USB_EP_TYPE_INT,
USB_EP_ATTR_ALLOW_ISO = 1 << USB_EP_TYPE_ISO,
USB_EP_ATTR_ALLOW_ALL = USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_ALLOW_BULK |
USB_EP_ATTR_ALLOW_INT | USB_EP_ATTR_ALLOW_ISO,

USB_EP_ATTR_DIR_IN = 0 << 4,
USB_EP_ATTR_DIR_OUT = 1 << 4,
USB_EP_ATTR_DIR_IN_OR_OUT = 2 << 4,
USB_EP_ATTR_DIR_IN_AND_OUT = 3 << 4,
USB_EP_ATTR_DIR_MASK = 3 << 4
};
typedef uint8_t usb_ep_attr_t;

struct usb_ep_entry_t {
usb_ep_attr_t attributes;
uint8_t byte_cost;
uint16_t base_cost;
};

struct usb_ep_table_t {
uint32_t resources;
usb_ep_entry_t table[16];
};

class USBPhyEvents {
public:
USBPhyEvents() {};
virtual ~USBPhyEvents() {};

/**
* Callback called when a bus reset occurs
* @note called in the contex of USBPhy::process
*/
virtual void reset() = 0;

/**
* Callback called when an endpoint 0 setup packet is received
* @note called in the contex of USBPhy::process
*/
virtual void ep0_setup() = 0;

/**
* Callback called when an endpoint 0 out packet is received
* @note called in the contex of USBPhy::process
*/
virtual void ep0_out() = 0;

/**
* Callback called when an endpoint 0 in packet is received
* @note called in the contex of USBPhy::process
*/
virtual void ep0_in() = 0;

/**
* Callback called USB power is applied or removed
*
* @param powered true if USB power is present, false otherwise
* @note called in the contex of USBPhy::process
*/
virtual void power(bool powered) = 0;

/**
* Callback called when entering or leaving suspend mode
*
* @param suspended true if entering suspend mode false otherwise
* @note called in the contex of USBPhy::process
*/
virtual void suspend(bool suspended) = 0;

/**
* Callback called on start of frame
*
* @param frameNumber The current frame number
* @note This callback is enabled/disabled by
* calling USBPhy::sof_enable / USBPhy::sof_disable
* @note called in the contex of USBPhy::process
*/
virtual void sof(int frameNumber) = 0;

/**
* Callback called on the reception of an OUT packet
*
* @param endpoint Endpoint which received the OUT packet
* @note called in the contex of USBPhy::process
*/
virtual void out(usb_ep_t endpoint) = 0;

/**
* Callback called on the transmission of an IN packet
*
* @param endpoint Endpoint which sent the IN packet
* @note called in the contex of USBPhy::process
*/
virtual void in(usb_ep_t endpoint) = 0;

/**
* Callback called to indicate the USB processing needs to be done
*/
virtual void start_process() = 0;
};

class USBPhy {
public:
USBPhy() {};
Expand All @@ -181,6 +85,16 @@ class USBPhy {
*/
virtual void deinit() = 0;

/**
* Check if USB power is present
*
* Devices which don't support checking the USB power state
* must always return true.
*
* @return true if USB power is present, false otherwise
*/
virtual bool powered() = 0;

/**
* Make the USB phy visible to the USB host
*
Expand Down
107 changes: 107 additions & 0 deletions platform/USBPhyEvents.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef USBPHY_EVENTS_H
#define USBPHY_EVENTS_H

#include "USBPhyTypes.h"

/** Event handler for USBPhy
*
* This class is the event handler for the USBPhy class. Any events generated
* by USBPhy are passed to this class via the virtual functions.
*
* @ingroup usb_device_core
*
*/
class USBPhyEvents {
public:
USBPhyEvents() {};
virtual ~USBPhyEvents() {};

/**
* Callback called when a bus reset occurs
* @note called in the contex of USBPhy::process
*/
virtual void reset() = 0;

/**
* Callback called when an endpoint 0 setup packet is received
* @note called in the contex of USBPhy::process
*/
virtual void ep0_setup() = 0;

/**
* Callback called when an endpoint 0 out packet is received
* @note called in the contex of USBPhy::process
*/
virtual void ep0_out() = 0;

/**
* Callback called when an endpoint 0 in packet is received
* @note called in the contex of USBPhy::process
*/
virtual void ep0_in() = 0;

/**
* Callback called USB power is applied or removed
*
* @param powered true if USB power is present, false otherwise
* @note called in the contex of USBPhy::process
*/
virtual void power(bool powered) = 0;

/**
* Callback called when entering or leaving suspend mode
*
* @param suspended true if entering suspend mode false otherwise
* @note called in the contex of USBPhy::process
*/
virtual void suspend(bool suspended) = 0;

/**
* Callback called on start of frame
*
* @param frame_number The current frame number
* @note This callback is enabled/disabled by
* calling USBPhy::sof_enable / USBPhy::sof_disable
* @note called in the contex of USBPhy::process
*/
virtual void sof(int frame_number) = 0;

/**
* Callback called on the reception of an OUT packet
*
* @param endpoint Endpoint which received the OUT packet
* @note called in the contex of USBPhy::process
*/
virtual void out(usb_ep_t endpoint) = 0;

/**
* Callback called on the transmission of an IN packet
*
* @param endpoint Endpoint which sent the IN packet
* @note called in the contex of USBPhy::process
*/
virtual void in(usb_ep_t endpoint) = 0;

/**
* Callback called to indicate the USB processing needs to be done
*/
virtual void start_process() = 0;
};

#endif
Loading