xref: /aosp_15_r20/external/pigweed/pw_sys_io_rp2040/sys_io.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2022 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_sys_io/sys_io.h"
16 
17 #include <stdio.h>
18 
19 #include <cinttypes>
20 
21 #include "pico/stdlib.h"
22 #include "pw_status/status.h"
23 #include "pw_sync/thread_notification.h"
24 
25 namespace {
26 
27 pw::sync::ThreadNotification chars_available_signal;
28 
chars_available_callback(void * arg)29 void chars_available_callback([[maybe_unused]] void* arg) {
30   chars_available_signal.release();
31 }
32 
LazyInitSysIo()33 void LazyInitSysIo() {
34   static bool initialized = false;
35   if (!initialized) {
36     stdio_init_all();
37     stdio_set_chars_available_callback(chars_available_callback, nullptr);
38     initialized = true;
39   }
40 }
41 
42 }  // namespace
43 
44 // This whole implementation is very inefficient because it only reads / writes
45 // 1 byte at a time. It also does lazy initialization checks with every byte.
46 namespace pw::sys_io {
47 
ReadByte(std::byte * dest)48 Status ReadByte(std::byte* dest) {
49   LazyInitSysIo();
50 
51   while (true) {
52     int c = getchar_timeout_us(0);
53     if (c != PICO_ERROR_TIMEOUT) {
54       *dest = static_cast<std::byte>(c);
55       return OkStatus();
56     }
57 
58     // Wait for signal from the chars_available_callback().
59     chars_available_signal.acquire();
60   }
61 }
62 
TryReadByte(std::byte * dest)63 Status TryReadByte(std::byte* dest) {
64   LazyInitSysIo();
65   int c = getchar_timeout_us(0);
66   if (c == PICO_ERROR_TIMEOUT) {
67     return Status::DeadlineExceeded();
68   }
69   *dest = static_cast<std::byte>(c);
70   return OkStatus();
71 }
72 
WriteByte(std::byte b)73 Status WriteByte(std::byte b) {
74   // The return value of this is just the character sent.
75   LazyInitSysIo();
76   putchar_raw(static_cast<int>(b));
77   return OkStatus();
78 }
79 
80 // Writes a string using pw::sys_io, and add newline characters at the end.
WriteLine(std::string_view s)81 StatusWithSize WriteLine(std::string_view s) {
82   size_t chars_written = 0;
83   StatusWithSize result = WriteBytes(as_bytes(span(s)));
84   if (!result.ok()) {
85     return result;
86   }
87   chars_written += result.size();
88 
89   // Write trailing newline.
90   result = WriteBytes(as_bytes(span("\r\n", 2)));
91   chars_written += result.size();
92 
93   return StatusWithSize(OkStatus(), chars_written);
94 }
95 
96 }  // namespace pw::sys_io
97