Skip to content

Commit c31ca72

Browse files
authored
Merge pull request #21 from picoruby/separete_CDC_for_debug_print
Add dual CDC USB support for separate stdout and stderr
2 parents 9ff5262 + 96436d6 commit c31ca72

File tree

8 files changed

+96
-48
lines changed

8 files changed

+96
-48
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,9 @@ jobs:
3939
npm install
4040
popd
4141
- run: rake picoruby:pico:debug
42-
- run: |
43-
set -eux
44-
npm --prefix ./lib/rp2040js run start:micropython -- --image $PWD/build/picoruby/pico/debug/R2P2-PICORUBY-PICO*.uf2 | tee log.txt &
45-
sleep 10
46-
kill -9 %1
47-
# cat log.txt
48-
grep "/etc/init.d/r2p2" log.txt
49-
# grep "No app.(mrb|rb) found" log.txt
42+
- name: Verify build artifacts
43+
run: |
44+
ls -lh build/picoruby/pico/debug/R2P2-PICORUBY-PICO*.uf2
45+
echo "Build successful"
5046
5147

CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ endif()
183183
if(PICORB_VM_MRUBY)
184184
add_compile_definitions(PICORB_VM_MRUBY=1)
185185
target_include_directories(${PROJECT_NAME} PRIVATE
186-
${CMAKE_SOURCE_DIR}/lib/picoruby/mrbgems/picoruby-mruby/include
187186
${CMAKE_SOURCE_DIR}/lib/picoruby/mrbgems/picoruby-mruby/lib/mruby/include
188187
)
189188
elseif(PICORB_VM_MRUBYC)

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,29 @@ You may need to look for a fine configuration.
2323

2424
Anyway, it seems almost problems on the terminal emulator come from CR/LF handling.
2525

26+
### Dual CDC USB ports for debug output
27+
28+
R2P2 uses dual CDC (Communications Device Class) USB ports to separate standard output and debug output:
29+
30+
- **CDC 0** (in Linux, typically `/dev/ttyACM0`): Main terminal for shell interaction and application stdout
31+
- **CDC 1** (as in, `/dev/ttyACM1`): Debug output (stderr) for system messages and debug prints
32+
33+
Debug output is only enabled in debug builds (`rake debug` or `PICORUBY_DEBUG=1 rake`).
34+
35+
To view debug output:
36+
```sh
37+
# Terminal 1: Main shell
38+
gtkterm --port /dev/ttyACM0
39+
40+
# Terminal 2: Debug messages
41+
gtkterm --port /dev/ttyACM1
42+
```
43+
44+
In Ruby code, use `Machine.debug_puts` to output to the debug port:
45+
```ruby
46+
Machine.debug_puts "Debug message"
47+
```
48+
2649
## Demonstration
2750

2851
### Opening crawl

include/tusb_config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@
113113
#endif
114114

115115
//------------- CLASS -------------//
116-
#define CFG_TUD_CDC 1
116+
#define CFG_TUD_CDC 2
117117
#define CFG_TUD_MSC 1
118118
#define CFG_TUD_HID 0
119119
#define CFG_TUD_MIDI 0

src/main.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
#include <hardware/clocks.h>
77

88
#include <stdio.h>
9+
#include <string.h>
910

1011
/* PicoRuby */
1112
#include "picoruby.h"
13+
#include "picoruby/debug.h"
14+
#include "hal.h" // in picoruby-machine
1215
#include "main_task.c"
1316

