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_usbd.h"
47 #include "app_usbd.h"
48 #include "app_usbd_core.h"
49 #include "app_usbd_string_desc.h"
50 #include "app_usbd_cdc_acm.h"
51 #include "app_usbd_serial_num.h"
52 
53 #include <stdint.h>
54 /*---------------------------------------------------------------------------*/
55 static void
56 cdc_acm_port_ev_handler(app_usbd_class_inst_t const *p_inst,
57  app_usbd_cdc_acm_user_event_t event);
58 /*---------------------------------------------------------------------------*/
59 #define CDC_ACM_COMM_INTERFACE 0
60 #define CDC_ACM_COMM_EPIN NRF_DRV_USBD_EPIN2
61 
62 #define CDC_ACM_DATA_INTERFACE 1
63 #define CDC_ACM_DATA_EPIN NRF_DRV_USBD_EPIN1
64 #define CDC_ACM_DATA_EPOUT NRF_DRV_USBD_EPOUT1
65 
66 APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm, cdc_acm_port_ev_handler,
67  CDC_ACM_COMM_INTERFACE, CDC_ACM_DATA_INTERFACE,
68  CDC_ACM_COMM_EPIN, CDC_ACM_DATA_EPIN,
69  CDC_ACM_DATA_EPOUT,
70  APP_USBD_CDC_COMM_PROTOCOL_NONE);
71 /*---------------------------------------------------------------------------*/
72 #define RX_BUFFER_SIZE NRF_DRV_USBD_EPSIZE
73 #define TX_BUFFER_SIZE NRF_DRV_USBD_EPSIZE
74 
75 static uint8_t usb_rx_data[RX_BUFFER_SIZE];
76 static uint8_t usb_tx_data[TX_BUFFER_SIZE];
77 
78 static volatile uint8_t enabled = 0;
79 static volatile uint8_t buffered_data = 0;
80 static volatile uint8_t tx_buffer_busy = 0;
81 /*---------------------------------------------------------------------------*/
82 /* Callback to the input handler */
83 static int (*input_handler)(unsigned char c);
84 /*---------------------------------------------------------------------------*/
85 static void
86 cdc_acm_port_ev_handler(app_usbd_class_inst_t const *p_inst,
87  app_usbd_cdc_acm_user_event_t event)
88 {
89  app_usbd_cdc_acm_t const *p_cdc_acm = app_usbd_cdc_acm_class_get(p_inst);
90 
91  switch(event) {
92  case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
93  {
94  /* Set up first transfer */
95  app_usbd_cdc_acm_read_any(&m_app_cdc_acm, usb_rx_data, RX_BUFFER_SIZE);
96  enabled = 1;
97  break;
98  }
99 
100  case APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE:
101  {
102  tx_buffer_busy = 0;
103  enabled = 0;
104  break;
105  }
106 
107  case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
108  {
109  tx_buffer_busy = 0;
110  break;
111  }
112 
113  case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
114  {
115  ret_code_t ret;
116 
117  do {
118  size_t rx_size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
119 
120  if(input_handler) {
121  uint8_t i;
122 
123  for(i = 0; i < rx_size; i++) {
124  input_handler(usb_rx_data[i]);
125  }
126  }
127 
128  /* Fetch up to RX_BUFFER_SIZE bytes from the internal buffer */
129  ret = app_usbd_cdc_acm_read_any(&m_app_cdc_acm,
130  usb_rx_data, RX_BUFFER_SIZE);
131  } while(ret == NRF_SUCCESS);
132 
133  break;
134  }
135 
136  default:
137  break;
138  }
139 }
140 /*---------------------------------------------------------------------------*/
141 void
143 {
144  ret_code_t ret;
145  app_usbd_class_inst_t const *class_cdc_acm;
146 
147  app_usbd_serial_num_generate();
148 
149  ret = app_usbd_init(NULL);
150  if(ret != NRF_SUCCESS) {
151  return;
152  }
153 
154  class_cdc_acm = app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm);
155 
156  ret = app_usbd_class_append(class_cdc_acm);
157  if(ret != NRF_SUCCESS) {
158  return;
159  }
160 
161  enabled = 0;
162  buffered_data = 0;
163 
164  app_usbd_enable();
165  app_usbd_start();
166 }
167 /*---------------------------------------------------------------------------*/
168 void
170 {
171  if(!enabled || tx_buffer_busy || buffered_data == 0) {
172  return;
173  }
174 
175  ret_code_t ret;
176 
177  tx_buffer_busy = 1;
178  do {
179  ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, usb_tx_data, buffered_data);
181  } while(ret != NRF_SUCCESS);
182 
183  /* Block until APP_USBD_CDC_ACM_USER_EVT_TX_DONE fires */
184  while(tx_buffer_busy) {
186  }
187 
188  buffered_data = 0;
189 }
190 /*---------------------------------------------------------------------------*/
191 void
193 {
194  if(!enabled) {
195  buffered_data = 0;
196  return;
197  }
198 
199  if(buffered_data < TX_BUFFER_SIZE) {
200  usb_tx_data[buffered_data] = b;
201  buffered_data++;
202  }
203 
204  if(buffered_data == TX_BUFFER_SIZE) {
206  }
207 }
208 /*---------------------------------------------------------------------------*/
209 void
210 usb_serial_set_input(int (*input)(unsigned char c))
211 {
212  input_handler = input;
213 }
214 /*---------------------------------------------------------------------------*/
215 
216 /** @} */
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:1813
void usb_serial_set_input(int(*input)(unsigned char c))
Set an input hook for bytes received over USB.
Definition: usb-serial.c:295