mirror of
https://github.com/oliverschmidt/contiki.git
synced 2024-08-16 22:28:59 +00:00
297 lines
6.2 KiB
C
297 lines
6.2 KiB
C
|
#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;
|
||
|
}
|