Contiki 2.6

cdc_ecm.c

00001 #include <stdbool.h>
00002 #include "cdc_ecm.h"
00003 #include "contiki.h"
00004 #include "usb_drv.h"
00005 #include "usb_descriptors.h"
00006 #include "usb_specific_request.h"
00007 #include "rndis/rndis_task.h"
00008 #include "rndis/rndis_protocol.h"
00009 #include "uip.h"
00010 #include "sicslow_ethernet.h"
00011 #include <stdio.h>
00012 #if RF230BB
00013 #include "rf230bb.h"
00014 #endif
00015 
00016 #include <avr/pgmspace.h>
00017 #include <util/delay.h>
00018 
00019 #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
00020 #define PRINTF printf
00021 #define PRINTF_P printf_P
00022 
00023 extern uint8_t usb_eth_data_buffer[64];
00024 static U16 usb_ecm_packet_filter = 0;
00025 
00026 #define PACKET_TYPE_PROMISCUOUS         (1<<0)
00027 #define PACKET_TYPE_ALL_MULTICAST       (1<<1)
00028 #define PACKET_TYPE_DIRECTED            (1<<2)
00029 #define PACKET_TYPE_BROADCAST           (1<<3)
00030 #define PACKET_TYPE_MULTICAST           (1<<4)
00031 
00032 #define Usb_write_word(x)       Usb_write_byte((x)&0xFF),Usb_write_byte((x>>8)&0xFF)
00033 #define Usb_write_long(x)       Usb_write_word((x)&0xFFFF),Usb_write_word((x>>16)&0xFFFF)
00034 
00035 #define Usb_read_word() ((U16)Usb_read_byte()+((U16)Usb_read_byte()<<8))
00036 
00037 void
00038 cdc_ecm_set_ethernet_packet_filter(void) {
00039         usb_ecm_packet_filter = Usb_read_word();
00040 
00041         Usb_ack_receive_setup();
00042         Usb_send_control_in();
00043         usb_endpoint_wait_for_read_control_enabled();
00044         
00045         PRINTF_P(PSTR("cdc_ecm: Received SET_ETHERNET_PACKET_FILTER: (0x%04X) "),usb_ecm_packet_filter);
00046         if(usb_ecm_packet_filter & PACKET_TYPE_PROMISCUOUS) {
00047                 PRINTF_P(PSTR("PROMISCUOUS "));
00048                 USB_ETH_HOOK_SET_PROMISCIOUS_MODE(true);
00049         } else {
00050                 USB_ETH_HOOK_SET_PROMISCIOUS_MODE(false);
00051         }
00052 
00053         if(usb_ecm_packet_filter & PACKET_TYPE_ALL_MULTICAST)
00054                 PRINTF_P(PSTR("ALL_MULTICAST "));
00055         if(usb_ecm_packet_filter & PACKET_TYPE_DIRECTED)
00056                 PRINTF_P(PSTR("DIRECTED "));
00057         if(usb_ecm_packet_filter & PACKET_TYPE_BROADCAST)
00058                 PRINTF_P(PSTR("BROADCAST "));
00059         if(usb_ecm_packet_filter & PACKET_TYPE_MULTICAST)
00060                 PRINTF_P(PSTR("MULTICAST "));
00061                 
00062         PRINTF_P(PSTR("\n"));
00063 }
00064 
00065 
00066 #define CDC_NOTIFY_NETWORK_CONNECTION   (0x00)
00067 #define CDC_NOTIFY_CONNECTION_SPEED_CHANGE      (0x2A)
00068 
00069 void
00070 cdc_ecm_notify_network_connection(uint8_t value) {
00071 #if CDC_ECM_USES_INTERRUPT_ENDPOINT
00072         Usb_select_endpoint(INT_EP);
00073 
00074         if(!Is_usb_endpoint_enabled()) {
00075                 //PRINTF_P(PSTR("cdc_ecm: cdc_ecm_notify_network_connection: endpoint not enabled\n"));
00076                 return;
00077         }
00078 
00079         if(usb_endpoint_wait_for_IN_ready()!=0) {
00080                 //PRINTF_P(PSTR("cdc_ecm: cdc_ecm_notify_network_connection: Timeout waiting for interrupt endpoint to be available\n"));
00081                 return;
00082         }
00083 
00084         Usb_send_control_in();
00085 
00086         Usb_write_byte(0x51); // 10100001b
00087         Usb_write_byte(CDC_NOTIFY_NETWORK_CONNECTION);
00088         Usb_write_byte(value);
00089         Usb_write_byte(0x00);
00090         Usb_write_word(ECM_INTERFACE0_NB);
00091         Usb_write_word(0x0000);
00092 
00093         Usb_send_in();
00094         PRINTF_P(PSTR("cdc_ecm: CDC_NOTIFY_NETWORK_CONNECTION %d\n"),value);
00095 #endif
00096 }
00097 
00098 #define CDC_ECM_DATA_ENDPOINT_SIZE              64
00099 
00100 void cdc_ecm_configure_endpoints() {
00101 #if CDC_ECM_USES_INTERRUPT_ENDPOINT
00102         usb_configure_endpoint(INT_EP,      \
00103                                                  TYPE_INTERRUPT,     \
00104                                                  DIRECTION_IN,  \
00105                                                  SIZE_8,       \
00106                                                  TWO_BANKS,     \
00107                                                  NYET_ENABLED);
00108 #endif
00109 
00110         usb_configure_endpoint(TX_EP,      \
00111                                                  TYPE_BULK,  \
00112                                                  DIRECTION_IN,  \
00113                                                  SIZE_64,     \
00114                                                  TWO_BANKS,     \
00115                                                  NYET_ENABLED);
00116 
00117         usb_configure_endpoint(RX_EP,      \
00118                                                  TYPE_BULK,     \
00119                                                  DIRECTION_OUT,  \
00120                                                  SIZE_64,       \
00121                                                  TWO_BANKS,     \
00122                                                  NYET_ENABLED);
00123 #if CDC_ECM_USES_INTERRUPT_ENDPOINT
00124         Usb_reset_endpoint(INT_EP);
00125 #endif
00126         Usb_reset_endpoint(TX_EP);
00127         Usb_reset_endpoint(RX_EP);
00128         usb_eth_is_active = 1;
00129 }
00130 
00131 
00132 void
00133 cdc_ecm_notify_connection_speed_change(uint32_t upstream,uint32_t downstream) {
00134 #if CDC_ECM_USES_INTERRUPT_ENDPOINT
00135         Usb_select_endpoint(INT_EP);
00136 
00137         if(!Is_usb_endpoint_enabled())
00138                 return;
00139 
00140         if(usb_endpoint_wait_for_IN_ready()!=0)
00141                 return;
00142 
00143         Usb_send_control_in();
00144 
00145         Usb_write_byte(0x51); // 10100001b
00146         Usb_write_byte(CDC_NOTIFY_CONNECTION_SPEED_CHANGE);
00147         Usb_write_word(0x0000);
00148         Usb_write_word(ECM_INTERFACE0_NB);
00149         Usb_write_word(0x0008);
00150 
00151         Usb_send_in();
00152 
00153         if(usb_endpoint_wait_for_write_enabled()!=0)
00154                 return;
00155 
00156         Usb_write_long(upstream);
00157         Usb_write_long(downstream);
00158         Usb_send_in();
00159 
00160         PRINTF_P(PSTR("cdc_ecm: CDC_NOTIFY_CONNECTION_SPEED_CHANGE UP:%d DOWN:%d\n"),upstream,downstream);
00161 #endif
00162 }
00163 
00164 void cdc_ecm_set_active(uint8_t value) {
00165         if(value!=usb_eth_is_active) {
00166                 Led3_on();
00167 
00168                 usb_eth_is_active = value;
00169                 cdc_ecm_notify_network_connection(value);
00170                 if(value) {
00171                         cdc_ecm_notify_connection_speed_change(250000,250000);
00172                 } else {
00173                         cdc_ecm_notify_connection_speed_change(0,0);
00174                 }
00175         }
00176 }
00177 
00178 uint8_t
00179 cdc_ecm_process(void) {
00180         static uint8_t doInit = 1;
00181         
00182         Usb_select_endpoint(RX_EP);
00183 
00184         if(!Is_usb_endpoint_enabled()) {
00185                 return 0;
00186         }
00187 
00188         if (doInit) {
00189 #ifdef USB_ETH_HOOK_INIT
00190                 USB_ETH_HOOK_INIT();
00191 #endif
00192                 cdc_ecm_notify_network_connection(1);
00193                 cdc_ecm_notify_connection_speed_change(250000,250000);
00194                 doInit = 0;
00195                 if(usb_ecm_packet_filter & PACKET_TYPE_PROMISCUOUS) {
00196 #if RF230BB
00197                         rf230_set_promiscuous_mode(true);
00198 #else           
00199                         radio_set_trx_state(RX_ON);
00200 #endif
00201                 }
00202 
00203                 // Select again, just to make sure.
00204                 Usb_select_endpoint(RX_EP);
00205         }
00206 
00207         if(!usb_eth_is_active) {
00208                 // If we aren't active, just eat the packets.
00209                 if(Is_usb_read_enabled()) {
00210                         Usb_ack_receive_out();
00211                 }
00212                 return 0;
00213         }
00214 
00215         //Connected!
00216         Led0_on();
00217 
00218         if(Is_usb_read_enabled()) {
00219                 uint16_t bytecounter;
00220                 uint16_t bytes_received = 0;
00221                 U8 * buffer = uip_buf;
00222 
00223                 if(!usb_eth_ready_for_next_packet()) {
00224                         // Since we aren't ready for a packet yet,
00225                         // just return.
00226                         goto bail;
00227                 }
00228 
00229 #ifdef USB_ETH_HOOK_RX_START
00230                 USB_ETH_HOOK_RX_START();
00231 #endif
00232 
00233                 while((bytecounter=Usb_byte_counter_8())==CDC_ECM_DATA_ENDPOINT_SIZE) {
00234                         while((bytes_received<USB_ETH_MTU) && (bytecounter--)) {
00235                                 *buffer++ = Usb_read_byte();
00236                                 bytes_received++;
00237                         }
00238                         bytes_received+=bytecounter+1;
00239 
00240                         //ACK previous data
00241                         Usb_ack_receive_out();
00242 
00243                         //Wait for new data
00244                         if(usb_endpoint_wait_for_read_enabled()!=0) {
00245                                 USB_ETH_HOOK_RX_ERROR("Timeout: read enabled");
00246                                 goto bail;
00247                         }
00248                 }
00249                 bytecounter = Usb_byte_counter_8();
00250                 while((bytes_received<USB_ETH_MTU) && (bytecounter--)) {
00251                         *buffer++ = Usb_read_byte();
00252                         bytes_received++;
00253                 }
00254                 bytes_received+=bytecounter+1;
00255                 
00256                 //Ack final data packet
00257                 Usb_ack_receive_out();
00258 
00259                 //PRINTF_P(PSTR("cdc_ecm: Got packet %d bytes long\n"),bytes_received);
00260 
00261 #ifdef USB_ETH_HOOK_RX_END
00262                 USB_ETH_HOOK_RX_END();
00263 #endif
00264                 
00265                 //Send data over RF or to local stack
00266                 if(bytes_received<=USB_ETH_MTU) {
00267 
00268                         USB_ETH_HOOK_HANDLE_INBOUND_PACKET(uip_buf,bytes_received);
00269                 } else {
00270                         USB_ETH_HOOK_RX_ERROR("Oversized packet");
00271                 }
00272         }
00273 bail:
00274         return 1;
00275 }
00276 
00277 uint8_t
00278 ecm_send(uint8_t * senddata, uint16_t sendlen, uint8_t led) {
00279         U8 byte_in_packet = 0;
00280 
00281         //Send Data
00282         Usb_select_endpoint(TX_EP);
00283 
00284         if(usb_endpoint_wait_for_write_enabled()!=0) {
00285                 USB_ETH_HOOK_TX_ERROR("Timeout: write enabled");
00286                 return 0;
00287         }
00288 
00289 #ifdef USB_ETH_HOOK_TX_START
00290         USB_ETH_HOOK_TX_START();
00291 #endif
00292 
00293         //Send packet
00294         while(sendlen) {
00295                 Usb_write_byte(*senddata);
00296                 senddata++;
00297                 sendlen--;
00298                 byte_in_packet++;
00299                 
00300                 //If endpoint is full, send data in
00301                 //And then wait for data to transfer
00302                 if (!Is_usb_write_enabled()) {
00303                         Usb_ack_in_ready();
00304 
00305                         if(usb_endpoint_wait_for_write_enabled()!=0) {
00306                                 USB_ETH_HOOK_TX_ERROR("Timeout: write enabled");
00307                                 return 0;
00308                         }
00309                         byte_in_packet=0;
00310                 }
00311 
00312         }
00313 
00314         //Send last data in - also handles sending a ZLP if needed
00315         Usb_ack_in_ready();
00316 
00317 #ifdef USB_ETH_HOOK_TX_END
00318         USB_ETH_HOOK_TX_END();
00319 #endif
00320 
00321     //Wait for ready
00322         if(usb_endpoint_wait_for_IN_ready()!=0) {
00323                 USB_ETH_HOOK_TX_ERROR("Timeout: IN ready");
00324                 return 0;
00325         }
00326 
00327         return 1;
00328 }
00329 
00330