1 // Copyright 2020 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 <cinttypes>
18
19 #include "am_bsp.h"
20 #include "am_mcu_apollo.h"
21 #include "pw_preprocessor/compiler.h"
22
23 namespace {
24 void* hal_uart_handle{};
25 } // namespace
26
pw_sys_io_Init()27 PW_EXTERN_C void pw_sys_io_Init() {
28 // Use baud rate of 115200 (8N1).
29 static constexpr am_hal_uart_config_t kUartConfig = {
30 .ui32BaudRate = 115200,
31 .eDataBits = AM_HAL_UART_DATA_BITS_8,
32 .eParity = AM_HAL_UART_PARITY_NONE,
33 .eStopBits = AM_HAL_UART_ONE_STOP_BIT,
34 .eFlowControl = AM_HAL_UART_FLOW_CTRL_NONE,
35 .eTXFifoLevel = AM_HAL_UART_FIFO_LEVEL_16,
36 .eRXFifoLevel = AM_HAL_UART_FIFO_LEVEL_16,
37 };
38
39 // Initialize the UART peripheral.
40 am_hal_uart_initialize(AM_BSP_UART_PRINT_INST, &hal_uart_handle);
41
42 // Change the power state of the UART peripheral.
43 am_hal_uart_power_control(hal_uart_handle, AM_HAL_SYSCTRL_WAKE, false);
44
45 // Configure UART (baudrate etc.).
46 am_hal_uart_configure(hal_uart_handle, &kUartConfig);
47
48 // Enable the UART TX and RX GPIO's.
49 am_hal_gpio_pinconfig(AM_BSP_GPIO_COM_UART_TX, g_AM_BSP_GPIO_COM_UART_TX);
50 am_hal_gpio_pinconfig(AM_BSP_GPIO_COM_UART_RX, g_AM_BSP_GPIO_COM_UART_RX);
51 }
52
53 namespace pw::sys_io {
54
55 // Wait for a byte to read on UART0. This blocks until a byte is read. This is
56 // extremely inefficient as it requires the target to burn CPU cycles polling to
57 // see if a byte is ready yet.
ReadByte(std::byte * dest)58 Status ReadByte(std::byte* dest) {
59 while (true) {
60 if (TryReadByte(dest).ok()) {
61 return OkStatus();
62 }
63 }
64 }
65
TryReadByte(std::byte * dest)66 Status TryReadByte(std::byte* dest) {
67 am_hal_uart_transfer_t transaction{};
68 uint32_t bytes_read{};
69
70 // Configure UART transaction for the read operation.
71 transaction.eType = AM_HAL_UART_BLOCKING_READ;
72 transaction.pui8Data = reinterpret_cast<uint8_t*>(dest);
73 transaction.ui32NumBytes = 1;
74 transaction.ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER;
75 transaction.pui32BytesTransferred = &bytes_read;
76
77 // Do read data over UART.
78 if (am_hal_uart_transfer(hal_uart_handle, &transaction) !=
79 AM_HAL_STATUS_SUCCESS) {
80 return Status::ResourceExhausted();
81 }
82
83 if (bytes_read != 1u) {
84 return Status::DataLoss();
85 }
86
87 return OkStatus();
88 }
89
WriteByte(std::byte b)90 Status WriteByte(std::byte b) {
91 am_hal_uart_transfer_t transaction{};
92 uint32_t chars_written{};
93
94 // Configure UART transaction for the write operation.
95 transaction.eType = AM_HAL_UART_BLOCKING_WRITE;
96 transaction.pui8Data =
97 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(&b));
98 transaction.ui32NumBytes = 1;
99 transaction.ui32TimeoutMs = AM_HAL_UART_WAIT_FOREVER;
100 transaction.pui32BytesTransferred = &chars_written;
101
102 // Do write data over UART.
103 if (am_hal_uart_transfer(hal_uart_handle, &transaction) !=
104 AM_HAL_STATUS_SUCCESS) {
105 return Status::ResourceExhausted();
106 }
107
108 if (chars_written != 1) {
109 return Status::DataLoss();
110 }
111
112 return OkStatus();
113 }
114
115 // Writes a string using pw::sys_io, and add newline characters at the end.
WriteLine(std::string_view s)116 StatusWithSize WriteLine(std::string_view s) {
117 StatusWithSize result = WriteBytes(as_bytes(span(s)));
118 if (!result.ok()) {
119 return result;
120 }
121
122 size_t chars_written = result.size();
123 if (chars_written != s.size()) {
124 return StatusWithSize::DataLoss(chars_written);
125 }
126
127 // Write trailing newline.
128 result = WriteBytes(as_bytes(span("\r\n", 2)));
129 chars_written += result.size();
130
131 if (result.size() != 2) {
132 return StatusWithSize::DataLoss(chars_written);
133 }
134
135 return StatusWithSize(chars_written);
136 }
137
138 } // namespace pw::sys_io
139