Contiki-NG
usb-serial.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012, Philippe Retornaz
3  * Copyright (c) 2012, EPFL STI IMT LSRO1 -- Mobots group
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /**
33  * \addtogroup cc2538-usb
34  * @{
35  *
36  * \file
37  * Platform process which implements a UART-like functionality over the
38  * cc2538's USB hardware.
39  *
40  * This has been ported over from platform/cc2530dk
41  *
42  * \author
43  * - Philippe Retornaz (EPFL) - Original code
44  * - George Oikonomou - <oikonomou@users.sourceforge.net>
45  * Turned this to a 'serial over USB' platform process, ported for cc2538
46  */
47 #include "contiki.h"
48 #include "sys/process.h"
49 #include "net/linkaddr.h"
50 #include "usb-api.h"
51 #include "usb.h"
52 #include "usb-arch.h"
53 #include "cdc-acm/cdc-acm.h"
54 #include "ieee-addr.h"
55 
56 #include <stdint.h>
57 /*---------------------------------------------------------------------------*/
58 #define DEBUG 0
59 
60 #if DEBUG
61 #include <stdio.h>
62 #define PRINTF(...) printf(__VA_ARGS__)
63 #else
64 #define PRINTF(...)
65 #endif
66 /*---------------------------------------------------------------------------*/
67 struct lang_id {
68  uint8_t size;
69  uint8_t type;
70  uint16_t langid;
71 };
72 static const struct lang_id lang_id = { sizeof(lang_id), 3, 0x0409 };
73 /*---------------------------------------------------------------------------*/
74 struct serial_nr {
75  uint8_t size;
76  uint8_t type;
77  uint16_t string[16];
78 };
79 static struct serial_nr serial_nr = {
80  sizeof(serial_nr),
81  3, {
82  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
83  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'
84  }
85 };
86 /*---------------------------------------------------------------------------*/
87 struct manufacturer {
88  uint8_t size;
89  uint8_t type;
90  uint16_t string[17];
91 };
92 static const struct manufacturer manufacturer = {
93  sizeof(manufacturer),
94  3,
95  {
96  'T', 'e', 'x', 'a', 's', ' ',
97  'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 's'
98  }
99 };
100 /*---------------------------------------------------------------------------*/
101 struct product {
102  uint8_t size;
103  uint8_t type;
104  uint16_t string[21];
105 };
106 static const struct product product = {
107  sizeof(product),
108  3,
109  {
110  'c', 'c', '2', '5', '3', '8', ' ',
111  'S', 'y', 's', 't', 'e', 'm', '-', 'o', 'n', '-', 'C', 'h', 'i', 'p'
112  }
113 };
114 /*---------------------------------------------------------------------------*/
115 #define EPIN 0x82
116 #define EPOUT 0x03
117 
118 #define RX_BUFFER_SIZE USB_EP3_SIZE
119 #define TX_BUFFER_SIZE (USB_EP2_SIZE - 1)
120 
121 typedef struct _USBBuffer usb_buffer;
122 
123 static usb_buffer data_rx_urb;
124 static usb_buffer data_tx_urb;
125 static uint8_t usb_rx_data[RX_BUFFER_SIZE];
126 static uint8_t enabled = 0;
127 
128 #define SLIP_END 0300
129 static uint8_t usb_tx_data[TX_BUFFER_SIZE];
130 static uint8_t buffered_data = 0;
131 
132 /* Callback to the input handler */
133 static int (* input_handler)(unsigned char c);
134 /*---------------------------------------------------------------------------*/
135 uint8_t *
136 usb_class_get_string_descriptor(uint16_t lang, uint8_t string)
137 {
138  switch (string) {
139  case 0:
140  return (uint8_t *)&lang_id;
141  case 1:
142  return (uint8_t *)&manufacturer;
143  case 2:
144  return (uint8_t *)&product;
145  case 3:
146  return (uint8_t *)&serial_nr;
147  default:
148  return NULL;
149  }
150 }
151 /*---------------------------------------------------------------------------*/
152 static void
153 set_serial_number(void)
154 {
155  uint8_t i;
156  uint8_t ieee[8];
157  uint8_t lown, highn;
158  uint8_t c;
159 
160  ieee_addr_cpy_to(ieee, 8);
161 
162  for(i = 0; i < 8; i++) {
163  lown = ieee[i] & 0x0F;
164  highn = ieee[i] >> 4;
165  c = lown > 9 ? 'A' + lown - 0xA : lown + '0';
166  serial_nr.string[i * 2 + 1] = c;
167  c = highn > 9 ? 'A' + highn - 0xA : highn + '0';
168  serial_nr.string[i * 2] = c;
169  }
170 }
171 /*---------------------------------------------------------------------------*/
172 static void
173 queue_rx_urb(void)
174 {
175  data_rx_urb.flags = USB_BUFFER_PACKET_END;
176  data_rx_urb.flags |= USB_BUFFER_NOTIFY;
177  data_rx_urb.data = usb_rx_data;
178  data_rx_urb.left = RX_BUFFER_SIZE;
179  data_rx_urb.next = NULL;
180  usb_submit_recv_buffer(EPOUT, &data_rx_urb);
181 }
182 /*---------------------------------------------------------------------------*/
183 static void
184 do_work(void)
185 {
186  unsigned int events;
187 
188  events = usb_get_global_events();
189  if(events & USB_EVENT_CONFIG) {
190  /* Configure EPs. Don't enable them yet, until the CDC line is up */
191  usb_setup_bulk_endpoint(EPIN);
192  usb_setup_bulk_endpoint(EPOUT);
193 
194  queue_rx_urb();
195  }
196  if(events & USB_EVENT_RESET) {
197  enabled = 0;
198  }
199 
200  events = usb_cdc_acm_get_events();
201  if(events & USB_CDC_ACM_LINE_STATE) {
202  uint8_t line_state = usb_cdc_acm_get_line_state();
203  PRINTF("CDC-ACM event 0x%04x, Line State = %u\n", events, line_state);
204  if(line_state & USB_CDC_ACM_DTE) {
205  enabled = 1;
206  } else {
207  enabled = 0;
208  }
209  }
210 
211  if(!enabled) {
212  return;
213  }
214 
215  events = usb_get_ep_events(EPOUT);
216  if((events & USB_EP_EVENT_NOTIFICATION)
217  && !(data_rx_urb.flags & USB_BUFFER_SUBMITTED)) {
218  if(!(data_rx_urb.flags & USB_BUFFER_FAILED)) {
219  if(input_handler) {
220  uint8_t len;
221  uint8_t i;
222 
223  len = RX_BUFFER_SIZE - data_rx_urb.left;
224  for(i = 0; i < len; i++) {
225  input_handler(usb_rx_data[i]);
226  }
227  }
228  }
229  queue_rx_urb();
230  }
231 }
232 /*---------------------------------------------------------------------------*/
233 void
235 {
236  if(buffered_data == 0) {
237  return;
238  }
239 
240  data_tx_urb.flags = USB_BUFFER_SHORT_END;
241  data_tx_urb.flags |= USB_BUFFER_NOTIFY;
242  data_tx_urb.next = NULL;
243  data_tx_urb.data = usb_tx_data;
244  data_tx_urb.left = buffered_data;
245  buffered_data = 0;
246  usb_submit_xmit_buffer(EPIN, &data_tx_urb);
247 }
248 /*---------------------------------------------------------------------------*/
249 void
251 {
252  if(!enabled) {
253  buffered_data = 0;
254  return;
255  }
256 
257  usb_tx_data[buffered_data] = b;
258  buffered_data++;
259 
260  if(buffered_data == TX_BUFFER_SIZE) {
262  }
263 }
264 /*---------------------------------------------------------------------------*/
265 PROCESS(usb_serial_process, "USB-Serial process");
266 /*---------------------------------------------------------------------------*/
267 PROCESS_THREAD(usb_serial_process, ev, data)
268 {
269 
270  PROCESS_BEGIN();
271 
272  set_serial_number();
273 
274  usb_setup();
275  usb_cdc_acm_setup();
276  usb_set_global_event_process(&usb_serial_process);
277  usb_cdc_acm_set_event_process(&usb_serial_process);
278  usb_set_ep_event_process(EPIN, &usb_serial_process);
279  usb_set_ep_event_process(EPOUT, &usb_serial_process);
280 
281  while(1) {
283  if(ev == PROCESS_EVENT_EXIT) {
284  break;
285  }
286  if(ev == PROCESS_EVENT_POLL) {
287  do_work();
288  }
289  }
290 
291  PROCESS_END();
292 }
293 /*---------------------------------------------------------------------------*/
294 void
295 usb_serial_set_input(int (* input)(unsigned char c))
296 {
297  input_handler = input;
298 }
299 /*---------------------------------------------------------------------------*/
300 void
302 {
303  process_start(&usb_serial_process, NULL);
304 }
305 /*---------------------------------------------------------------------------*/
306 
307 /** @} */
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
void usb_serial_init()
Initialise the Serial-over-USB process.
Definition: usb-serial.c:301
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
Header file for the link-layer address representation
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void usb_serial_writeb(uint8_t b)
Write a byte over USB.
Definition: usb-serial.c:250
void ieee_addr_cpy_to(uint8_t *dst, uint8_t len)
Copy the node&#39;s IEEE address to a destination memory area.
Definition: ieee-addr.c:46
void usb_serial_flush()
Immediately transmit the content of Serial-over-USB TX buffers.
Definition: usb-serial.c:234
Header file for the Contiki process interface.
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1110
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1847
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
void usb_serial_set_input(int(*input)(unsigned char c))
Set an input hook for bytes received over USB.
Definition: usb-serial.c:295