Contiki 2.5
cdc_ecm.c
1 #include <stdbool.h>
2 #include "cdc_ecm.h"
3 #include "contiki.h"
4 #include "usb_drv.h"
5 #include "usb_descriptors.h"
6 #include "usb_specific_request.h"
7 #include "rndis/rndis_task.h"
8 #include "rndis/rndis_protocol.h"
9 #include "uip.h"
10 #include "sicslow_ethernet.h"
11 #include <stdio.h>
12 #if RF230BB
13 #include "rf230bb.h"
14 #endif
15 
16 #include <avr/pgmspace.h>
17 #include <util/delay.h>
18 
19 #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
20 #define PRINTF printf
21 #define PRINTF_P printf_P
22 
23 extern uint8_t usb_eth_data_buffer[64];
24 static U16 usb_ecm_packet_filter = 0;
25 
26 #define PACKET_TYPE_PROMISCUOUS (1<<0)
27 #define PACKET_TYPE_ALL_MULTICAST (1<<1)
28 #define PACKET_TYPE_DIRECTED (1<<2)
29 #define PACKET_TYPE_BROADCAST (1<<3)
30 #define PACKET_TYPE_MULTICAST (1<<4)
31 
32 #define Usb_write_word(x) Usb_write_byte((x)&0xFF),Usb_write_byte((x>>8)&0xFF)
33 #define Usb_write_long(x) Usb_write_word((x)&0xFFFF),Usb_write_word((x>>16)&0xFFFF)
34 
35 #define Usb_read_word() ((U16)Usb_read_byte()+((U16)Usb_read_byte()<<8))
36 
37 void
38 cdc_ecm_set_ethernet_packet_filter(void) {
39  usb_ecm_packet_filter = Usb_read_word();
40 
43  usb_endpoint_wait_for_read_control_enabled();
44 
45  PRINTF_P(PSTR("cdc_ecm: Received SET_ETHERNET_PACKET_FILTER: (0x%04X) "),usb_ecm_packet_filter);
46  if(usb_ecm_packet_filter & PACKET_TYPE_PROMISCUOUS) {
47  PRINTF_P(PSTR("PROMISCUOUS "));
48  USB_ETH_HOOK_SET_PROMISCIOUS_MODE(true);
49  } else {
50  USB_ETH_HOOK_SET_PROMISCIOUS_MODE(false);
51  }
52 
53  if(usb_ecm_packet_filter & PACKET_TYPE_ALL_MULTICAST)
54  PRINTF_P(PSTR("ALL_MULTICAST "));
55  if(usb_ecm_packet_filter & PACKET_TYPE_DIRECTED)
56  PRINTF_P(PSTR("DIRECTED "));
57  if(usb_ecm_packet_filter & PACKET_TYPE_BROADCAST)
58  PRINTF_P(PSTR("BROADCAST "));
59  if(usb_ecm_packet_filter & PACKET_TYPE_MULTICAST)
60  PRINTF_P(PSTR("MULTICAST "));
61 
62  PRINTF_P(PSTR("\n"));
63 }
64 
65 
66 #define CDC_NOTIFY_NETWORK_CONNECTION (0x00)
67 #define CDC_NOTIFY_CONNECTION_SPEED_CHANGE (0x2A)
68 
69 void
70 cdc_ecm_notify_network_connection(uint8_t value) {
71 #if CDC_ECM_USES_INTERRUPT_ENDPOINT
72  Usb_select_endpoint(INT_EP);
73 
75  //PRINTF_P(PSTR("cdc_ecm: cdc_ecm_notify_network_connection: endpoint not enabled\n"));
76  return;
77  }
78 
79  if(usb_endpoint_wait_for_IN_ready()!=0) {
80  //PRINTF_P(PSTR("cdc_ecm: cdc_ecm_notify_network_connection: Timeout waiting for interrupt endpoint to be available\n"));
81  return;
82  }
83 
85 
86  Usb_write_byte(0x51); // 10100001b
87  Usb_write_byte(CDC_NOTIFY_NETWORK_CONNECTION);
88  Usb_write_byte(value);
89  Usb_write_byte(0x00);
90  Usb_write_word(ECM_INTERFACE0_NB);
91  Usb_write_word(0x0000);
92 
93  Usb_send_in();
94  PRINTF_P(PSTR("cdc_ecm: CDC_NOTIFY_NETWORK_CONNECTION %d\n"),value);
95 #endif
96 }
97 
98 #define CDC_ECM_DATA_ENDPOINT_SIZE 64
99 
100 void cdc_ecm_configure_endpoints() {
101 #if CDC_ECM_USES_INTERRUPT_ENDPOINT
102  usb_configure_endpoint(INT_EP, \
103  TYPE_INTERRUPT, \
104  DIRECTION_IN, \
105  SIZE_8, \
106  TWO_BANKS, \
107  NYET_ENABLED);
108 #endif
109 
110  usb_configure_endpoint(TX_EP, \
111  TYPE_BULK, \
112  DIRECTION_IN, \
113  SIZE_64, \
114  TWO_BANKS, \
115  NYET_ENABLED);
116 
117  usb_configure_endpoint(RX_EP, \
118  TYPE_BULK, \
119  DIRECTION_OUT, \
120  SIZE_64, \
121  TWO_BANKS, \
122  NYET_ENABLED);
123 #if CDC_ECM_USES_INTERRUPT_ENDPOINT
124  Usb_reset_endpoint(INT_EP);
125 #endif
126  Usb_reset_endpoint(TX_EP);
127  Usb_reset_endpoint(RX_EP);
128  usb_eth_is_active = 1;
129 }
130 
131 
132 void
133 cdc_ecm_notify_connection_speed_change(uint32_t upstream,uint32_t downstream) {
134 #if CDC_ECM_USES_INTERRUPT_ENDPOINT
135  Usb_select_endpoint(INT_EP);
136 
138  return;
139 
140  if(usb_endpoint_wait_for_IN_ready()!=0)
141  return;
142 
144 
145  Usb_write_byte(0x51); // 10100001b
146  Usb_write_byte(CDC_NOTIFY_CONNECTION_SPEED_CHANGE);
147  Usb_write_word(0x0000);
148  Usb_write_word(ECM_INTERFACE0_NB);
149  Usb_write_word(0x0008);
150 
151  Usb_send_in();
152 
153  if(usb_endpoint_wait_for_write_enabled()!=0)
154  return;
155 
156  Usb_write_long(upstream);
157  Usb_write_long(downstream);
158  Usb_send_in();
159 
160  PRINTF_P(PSTR("cdc_ecm: CDC_NOTIFY_CONNECTION_SPEED_CHANGE UP:%d DOWN:%d\n"),upstream,downstream);
161 #endif
162 }
163 
164 void cdc_ecm_set_active(uint8_t value) {
165  if(value!=usb_eth_is_active) {
166  Led3_on();
167 
168  usb_eth_is_active = value;
169  cdc_ecm_notify_network_connection(value);
170  if(value) {
171  cdc_ecm_notify_connection_speed_change(250000,250000);
172  } else {
173  cdc_ecm_notify_connection_speed_change(0,0);
174  }
175  }
176 }
177 
178 uint8_t
179 cdc_ecm_process(void) {
180  static uint8_t doInit = 1;
181 
182  Usb_select_endpoint(RX_EP);
183 
184  if(!Is_usb_endpoint_enabled()) {
185  return 0;
186  }
187 
188  if (doInit) {
189 #ifdef USB_ETH_HOOK_INIT
190  USB_ETH_HOOK_INIT();
191 #endif
192  cdc_ecm_notify_network_connection(1);
193  cdc_ecm_notify_connection_speed_change(250000,250000);
194  doInit = 0;
195  if(usb_ecm_packet_filter & PACKET_TYPE_PROMISCUOUS) {
196 #if RF230BB
197  rf230_set_promiscuous_mode(true);
198 #else
200 #endif
201  }
202 
203  // Select again, just to make sure.
204  Usb_select_endpoint(RX_EP);
205  }
206 
207  if(!usb_eth_is_active) {
208  // If we aren't active, just eat the packets.
209  if(Is_usb_read_enabled()) {
211  }
212  return 0;
213  }
214 
215  //Connected!
216  Led0_on();
217 
218  if(Is_usb_read_enabled()) {
219  uint16_t bytecounter;
220  uint16_t bytes_received = 0;
221  U8 * buffer = uip_buf;
222 
223  if(!usb_eth_ready_for_next_packet()) {
224  // Since we aren't ready for a packet yet,
225  // just return.
226  goto bail;
227  }
228 
229 #ifdef USB_ETH_HOOK_RX_START
230  USB_ETH_HOOK_RX_START();
231 #endif
232 
233  while((bytecounter=Usb_byte_counter_8())==CDC_ECM_DATA_ENDPOINT_SIZE) {
234  while((bytes_received<USB_ETH_MTU) && (bytecounter--)) {
235  *buffer++ = Usb_read_byte();
236  bytes_received++;
237  }
238  bytes_received+=bytecounter+1;
239 
240  //ACK previous data
242 
243  //Wait for new data
244  if(usb_endpoint_wait_for_read_enabled()!=0) {
245  USB_ETH_HOOK_RX_ERROR("Timeout: read enabled");
246  goto bail;
247  }
248  }
249  bytecounter = Usb_byte_counter_8();
250  while((bytes_received<USB_ETH_MTU) && (bytecounter--)) {
251  *buffer++ = Usb_read_byte();
252  bytes_received++;
253  }
254  bytes_received+=bytecounter+1;
255 
256  //Ack final data packet
258 
259  //PRINTF_P(PSTR("cdc_ecm: Got packet %d bytes long\n"),bytes_received);
260 
261 #ifdef USB_ETH_HOOK_RX_END
262  USB_ETH_HOOK_RX_END();
263 #endif
264 
265  //Send data over RF or to local stack
266  if(bytes_received<=USB_ETH_MTU) {
267 
268  USB_ETH_HOOK_HANDLE_INBOUND_PACKET(uip_buf,bytes_received);
269  } else {
270  USB_ETH_HOOK_RX_ERROR("Oversized packet");
271  }
272  }
273 bail:
274  return 1;
275 }
276 
277 uint8_t
278 ecm_send(uint8_t * senddata, uint16_t sendlen, uint8_t led) {
279  U8 byte_in_packet = 0;
280 
281  //Send Data
282  Usb_select_endpoint(TX_EP);
283 
284  if(usb_endpoint_wait_for_write_enabled()!=0) {
285  USB_ETH_HOOK_TX_ERROR("Timeout: write enabled");
286  return 0;
287  }
288 
289 #ifdef USB_ETH_HOOK_TX_START
290  USB_ETH_HOOK_TX_START();
291 #endif
292 
293  //Send packet
294  while(sendlen) {
295  Usb_write_byte(*senddata);
296  senddata++;
297  sendlen--;
298  byte_in_packet++;
299 
300  //If endpoint is full, send data in
301  //And then wait for data to transfer
302  if (!Is_usb_write_enabled()) {
304 
305  if(usb_endpoint_wait_for_write_enabled()!=0) {
306  USB_ETH_HOOK_TX_ERROR("Timeout: write enabled");
307  return 0;
308  }
309  byte_in_packet=0;
310  }
311 
312  }
313 
314  //Send last data in - also handles sending a ZLP if needed
316 
317 #ifdef USB_ETH_HOOK_TX_END
318  USB_ETH_HOOK_TX_END();
319 #endif
320 
321  //Wait for ready
322  if(usb_endpoint_wait_for_IN_ready()!=0) {
323  USB_ETH_HOOK_TX_ERROR("Timeout: IN ready");
324  return 0;
325  }
326 
327  return 1;
328 }
329 
330