1417
#if !defined(HEAP_SIZE)
@@ -45,6 +48,7 @@ int
4548
main(void)
4649
{
4750
stdio_init_all();
51+
// printf() goes to Picoprobe UART
4852
printf("R2P2 PicoRuby starting...\n");
4953
printf("Heap size: %d KB\n", HEAP_SIZE_KB);
5054
board_init();
@@ -59,7 +63,8 @@ main(void)
5963
mrb_value name = mrb_str_new_lit(mrb, "R2P2");
6064
mrb_value task = mrc_create_task(cc, irep, name, mrb_nil_value(), mrb_obj_value(mrb->top_self));
6165
if (mrb_nil_p(task)) {
62-
printf("mrbc_create_task failed\n");
66+
const char *msg = "mrbc_create_task failed\n";
67+
hal_write(1, msg, strlen(msg));
6368
ret = 1;
6469
}
6570
else {
@@ -75,7 +80,8 @@ main(void)
7580
mrbc_init(heap_pool, HEAP_SIZE);
7681
mrbc_tcb *main_tcb = mrbc_create_task(main_task, 0);
7782
if (!main_tcb) {
78-
printf("mrbc_create_task failed\n");
83+
const char *msg = "mrbc_create_task failed\n";
84+
hal_write(1, msg, strlen(msg));
7985
ret = 1;
8086
}
8187
else {

src/usb_descriptors.c

Lines changed: 58 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -87,64 +87,83 @@ uint8_t const * tud_descriptor_device_cb(void)
8787

8888
enum
8989
{
90-
ITF_NUM_CDC = 0,
91-
ITF_NUM_CDC_DATA,
90+
ITF_NUM_CDC_0 = 0,
91+
ITF_NUM_CDC_0_DATA,
92+
ITF_NUM_CDC_1,
93+
ITF_NUM_CDC_1_DATA,
9294
ITF_NUM_MSC,
9395
ITF_NUM_TOTAL
9496
};
9597

9698
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
9799
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
98-
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ...
99-
#define EPNUM_CDC_NOTIF 0x81
100-
#define EPNUM_CDC_OUT 0x02
101-
#define EPNUM_CDC_IN 0x82
100+
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
101+
#define EPNUM_CDC_0_NOTIF 0x81
102+
#define EPNUM_CDC_0_OUT 0x02
103+
#define EPNUM_CDC_0_IN 0x82
102104

103-
#define EPNUM_MSC_OUT 0x05
104-
#define EPNUM_MSC_IN 0x85
105+
#define EPNUM_CDC_1_NOTIF 0x84
106+
#define EPNUM_CDC_1_OUT 0x05
107+
#define EPNUM_CDC_1_IN 0x85
105108

106-
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
107-
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
108-
// e.g EP1 OUT & EP1 IN cannot exist together
109-
#define EPNUM_CDC_NOTIF 0x81
110-
#define EPNUM_CDC_OUT 0x02
111-
#define EPNUM_CDC_IN 0x83
112-
113-
#define EPNUM_MSC_OUT 0x04
114-
#define EPNUM_MSC_IN 0x85
109+
#define EPNUM_MSC_OUT 0x08
110+
#define EPNUM_MSC_IN 0x88
115111

116112
#elif CFG_TUSB_MCU == OPT_MCU_CXD56
117-
// CXD56 doesn't support a same endpoint number with different direction IN and OUT
118-
// e.g EP1 OUT & EP1 IN cannot exist together
119113
// CXD56 USB driver has fixed endpoint type (bulk/interrupt/iso) and direction (IN/OUT) by its number
120114
// 0 control (IN/OUT), 1 Bulk (IN), 2 Bulk (OUT), 3 In (IN), 4 Bulk (IN), 5 Bulk (OUT), 6 In (IN)
121-
#define EPNUM_CDC_NOTIF 0x83
122-
#define EPNUM_CDC_OUT 0x02
123-
#define EPNUM_CDC_IN 0x81
115+
#define EPNUM_CDC_0_NOTIF 0x83
116+
#define EPNUM_CDC_0_OUT 0x02
117+
#define EPNUM_CDC_0_IN 0x81
124118

125-
#define EPNUM_MSC_OUT 0x05
126-
#define EPNUM_MSC_IN 0x84
119+
#define EPNUM_CDC_1_NOTIF 0x86
120+
#define EPNUM_CDC_1_OUT 0x05
121+
#define EPNUM_CDC_1_IN 0x84
122+
123+
#define EPNUM_MSC_OUT 0x07
124+
#define EPNUM_MSC_IN 0x08
125+
126+
#elif defined(TUD_ENDPOINT_ONE_DIRECTION_ONLY)
127+
// MCUs that don't support a same endpoint number with different direction IN and OUT
128+
// e.g EP1 OUT & EP1 IN cannot exist together
129+
#define EPNUM_CDC_0_NOTIF 0x81
130+
#define EPNUM_CDC_0_OUT 0x02
131+
#define EPNUM_CDC_0_IN 0x83
132+
133+
#define EPNUM_CDC_1_NOTIF 0x84
134+
#define EPNUM_CDC_1_OUT 0x05
135+
#define EPNUM_CDC_1_IN 0x86
136+
137+
#define EPNUM_MSC_OUT 0x07
138+
#define EPNUM_MSC_IN 0x88
127139

128140
#else
129-
#define EPNUM_CDC_NOTIF 0x81
130-
#define EPNUM_CDC_OUT 0x02
131-
#define EPNUM_CDC_IN 0x82
141+
#define EPNUM_CDC_0_NOTIF 0x81
142+
#define EPNUM_CDC_0_OUT 0x02
143+
#define EPNUM_CDC_0_IN 0x82
144+
145+
#define EPNUM_CDC_1_NOTIF 0x83
146+
#define EPNUM_CDC_1_OUT 0x04
147+
#define EPNUM_CDC_1_IN 0x84
132148

133-
#define EPNUM_MSC_OUT 0x03
134-
#define EPNUM_MSC_IN 0x83
149+
#define EPNUM_MSC_OUT 0x05
150+
#define EPNUM_MSC_IN 0x85
135151

136152
#endif
137153

138-
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
154+
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN)
139155

140156
// full speed configuration
141157
uint8_t const desc_fs_configuration[] =
142158
{
143159
// Config number, interface count, string index, total length, attribute, power in mA
144160
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
145161

146-
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
147-
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 64),
162+
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
163+
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 64),
164+
165+
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
166+
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 6, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 64),
148167

149168
// Interface number, string index, EP Out & EP In address, EP size
150169
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64),
@@ -159,8 +178,11 @@ uint8_t const desc_hs_configuration[] =
159178
// Config number, interface count, string index, total length, attribute, power in mA
160179
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0x00, 100),
161180

162-
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
163-
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 4, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT, EPNUM_CDC_IN, 512),
181+
// 1st CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
182+
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_0, 4, EPNUM_CDC_0_NOTIF, 8, EPNUM_CDC_0_OUT, EPNUM_CDC_0_IN, 512),
183+
184+
// 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size.
185+
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 6, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512),
164186

165187
// Interface number, string index, EP Out & EP In address, EP size
166188
TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512),
@@ -249,8 +271,9 @@ char const *string_desc_arr[] =
249271
"PicoRuby", // 1: Manufacturer
250272
"R2P2", // 2: Product
251273
NULL, // 3: Serials will use unique ID if possible
252-
"PicoRuby CDC", // 4: CDC Interface
274+
"PicoRuby CDC", // 4: CDC Interface 0 (Application)
253275
"PicoRuby MSC", // 5: MSC Interface
276+
"PicoRuby CDC Debug", // 6: CDC Interface 1 (Debug)
254277
};
255278

256279
static uint16_t _desc_str[32 + 1];

src/usb_tud.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <pico/stdlib.h>
22
#include <stdio.h>
3+
#include "picoruby/debug.h"
34

45
//--------------------------------------------------------------------+
56
// Device callbacks

0 commit comments

Comments
 (0)