/
usb_console.c
157 lines (137 loc) · 3.52 KB
/
usb_console.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <stdbool.h>
#include "usb_console.h"
#include "data-logger.desc.h"
static struct cdc_ctx cdc;
bool usb_enabled = false;
// ACM device receive buffer
static char rx_buffer[32];
static unsigned int rx_tail = 0;
void (*usb_console_line_recvd_cb)(const char *cmd, size_t len) = NULL;
static void
new_data(uint8_t *data, size_t len)
{
for (unsigned int i=0; i<len; i++) {
if (data[i] == '\n' || data[i] == '\r') {
rx_buffer[rx_tail] = 0;
if (usb_console_line_recvd_cb)
usb_console_line_recvd_cb(rx_buffer, rx_tail);
rx_tail = 0;
} else if (data[i] == '\b') {
// backspace
} else {
rx_buffer[rx_tail] = data[i];
rx_tail = (rx_tail + 1) % sizeof(rx_buffer);
}
}
cdc_read_more(&cdc);
}
// ACM transmit
#define TX_BUF_SIZE 256
static char tx_buffer[TX_BUF_SIZE];
static volatile unsigned int tx_head = 0; // where data is placed
static volatile size_t tx_tail = 0; // where data is read out
static flush_cb cur_flush_cb = NULL;
static void *flush_cbdata = NULL;
static size_t
out_file_write(const uint8_t *buf, size_t len, void *ops_data)
{
crit_enter();
if (len + tx_head > TX_BUF_SIZE)
len = TX_BUF_SIZE - tx_head;
memcpy(&tx_buffer[tx_head], buf, len);
tx_head += len;
crit_exit();
return len;
}
struct _stdio_file_ops out_file_ops = {
.init = NULL,
.write = out_file_write
};
FILE out_file = {
.ops = &out_file_ops,
};
int
usb_console_printf(const char *fmt, ...)
{
va_list args;
int ret;
va_start(args, fmt);
ret = vfprintf(&out_file, fmt, args);
va_end(args);
return ret;
}
size_t
usb_console_write(const char *buf, size_t len)
{
return out_file_write((const uint8_t *) buf, len, NULL);
}
static void
do_flush(size_t sent)
{
crit_enter();
if (tx_tail < tx_head) {
size_t written = cdc_write((const uint8_t *) &tx_buffer[tx_tail],
tx_head - tx_tail, &cdc);
tx_tail += written;
crit_exit();
} else {
tx_head = 0;
flush_cb cb = cur_flush_cb;
cur_flush_cb = NULL;
crit_exit();
if (cb)
cb(flush_cbdata);
}
}
void
usb_console_flush(flush_cb cb, void *cbdata)
{
crit_enter();
cur_flush_cb = cb;
flush_cbdata = cbdata;
tx_tail = 0;
do_flush(0);
crit_exit();
}
static void
data_sent_cb(size_t sent)
{
do_flush(sent);
}
void
usb_console_reset()
{
crit_enter();
rx_tail = 0;
tx_head = 0;
tx_tail = 0;
crit_exit();
}
void
init_vcdc(int config)
{
cdc_init(new_data, data_sent_cb, &cdc);
cdc_set_stdout(&cdc);
}
void
usb_console_init()
{
if (usb_enabled)
return;
usb_console_reset();
usb_init(&cdc_device);
usb_enabled = true;
}
void
usb_console_power_down()
{
if (!usb_enabled)
return;
USB0.ctl.raw |= ((struct USB_CTL_t){
.txd_suspend = 1,
.usben = 0,
.oddrst = 1,
}).raw;
SIM.scgc4.usbotg = 0;
usb_enabled = false;
}