template struct queue { std::array data; volatile std::size_t put_idx; volatile std::size_t get_idx; async_flag put_flag; async_flag get_flag; constexpr std::size_t _inc(std::size_t n) { return n + 1 < N ? n + 1 : 0; } bool empty() { return put_idx == get_idx; } bool full() { return _inc(put_idx) == get_idx; } bool put(T v) { if(full()) { return false; } data[put_idx] = v; put_idx = _inc(put_idx); put_flag.set(); return true; } bool get(T& v) { if(empty()) { return false; } v = data[get_idx]; get_idx = _inc(get_idx); get_flag.set(); return true; } async<> async_put(T v) { while(!put(v)) { co_await get_flag; } } async async_get() { T v; while(!get(v)) { co_await put_flag; } co_return v; } }; queue uart1_rx; queue uart1_tx; template <> void interrupt::handler() { if(USART1.reg.SR & (1 << 5)) { // RXNE char c = USART1.reg.DR; //printf("USART1 ISR RX: %c\n", c); uart1_rx.put(c); } if(USART1.reg.SR & (1 << 7)) { // TXE char c; if(uart1_tx.get(c)) { USART1.reg.DR = c; } else { USART1.reg.CR1 &= ~(1 << 7); // TXEIE } } } struct shell_io_t { async getchar() { return uart1_rx.async_get(); } async<> putchar(char c) { co_await uart1_tx.async_put(c); USART1.reg.CR1 |= 1 << 7; // TXEIE } async<> print(std::string_view s) { for(auto c : s) { co_await putchar(c); } } template async<> print(T... args) { auto s = std::format(args...); co_await print(std::string_view(s)); } }; task shell_task(shell_io_t& io, std::span cmds) { std::array buf; std::size_t idx = 0; while(1) { char c = co_await io.getchar(); if(c >= 0x20) { if(idx >= buf.size()) { continue; } buf[idx++] = c; co_await io.putchar(c); } if(c == '\r') { if(!idx) { continue; } co_await io.putchar('\n'); auto [name, args] = split_first(std::string_view(buf.data(), idx)); bool found = false; for(auto cmd : cmds) { if(name != cmd.name) { continue; } co_await cmd.cmd(io); found = true; break; } if(!found) { buf[name.size()] = 0; co_await io.print("No such command: {}\n", name); } idx = 0; } } } shell_cmd shell_cmds[] = { { "foo", [](auto io) -> async<> { co_await io.print("Hello world!\n"); }, }, };