Skip to content

Commit e0d9661

Browse files
committed
Implement SerialUSB
1 parent 312c258 commit e0d9661

File tree

6 files changed

+137
-5
lines changed

6 files changed

+137
-5
lines changed

cores/arduino/Arduino.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,5 +108,6 @@ int digitalPinToInterrupt(pin_size_t pin);
108108

109109
#include <variant.h>
110110
#ifdef __cplusplus
111+
#include <SerialUSB.h>
111112
#include <zephyrSerial.h>
112-
#endif // __cplusplus
113+
#endif // __cplusplus

cores/arduino/SerialUSB.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (c) 2024 Arduino SA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#include <zephyrSerial.h>
10+
11+
namespace arduino {
12+
13+
class SerialUSB_ : public ZephyrSerial {
14+
15+
public:
16+
SerialUSB_(const struct device *dev) : ZephyrSerial(dev) { }
17+
void begin(unsigned long baudrate, uint16_t config);
18+
void begin(unsigned long baudrate) { begin(baudrate, SERIAL_8N1); }
19+
20+
operator bool() override;
21+
22+
protected:
23+
uint32_t dtr = 0;
24+
uint32_t baudrate;
25+
void _baudChangeHandler();
26+
static void _baudChangeDispatch(struct k_timer *timer);
27+
28+
private:
29+
struct k_timer baud_timer;
30+
bool started = false;
31+
};
32+
} // namespace arduino
33+
34+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), cdc_acm)
35+
extern arduino::SerialUSB_ Serial;
36+
#endif

cores/arduino/USB.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright (c) 2024 Arduino SA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
// Make PluggableUSB link happy
8+
#include "api/PluggableUSB.h"
9+
10+
static uint8_t _epBuffer[1];
11+
void* epBuffer(unsigned int n) {
12+
return &_epBuffer[n];
13+
};
14+
15+
arduino::PluggableUSB_::PluggableUSB_() {}
16+
17+
#include <zephyr/devicetree.h>
18+
#include <zephyr/drivers/uart.h>
19+
#include <zephyr/drivers/uart/cdc_acm.h>
20+
#include <zephyr/usb/usb_device.h>
21+
#include <SerialUSB.h>
22+
23+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), cdc_acm)
24+
const struct device *const usb_dev = DEVICE_DT_GET(DT_PHANDLE_BY_IDX(DT_PATH(zephyr_user), cdc_acm, 0));
25+
26+
void usb_status_cb(enum usb_dc_status_code cb_status, const uint8_t *param) {
27+
if (cb_status == USB_DC_CONFIGURED) {
28+
29+
}
30+
}
31+
32+
void __attribute__((weak)) _on_1200_bps() {
33+
NVIC_SystemReset();
34+
}
35+
36+
void arduino::SerialUSB_::_baudChangeHandler()
37+
{
38+
uart_line_ctrl_get(uart, UART_LINE_CTRL_BAUD_RATE, &baudrate);
39+
if (baudrate == 1200) {
40+
usb_disable();
41+
_on_1200_bps();
42+
}
43+
}
44+
45+
static void _baudChangeHandler(const struct device *dev, uint32_t rate)
46+
{
47+
if (rate == 1200) {
48+
usb_disable();
49+
_on_1200_bps();
50+
}
51+
}
52+
53+
void arduino::SerialUSB_::_baudChangeDispatch(struct k_timer *timer) {
54+
arduino::SerialUSB_* dev = (arduino::SerialUSB_*)k_timer_user_data_get(timer);
55+
dev->_baudChangeHandler();
56+
}
57+
58+
59+
void arduino::SerialUSB_::begin(unsigned long baudrate, uint16_t config) {
60+
if (!started) {
61+
usb_enable(NULL);
62+
#ifndef CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT
63+
k_timer_init(&baud_timer, SerialUSB_::_baudChangeDispatch, NULL);
64+
k_timer_user_data_set(&baud_timer, this);
65+
k_timer_start(&baud_timer, K_MSEC(100), K_MSEC(100));
66+
#else
67+
cdc_acm_dte_rate_callback_set(usb_dev, ::_baudChangeHandler);
68+
#endif
69+
ZephyrSerial::begin(baudrate, config);
70+
started = true;
71+
}
72+
}
73+
74+
arduino::SerialUSB_::operator bool() {
75+
uart_line_ctrl_get(uart, UART_LINE_CTRL_DTR, &dtr);
76+
return dtr;
77+
}
78+
79+
arduino::SerialUSB_ Serial(usb_dev);
80+
#endif

