USBCDC_ECM: Add receive functionality

Handle SET_ETHERNET_PACKET_FILTER request
pull/9443/head
Juha Ylinen 2019-02-05 15:48:37 +02:00
parent fc00718917
commit 87f2f7f93f
2 changed files with 120 additions and 30 deletions

View File

@ -22,11 +22,14 @@
#include "mbed_interface.h" #include "mbed_interface.h"
#include "mbed_assert.h" #include "mbed_assert.h"
#define MAX_SEGMENT_SIZE (1514) #ifndef MAX_SEGMENT_SIZE
#define FLAG_WRITE_DONE (1 << 0) #define MAX_SEGMENT_SIZE (1514)
#define FLAG_DISCONNECT (1 << 1) #endif
#define FLAG_CONNECT (1 << 2)
#define FLAG_INT_DONE (1 << 3) #define FLAG_WRITE_DONE (1 << 0)
#define FLAG_DISCONNECT (1 << 1)
#define FLAG_CONNECT (1 << 2)
#define FLAG_INT_DONE (1 << 3)
#define SET_ETHERNET_MULTICAST_FILTERS 0x40 #define SET_ETHERNET_MULTICAST_FILTERS 0x40
#define SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER 0x41 #define SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER 0x41
@ -34,19 +37,13 @@
#define SET_ETHERNET_PACKET_FILTER 0x43 #define SET_ETHERNET_PACKET_FILTER 0x43
#define GET_ETHERNET_STATISTIC 0x44 #define GET_ETHERNET_STATISTIC 0x44
#define PACKET_TYPE_PROMISCUOUS (1<<0)
#define PACKET_TYPE_ALL_MULTICAST (1<<1)
#define PACKET_TYPE_DIRECTED (1<<2)
#define PACKET_TYPE_BROADCAST (1<<3)
#define PACKET_TYPE_MULTICAST (1<<4)
#define CS_INTERFACE 0x24 #define CS_INTERFACE 0x24
#define NETWORK_CONNECTION 0x00 #define NETWORK_CONNECTION 0x00
#define CONNECTION_SPEED_CHANGE 0x2A #define CONNECTION_SPEED_CHANGE 0x2A
#define LINK_SPEED (10000000) #define LINK_SPEED (10000000)
USBCDC_ECM::USBCDC_ECM(bool connect_blocking, uint16_t vendor_id, uint16_t product_id, uint16_t product_release) USBCDC_ECM::USBCDC_ECM(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), _queue(4 * EVENTS_EVENT_SIZE) : USBDevice(get_usb_phy(), vendor_id, product_id, product_release), _packet_filter(0), _queue(4 * EVENTS_EVENT_SIZE)
{ {
_init(); _init();
@ -60,7 +57,7 @@ USBCDC_ECM::USBCDC_ECM(bool connect_blocking, uint16_t vendor_id, uint16_t produ
} }
USBCDC_ECM::USBCDC_ECM(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release) USBCDC_ECM::USBCDC_ECM(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
: USBDevice(phy, vendor_id, product_id, product_release), _queue(4 * EVENTS_EVENT_SIZE) : USBDevice(phy, vendor_id, product_id, product_release), _packet_filter(0), _queue(4 * EVENTS_EVENT_SIZE)
{ {
_init(); _init();
@ -235,6 +232,41 @@ bool USBCDC_ECM::send(uint8_t *buffer, uint32_t size)
return ret; return ret;
} }
void USBCDC_ECM::receive_nb(uint8_t *buffer, uint32_t size, uint32_t *actual)
{
lock();
uint32_t available = _rx_queue.size();
uint32_t copy_size = available > size ? size : available;
_rx_queue.read(buffer, copy_size);
*actual = copy_size;
unlock();
}
void USBCDC_ECM::attach_rx(mbed::Callback<void()> cb)
{
lock();
_callback_rx = cb;
unlock();
}
void USBCDC_ECM::attach_filter(mbed::Callback<void()> cb)
{
lock();
_callback_filter = cb;
unlock();
}
uint16_t USBCDC_ECM::read_packet_filter()
{
return _packet_filter;
}
void USBCDC_ECM::callback_request(const setup_packet_t *setup) void USBCDC_ECM::callback_request(const setup_packet_t *setup)
{ {
assert_locked(); assert_locked();
@ -247,30 +279,26 @@ void USBCDC_ECM::callback_request(const setup_packet_t *setup)
//printf("In USBCallback_request: CLASS specific Request: %02x\n", setup->bRequest); //printf("In USBCallback_request: CLASS specific Request: %02x\n", setup->bRequest);
switch (setup->bRequest) { switch (setup->bRequest) {
case SET_ETHERNET_MULTICAST_FILTERS: case SET_ETHERNET_MULTICAST_FILTERS:
/* TODO: Support is optional, not implemented here */
break; break;
case SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER: case SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER:
/* TODO: Support is optional, not implemented here */
break; break;
case GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER: case GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER:
/* TODO: Support is optional, not implemented here */
break; break;
case SET_ETHERNET_PACKET_FILTER: case SET_ETHERNET_PACKET_FILTER:
/*if (setup->wValue & PACKET_TYPE_PROMISCUOUS) { if (_packet_filter != setup->wValue) {
printf("PROMISCUOUS\n"); _packet_filter = setup->wValue;
// Signal that packet filter configuration is changed
if (_callback_filter) {
_callback_filter();
}
} }
if (setup->wValue & PACKET_TYPE_ALL_MULTICAST) {
printf("ALL_MULTICAST\n");
}
if (setup->wValue & PACKET_TYPE_DIRECTED) {
printf("DIRECTED\n");
}
if (setup->wValue & PACKET_TYPE_BROADCAST) {
printf("BROADCAST\n");
}
if (setup->wValue & PACKET_TYPE_MULTICAST) {
printf("MULTICAST\n");
}*/
result = Success; result = Success;
break; break;
case GET_ETHERNET_STATISTIC: case GET_ETHERNET_STATISTIC:
/* TODO: Support is optional, not implemented here */
break; break;
default: default:
result = Failure; result = Failure;
@ -287,6 +315,9 @@ void USBCDC_ECM::callback_set_interface(uint16_t interface, uint8_t alternate)
/* Called in ISR context */ /* Called in ISR context */
if (alternate) { if (alternate) {
_packet_filter = 0;
_rx_queue.resize(MAX_SEGMENT_SIZE);
endpoint_add(_int_in, MAX_PACKET_SIZE_INT, USB_EP_TYPE_INT, &USBCDC_ECM::_int_callback); endpoint_add(_int_in, MAX_PACKET_SIZE_INT, USB_EP_TYPE_INT, &USBCDC_ECM::_int_callback);
endpoint_add(_bulk_in, MAX_PACKET_SIZE_BULK, USB_EP_TYPE_BULK, &USBCDC_ECM::_bulk_in_callback); endpoint_add(_bulk_in, MAX_PACKET_SIZE_BULK, USB_EP_TYPE_BULK, &USBCDC_ECM::_bulk_in_callback);
endpoint_add(_bulk_out, MAX_PACKET_SIZE_BULK, USB_EP_TYPE_BULK, &USBCDC_ECM::_bulk_out_callback); endpoint_add(_bulk_out, MAX_PACKET_SIZE_BULK, USB_EP_TYPE_BULK, &USBCDC_ECM::_bulk_out_callback);
@ -511,7 +542,17 @@ void USBCDC_ECM::_bulk_out_callback()
{ {
assert_locked(); assert_locked();
_bulk_buf_size = read_finish(_bulk_out); uint32_t read_size = read_finish(_bulk_out);
if (read_size <= _rx_queue.free()) {
// Copy data over
_rx_queue.write(_bulk_buf, read_size);
}
// Signal that there is ethernet packet available
if (_callback_rx && (read_size < USBDevice::endpoint_max_packet_size(_bulk_out))) {
_callback_rx();
}
read_start(_bulk_out, _bulk_buf, MAX_PACKET_SIZE_BULK); read_start(_bulk_out, _bulk_buf, MAX_PACKET_SIZE_BULK);
} }

View File

@ -20,17 +20,24 @@
#include "USBDescriptor.h" #include "USBDescriptor.h"
#include "USBDevice.h" #include "USBDevice.h"
#include "ByteBuffer.h"
#include "Mutex.h" #include "Mutex.h"
#include "EventFlags.h" #include "EventFlags.h"
#include "EventQueue.h" #include "EventQueue.h"
#include "Thread.h" #include "Thread.h"
#include "Callback.h"
#define MAX_PACKET_SIZE_INT (64) #define MAX_PACKET_SIZE_INT (64)
#define MAX_PACKET_SIZE_BULK (64) #define MAX_PACKET_SIZE_BULK (64)
#define MAX_PACKET_SIZE_EP0 (64) #define MAX_PACKET_SIZE_EP0 (64)
#define DEFAULT_CONFIGURATION (1) #define DEFAULT_CONFIGURATION (1)
#define PACKET_TYPE_PROMISCUOUS (1<<0)
#define PACKET_TYPE_ALL_MULTICAST (1<<1)
#define PACKET_TYPE_DIRECTED (1<<2)
#define PACKET_TYPE_BROADCAST (1<<3)
#define PACKET_TYPE_MULTICAST (1<<4)
class USBCDC_ECM: public USBDevice { class USBCDC_ECM: public USBDevice {
public: public:
@ -98,6 +105,45 @@ public:
*/ */
bool send(uint8_t *buffer, uint32_t size); bool send(uint8_t *buffer, uint32_t size);
/**
* Read from the receive buffer
*
* @param buffer buffer to fill with data
* @param size maximum number of bytes read
* @param actual a pointer to where to store the number of bytes actually received
*/
void receive_nb(uint8_t *buffer, uint32_t size, uint32_t *actual);
/**
* Return ethernet packet filter bitmap
*
* The Packet Filter is the inclusive OR of the bitmap
* D0: PACKET_TYPE_PROMISCUOUS
* D1: PACKET_TYPE_ALL_MULTICAST
* D2: PACKET_TYPE_DIRECTED
* D3: PACKET_TYPE_BROADCAST
* D4: PACKET_TYPE_MULTICAST
* D5-D15: Reserved (zero)
*
* @return ethernet packet filter bitmap
*/
uint16_t read_packet_filter();
/**
* Attach a callback for when an ethernet packet is received
*
* @param cb code to call when a packet is received
*/
void attach_rx(mbed::Callback<void()> cb);
/**
* Attach a callback for when a request to configure device ethernet
* packet filter is received
*
* @param cb code to call when a packet filter request is received
*/
void attach_filter(mbed::Callback<void()> cb);
protected: protected:
/* /*
@ -200,13 +246,16 @@ private:
uint8_t _string_imac_addr[26]; uint8_t _string_imac_addr[26];
uint8_t _bulk_buf[MAX_PACKET_SIZE_BULK]; uint8_t _bulk_buf[MAX_PACKET_SIZE_BULK];
uint32_t _bulk_buf_size; uint16_t _packet_filter;
ByteBuffer _rx_queue;
rtos::EventFlags _flags; rtos::EventFlags _flags;
rtos::Mutex _write_mutex; rtos::Mutex _write_mutex;
events::EventQueue _queue; events::EventQueue _queue;
rtos::Thread _thread; rtos::Thread _thread;
mbed::Callback<void()> _callback_rx;
mbed::Callback<void()> _callback_filter;
void _init(); void _init();
void _int_callback(); void _int_callback();