328 lines
7.3 KiB
C
328 lines
7.3 KiB
C
|
#include <stdbool.h>
|
||
|
#include "cdc_ecm.h"
|
||
|
#include "contiki.h"
|
||
|
#include "usb_drv.h"
|
||
|
#include "usb_descriptors.h"
|
||
|
#include "usb_specific_request.h"
|
||
|
#include "rndis/rndis_task.h"
|
||
|
#include "rndis/rndis_protocol.h"
|
||
|
#include "uip.h"
|
||
|
#include "sicslow_ethernet.h"
|
||
|
#include <stdio.h>
|
||
|
|
||
|
#include <avr/pgmspace.h>
|
||
|
#include <util/delay.h>
|
||
|
|
||
|
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
|
||
|
#define PRINTF printf
|
||
|
#define PRINTF_P printf_P
|
||
|
|
||
|
extern uint8_t usb_eth_data_buffer[64];
|
||
|
static U16 usb_ecm_packet_filter = 0;
|
||
|
|
||
|
#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 Usb_write_word(x) Usb_write_byte((x)&0xFF),Usb_write_byte((x>>8)&0xFF)
|
||
|
#define Usb_write_long(x) Usb_write_word((x)&0xFFFF),Usb_write_word((x>>16)&0xFFFF)
|
||
|
|
||
|
#define Usb_read_word() ((U16)Usb_read_byte()+((U16)Usb_read_byte()<<8))
|
||
|
|
||
|
void
|
||
|
cdc_ecm_set_ethernet_packet_filter(void) {
|
||
|
usb_ecm_packet_filter = Usb_read_word();
|
||
|
|
||
|
Usb_ack_receive_setup();
|
||
|
Usb_send_control_in();
|
||
|
usb_endpoint_wait_for_read_control_enabled();
|
||
|
|
||
|
PRINTF_P(PSTR("cdc_ecm: Received SET_ETHERNET_PACKET_FILTER: (0x%04X) "),usb_ecm_packet_filter);
|
||
|
if(usb_ecm_packet_filter & PACKET_TYPE_PROMISCUOUS) {
|
||
|
PRINTF_P(PSTR("PROMISCUOUS "));
|
||
|
USB_ETH_HOOK_SET_PROMISCIOUS_MODE(true);
|
||
|
} else {
|
||
|
USB_ETH_HOOK_SET_PROMISCIOUS_MODE(false);
|
||
|
}
|
||
|
|
||
|
if(usb_ecm_packet_filter & PACKET_TYPE_ALL_MULTICAST)
|
||
|
PRINTF_P(PSTR("ALL_MULTICAST "));
|
||
|
if(usb_ecm_packet_filter & PACKET_TYPE_DIRECTED)
|
||
|
PRINTF_P(PSTR("DIRECTED "));
|
||
|
if(usb_ecm_packet_filter & PACKET_TYPE_BROADCAST)
|
||
|
PRINTF_P(PSTR("BROADCAST "));
|
||
|
if(usb_ecm_packet_filter & PACKET_TYPE_MULTICAST)
|
||
|
PRINTF_P(PSTR("MULTICAST "));
|
||
|
|
||
|
PRINTF_P(PSTR("\n"));
|
||
|
}
|
||
|
|
||
|
|
||
|
#define CDC_NOTIFY_NETWORK_CONNECTION (0x00)
|
||
|
#define CDC_NOTIFY_CONNECTION_SPEED_CHANGE (0x2A)
|
||
|
|
||
|
void
|
||
|
cdc_ecm_notify_network_connection(uint8_t value) {
|
||
|
#if CDC_ECM_USES_INTERRUPT_ENDPOINT
|
||
|
Usb_select_endpoint(INT_EP);
|
||
|
|
||
|
if(!Is_usb_endpoint_enabled()) {
|
||
|
//PRINTF_P(PSTR("cdc_ecm: cdc_ecm_notify_network_connection: endpoint not enabled\n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(usb_endpoint_wait_for_IN_ready()!=0) {
|
||
|
//PRINTF_P(PSTR("cdc_ecm: cdc_ecm_notify_network_connection: Timeout waiting for interrupt endpoint to be available\n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Usb_send_control_in();
|
||
|
|
||
|
Usb_write_byte(0x51); // 10100001b
|
||
|
Usb_write_byte(CDC_NOTIFY_NETWORK_CONNECTION);
|
||
|
Usb_write_byte(value);
|
||
|
Usb_write_byte(0x00);
|
||
|
Usb_write_word(ECM_INTERFACE0_NB);
|
||
|
Usb_write_word(0x0000);
|
||
|
|
||
|
Usb_send_in();
|
||
|
PRINTF_P(PSTR("cdc_ecm: CDC_NOTIFY_NETWORK_CONNECTION %d\n"),value);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#define CDC_ECM_DATA_ENDPOINT_SIZE 64
|
||
|
|
||
|
void cdc_ecm_configure_endpoints() {
|
||
|
#if CDC_ECM_USES_INTERRUPT_ENDPOINT
|
||
|
usb_configure_endpoint(INT_EP, \
|
||
|
TYPE_INTERRUPT, \
|
||
|
DIRECTION_IN, \
|
||
|
SIZE_8, \
|
||
|
TWO_BANKS, \
|
||
|
NYET_ENABLED);
|
||
|
#endif
|
||
|
|
||
|
usb_configure_endpoint(TX_EP, \
|
||
|
TYPE_BULK, \
|
||
|
DIRECTION_IN, \
|
||
|
SIZE_64, \
|
||
|
TWO_BANKS, \
|
||
|
NYET_ENABLED);
|
||
|
|
||
|
usb_configure_endpoint(RX_EP, \
|
||
|
TYPE_BULK, \
|
||
|
DIRECTION_OUT, \
|
||
|
SIZE_64, \
|
||
|
TWO_BANKS, \
|
||
|
NYET_ENABLED);
|
||
|
#if CDC_ECM_USES_INTERRUPT_ENDPOINT
|
||
|
Usb_reset_endpoint(INT_EP);
|
||
|
#endif
|
||
|
Usb_reset_endpoint(TX_EP);
|
||
|
Usb_reset_endpoint(RX_EP);
|
||
|
usb_eth_is_active = 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
cdc_ecm_notify_connection_speed_change(uint32_t upstream,uint32_t downstream) {
|
||
|
#if CDC_ECM_USES_INTERRUPT_ENDPOINT
|
||
|
Usb_select_endpoint(INT_EP);
|
||
|
|
||
|
if(!Is_usb_endpoint_enabled())
|
||
|
return;
|
||
|
|
||
|
if(usb_endpoint_wait_for_IN_ready()!=0)
|
||
|
return;
|
||
|
|
||
|
Usb_send_control_in();
|
||
|
|
||
|
Usb_write_byte(0x51); // 10100001b
|
||
|
Usb_write_byte(CDC_NOTIFY_CONNECTION_SPEED_CHANGE);
|
||
|
Usb_write_word(0x0000);
|
||
|
Usb_write_word(ECM_INTERFACE0_NB);
|
||
|
Usb_write_word(0x0008);
|
||
|
|
||
|
Usb_send_in();
|
||
|
|
||
|
if(usb_endpoint_wait_for_write_enabled()!=0)
|
||
|
return;
|
||
|
|
||
|
Usb_write_long(upstream);
|
||
|
Usb_write_long(downstream);
|
||
|
Usb_send_in();
|
||
|
|
||
|
PRINTF_P(PSTR("cdc_ecm: CDC_NOTIFY_CONNECTION_SPEED_CHANGE UP:%d DOWN:%d\n"),upstream,downstream);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void cdc_ecm_set_active(uint8_t value) {
|
||
|
if(value!=usb_eth_is_active) {
|
||
|
Led3_on();
|
||
|
|
||
|
usb_eth_is_active = value;
|
||
|
cdc_ecm_notify_network_connection(value);
|
||
|
if(value) {
|
||
|
cdc_ecm_notify_connection_speed_change(250000,250000);
|
||
|
} else {
|
||
|
cdc_ecm_notify_connection_speed_change(0,0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint8_t
|
||
|
cdc_ecm_process(void) {
|
||
|
static uint8_t doInit = 1;
|
||
|
|
||
|
Usb_select_endpoint(RX_EP);
|
||
|
|
||
|
if(!Is_usb_endpoint_enabled()) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (doInit) {
|
||
|
#ifdef USB_ETH_HOOK_INIT
|
||
|
USB_ETH_HOOK_INIT();
|
||
|
#endif
|
||
|
cdc_ecm_notify_network_connection(1);
|
||
|
cdc_ecm_notify_connection_speed_change(250000,250000);
|
||
|
doInit = 0;
|
||
|
if(usb_ecm_packet_filter & PACKET_TYPE_PROMISCUOUS) {
|
||
|
#if RF230BB
|
||
|
rf230_set_promiscuous_mode(true);
|
||
|
#else
|
||
|
radio_set_trx_state(RX_ON);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Select again, just to make sure.
|
||
|
Usb_select_endpoint(RX_EP);
|
||
|
}
|
||
|
|
||
|
if(!usb_eth_is_active) {
|
||
|
// If we aren't active, just eat the packets.
|
||
|
if(Is_usb_read_enabled()) {
|
||
|
Usb_ack_receive_out();
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//Connected!
|
||
|
Led0_on();
|
||
|
|
||
|
if(Is_usb_read_enabled()) {
|
||
|
uint16_t bytecounter;
|
||
|
uint16_t bytes_received = 0;
|
||
|
U8 * buffer = uip_buf;
|
||
|
|
||
|
if(!usb_eth_ready_for_next_packet()) {
|
||
|
// Since we aren't ready for a packet yet,
|
||
|
// just return.
|
||
|
goto bail;
|
||
|
}
|
||
|
|
||
|
#ifdef USB_ETH_HOOK_RX_START
|
||
|
USB_ETH_HOOK_RX_START();
|
||
|
#endif
|
||
|
|
||
|
while((bytecounter=Usb_byte_counter_8())==CDC_ECM_DATA_ENDPOINT_SIZE) {
|
||
|
while((bytes_received<USB_ETH_MTU) && (bytecounter--)) {
|
||
|
*buffer++ = Usb_read_byte();
|
||
|
bytes_received++;
|
||
|
}
|
||
|
bytes_received+=bytecounter+1;
|
||
|
|
||
|
//ACK previous data
|
||
|
Usb_ack_receive_out();
|
||
|
|
||
|
//Wait for new data
|
||
|
if(usb_endpoint_wait_for_read_enabled()!=0) {
|
||
|
USB_ETH_HOOK_RX_ERROR("Timeout: read enabled");
|
||
|
goto bail;
|
||
|
}
|
||
|
}
|
||
|
bytecounter = Usb_byte_counter_8();
|
||
|
while((bytes_received<USB_ETH_MTU) && (bytecounter--)) {
|
||
|
*buffer++ = Usb_read_byte();
|
||
|
bytes_received++;
|
||
|
}
|
||
|
bytes_received+=bytecounter+1;
|
||
|
|
||
|
//Ack final data packet
|
||
|
Usb_ack_receive_out();
|
||
|
|
||
|
//PRINTF_P(PSTR("cdc_ecm: Got packet %d bytes long\n"),bytes_received);
|
||
|
|
||
|
#ifdef USB_ETH_HOOK_RX_END
|
||
|
USB_ETH_HOOK_RX_END();
|
||
|
#endif
|
||
|
|
||
|
//Send data over RF or to local stack
|
||
|
if(bytes_received<=USB_ETH_MTU) {
|
||
|
|
||
|
USB_ETH_HOOK_HANDLE_INBOUND_PACKET(uip_buf,bytes_received);
|
||
|
} else {
|
||
|
USB_ETH_HOOK_RX_ERROR("Oversized packet");
|
||
|
}
|
||
|
}
|
||
|
bail:
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
uint8_t
|
||
|
ecm_send(uint8_t * senddata, uint16_t sendlen, uint8_t led) {
|
||
|
U8 byte_in_packet = 0;
|
||
|
|
||
|
//Send Data
|
||
|
Usb_select_endpoint(TX_EP);
|
||
|
|
||
|
if(usb_endpoint_wait_for_write_enabled()!=0) {
|
||
|
USB_ETH_HOOK_TX_ERROR("Timeout: write enabled");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#ifdef USB_ETH_HOOK_TX_START
|
||
|
USB_ETH_HOOK_TX_START();
|
||
|
#endif
|
||
|
|
||
|
//Send packet
|
||
|
while(sendlen) {
|
||
|
Usb_write_byte(*senddata);
|
||
|
senddata++;
|
||
|
sendlen--;
|
||
|
byte_in_packet++;
|
||
|
|
||
|
//If endpoint is full, send data in
|
||
|
//And then wait for data to transfer
|
||
|
if (!Is_usb_write_enabled()) {
|
||
|
Usb_ack_in_ready();
|
||
|
|
||
|
if(usb_endpoint_wait_for_write_enabled()!=0) {
|
||
|
USB_ETH_HOOK_TX_ERROR("Timeout: write enabled");
|
||
|
return 0;
|
||
|
}
|
||
|
byte_in_packet=0;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//Send last data in - also handles sending a ZLP if needed
|
||
|
Usb_ack_in_ready();
|
||
|
|
||
|
#ifdef USB_ETH_HOOK_TX_END
|
||
|
USB_ETH_HOOK_TX_END();
|
||
|
#endif
|
||
|
|
||
|
//Wait for ready
|
||
|
if(usb_endpoint_wait_for_IN_ready()!=0) {
|
||
|
USB_ETH_HOOK_TX_ERROR("Timeout: IN ready");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|