1 /*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <string.h>
8 #include <stdio.h>
9 #include <stdarg.h>
10
11 #include "pico.h"
12 #if LIB_PICO_PRINTF_PICO
13 #include "pico/printf.h"
14 #endif
15 #include "pico/stdio.h"
16 #include "pico/stdio/driver.h"
17 #include "pico/time.h"
18 #if PICO_STDOUT_MUTEX
19 #include "pico/mutex.h"
20 #endif
21
22 #if LIB_PICO_STDIO_UART
23 #include "pico/stdio_uart.h"
24 #endif
25
26 #if LIB_PICO_STDIO_USB
27 #include "pico/stdio_usb.h"
28 #endif
29
30 #if LIB_PICO_STDIO_SEMIHOSTING
31 #include "pico/stdio_semihosting.h"
32 #endif
33
34 #if LIB_PICO_STDIO_RTT
35 #include "pico/stdio_rtt.h"
36 #endif
37
38 static stdio_driver_t *drivers;
39 static stdio_driver_t *filter;
40
41 #if PICO_STDOUT_MUTEX
42 auto_init_mutex(print_mutex);
43
stdout_serialize_begin(void)44 bool stdout_serialize_begin(void) {
45 return mutex_try_enter_block_until(&print_mutex, make_timeout_time_ms(PICO_STDIO_DEADLOCK_TIMEOUT_MS));
46 }
47
stdout_serialize_end(void)48 void stdout_serialize_end(void) {
49 mutex_exit(&print_mutex);
50 }
51
52 #else
stdout_serialize_begin(void)53 static bool stdout_serialize_begin(void) {
54 return true;
55 }
stdout_serialize_end(void)56 static void stdout_serialize_end(void) {
57 }
58 #endif
stdio_out_chars_no_crlf(stdio_driver_t * driver,const char * s,int len)59 static void stdio_out_chars_no_crlf(stdio_driver_t *driver, const char *s, int len) {
60 driver->out_chars(s, len);
61 }
62
stdio_out_chars_crlf(stdio_driver_t * driver,const char * s,int len)63 static void stdio_out_chars_crlf(stdio_driver_t *driver, const char *s, int len) {
64 #if PICO_STDIO_ENABLE_CRLF_SUPPORT
65 if (!driver->crlf_enabled) {
66 driver->out_chars(s, len);
67 return;
68 }
69 int first_of_chunk = 0;
70 static const char crlf_str[] = {'\r', '\n'};
71 for (int i = 0; i < len; i++) {
72 bool prev_char_was_cr = i > 0 ? s[i - 1] == '\r' : driver->last_ended_with_cr;
73 if (s[i] == '\n' && !prev_char_was_cr) {
74 if (i > first_of_chunk) {
75 driver->out_chars(&s[first_of_chunk], i - first_of_chunk);
76 }
77 driver->out_chars(crlf_str, 2);
78 first_of_chunk = i + 1;
79 }
80 }
81 if (first_of_chunk < len) {
82 driver->out_chars(&s[first_of_chunk], len - first_of_chunk);
83 }
84 if (len > 0) {
85 driver->last_ended_with_cr = s[len - 1] == '\r';
86 }
87 #else
88 driver->out_chars(s, len);
89 #endif
90 }
91
stdio_put_string(const char * s,int len,bool newline,bool cr_translation)92 int stdio_put_string(const char *s, int len, bool newline, bool cr_translation) {
93 bool serialized = stdout_serialize_begin();
94 if (!serialized) {
95 #if PICO_STDIO_IGNORE_NESTED_STDOUT
96 return 0;
97 #endif
98 }
99 if (len == -1) len = (int)strlen(s);
100 void (*out_func)(stdio_driver_t *, const char *, int) = cr_translation ? stdio_out_chars_crlf : stdio_out_chars_no_crlf;
101 for (stdio_driver_t *driver = drivers; driver; driver = driver->next) {
102 if (!driver->out_chars) continue;
103 if (filter && filter != driver) continue;
104 out_func(driver, s, len);
105 if (newline) {
106 const char c = '\n';
107 out_func(driver, &c, 1);
108 }
109 }
110 if (serialized) {
111 stdout_serialize_end();
112 }
113 return len;
114 }
115
stdio_get_until(char * buf,int len,absolute_time_t until)116 int stdio_get_until(char *buf, int len, absolute_time_t until) {
117 do {
118 // todo round robin might be nice on each call, but then again hopefully
119 // no source will starve the others
120 for (stdio_driver_t *driver = drivers; driver; driver = driver->next) {
121 if (filter && filter != driver) continue;
122 if (driver->in_chars) {
123 int read = driver->in_chars(buf, len);
124 if (read > 0) {
125 return read;
126 }
127 }
128 }
129 if (time_reached(until)) {
130 return PICO_ERROR_TIMEOUT;
131 }
132 // we sleep here in case the in_chars methods acquire mutexes or disable IRQs and
133 // potentially starve out what they are waiting on (have seen this with USB)
134 busy_wait_us(1);
135 } while (true);
136 }
137
stdio_putchar_raw(int c)138 int stdio_putchar_raw(int c) {
139 char cc = (char)c;
140 stdio_put_string(&cc, 1, false, false);
141 return c;
142 }
143
stdio_puts_raw(const char * s)144 int stdio_puts_raw(const char *s) {
145 int len = (int)strlen(s);
146 stdio_put_string(s, len, true, false);
147 stdio_flush();
148 return len;
149 }
150
stdio_set_driver_enabled(stdio_driver_t * driver,bool enable)151 void stdio_set_driver_enabled(stdio_driver_t *driver, bool enable) {
152 stdio_driver_t **prev = &drivers;
153 while (*prev) {
154 if (*prev == driver) {
155 if (!enable) {
156 *prev = driver->next;
157 driver->next = NULL;
158 }
159 return;
160 }
161 prev = &(*prev)->next;
162 }
163 if (enable) {
164 *prev = driver;
165 }
166 }
167
stdio_flush(void)168 void stdio_flush(void) {
169 for (stdio_driver_t *d = drivers; d; d = d->next) {
170 if (d->out_flush) d->out_flush();
171 }
172 }
173
174 #if LIB_PICO_PRINTF_PICO
175 typedef struct stdio_stack_buffer {
176 int used;
177 char buf[PICO_STDIO_STACK_BUFFER_SIZE];
178 } stdio_stack_buffer_t;
179
stdio_stack_buffer_flush(stdio_stack_buffer_t * buffer)180 static void stdio_stack_buffer_flush(stdio_stack_buffer_t *buffer) {
181 if (buffer->used) {
182 for (stdio_driver_t *d = drivers; d; d = d->next) {
183 if (!d->out_chars) continue;
184 if (filter && filter != d) continue;
185 stdio_out_chars_crlf(d, buffer->buf, buffer->used);
186 }
187 buffer->used = 0;
188 }
189 }
190
stdio_buffered_printer(char c,void * arg)191 static void stdio_buffered_printer(char c, void *arg) {
192 stdio_stack_buffer_t *buffer = (stdio_stack_buffer_t *)arg;
193 if (buffer->used == PICO_STDIO_STACK_BUFFER_SIZE) {
194 stdio_stack_buffer_flush(buffer);
195 }
196 buffer->buf[buffer->used++] = c;
197 }
198 #endif
199
stdio_init_all(void)200 bool stdio_init_all(void) {
201 // todo add explicit custom, or registered although you can call stdio_enable_driver explicitly anyway
202 // These are well known ones
203
204 bool rc = false;
205 #if LIB_PICO_STDIO_UART
206 stdio_uart_init();
207 rc = true;
208 #endif
209
210 #if LIB_PICO_STDIO_SEMIHOSTING
211 stdio_semihosting_init();
212 rc = true;
213 #endif
214
215 #if LIB_PICO_STDIO_RTT
216 stdio_rtt_init();
217 rc = true;
218 #endif
219
220 #if LIB_PICO_STDIO_USB
221 rc |= stdio_usb_init();
222 #endif
223 return rc;
224 }
225
stdio_deinit_all(void)226 bool stdio_deinit_all(void) {
227 // todo add explicit custom, or registered although you can call stdio_enable_driver explicitly anyway
228 // These are well known ones
229
230 // First flush, to make sure everything is printed
231 stdio_flush();
232
233 bool rc = false;
234 #if LIB_PICO_STDIO_UART
235 stdio_uart_deinit();
236 rc = true;
237 #endif
238
239 #if LIB_PICO_STDIO_SEMIHOSTING
240 stdio_semihosting_deinit();
241 rc = true;
242 #endif
243
244 #if LIB_PICO_STDIO_RTT
245 stdio_rtt_deinit();
246 rc = true;
247 #endif
248
249 #if LIB_PICO_STDIO_USB
250 rc = stdio_usb_deinit();
251 #endif
252 return rc;
253 }
254
stdio_getchar_timeout_us(uint32_t timeout_us)255 int stdio_getchar_timeout_us(uint32_t timeout_us) {
256 char buf[1];
257 int rc = stdio_get_until(buf, sizeof(buf), make_timeout_time_us(timeout_us));
258 if (rc < 0) return rc;
259 assert(rc);
260 return (uint8_t)buf[0];
261 }
262
stdio_filter_driver(stdio_driver_t * driver)263 void stdio_filter_driver(stdio_driver_t *driver) {
264 filter = driver;
265 }
266
stdio_set_translate_crlf(stdio_driver_t * driver,bool enabled)267 void stdio_set_translate_crlf(stdio_driver_t *driver, bool enabled) {
268 #if PICO_STDIO_ENABLE_CRLF_SUPPORT
269 if (enabled && !driver->crlf_enabled) {
270 driver->last_ended_with_cr = false;
271 }
272 driver->crlf_enabled = enabled;
273 #else
274 // Suppress -Wunused-parameter
275 (void)driver;
276 (void)enabled;
277
278 panic_unsupported();
279 #endif
280 }
281
stdio_set_chars_available_callback(void (* fn)(void *),void * param)282 void stdio_set_chars_available_callback(void (*fn)(void*), void *param) {
283 for (stdio_driver_t *s = drivers; s; s = s->next) {
284 if (s->set_chars_available_callback) s->set_chars_available_callback(fn, param);
285 }
286 }
287
288 #if PICO_STDIO_SHORT_CIRCUIT_CLIB_FUNCS
289 #define PRIMARY_STDIO_FUNC(x) WRAPPER_FUNC(x)
290 #else
291 #define PRIMARY_STDIO_FUNC(x) stdio_ ## x
292 #endif
293
PRIMARY_STDIO_FUNC(getchar)294 int PRIMARY_STDIO_FUNC(getchar)(void) {
295 char buf[1];
296 int len = stdio_get_until(buf, 1, at_the_end_of_time);
297 if (len < 0) return len;
298 assert(len == 1);
299 return (uint8_t)buf[0];
300 }
301
PRIMARY_STDIO_FUNC(putchar)302 int PRIMARY_STDIO_FUNC(putchar)(int c) {
303 char cc = (char)c;
304 stdio_put_string(&cc, 1, false, true);
305 return c;
306 }
307
PRIMARY_STDIO_FUNC(puts)308 int PRIMARY_STDIO_FUNC(puts)(const char *s) {
309 int len = (int)strlen(s);
310 stdio_put_string(s, len, true, true);
311 stdio_flush();
312 return len;
313 }
314
315 int REAL_FUNC(vprintf)(const char *format, va_list va);
316
PRIMARY_STDIO_FUNC(vprintf)317 int PRIMARY_STDIO_FUNC(vprintf)(const char *format, va_list va) {
318 bool serialzed = stdout_serialize_begin();
319 if (!serialzed) {
320 #if PICO_STDIO_IGNORE_NESTED_STDOUT
321 return 0;
322 #endif
323 }
324 int ret;
325 #if LIB_PICO_PRINTF_PICO
326 struct stdio_stack_buffer buffer;
327 buffer.used = 0;
328 ret = vfctprintf(stdio_buffered_printer, &buffer, format, va);
329 stdio_stack_buffer_flush(&buffer);
330 stdio_flush();
331 #elif LIB_PICO_PRINTF_NONE
332 ((void)format);
333 ((void)va);
334 extern void printf_none_assert(void);
335 printf_none_assert();
336 ret = 0;
337 #else
338 ret = REAL_FUNC(vprintf)(format, va);
339 #endif
340 if (serialzed) {
341 stdout_serialize_end();
342 }
343 return ret;
344 }
345
PRIMARY_STDIO_FUNC(printf)346 int __printflike(1, 0) PRIMARY_STDIO_FUNC(printf)(const char* format, ...)
347 {
348 va_list va;
349 va_start(va, format);
350 int ret = vprintf(format, va);
351 va_end(va);
352 return ret;
353 }
354
355 #if PICO_STDIO_SHORT_CIRCUIT_CLIB_FUNCS
356 // define the stdio_ versions to be the same as our wrappers
357 int stdio_getchar(void) __attribute__((alias(__XSTRING(WRAPPER_FUNC(getchar)))));
358 int stdio_putchar(int) __attribute__((alias(__XSTRING(WRAPPER_FUNC(putchar)))));
359 int stdio_puts(const char *s) __attribute__((alias(__XSTRING(WRAPPER_FUNC(puts)))));
360 int stdio_vprintf(const char *format, va_list va) __attribute__((alias(__XSTRING(WRAPPER_FUNC(vprintf)))));
361 int __printflike(1, 0) stdio_printf(const char* format, ...) __attribute__((alias(__XSTRING(WRAPPER_FUNC(printf)))));
362 #else
363 // todo there is no easy way to avoid the wrapper functions since they are in the CMake, so lets just forward for now
364
365 int REAL_FUNC(getchar)(void);
366 int REAL_FUNC(putchar)(int);
367 int REAL_FUNC(puts)(const char *s);
368 int __printflike(1, 0) REAL_FUNC(printf)(const char* format, ...);
369
WRAPPER_FUNC(getchar)370 int WRAPPER_FUNC(getchar)(void) {
371 return REAL_FUNC(getchar)();
372 }
WRAPPER_FUNC(putchar)373 int WRAPPER_FUNC(putchar)(int c) {
374 return REAL_FUNC(putchar)(c);
375 }
WRAPPER_FUNC(puts)376 int WRAPPER_FUNC(puts)(const char *s) {
377 return REAL_FUNC(puts)(s);
378 }
WRAPPER_FUNC(vprintf)379 int WRAPPER_FUNC(vprintf)(const char *format, va_list va) {
380 return REAL_FUNC(vprintf)(format, va);
381 }
WRAPPER_FUNC(printf)382 int __printflike(1, 0) WRAPPER_FUNC(printf)(const char* format, ...) {
383 va_list va;
384 va_start(va, format);
385 int ret = REAL_FUNC(vprintf)(format, va);
386 va_end(va);
387 return ret;
388 }
389 #endif
390
391
392