cores/arduino/main.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
#endif
1111

1212
int main(void) {
13+
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), cdc_acm)
14+
Serial.begin(115200);
15+
#endif
1316
setup();
1417

1518
for (;;) {

cores/arduino/zephyrSerial.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <api/HardwareSerial.h>
1111
#include <zephyrSerial.h>
12+
#include <Arduino.h>
1213

1314
namespace
1415
{
@@ -164,7 +165,10 @@ size_t arduino::ZephyrSerial::write(const uint8_t *buffer, size_t size)
164165
}
165166

166167
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), serials)
168+
#if !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), cdc_acm)
169+
// If CDC USB, use that object as Serial (and SerialUSB)
167170
arduino::ZephyrSerial Serial(DEVICE_DT_GET(DT_PHANDLE_BY_IDX(DT_PATH(zephyr_user), serials, 0)));
171+
#endif
168172
#if (DT_PROP_LEN(DT_PATH(zephyr_user), serials) > 1)
169173
#define ARDUINO_SERIAL_DEFINED_0 1
170174

cores/arduino/zephyrSerial.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
#pragma once
88

99
#include <zephyr/sys/ring_buffer.h>
10-
11-
#include <Arduino.h>
1210
#include <api/HardwareSerial.h>
1311

1412
namespace arduino {
@@ -38,7 +36,7 @@ class ZephyrSerial : public HardwareSerial
3836
template <int SZ>
3937
class ZephyrSerialBuffer
4038
{
41-
friend arduino::ZephyrSerial;
39+
friend arduino::ZephyrSerial;
4240
struct ring_buf ringbuf;
4341
uint8_t buffer[SZ];
4442
struct k_sem sem;
@@ -53,10 +51,15 @@ class ZephyrSerial : public HardwareSerial
5351
ZephyrSerial(const struct device *dev) : uart(dev) { }
5452
void begin(unsigned long baudrate, uint16_t config);
5553
void begin(unsigned long baudrate) { begin(baudrate, SERIAL_8N1); }
56-
void flush() { }
54+
void flush() {
55+
while (ring_buf_size_get(&tx.ringbuf) > 0) {
56+
k_yield();
57+
}
58+
}
5759
void end() { }
5860
size_t write(const uint8_t *buffer, size_t size);
5961
size_t write(const uint8_t data) { return write(&data, 1); }
62+
using Print::write; // pull in write(str) and write(buf, size) from Print
6063
int available();
6164
int peek();
6265
int read();
@@ -66,6 +69,8 @@ class ZephyrSerial : public HardwareSerial
6669
return true;
6770
}
6871

72+
friend class SerialUSB_;
73+
6974
protected:
7075
void IrqHandler();
7176
static void IrqDispatch(const struct device *dev, void *data);
@@ -79,7 +84,10 @@ class ZephyrSerial : public HardwareSerial
7984
} // namespace arduino
8085

8186
#if DT_NODE_HAS_PROP(DT_PATH(zephyr_user), serials)
87+
#if !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), cdc_acm)
88+
// If CDC USB, use that object as Serial (and SerialUSB)
8289
extern arduino::ZephyrSerial Serial;
90+
#endif
8391
#if (DT_PROP_LEN(DT_PATH(zephyr_user), serials) > 1)
8492
#define SERIAL_DEFINED_0 1
8593
#define EXTERN_SERIAL_N(i) extern arduino::ZephyrSerial Serial##i;

0 commit comments

Comments
 (0)