Merge CDC-ECM, RNG, DFU bootloader, watchdog, settings manager, energy scan routines of Robert Quattlebaum

This commit is contained in:
dak664 2010-09-17 21:59:09 +00:00
parent 7b529cac03
commit 110bc0242e
42 changed files with 4739 additions and 2669 deletions

View file

@ -0,0 +1,327 @@
#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;
}

View file

@ -0,0 +1,18 @@
#ifndef __CDC_ECM_H__
#define __CDC_ECM_H__
#include "contiki.h"
#include <stdint.h>
#include "conf_usb.h"
#define SET_ETHERNET_PACKET_FILTER (0x43)
extern uint8_t cdc_ecm_process(void);
extern uint8_t ecm_send(uint8_t * senddata, uint16_t sendlen, uint8_t led);
extern void cdc_ecm_set_ethernet_packet_filter(void);
extern void cdc_ecm_configure_endpoints();
extern void cdc_ecm_set_active(uint8_t value);
#endif // __CDC_ECM_H__

View file

@ -0,0 +1,296 @@
#include "cdc_eem.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];
//_____ M A C R O S ________________________________________________________
#define EEMCMD_ECHO 0x00 ///bmEEMCmd Echo
#define EEMCMD_ECHO_RESPONSE 0x01 ///bmEEMCmd Echo Response
#define EEMCMD_SUSPEND_HINT 0x02 ///bmEEMCmd Suspend Hint
#define EEMCMD_RESPONSE_HINT 0x03 ///bmEEMCmd Response Hint
#define EEMCMD_RESPONSE_COMPLETE_HINT 0x04 ///bmEEMCmd Response Complete Hint
#define EEMCMD_TICKLE 0x05 ///bmEEMCmd Tickle
void cdc_eem_configure_endpoints() {
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);
Usb_reset_endpoint(TX_EP);
Usb_reset_endpoint(RX_EP);
}
void cdc_eem_process(void) {
uint16_t datalength;
uint8_t bytecounter, headercounter;
uint16_t i;
#ifdef USB_ETH_HOOK_INIT
static uint8_t doInit = 1;
if (doInit) {
USB_ETH_HOOK_INIT();
doInit = 0;
}
#endif
//Connected!
Led0_on();
Usb_select_endpoint(RX_EP);
//If we have data and a free buffer
if(Is_usb_receive_out() && (uip_len == 0)) {
//Read how much (endpoint only stores up to 64 bytes anyway)
bytecounter = Usb_byte_counter_8();
//EEM uses 2 bytes as a header
headercounter = 2;
uint8_t fail = 0;
//Hmm.. what's going on here?
if (bytecounter < headercounter) {
Usb_ack_receive_out();
//TODO CO done = 1;
}
//Read EEM Header
i = 0;
while (headercounter) {
usb_eth_data_buffer[i] = Usb_read_byte();
bytecounter--;
headercounter--;
i++;
}
//Order is LSB/MSB, so MSN is in usb_eth_data_buffer[1]
//Bit 15 indicates command packet when set
if (usb_eth_data_buffer[1] & 0x80) {
//not a data payload
datalength = 0;
} else {
//'0' indicates data packet
//Length is lower 14 bits
datalength = usb_eth_data_buffer[0] | ((usb_eth_data_buffer[1] & 0x3F) << 8);
}
/* EEM Command Packet */
if ((datalength == 0) && (fail == 0))
{
uint8_t command;
uint16_t echoLength;
//Strip command off
command = usb_eth_data_buffer[1] & 0x38;
command = command >> 3;
//Decode command type
switch (command)
{
/* Echo Request */
case EEMCMD_ECHO:
//Get echo length
echoLength = (usb_eth_data_buffer[1] & 0x07) << 8; //MSB
echoLength |= usb_eth_data_buffer[0]; //LSB
//TODO: everything. oops.
break;
/* Everything else: Whatever. */
case EEMCMD_ECHO_RESPONSE:
case EEMCMD_SUSPEND_HINT:
case EEMCMD_RESPONSE_HINT:
case EEMCMD_RESPONSE_COMPLETE_HINT:
case EEMCMD_TICKLE:
break;
default: break;
}
}
/* EEM Data Packet */
else if (datalength && (fail == 0))
{
//Looks like we've got a live one
#ifdef USB_ETH_HOOK_RX_START
USB_ETH_HOOK_RX_START();
#endif
uint16_t bytes_received = 0;
uint16_t dataleft = datalength;
U8 * buffer = uip_buf;
while(dataleft)
{
*buffer++ = Usb_read_byte();
dataleft--;
bytecounter--;
bytes_received++;
//Check if endpoint is done but we are expecting more data
if ((bytecounter == 0) && (dataleft))
{
//ACK previous data
Usb_ack_receive_out();
//Wait for new data
while (!Is_usb_receive_out());
//Get new data
bytecounter = Usb_byte_counter_8();
//ZLP?
if (bytecounter == 0)
{
//Incomplete!!
break;
}
}
}
//Ack final data packet
Usb_ack_receive_out();
#ifdef USB_ETH_HOOK_RX_END
USB_ETH_HOOK_RX_END();
#endif
//Packet has CRC, nobody wants that garbage
datalength -= 4;
//Send data over RF or to local stack
if(datalength <= USB_ETH_MTU) {
USB_ETH_HOOK_HANDLE_INBOUND_PACKET(uip_buf,datalength);
} else {
USB_ETH_HOOK_RX_ERROR("Oversized packet");
}
} //if (datalength)
} //if(Is_usb_receive_out() && (uip_len == 0))
}
/**
\brief Send a single ethernet frame using EEM
*/
uint8_t eem_send(uint8_t * senddata, uint16_t sendlen, uint8_t led)
{
//Make a header
uint8_t header[2];
//Fake CRC! Add 4 to length for CRC
sendlen += 4;
header[0] = (sendlen >> 8) & 0x3f;
header[1] = sendlen & 0xff;
//We send CRC seperatly..
sendlen -= 4;
//Send Data
Usb_select_endpoint(TX_EP);
//Usb_send_in();
//Wait for ready
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 header (LSB then MSB)
Usb_write_byte(header[1]);
Usb_write_byte(header[0]);
//Send packet
while(sendlen) {
Usb_write_byte(*senddata);
senddata++;
sendlen--;
//If endpoint is full, send data in
//And then wait for data to transfer
if (!Is_usb_write_enabled()) {
Usb_send_in();
if(usb_endpoint_wait_for_write_enabled()!=0) {
USB_ETH_HOOK_TX_ERROR("Timeout: write enabled");
return 0;
}
}
}
//CRC = 0xdeadbeef
//Linux kernel 2.6.31 needs 0xdeadbeef in wrong order,
//like this: uint8_t crc[4] = {0xef, 0xbe, 0xad, 0xde};
//This is fixed in 2.6.32 to the correct order (0xde, 0xad, 0xbe, 0xef)
uint8_t crc[4] = {0xde, 0xad, 0xbe, 0xef};
sendlen = 4;
uint8_t i = 0;
//Send fake CRC
while(sendlen) {
Usb_write_byte(crc[i]);
i++;
sendlen--;
//If endpoint is full, send data in
//And then wait for data to transfer
if (!Is_usb_write_enabled()) {
Usb_send_in();
if(usb_endpoint_wait_for_write_enabled()!=0) {
USB_ETH_HOOK_TX_ERROR("Timeout: write enabled");
return 0;
}
}
}
//Send last data in - also handles sending a ZLP if needed
Usb_send_in();
#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;
}

