Contiki-NG
Loading...
Searching...
No Matches
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/*---------------------------------------------------------------------------*/
56static void
57cdc_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
67APP_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
76static uint8_t usb_rx_data[RX_BUFFER_SIZE];
77static uint8_t usb_tx_data[TX_BUFFER_SIZE];
78
79static volatile uint8_t enabled = 0;
80static volatile uint8_t buffered_data = 0;
81static volatile uint8_t tx_buffer_busy = 0;
82/*---------------------------------------------------------------------------*/
83/* Callback to the input handler */
84static int (*input_handler)(unsigned char c);
85/*---------------------------------------------------------------------------*/
86static void
87cdc_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/*---------------------------------------------------------------------------*/
142static void
143usbd_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/*---------------------------------------------------------------------------*/
181void
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/*---------------------------------------------------------------------------*/
214void
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/*---------------------------------------------------------------------------*/
237void
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/*---------------------------------------------------------------------------*/
255void
256usb_serial_set_input(int (*input)(unsigned char c))
257{
258 input_handler = input;
259}
260/*---------------------------------------------------------------------------*/
261
262/** @} */
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
void watchdog_periodic(void)
Writes the WDT clear sequence.
Definition watchdog.c:85