Contiki 3.x
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  * 3. The name of the author may not be used to endorse or promote
15  * products derived from this software without specific prior
16  * written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 /**
31  * \file
32  * Platform process which implements a UART-like functionality over
33  * the cc2531 dongle's USB hardware.
34  *
35  * With it in place, putchar can be redirected to the USB and USB
36  * incoming traffic can be handled as input
37  *
38  * \author
39  * Philippe Retornaz (EPFL) - Original code
40  * George Oikonomou - <oikonomou@users.sourceforge.net>
41  * Turned this to a 'serial over USB' platform process
42  */
43 #include "contiki.h"
44 #include "sys/process.h"
45 #include "usb/common/usb-api.h"
46 #include "usb/common/cdc-acm/cdc-acm.h"
47 #include "usb/common/usb.h"
48 #include "usb/common/usb-arch.h"
49 /*---------------------------------------------------------------------------*/
50 static const struct {
51  uint8_t size;
52  uint8_t type;
53  uint16_t langid;
54 } lang_id = { sizeof(lang_id), 3, 0x0409 };
55 
56 static struct {
57  uint8_t size;
58  uint8_t type;
59  uint16_t string[16];
60 } string_serial_nr = {
61  sizeof(string_serial_nr),
62  3, {
63  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A',
64  'A', 'A', 'A', 'A', 'A', 'A', 'A', 'A'
65  }
66 };
67 
68 static const struct {
69  uint8_t size;
70  uint8_t type;
71  uint16_t string[17];
72 } string_manufacturer = {
73  sizeof(string_manufacturer),
74  3,
75  {
76  'T', 'e', 'x', 'a', 's', ' ',
77  'I', 'n', 's', 't', 'r', 'u', 'm', 'e', 'n', 't', 's'
78  }
79 };
80 
81 static const struct {
82  uint8_t size;
83  uint8_t type;
84  uint16_t string[17];
85 } string_product = {
86  sizeof(string_product),
87  3, {
88  'C', 'C', '2', '5', '3', '1', ' ',
89  'U', 'S', 'B', ' ', 'D', 'o', 'n', 'g', 'l', 'e'
90  }
91 };
92 /*---------------------------------------------------------------------------*/
93 #define EPIN 0x82
94 #define EPOUT 0x03
95 
96 #define BUFFER_SIZE USB_EP2_SIZE
97 
98 static USBBuffer data_rx_urb;
99 static USBBuffer data_tx_urb;
100 static uint8_t usb_rx_data[BUFFER_SIZE];
101 static uint8_t enabled = 0;
102 
103 #if USB_SERIAL_CONF_BUFFERED
104 #define SLIP_END 0300
105 static uint8_t usb_tx_data[BUFFER_SIZE];
106 static uint8_t buffered_data = 0;
107 #endif
108 
109 /* Callback to the input handler */
110 static int (* input_handler)(unsigned char c);
111 /*---------------------------------------------------------------------------*/
112 uint8_t *
113 usb_class_get_string_descriptor(uint16_t lang, uint8_t string)
114 {
115  switch (string) {
116  case 0:
117  return (uint8_t *)&lang_id;
118  case 1:
119  return (uint8_t *)&string_manufacturer;
120  case 2:
121  return (uint8_t *)&string_product;
122  case 3:
123  return (uint8_t *)&string_serial_nr;
124  default:
125  return NULL;
126  }
127 }
128 /*---------------------------------------------------------------------------*/
129 static void
130 set_serial_number(void)
131 {
132  uint8_t i;
133  uint8_t *ieee = &X_IEEE_ADDR;
134  uint8_t lown, highn;
135  uint8_t c;
136 
137  for(i = 0; i < 8; i++) {
138  lown = ieee[i] & 0x0F;
139  highn = ieee[i] >> 4;
140  c = lown > 9 ? 'A' + lown - 0xA : lown + '0';
141  string_serial_nr.string[14 - i * 2 + 1] = c;
142  c = highn > 9 ? 'A' + highn - 0xA : highn + '0';
143  string_serial_nr.string[14 - i * 2] = c;
144  }
145 }
146 /*---------------------------------------------------------------------------*/
147 static void
148 queue_rx_urb(void)
149 {
150  data_rx_urb.flags = USB_BUFFER_PACKET_END; /* Make sure we are getting immediately the packet. */
151  data_rx_urb.flags |= USB_BUFFER_NOTIFY;
152  data_rx_urb.data = usb_rx_data;
153  data_rx_urb.left = BUFFER_SIZE;
154  data_rx_urb.next = NULL;
155  usb_submit_recv_buffer(EPOUT, &data_rx_urb);
156 }
157 /*---------------------------------------------------------------------------*/
158 static void
159 do_work(void)
160 {
161  unsigned int events;
162 
163  events = usb_get_global_events();
164  if(events & USB_EVENT_CONFIG) {
165  /* Enable endpoints */
166  enabled = 1;
167  usb_setup_bulk_endpoint(EPIN);
168  usb_setup_bulk_endpoint(EPOUT);
169 
170  queue_rx_urb();
171  }
172  if(events & USB_EVENT_RESET) {
173  enabled = 0;
174  }
175 
176  events = usb_cdc_acm_get_events();
177  if(events & USB_CDC_ACM_LINE_STATE) {
178  uint8_t line_state = usb_cdc_acm_get_line_state();
179  if(line_state & USB_CDC_ACM_DTE) {
180  enabled = 1;
181  } else {
182  enabled = 0;
183  }
184  }
185 
186  if(!enabled) {
187  return;
188  }
189 
190  events = usb_get_ep_events(EPOUT);
191  if((events & USB_EP_EVENT_NOTIFICATION)
192  && !(data_rx_urb.flags & USB_BUFFER_SUBMITTED)) {
193  if(!(data_rx_urb.flags & USB_BUFFER_FAILED)) {
194  if(input_handler) {
195  uint8_t len;
196  uint8_t i;
197 
198  len = BUFFER_SIZE - data_rx_urb.left;
199  for(i = 0; i < len; i++) {
200  input_handler(usb_rx_data[i]);
201  }
202  }
203  }
204  queue_rx_urb();
205  }
206 }
207 /*---------------------------------------------------------------------------*/
208 #if USB_SERIAL_CONF_BUFFERED
209 void
211 {
212  if(buffered_data == BUFFER_SIZE) {
213  data_tx_urb.flags = 0;
214  } else {
215  data_tx_urb.flags = USB_BUFFER_SHORT_END;
216  }
217  data_tx_urb.flags |= USB_BUFFER_NOTIFY;
218  data_tx_urb.next = NULL;
219  data_tx_urb.data = usb_tx_data;
220  data_tx_urb.left = buffered_data;
221  buffered_data = 0;
222  usb_submit_xmit_buffer(EPIN, &data_tx_urb);
223 }
224 /*---------------------------------------------------------------------------*/
225 void
226 usb_serial_writeb(uint8_t b)
227 {
228  if(!enabled) {
229  buffered_data = 0;
230  return;
231  }
232 
233  usb_tx_data[buffered_data] = b;
234  buffered_data++;
235 
236  if(buffered_data == BUFFER_SIZE || b == SLIP_END || b == '\n') {
238  }
239 }
240 /*---------------------------------------------------------------------------*/
241 #else
242 void
244 {
245  if(!enabled) {
246  return;
247  }
248 
249  data_tx_urb.flags = USB_BUFFER_SHORT_END;
250  data_tx_urb.flags |= USB_BUFFER_NOTIFY;
251  data_tx_urb.next = NULL;
252  data_tx_urb.data = &b;
253  data_tx_urb.left = 1;
254  usb_submit_xmit_buffer(EPIN, &data_tx_urb);
255 }
256 #endif
257 /*---------------------------------------------------------------------------*/
258 PROCESS(usb_serial_process, "USB-Serial process");
259 /*---------------------------------------------------------------------------*/
260 PROCESS_THREAD(usb_serial_process, ev, data)
261 {
262 
263  PROCESS_BEGIN();
264 
265  set_serial_number();
266 
267  usb_setup();
268  usb_cdc_acm_setup();
269  usb_set_global_event_process(&usb_serial_process);
270  usb_cdc_acm_set_event_process(&usb_serial_process);
271  usb_set_ep_event_process(EPIN, &usb_serial_process);
272  usb_set_ep_event_process(EPOUT, &usb_serial_process);
273 
274  while(1) {
276  if(ev == PROCESS_EVENT_EXIT) {
277  break;
278  }
279  if(ev == PROCESS_EVENT_POLL) {
280  do_work();
281  }
282  }
283 
284  PROCESS_END();
285 }
286 /*---------------------------------------------------------------------------*/
287 void
288 usb_serial_set_input(int (* input)(unsigned char c))
289 {
290  input_handler = input;
291 }
292 /*---------------------------------------------------------------------------*/
293 void
295 {
296  process_start(&usb_serial_process, NULL);
297 }
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
void usb_serial_set_input(int(*input)(unsigned char c))
Set an input hook for bytes received over USB.
Definition: usb-serial.c:295
#define NULL
The null pointer.
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void usb_serial_init()
Initialise the Serial-over-USB process.
Definition: usb-serial.c:301
#define PROCESS_WAIT_EVENT()
Wait for an event to be posted to the process.
Definition: process.h:141
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
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.
void usb_serial_writeb(uint8_t b)
Write a byte over USB.
Definition: usb-serial.c:250