View file

@ -0,0 +1,12 @@
#ifndef __CDC_EEM_H__
#define __CDC_EEM_H__
#include "contiki.h"
#include <stdint.h>
extern void cdc_eem_process(void);
extern uint8_t eem_send(uint8_t * senddata, uint16_t sendlen, uint8_t led);
extern void cdc_eem_configure_endpoints();
#endif // __CDC_EEM_H__

View file

@ -58,6 +58,7 @@ RNDIS Status Information:
//_____ I N C L U D E S ____________________________________________________
#include <stdbool.h>
#include "radio.h"
#include "contiki.h"
#include "config.h"
@ -65,12 +66,18 @@ RNDIS Status Information:
#include "usb_descriptors.h"
#include "usb_specific_request.h"
#include "rndis/rndis_protocol.h"
#include "rndis/rndis_task.h"
#include "uip.h"
#include "serial/uart_usb_lib.h"
#include "sicslow_ethernet.h"
#include <avr/pgmspace.h>
#include <string.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
//_____ M A C R O S ________________________________________________________
//_____ D E F I N I T I O N ________________________________________________
@ -80,14 +87,10 @@ RNDIS Status Information:
extern PGM_VOID_P pbuffer;
extern U8 data_to_transfer;
//NB: If you change the OID list be sure to update this!!!
//#define OID_LIST_LENGTH 50
#define OID_LIST_LENGTH 35
/**
* \brief List of supported RNDIS OID's
*/
prog_uint32_t OIDSupportedList[OID_LIST_LENGTH] = {
prog_uint32_t OIDSupportedList[] = {
/* Required General */
OID_GEN_SUPPORTED_LIST ,
OID_GEN_HARDWARE_STATUS ,
@ -128,7 +131,7 @@ prog_uint32_t OIDSupportedList[OID_LIST_LENGTH] = {
/*802.11 OID's not fully implemented yet. Hence do not say we
support them */
#ifdef DONOTEVERDEFINETHISORBADSTUFFHAPPENS
#if USB_ETH_EMULATE_WIFI
/* 802.11 OIDs */
OID_802_11_BSSID ,
OID_802_11_SSID ,
@ -156,18 +159,17 @@ prog_uint32_t OIDSupportedList[OID_LIST_LENGTH] = {
OID_PNP_ENABLE_WAKE_UP ,
OID_PNP_ADD_WAKE_UP_PATTERN ,
OID_PNP_REMOVE_WAKE_UP_PATTERN
};
};
#define OID_LIST_LENGTH sizeof(OIDSupportedList)/sizeof(*OIDSupportedList)
rndis_state_t rndis_state;
rndis_stat_t rndis_stat;
usb_eth_stat_t usb_eth_stat;
uint8_t schedule_interrupt = 0;
uint64_t rndis_ethernet_addr = 0x203478928323ULL;
//_____ D E C L A R A T I O N ______________________________________________
@ -188,7 +190,7 @@ U8 data_to_send = 0x00;
*
* \return True on success, false on failure.
*/
uint8_t send_encapsulated_command(uint16_t wLength)
uint8_t rndis_send_encapsulated_command(uint16_t wLength)
{
U8 i = 0;
@ -200,12 +202,6 @@ uint8_t send_encapsulated_command(uint16_t wLength)
if (wLength > ENC_BUF_SIZE)
wLength = ENC_BUF_SIZE;
//For debugging: this shouldn't happen, just checked it didn't
//if (data_to_send) {
// while(1);
//}
//Read in all the bytes...
uint8_t nb_counter;
@ -256,9 +252,13 @@ uint8_t send_encapsulated_command(uint16_t wLength)
m->MinorVersion = RNDIS_MAJOR_VERSION;
m->Status = RNDIS_STATUS_SUCCESS;
m->DeviceFlags = RNDIS_DF_CONNECTIONLESS;
#if USB_ETH_EMULATE_WIFI
m->Medium = NDIS_MEDIUM_WIRELESS_LAN;
#else
m->Medium = RNDIS_MEDIUM_802_3;
#endif // USB_ETH_EMULATE_WIFI
m->MaxPacketsPerTransfer = 1;
m->MaxTransferSize = 1338; /* Space for 1280 IP buffer, Ethernet Header,
m->MaxTransferSize = USB_ETH_MTU + 58; /* Space for 1280 IP buffer, Ethernet Header,
RNDIS messages */
m->PacketAlignmentFactor = 3;
m->AfListOffset = 0;
@ -353,7 +353,9 @@ void rndis_send_interrupt(void)
uint32_t oid_packet_filter = 0x0000000;
#if USB_ETH_EMULATE_WIFI
uint16_t panid = 0xbaad;
#endif
/**
* \brief Function to handle a RNDIS "QUERY" command in the encapsulated_buffer
@ -392,15 +394,20 @@ void rndis_query_process(void)
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
*INFBUF = NDIS_MEDIUM_802_3; /* NDIS_MEDIUM_WIRELESS_LAN instead? */
case OID_GEN_PHYSICAL_MEDIUM:
#if USB_ETH_EMULATE_WIFI
*INFBUF = NDIS_MEDIUM_WIRELESS_LAN;
#else
*INFBUF = NDIS_MEDIUM_802_3;
#endif
break;
case OID_GEN_MAXIMUM_FRAME_SIZE:
*INFBUF = (uint32_t) 1280; //1280 //102; /* Assume 25 octet header on 15.4 */
*INFBUF = (uint32_t) USB_ETH_MTU-14; //1280 //102; /* Assume 25 octet header on 15.4 */
break;
case OID_GEN_LINK_SPEED:
*INFBUF = (uint32_t) 100; /* in 100 bytes/sec units.. this is kinda a lie */
*INFBUF = (uint32_t) 250000/100; /* in 100 bytes/sec units.. this is kinda a lie */
break;
case OID_GEN_TRANSMIT_BLOCK_SIZE:
@ -422,57 +429,35 @@ void rndis_query_process(void)
break;
case OID_GEN_MAXIMUM_TOTAL_SIZE:
*INFBUF = (uint32_t) 1300; //127;
*INFBUF = (uint32_t) USB_ETH_MTU; //127;
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
*INFBUF = NDIS_MEDIA_STATE_CONNECTED;
*INFBUF = usb_eth_is_active?NDIS_MEDIA_STATE_CONNECTED:NDIS_MEDIA_STATE_DISCONNECTED;
break;
case OID_GEN_VENDOR_DRIVER_VERSION:
*INFBUF = 0x00001000;
break;
case OID_GEN_PHYSICAL_MEDIUM:
*INFBUF = NDIS_MEDIUM_802_3; /*NDIS_MEDIUM_WIRELESS_LAN;*/
break;
case OID_GEN_CURRENT_LOOKAHEAD:
*INFBUF = (uint32_t) 1280; //102;
*INFBUF = (uint32_t) USB_ETH_MTU-14; //102;
// case OID_GEN_RNDIS_CONFIG_PARAMETER:
// break;
/******* 802.3 (Ethernet) *******/
/*The address of the NIC encoded in the hardware.*/
case OID_802_3_PERMANENT_ADDRESS:
//Clear unused bytes
*(INFBUF + 1) = 0;
//Set address
*((uint8_t *)INFBUF + 0) = *(((uint8_t * ) &rndis_ethernet_addr) + 5);
*((uint8_t *)INFBUF + 1) = *(((uint8_t * ) &rndis_ethernet_addr) + 4);
*((uint8_t *)INFBUF + 2) = *(((uint8_t * ) &rndis_ethernet_addr) + 3);
*((uint8_t *)INFBUF + 3) = *(((uint8_t * ) &rndis_ethernet_addr) + 2);
*((uint8_t *)INFBUF + 4) = *(((uint8_t * ) &rndis_ethernet_addr) + 1);
*((uint8_t *)INFBUF + 5) = *(((uint8_t * ) &rndis_ethernet_addr) + 0);
/*4+2 = 6 Bytes of eth address */
c->InformationBufferLength += 2;
break;
/*The address the NIC is currently using.*/
case OID_802_3_CURRENT_ADDRESS:
//Clear unused bytes
*(INFBUF + 1) = 0;
//Set address
*((uint8_t *)INFBUF + 0) = *(((uint8_t * ) &rndis_ethernet_addr) + 5);
*((uint8_t *)INFBUF + 1) = *(((uint8_t * ) &rndis_ethernet_addr) + 4);
*((uint8_t *)INFBUF + 2) = *(((uint8_t * ) &rndis_ethernet_addr) + 3);
*((uint8_t *)INFBUF + 3) = *(((uint8_t * ) &rndis_ethernet_addr) + 2);
*((uint8_t *)INFBUF + 4) = *(((uint8_t * ) &rndis_ethernet_addr) + 1);
*((uint8_t *)INFBUF + 5) = *(((uint8_t * ) &rndis_ethernet_addr) + 0);
//get address
usb_eth_get_mac_address((uint8_t*)INFBUF);
/*4+2 = 6 Bytes of eth address */
c->InformationBufferLength += 2;
@ -495,20 +480,14 @@ void rndis_query_process(void)
/* Frames received with alignment error */
case OID_802_3_RCV_ERROR_ALIGNMENT:
*INFBUF = 0;
break;
/* Frames transmitted with one collision */
case OID_802_3_XMIT_ONE_COLLISION:
*INFBUF = 0;
break;
/* Frames transmitted with more than one collision */
case OID_802_3_XMIT_MORE_COLLISIONS:
*INFBUF = 0;
break;
#if USB_ETH_EMULATE_WIFI
/*** 802.11 OIDs ***/
case OID_802_11_BSSID:
*INFBUF = (uint32_t)panid;
@ -543,27 +522,28 @@ void rndis_query_process(void)
case OID_802_11_WEP_STATUS:
case OID_802_11_AUTHENTICATION_MODE:
break;
#endif //USB_ETH_EMULATE_WIFI
/*** Statistical ***/
/* Frames transmitted without errors */
case OID_GEN_XMIT_OK:
*INFBUF = rndis_stat.txok;
*INFBUF = usb_eth_stat.txok;
break;
/* Frames received without errors */
case OID_GEN_RCV_OK:
*INFBUF = rndis_stat.rxok;
*INFBUF = usb_eth_stat.rxok;
break;
/* Frames received with errors */
case OID_GEN_RCV_ERROR:
*INFBUF = rndis_stat.rxbad;
*INFBUF = usb_eth_stat.rxbad;
break;
/* Frames transmitted with errors */
case OID_GEN_XMIT_ERROR:
*INFBUF = rndis_stat.txbad;
*INFBUF = usb_eth_stat.txbad;
break;
/* Frames dropped due to lack of buffer space */
@ -617,9 +597,21 @@ void rndis_query_process(void)
#define CFGBUF ((rndis_config_parameter_t *) INFBUF)
#define PARMNAME ((uint8_t *)CFGBUF + CFGBUF->ParameterNameOffset)
#define PARMVALUE ((uint8_t *)CFGBUF + CFGBUF->ParameterValueOffset)
#define PARMVALUELENGTH CFGBUF->ParameterValueLength
#define PARM_NAME_LENGTH 25 /* Maximum parameter name length */
bool
rndis_handle_config_parm(const char* parmname,const uint8_t* parmvalue,size_t parmlength) {
if (strncmp_P(parmname, PSTR("rawmode"), 7) == 0) {
if (parmvalue[0] == '0') {
usbstick_mode.raw = 0;
} else {
usbstick_mode.raw = 1;
}
}
}
/**
* \brief Function to deal with a RNDIS "SET" command present in the
* encapsulated_buffer
@ -664,13 +656,7 @@ void rndis_set_process(void)
Parameter type: single octet
Parameter values: '0' = disabled, '1' = enabled
*/
if (strncmp_P(parmname, PSTR("rawmode"), 7) == 0) {
if (*PARMVALUE == '0') {
usbstick_mode.raw = 0;
} else {
usbstick_mode.raw = 1;
}
}
rndis_handle_config_parm(parmname,PARMVALUE,PARMVALUELENGTH);
break;
@ -700,6 +686,7 @@ void rndis_set_process(void)
case OID_802_3_MULTICAST_LIST:
break;
#if USB_ETH_EMULATE_WIFI
/* Mandatory 802.11 OIDs */
case OID_802_11_BSSID:
panid = *INFBUF;
@ -708,6 +695,7 @@ void rndis_set_process(void)
case OID_802_11_SSID:
break;
//TODO: rest of 802.11
#endif // USB_ETH_EMULATE_WIFI
/* Power Managment: fails for now */
case OID_PNP_ADD_WAKE_UP_PATTERN:
@ -743,7 +731,7 @@ void rndis_set_process(void)
* the "SEND ENCAPSULATED COMMAND" message, which will trigger
* and interrupt on the host so it knows data is ready.
*/
uint8_t get_encapsulated_command(void)
uint8_t rndis_get_encapsulated_command(void)
{
U8 nb_byte, zlp, i;
@ -828,6 +816,261 @@ uint8_t rndis_send_status(rndis_Status_t stat)
return 0;
}
void rndis_configure_endpoints() {
usb_configure_endpoint(INT_EP, \
TYPE_INTERRUPT, \
DIRECTION_IN, \
SIZE_8, \
ONE_BANK, \
NYET_ENABLED);
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);
Usb_reset_endpoint(INT_EP);
Usb_reset_endpoint(TX_EP);
Usb_reset_endpoint(RX_EP);
}
extern char usb_busy;
extern uint8_t usb_eth_data_buffer[64];
#define PBUF ((rndis_data_packet_t *) usb_eth_data_buffer)
uint8_t rndis_process(void)
{
uint8_t bytecounter, headercounter;
uint16_t i, dataoffset;
if(rndis_state != rndis_data_initialized) { //Enumeration processs OK ?
return 0;
}
#ifdef USB_ETH_HOOK_INIT
static uint8_t doInit = 1;
if (doInit) {
USB_ETH_HOOK_INIT();
doInit = 0;
}
#endif
//Connected!
Led0_on();
Usb_select_endpoint(RX_EP);
//If we have data and a free buffer
if(Is_usb_receive_out() && (uip_len == 0)) {
//Read how much (endpoint only stores up to 64 bytes anyway)
bytecounter = Usb_byte_counter_8();
//Try and read the header in
headercounter = sizeof(rndis_data_packet_t);
uint8_t fail = 0;
//Hmm.. what's going on here
if (bytecounter < headercounter) {
Usb_ack_receive_out();
fail = 1;
}
i = 0;
while (headercounter) {
usb_eth_data_buffer[i] = Usb_read_byte();
bytecounter--;
headercounter--;
i++;
}
//This is no good. Probably lost syncronization... just drop it for now
if(PBUF->MessageType != REMOTE_NDIS_PACKET_MSG) {
Usb_ack_receive_out();
fail = 1;
}
//802.3 does not have OOB data, and we don't care about per-packet data
//so that just leave regular packet data...
if (PBUF->DataLength && (fail == 0)) {
//Looks like we've got a live one
#ifdef USB_ETH_HOOK_RX_START
USB_ETH_HOOK_RX_START();
#endif
//Get offset
dataoffset = PBUF->DataOffset;
//Make it offset from start of message, not DataOffset field
dataoffset += (sizeof(rndis_MessageType_t) + sizeof(rndis_MessageLength_t));
//Subtract what we already took
dataoffset -= sizeof(rndis_data_packet_t);
//Clear this flag
Usb_ack_nak_out();
//Read to the start of data
while(dataoffset) {
Usb_read_byte();
dataoffset--;
bytecounter--;
//If endpoint is done
if (bytecounter == 0) {
Usb_ack_receive_out();
//Wait for new data
while (!Is_usb_receive_out() && (!Is_usb_receive_nak_out()));
//Check for NAK
// TODO: darco: What in the world is this for?
if (Is_usb_receive_nak_out()) {
Usb_ack_nak_out();
break;
}
bytecounter = Usb_byte_counter_8();
//ZLP?
if (bytecounter == 0)
break;
}
}
//Read the data itself in
uint8_t * uipdata = uip_buf;
uint16_t datalen = PBUF->DataLength;
while(datalen) {
*uipdata++ = Usb_read_byte();
datalen--;
bytecounter--;
//If endpoint is done
if (bytecounter == 0) {
//Might be everything we need!
if (datalen) {
Usb_ack_receive_out();
//Wait for new data
if(usb_endpoint_wait_for_receive_out()!=0) {
USB_ETH_HOOK_RX_ERROR("Timeout: receive out");
goto bail;
}
bytecounter = Usb_byte_counter_8();
}
}
}
//Ack final data packet
Usb_ack_receive_out();
#ifdef USB_ETH_HOOK_RX_END
USB_ETH_HOOK_RX_END();
#endif
//Send data over RF or to local stack
if(PBUF->DataLength <= USB_ETH_MTU) {
USB_ETH_HOOK_HANDLE_INBOUND_PACKET(uip_buf,PBUF->DataLength);
} else {
USB_ETH_HOOK_RX_ERROR("Oversized packet");
}
} //if (PBUF->DataLength)
}
bail:
return 1;
}
/**
\brief Send data over RNDIS interface, data is in uipbuf and length is uiplen
*/
uint8_t rndis_send(uint8_t * senddata, uint16_t sendlen, uint8_t led)
{
uint16_t i;
//Setup Header
PBUF->MessageType = REMOTE_NDIS_PACKET_MSG;
PBUF->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_MessageType_t) - sizeof(rndis_MessageLength_t);
PBUF->DataLength = sendlen;
PBUF->OOBDataLength = 0;
PBUF->OOBDataOffset = 0;
PBUF->NumOOBDataElements = 0;
PBUF->PerPacketInfoOffset = 0;
PBUF->PerPacketInfoLength = 0;
PBUF->DeviceVcHandle = 0;
PBUF->Reserved = 0;
PBUF->MessageLength = sizeof(rndis_data_packet_t) + PBUF->DataLength;
//Send Data
Usb_select_endpoint(TX_EP);
Usb_send_in();
//Wait for ready
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
//Setup first part of transfer...
for(i = 0; i < sizeof(rndis_data_packet_t); i++) {
Usb_write_byte(usb_eth_data_buffer[i]);
}
//Send packet
while(sendlen) {
Usb_write_byte(*senddata);
senddata++;
sendlen--;
//If endpoint is full, send data in
//And then wait for data to transfer
if (!Is_usb_write_enabled()) {
Usb_send_in();
if(usb_endpoint_wait_for_write_enabled()!=0) {
USB_ETH_HOOK_TX_ERROR("Timeout: write enabled");
return 0;
}
}
}
Usb_send_in();
#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;
}
/****************** Radio Interface ****************/
@ -837,15 +1080,11 @@ uint8_t rndis_send_status(rndis_Status_t stat)
*/
void rndis_packetFilter(uint32_t newfilter)
{
#if !RF230BB
if (newfilter & NDIS_PACKET_TYPE_PROMISCUOUS) {
rxMode = RX_ON;
radio_set_trx_state(RX_ON);
USB_ETH_HOOK_SET_PROMISCIOUS_MODE(true);
} else {
rxMode = RX_AACK_ON;
radio_set_trx_state(RX_AACK_ON);
USB_ETH_HOOK_SET_PROMISCIOUS_MODE(false);
}
#endif
}
/** @} */

View file

@ -303,22 +303,23 @@ typedef struct{
uint32_t rxok;
uint32_t txbad;
uint32_t rxbad;
} rndis_stat_t;
} usb_eth_stat_t;
extern rndis_stat_t rndis_stat;
extern usb_eth_stat_t usb_eth_stat;
extern rndis_state_t rndis_state;
extern uint8_t schedule_interrupt;
extern uint64_t rndis_ethernet_addr;
uint8_t send_encapsulated_command(uint16_t wLength);
uint8_t get_encapsulated_command(void);
uint8_t rndis_send_encapsulated_command(uint16_t wLength);
uint8_t rndis_get_encapsulated_command(void);
void rndis_send_interrupt(void);
void rndis_query_process(void);
void rndis_set_process(void);
uint8_t rndis_send_status(rndis_Status_t stat);
uint8_t rndis_process(void);
uint8_t rndis_send(uint8_t * senddata, uint16_t sendlen, uint8_t led);
extern void rndis_configure_endpoints();
#endif //_RNDIS_H

