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/*---------------------------------------------------------------------------*/
67struct lang_id {
68 uint8_t size;
69 uint8_t type;
70 uint16_t langid;
71};
72static const struct lang_id lang_id = { sizeof(lang_id), 3, 0x0409 };
73/*---------------------------------------------------------------------------*/
74struct serial_nr {
75 uint8_t size;
76 uint8_t type;
77 uint16_t string[16];
78};
79static 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/*---------------------------------------------------------------------------*/
87struct manufacturer {
88 uint8_t size;
89 uint8_t type;
90 uint16_t string[17];
91};
92static 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/*---------------------------------------------------------------------------*/
101struct product {
102 uint8_t size;
103 uint8_t type;
104 uint16_t string[21];
105};
106static 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
121typedef struct _USBBuffer usb_buffer;
122
123static usb_buffer data_rx_urb;
124static usb_buffer data_tx_urb;
125static uint8_t usb_rx_data[RX_BUFFER_SIZE];
126static uint8_t enabled = 0;
127
128#define SLIP_END 0300
129static uint8_t usb_tx_data[TX_BUFFER_SIZE];
130static uint8_t buffered_data = 0;
131
132/* Callback to the input handler */
133static int (* input_handler)(unsigned char c);
134/*---------------------------------------------------------------------------*/
135uint8_t *
136usb_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/*---------------------------------------------------------------------------*/
152static void
153set_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/*---------------------------------------------------------------------------*/
172static void
173queue_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/*---------------------------------------------------------------------------*/
183static void
184do_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/*---------------------------------------------------------------------------*/
233void
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/*---------------------------------------------------------------------------*/
249void
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/*---------------------------------------------------------------------------*/
265PROCESS(usb_serial_process, "USB-Serial process");
266/*---------------------------------------------------------------------------*/
267PROCESS_THREAD(usb_serial_process, ev, data)
268{
269
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/*---------------------------------------------------------------------------*/
294void
295usb_serial_set_input(int (* input)(unsigned char c))
296{
297 input_handler = input;
298}
299/*---------------------------------------------------------------------------*/
300void
302{
303 process_start(&usb_serial_process, NULL);
304}
305/*---------------------------------------------------------------------------*/
306
307/** @} */
void ieee_addr_cpy_to(uint8_t *dst, uint8_t len)
Copy the node's IEEE address to a destination memory area.
Definition: ieee-addr.c:47
PROCESS_THREAD(cc2538_rf_process, ev, data)
Implementation of the cc2538 RF driver process.
Definition: cc2538-rf.c:1154
void usb_serial_writeb(uint8_t b)
Write a byte over USB.
Definition: usb-serial.c:250
void usb_serial_set_input(int(*input)(unsigned char c))
Set an input hook for bytes received over USB.
Definition: usb-serial.c:295
void usb_serial_flush()
Immediately transmit the content of Serial-over-USB TX buffers.
Definition: usb-serial.c:234
void usb_serial_init()
Initialise the Serial-over-USB process.
Definition: usb-serial.c:301
#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
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1833
Header file for the link-layer address representation.
Header file for the Contiki process interface.