Contiki-NG
usb-serial.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020, Alex Stanoev - https://astanoev.com
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
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. Neither the name of the copyright holder nor the names of its
15  * contributors may be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29  * OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /**
32  * \addtogroup nrf52840-usb
33  * @{
34  *
35  * \file
36  * Wrapper around the nRF SDK USB CDC-ACM implementation.
37  * Implements a UART-like functionality over the nRF52840's USB hardware.
38  *
39  * This exposes a similar interface to cpu/cc2538/usb
40  *
41  * \author
42  * - Alex Stanoev - <alex@astanoev.com>
43  */
44 #include "contiki.h"
45 
46 #include "nrf_drv_power.h"
47 #include "nrf_drv_usbd.h"
48 #include "app_usbd.h"
49 #include "app_usbd_core.h"
50 #include "app_usbd_string_desc.h"
51 #include "app_usbd_cdc_acm.h"
52 #include "app_usbd_serial_num.h"
53 
54 #include <stdint.h>
55 /*---------------------------------------------------------------------------*/
56 static void
57 cdc_acm_port_ev_handler(app_usbd_class_inst_t const *p_inst,
58  app_usbd_cdc_acm_user_event_t event);
59 /*---------------------------------------------------------------------------*/
60 #define CDC_ACM_COMM_INTERFACE 0
61 #define CDC_ACM_COMM_EPIN NRF_DRV_USBD_EPIN2
62 
63 #define CDC_ACM_DATA_INTERFACE 1
64 #define CDC_ACM_DATA_EPIN NRF_DRV_USBD_EPIN1
65 #define CDC_ACM_DATA_EPOUT NRF_DRV_USBD_EPOUT1
66 
67 APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm, cdc_acm_port_ev_handler,
68  CDC_ACM_COMM_INTERFACE, CDC_ACM_DATA_INTERFACE,
69  CDC_ACM_COMM_EPIN, CDC_ACM_DATA_EPIN,
70  CDC_ACM_DATA_EPOUT,
71  APP_USBD_CDC_COMM_PROTOCOL_NONE);
72 /*---------------------------------------------------------------------------*/
73 #define RX_BUFFER_SIZE NRF_DRV_USBD_EPSIZE
74 #define TX_BUFFER_SIZE NRF_DRV_USBD_EPSIZE
75 
76 static uint8_t usb_rx_data[RX_BUFFER_SIZE];
77 static uint8_t usb_tx_data[TX_BUFFER_SIZE];
78 
79 static volatile uint8_t enabled = 0;
80 static volatile uint8_t buffered_data = 0;
81 static volatile uint8_t tx_buffer_busy = 0;
82 /*---------------------------------------------------------------------------*/
83 /* Callback to the input handler */
84 static int (*input_handler)(unsigned char c);
85 /*---------------------------------------------------------------------------*/
86 static void
87 cdc_acm_port_ev_handler(app_usbd_class_inst_t const *p_inst,
88  app_usbd_cdc_acm_user_event_t event)
89 {
90  app_usbd_cdc_acm_t const *p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst);
91 
92  switch(event) {
93  case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
94  {
95  /* Set up first transfer */
96  app_usbd_cdc_acm_read_any(&m_app_cdc_acm, usb_rx_data, RX_BUFFER_SIZE);
97  enabled = 1;
98  break;
99  }
100 
101  case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
102  {
103  tx_buffer_busy = 0;
104  enabled = 0;
105  break;
106  }
107 
108  case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
109  {
110  tx_buffer_busy = 0;
111  break;
112  }
113 
114  case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
115  {
116  ret_code_t ret;
117 
118  do {
119  size_t rx_size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
120 
121  if(input_handler) {
122  uint8_t i;
123 
124  for(i = 0; i < rx_size; i++) {
125  input_handler(usb_rx_data[i]);
126  }
127  }
128 
129  /* Fetch up to RX_BUFFER_SIZE bytes from the internal buffer */
130  ret = app_usbd_cdc_acm_read_any(&m_app_cdc_acm,
131  usb_rx_data, RX_BUFFER_SIZE);
132  } while(ret == NRF_SUCCESS);
133 
134  break;
135  }
136 
137  default:
138  break;
139  }
140 }
141 /*---------------------------------------------------------------------------*/
142 static void
143 usbd_user_ev_handler(app_usbd_event_type_t event)
144 {
145  switch(event) {
146  case APP_USBD_EVT_STOPPED:
147  {
148  tx_buffer_busy = 0;
149  enabled = 0;
150  app_usbd_disable();
151  break;
152  }
153 
154  case APP_USBD_EVT_POWER_DETECTED:
155  {
156  if(!nrf_drv_usbd_is_enabled()) {
157  app_usbd_enable();
158  }
159  break;
160  }
161 
162  case APP_USBD_EVT_POWER_REMOVED:
163  {
164  tx_buffer_busy = 0;
165  enabled = 0;
166  app_usbd_stop();
167  break;
168  }
169 
170  case APP_USBD_EVT_POWER_READY:
171  {
172  app_usbd_start();
173  break;
174  }
175 
176  default:
177  break;
178  }
179 }
180 /*---------------------------------------------------------------------------*/
181 void
183 {
184  static const app_usbd_config_t usbd_config = {
185  .ev_state_proc = usbd_user_ev_handler
186  };
187 
188  ret_code_t ret;
189  app_usbd_class_inst_t const *class_cdc_acm;
190 
191  app_usbd_serial_num_generate();
192 
193  ret = app_usbd_init(&usbd_config);
194  if(ret != NRF_SUCCESS) {
195  return;
196  }
197 
198  class_cdc_acm = app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm);
199 
200  ret = app_usbd_class_append(class_cdc_acm);
201  if(ret != NRF_SUCCESS) {
202  return;
203  }
204 
205  ret = app_usbd_power_events_enable();
206  if(ret != NRF_SUCCESS) {
207  return;
208  }
209 
210  enabled = 0;
211  buffered_data = 0;
212 }
213 /*---------------------------------------------------------------------------*/
214 void
216 {
217  if(!enabled || tx_buffer_busy || buffered_data == 0) {
218  return;
219  }
220 
221  ret_code_t ret;
222 
223  tx_buffer_busy = 1;
224  do {
225  ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_tx_data, buffered_data);
227  } while(ret != NRF_SUCCESS);
228 
229  /* Block until APP_USBD_CDC_ACM_USER_EVT_TX_DONE fires */
230  while(tx_buffer_busy) {
232  }
233 
234  buffered_data = 0;
235 }
236 /*---------------------------------------------------------------------------*/
237 void
239 {
240  if(!enabled) {
241  buffered_data = 0;
242  return;
243  }
244 
245  if(buffered_data < TX_BUFFER_SIZE) {
246  usb_tx_data[buffered_data] = b;
247  buffered_data++;
248  }
249 
250  if(buffered_data == TX_BUFFER_SIZE) {
252  }
253 }
254 /*---------------------------------------------------------------------------*/
255 void
256 usb_serial_set_input(int (*input)(unsigned char c))
257 {
258  input_handler = input;
259 }
260 /*---------------------------------------------------------------------------*/
261 
262 /** @} */
void usb_serial_init()
Initialise the Serial-over-USB process.
Definition: usb-serial.c:301
void usb_serial_writeb(uint8_t b)
Write a byte over USB.
Definition: usb-serial.c:250
void usb_serial_flush()
Immediately transmit the content of Serial-over-USB TX buffers.
Definition: usb-serial.c:234
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition: watchdog.c:85
static void input(void)
Process a received 6lowpan packet.
Definition: sicslowpan.c:1847
void usb_serial_set_input(int(*input)(unsigned char c))
Set an input hook for bytes received over USB.
Definition: usb-serial.c:295