View file

@ -59,6 +59,9 @@
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "rndis/cdc_ecm.h"
#include "rndis/cdc_eem.h"
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
#define PRINTF printf
#define PRINTF_P printf_P
@ -66,12 +69,6 @@
//_____ M A C R O S ________________________________________________________
#define EEMCMD_ECHO 0x00 ///bmEEMCmd Echo
#define EEMCMD_ECHO_RESPONSE 0x01 ///bmEEMCmd Echo Response
#define EEMCMD_SUSPEND_HINT 0x02 ///bmEEMCmd Suspend Hint
#define EEMCMD_RESPONSE_HINT 0x03 ///bmEEMCmd Response Hint
#define EEMCMD_RESPONSE_COMPLETE_HINT 0x04 ///bmEEMCmd Response Complete Hint
#define EEMCMD_TICKLE 0x05 ///bmEEMCmd Tickle
@ -84,436 +81,210 @@
#define RNDIS_TIMEOUT_DETACH 900
#define RNDIS_TIMEOUT_ATTACH 1000
#define PBUF ((rndis_data_packet_t *) data_buffer)
#define PBUF ((rndis_data_packet_t *) usb_eth_data_buffer)
//! Temp data buffer when adding RNDIS headers
uint8_t usb_eth_data_buffer[64];
uint64_t usb_ethernet_addr = 0x010000000002ULL;
//_____ D E C L A R A T I O N S ____________________________________________
uint8_t eem_send(uint8_t * senddata, uint16_t sendlen, uint8_t led);
uint8_t rndis_send(uint8_t * senddata, uint16_t sendlen, uint8_t led);
//! Timers for LEDs
uint8_t led1_timer, led2_timer;
//! Temp data buffer when adding RNDIS headers
uint8_t data_buffer[64];
//! Usb is busy with RNDIS
char usb_busy = 0;
uint8_t usb_eth_is_active = 1;
static struct etimer et;
static struct timer flood_timer;
uint8_t usb_eth_packet_is_available() {
Usb_select_endpoint(RX_EP);
return Is_usb_read_enabled();
}
static uint8_t doInit = 1;
extern uint8_t fingerPresent;
uint8_t usb_eth_ready_for_next_packet() {
#ifdef USB_ETH_HOOK_IS_READY_FOR_INBOUND_PACKET
return USB_ETH_HOOK_IS_READY_FOR_INBOUND_PACKET();
#else
return 1;
#endif
PROCESS(rndis_process, "RNDIS process");
return 1;
}
void rxtx_led_update(void)
{
// turn off LED's if necessary
if (led1_timer) {
led1_timer--;
if(led1_timer&(1<<2))
Led1_on();
else
Led1_off();
}
else
Led1_off();
if (led2_timer) {
led2_timer--;
if(led2_timer&(1<<2))
Led2_on();
else
Led2_off();
}
else
Led2_off();
}
/**
@brief This will enable the RX_START LED for a period
*/
void rx_start_led(void)
{
led1_timer|=(1<<3);
if(((led1_timer-1)&(1<<2)))
Led1_on();
}
/**
@brief This will enable the TRX_END LED for a period
*/
void tx_end_led(void)
{
led2_timer|=(1<<3);
if(((led2_timer-1)&(1<<2)))
Led1_on();
}
#if USB_ETH_CONF_MASS_STORAGE_FALLBACK
static void
usb_eth_setup_timeout_fallback_check() {
extern uint8_t fingerPresent;
/* Device is Enumerated but RNDIS not loading. We might
have a system that does not support IAD (winXP). If so
count the timeout then switch to just network interface. */
static uint16_t iad_fail_timeout, rndis_fail_timeout;
if (usb_mode == rndis_debug) {
//If we have timed out, detach
if (iad_fail_timeout == IAD_TIMEOUT_DETACH) {
//Failed - BUT we are using "reverse logic", hence we force device
//into this mode. This is used to allow Windows Vista have time to
//install the drivers
if (fingerPresent && (rndis_state != rndis_data_initialized) && Is_device_enumerated() ) {
iad_fail_timeout = 0;
} else {
stdout = NULL;
Usb_detach();
doInit = 1; //Also mark system as needing intilizing
}
//Then wait a few before re-attaching
} else if (iad_fail_timeout == IAD_TIMEOUT_ATTACH) {
if (fingerPresent) {
usb_mode = mass_storage;
} else {
usb_mode = rndis_only;
}
Usb_attach();
}
//Increment timeout when device is not initializing, OR we have already detached,
//OR the user had their finger on the device, indicating a reverse of logic
if ( ( (rndis_state != rndis_data_initialized) && Is_device_enumerated() ) ||
(iad_fail_timeout > IAD_TIMEOUT_DETACH) ||
(fingerPresent) ) {
iad_fail_timeout++;
} else {
iad_fail_timeout = 0;
}
} //usb_mode == rndis_debug
/* Device is Enumerated but RNDIS STIL not loading. We just
have RNDIS interface, so obviously no drivers on target.
Just go ahead and mount ourselves as mass storage... */
if (usb_mode == rndis_only) {
//If we have timed out, detach
if (rndis_fail_timeout == RNDIS_TIMEOUT_DETACH) {
Usb_detach();
//Then wait a few before re-attaching
} else if (rndis_fail_timeout == RNDIS_TIMEOUT_ATTACH) {
usb_mode = mass_storage;
Usb_attach();
}
//Increment timeout when device is not initializing, OR we are already
//counting to detach
if ( ( (rndis_state != rndis_data_initialized)) ||
(rndis_fail_timeout > RNDIS_TIMEOUT_DETACH) ) {
rndis_fail_timeout++;
} else {
rndis_fail_timeout = 0;
}
}//usb_mode == rnids_only
}
#endif
PROCESS(usb_eth_process, "USB Ethernet process");
/**
* \brief RNDIS Process
*
* This is the link between USB and the "good stuff". In this routine data
* is received and processed by RNDIS
* is received and processed by RNDIS, CDC-ECM, or CDC-EEM
*/
PROCESS_THREAD(rndis_process, ev, data_proc)
PROCESS_THREAD(usb_eth_process, ev, data_proc)
{
static struct etimer et;
PROCESS_BEGIN();
uint8_t bytecounter, headercounter;
uint16_t i, dataoffset;
clock_time_t timediff;
clock_time_t thetime;
while(1) {
rxtx_led_update();
// turn off LED's if necessary
if (led1_timer) led1_timer--;
else Led1_off();
if (led2_timer) led2_timer--;
else Led2_off();
/* Device is Enumerated but RNDIS not loading. We might
have a system that does not support IAD (winXP). If so
count the timeout then switch to just network interface. */
#if 0
static uint16_t iad_fail_timeout, rndis_fail_timeout;
if (usb_mode == rndis_debug) {
//If we have timed out, detach
if (iad_fail_timeout == IAD_TIMEOUT_DETACH) {
//Failed - BUT we are using "reverse logic", hence we force device
//into this mode. This is used to allow Windows Vista have time to
//install the drivers
if (fingerPresent && (rndis_state != rndis_data_initialized) && Is_device_enumerated() ) {
iad_fail_timeout = 0;
} else {
stdout = NULL;
Usb_detach();
doInit = 1; //Also mark system as needing intilizing
}
//Then wait a few before re-attaching
} else if (iad_fail_timeout == IAD_TIMEOUT_ATTACH) {
if (fingerPresent) {
usb_mode = mass_storage;
} else {
usb_mode = rndis_only;
}
Usb_attach();
}
//Increment timeout when device is not initializing, OR we have already detached,
//OR the user had their finger on the device, indicating a reverse of logic
if ( ( (rndis_state != rndis_data_initialized) && Is_device_enumerated() ) ||
(iad_fail_timeout > IAD_TIMEOUT_DETACH) ||
(fingerPresent) ) {
iad_fail_timeout++;
} else {
iad_fail_timeout = 0;
}
} //usb_mode == rndis_debug
/* Device is Enumerated but RNDIS STIL not loading. We just
have RNDIS interface, so obviously no drivers on target.
Just go ahead and mount ourselves as mass storage... */
if (usb_mode == rndis_only) {
//If we have timed out, detach
if (rndis_fail_timeout == RNDIS_TIMEOUT_DETACH) {
Usb_detach();
//Then wait a few before re-attaching
} else if (rndis_fail_timeout == RNDIS_TIMEOUT_ATTACH) {
usb_mode = mass_storage;
Usb_attach();
}
//Increment timeout when device is not initializing, OR we are already
//counting to detach
if ( ( (rndis_state != rndis_data_initialized)) ||
(rndis_fail_timeout > RNDIS_TIMEOUT_DETACH) ) {
rndis_fail_timeout++;
} else {
rndis_fail_timeout = 0;
}
}//usb_mode == rnids_only
#if USB_ETH_CONF_MASS_STORAGE_FALLBACK
usb_eth_setup_timeout_fallback_check();
#endif
if(rndis_state == rndis_data_initialized) //Enumeration processs OK ?
{
if (doInit) {
//start flood timer
timer_set(&flood_timer, CLOCK_SECOND / 5);
mac_ethernetSetup();
doInit = 0;
}
//Connected!
Led0_on();
Usb_select_endpoint(RX_EP);
//If we have data and a free buffer
if(Is_usb_receive_out() && (uip_len == 0)) {
//TODO: Fix this some better way
//If you need a delay in RNDIS to slow down super-fast sending, insert it here
//Also mark the USB as "in use"
//This is done as "flood control" by only allowing one IP packet per time limit
thetime = clock_time();
timediff = thetime - flood_timer.start;
//Oops, timer wrapped! Just ignore it for now
if (thetime < flood_timer.start) {
timediff = flood_timer.interval;
}
//If timer not yet expired
//if (timediff < flood_timer.interval) {
if (!timer_expired(&flood_timer)) {
//Wait until timer expiers
usb_busy = 1;
etimer_set(&et, flood_timer.interval - timediff);
//Try commenting out the next line if Jackdaw stops RF transmission in Windows after a 5 minute idle period - dak
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
//Reselect endpoint in case we lost it
Usb_select_endpoint(RX_EP);
usb_busy = 0;
}
//Restart flood timer
timer_restart(&flood_timer);
//Read how much (endpoint only stores up to 64 bytes anyway)
bytecounter = Usb_byte_counter_8();
//Try and read the header in
headercounter = sizeof(rndis_data_packet_t);
uint8_t fail = 0;
//Hmm.. what's going on here
if (bytecounter < headercounter) {
Usb_ack_receive_out();
fail = 1;
}
i = 0;
while (headercounter) {
data_buffer[i] = Usb_read_byte();
bytecounter--;
headercounter--;
i++;
}
//This is no good. Probably lost syncronization... just drop it for now
if(PBUF->MessageType != REMOTE_NDIS_PACKET_MSG) {
Usb_ack_receive_out();
fail = 1;
}
//802.3 does not have OOB data, and we don't care about per-packet data
//so that just leave regular packet data...
if (PBUF->DataLength && (fail == 0)) {
//Looks like we've got a live one
rx_start_led();
//Get offset
dataoffset = PBUF->DataOffset;
//Make it offset from start of message, not DataOffset field
dataoffset += (sizeof(rndis_MessageType_t) + sizeof(rndis_MessageLength_t));
//Subtract what we already took
dataoffset -= sizeof(rndis_data_packet_t);
//Clear this flag
Usb_ack_nak_out();
//Read to the start of data
while(dataoffset) {
Usb_read_byte();
dataoffset--;
bytecounter--;
//If endpoint is done
if (bytecounter == 0) {
Usb_ack_receive_out();
//Wait for new data
while (!Is_usb_receive_out() && (!Is_usb_receive_nak_out()));
//Check for NAK
if (Is_usb_receive_nak_out()) {
Usb_ack_nak_out();
break;
}
bytecounter = Usb_byte_counter_8();
//ZLP?
if (bytecounter == 0)
break;
}
}
//Read the data itself in
uint8_t * uipdata = uip_buf;
uint16_t datalen = PBUF->DataLength;
while(datalen) {
*uipdata++ = Usb_read_byte();
datalen--;
bytecounter--;
//If endpoint is done
if (bytecounter == 0) {
//Might be everything we need!
if (datalen) {
Usb_ack_receive_out();
//Wait for new data
while (!Is_usb_receive_out());
bytecounter = Usb_byte_counter_8();
}
}
}
//Ack final data packet
Usb_ack_receive_out();
//Send data over RF or to local stack
uip_len = PBUF->DataLength; //uip_len includes LLH_LEN
mac_ethernetToLowpan(uip_buf);
} //if (PBUF->DataLength)
} //if(Is_usb_receive_out() && (uip_len == 0))
} // if (rndis_data_intialized)
else if(Is_device_enumerated() && //Enumeration processs OK &&
(usb_mode == eem) ) //USB Stick is using EEM
{
uint16_t datalength;
if (doInit) {
mac_ethernetSetup();
doInit = 0;
}
//Connected!
Led0_on();
Usb_select_endpoint(RX_EP);
//If we have data and a free buffer
if(Is_usb_receive_out() && (uip_len == 0)) {
//Read how much (endpoint only stores up to 64 bytes anyway)
bytecounter = Usb_byte_counter_8();
//EEM uses 2 bytes as a header
headercounter = 2;
uint8_t fail = 0;
//Hmm.. what's going on here?
if (bytecounter < headercounter) {
Usb_ack_receive_out();
//TODO CO done = 1;
}
//Read EEM Header
i = 0;
while (headercounter) {
data_buffer[i] = Usb_read_byte();
bytecounter--;
headercounter--;
i++;
}
//Order is LSB/MSB, so MSN is in data_buffer[1]
//Bit 15 indicates command packet when set
if (data_buffer[1] & 0x80) {
//not a data payload
datalength = 0;
} else {
//'0' indicates data packet
//Length is lower 14 bits
datalength = data_buffer[0] | ((data_buffer[1] & 0x3F) << 8);
}
/* EEM Command Packet */
if ((datalength == 0) && (fail == 0))
{
uint8_t command;
uint16_t echoLength;
//Strip command off
command = data_buffer[1] & 0x38;
command = command >> 3;
//Decode command type
switch (command)
{
/* Echo Request */
case EEMCMD_ECHO:
//Get echo length
echoLength = (data_buffer[1] & 0x07) << 8; //MSB
echoLength |= data_buffer[0]; //LSB
//TODO: everything. oops.
break;
/* Everything else: Whatever. */
case EEMCMD_ECHO_RESPONSE:
case EEMCMD_SUSPEND_HINT:
case EEMCMD_RESPONSE_HINT:
case EEMCMD_RESPONSE_COMPLETE_HINT:
case EEMCMD_TICKLE:
break;
default: break;
}
}
/* EEM Data Packet */
else if (datalength && (fail == 0))
{
//Looks like we've got a live one
rx_start_led();
uint16_t bytes_received = 0;
uint16_t dataleft = datalength;
U8 * buffer = uip_buf;
while(dataleft)
{
*buffer++ = Usb_read_byte();
dataleft--;
bytecounter--;
bytes_received++;
//Check if endpoint is done but we are expecting more data
if ((bytecounter == 0) && (dataleft))
{
//ACK previous data
Usb_ack_receive_out();
//Wait for new data
while (!Is_usb_receive_out());
//Get new data
bytecounter = Usb_byte_counter_8();
//ZLP?
if (bytecounter == 0)
{
//Incomplete!!
break;
}
switch(usb_configuration_nb) {
case USB_CONFIG_RNDIS_DEBUG:
case USB_CONFIG_RNDIS:
if(Is_device_enumerated()) {
if(rndis_process()) {
etimer_set(&et, CLOCK_SECOND/80);
} else {
Led0_toggle();
etimer_set(&et, CLOCK_SECOND/8);
}
}
//Ack final data packet
Usb_ack_receive_out();
//Packet has CRC, nobody wants that garbage
datalength -= 4;
//Send data over RF or to local stack
uip_len = datalength; //uip_len includes LLH_LEN
mac_ethernetToLowpan(uip_buf);
} //if (datalength)
} //if(Is_usb_receive_out() && (uip_len == 0))
} // if (Is_device_enumerated())
if ((usb_mode == rndis_only) || (usb_mode == rndis_debug) || (usb_mode == eem)) {
etimer_set(&et, CLOCK_SECOND/80);
} else {
etimer_set(&et, CLOCK_SECOND);
break;
case USB_CONFIG_EEM:
if(Is_device_enumerated())
cdc_eem_process();
etimer_set(&et, CLOCK_SECOND/80);
break;
case USB_CONFIG_ECM:
case USB_CONFIG_ECM_DEBUG:
if(Is_device_enumerated()) {
if(cdc_ecm_process()) {
etimer_set(&et, CLOCK_SECOND/80);
} else {
Led0_toggle();
etimer_set(&et, CLOCK_SECOND/8);
}
}
break;
default:
Led0_toggle();
etimer_set(&et, CLOCK_SECOND/4);
break;
}
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)||(usb_eth_packet_is_available()&&usb_eth_ready_for_next_packet()));
} // while(1)
PROCESS_END();
@ -527,172 +298,70 @@ static uint16_t iad_fail_timeout, rndis_fail_timeout;
*/
uint8_t usb_eth_send(uint8_t * senddata, uint16_t sendlen, uint8_t led)
{
if (usb_mode == eem)
return eem_send(senddata, sendlen, led);
uint8_t ret = 0;
if(!usb_eth_is_active) {
USB_ETH_HOOK_TX_ERROR("Inactive");
goto bail;
}
if ((usb_mode == rndis_only) || (usb_mode == rndis_debug))
return rndis_send(senddata, sendlen, led);
//Check device is set up
if (Is_device_enumerated() == 0) {
USB_ETH_HOOK_TX_ERROR("Device not enumerated");
goto bail;
}
switch(usb_configuration_nb) {
case USB_CONFIG_RNDIS_DEBUG:
case USB_CONFIG_RNDIS:
ret = rndis_send(senddata, sendlen, led);
break;
case USB_CONFIG_EEM:
ret = eem_send(senddata, sendlen, led);
break;
case USB_CONFIG_ECM:
case USB_CONFIG_ECM_DEBUG:
ret = ecm_send(senddata, sendlen, led);
break;
}
bail:
if(!ret) // Hit the watchdog if we have a successful send.
watchdog_periodic();
return ret;
}
uint8_t
usb_eth_set_active(uint8_t active) {
if(usb_eth_is_active!=active) {
switch(usb_configuration_nb) {
case USB_CONFIG_RNDIS_DEBUG:
case USB_CONFIG_RNDIS:
usb_eth_is_active = active;
rndis_send_interrupt();
break;
case USB_CONFIG_EEM:
break;
case USB_CONFIG_ECM:
case USB_CONFIG_ECM_DEBUG:
cdc_ecm_set_active(active);
usb_eth_is_active = active;
break;
}
}
return 0;
}
/**
\brief Send a single ethernet frame using EEM
*/
uint8_t eem_send(uint8_t * senddata, uint16_t sendlen, uint8_t led)
{
//Check device is set up
if (Is_device_enumerated() == 0)
return 0;
//Make a header
uint8_t header[2];
//Fake CRC! Add 4 to length for CRC
sendlen += 4;
header[0] = (sendlen >> 8) & 0x3f;
header[1] = sendlen & 0xff;
//We send CRC seperatly..
sendlen -= 4;
//Send Data
Usb_select_endpoint(TX_EP);
//Usb_send_in();
//Wait for ready
while(!Is_usb_write_enabled());
//Send header (LSB then MSB)
Usb_write_byte(header[1]);
Usb_write_byte(header[0]);
//Send packet
while(sendlen) {
Usb_write_byte(*senddata);
senddata++;
sendlen--;
//If endpoint is full, send data in
//And then wait for data to transfer
if (!Is_usb_write_enabled()) {
Usb_send_in();
while(!Is_usb_write_enabled());
}
}
//CRC = 0xdeadbeef
//Linux kernel 2.6.31 needs 0xdeadbeef in wrong order,
//like this: uint8_t crc[4] = {0xef, 0xbe, 0xad, 0xde};
//This is fixed in 2.6.32 to the correct order (0xde, 0xad, 0xbe, 0xef)
uint8_t crc[4] = {0xde, 0xad, 0xbe, 0xef};
sendlen = 4;
uint8_t i = 0;
//Send fake CRC
while(sendlen) {
Usb_write_byte(crc[i]);
i++;
sendlen--;
//If endpoint is full, send data in
//And then wait for data to transfer
if (!Is_usb_write_enabled()) {
Usb_send_in();
while(!Is_usb_write_enabled());
}
if (led) {
tx_end_led();
}
}
//Send last data in - also handles sending a ZLP if needed
Usb_send_in();
//Wait for ready
while(!Is_usb_write_enabled());
return 1;
void
usb_eth_get_mac_address(uint8_t dest[6]) {
memcpy(dest,&usb_ethernet_addr,6);
}
/**
\brief Send data over RNDIS interface, data is in uipbuf and length is uiplen
*/
uint8_t rndis_send(uint8_t * senddata, uint16_t sendlen, uint8_t led)
{
uint16_t i;
//Setup Header
PBUF->MessageType = REMOTE_NDIS_PACKET_MSG;
PBUF->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_MessageType_t) - sizeof(rndis_MessageLength_t);
PBUF->DataLength = sendlen;
PBUF->OOBDataLength = 0;
PBUF->OOBDataOffset = 0;
PBUF->NumOOBDataElements = 0;
PBUF->PerPacketInfoOffset = 0;
PBUF->PerPacketInfoLength = 0;
PBUF->DeviceVcHandle = 0;
PBUF->Reserved = 0;
PBUF->MessageLength = sizeof(rndis_data_packet_t) + PBUF->DataLength;
//Send Data
Usb_select_endpoint(TX_EP);
Usb_send_in();
//Wait for ready
while(!Is_usb_write_enabled());
//Setup first part of transfer...
for(i = 0; i < sizeof(rndis_data_packet_t); i++) {
Usb_write_byte(data_buffer[i]);
}
//Send packet
while(sendlen) {
Usb_write_byte(*senddata);
senddata++;
sendlen--;
//If endpoint is full, send data in
//And then wait for data to transfer
if (!Is_usb_write_enabled()) {
Usb_send_in();
while(!Is_usb_write_enabled());
}
if (led) {
tx_end_led();
}
}
Usb_send_in();
return 1;
void
usb_eth_set_mac_address(const uint8_t src[6]) {
memcpy(&usb_ethernet_addr,src,6);
}
/**
@brief This will enable the RX_START LED for a period
*/
void rx_start_led(void)
{
Led1_on();
led1_timer = 10;
}
/**
@brief This will enable the TRX_END LED for a period
*/
void tx_end_led(void)
{
Led2_on();
led2_timer = 10;
}
/** @} */

View file

@ -52,22 +52,72 @@
#include "config.h"
#include "../conf_usb.h"
//_____ M A C R O S ________________________________________________________
#define USB_ETH_MTU UIP_BUFSIZE+4
/*! Hook Documentation
** USB_ETH_HOOK_RX_START()
** USB_ETH_HOOK_RX_END()
** USB_ETH_HOOK_RX_ERROR(string_reason)
**
** USB_ETH_HOOK_TX_START()
** USB_ETH_HOOK_TX_END()
** USB_ETH_HOOK_TX_ERROR(string_reason)
**
** USB_ETH_HOOK_INITIALIZED()
** USB_ETH_HOOK_UNINITIALIZED()
**
** USB_ETH_HOOK_INIT()
**
** USB_ETH_HOOK_SET_PROMISCIOUS_MODE(bool)
**
** USB_ETH_HOOK_HANDLE_INBOUND_PACKET(buffer,len)
** USB_ETH_HOOK_IS_READY_FOR_INBOUND_PACKET()
*/
#ifndef USB_ETH_HOOK_RX_START
void rx_start_led(void);
#define USB_ETH_HOOK_RX_START() rx_start_led()
#endif
#ifndef USB_ETH_HOOK_TX_END
void tx_end_led(void);
#define USB_ETH_HOOK_TX_END() tx_end_led()
#endif
#ifndef USB_ETH_HOOK_TX_ERROR
#define USB_ETH_HOOK_TX_ERROR(string) do { } while(0)
#endif
#ifndef USB_ETH_HOOK_RX_ERROR
#define USB_ETH_HOOK_RX_ERROR(string) do { } while(0)
#endif
//_____ D E C L A R A T I O N S ____________________________________________
uint8_t usb_eth_send(uint8_t * senddata, uint16_t sendlen, uint8_t led);
uint8_t usb_eth_set_active(uint8_t active);
uint8_t usb_eth_ready_for_next_packet();
void sof_action(void);
void rx_start_led(void);
void tx_end_led(void);
extern char usb_busy;
extern uint8_t usb_eth_is_active;
PROCESS_NAME(rndis_process);
// TIP: Avoid using usb_ethernet_addr directly and use the get/set mac_address functions below.
extern uint64_t usb_ethernet_addr;
void usb_eth_get_mac_address(uint8_t dest[6]);
void usb_eth_set_mac_address(const uint8_t src[6]);
PROCESS_NAME(usb_eth_process);
/** @} */