uart: capture RX input in terminal

This commit is contained in:
Zihao Yu 2024-01-09 01:50:32 +08:00
parent d06eb4811e
commit 28190b0c3e
6 changed files with 69 additions and 23 deletions

View File

@ -26,6 +26,8 @@ public:
Term(SDL_Renderer *r, int x, int y, int w, int h);
~Term();
void feed_ch(uint8_t ch);
void feed_str(const char *s);
void clear();
void update_gui();
};

View File

@ -3,14 +3,17 @@
#include <component.h>
#include <term.h>
#include <string>
class UART : public Component{
private:
Term *term;
Term *tx_term, *rx_term;
int state;
uint16_t divisor;
uint8_t data;
bool need_update_gui;
std::string rx_input;
static constexpr const char *rx_input_prompt = "UART TX (Press Enter to issue): ";
bool tx_update_gui, rx_update_gui;
uint8_t *p_tx;
public:
UART(SDL_Renderer *rend, int cnt, int init_val, int ct, int x, int y, int w, int h);
@ -19,7 +22,8 @@ public:
virtual void update_gui();
virtual void update_state();
void check_tx();
void tx_check();
void rx_getchar(uint8_t);
};
#endif

View File

@ -1,8 +1,8 @@
#include <keyboard.h>
#include <pins.h>
#include <string>
extern std::vector<Component *> components;
void uart_rx_getchar(uint8_t ch);
static void mousedown_handler(const SDL_Event &ev) {
int x_pos = ev.button.x;
@ -34,8 +34,6 @@ static void key_handler(uint8_t scancode, int is_keydown){
kb->push_key(scancode, is_keydown);
}
static std::string uart_rx_input = "";
void read_event() {
SDL_Event ev;
SDL_PollEvent(&ev);
@ -48,11 +46,10 @@ void read_event() {
case SDL_MOUSEBUTTONUP: mouseup_handler(ev); break;
case SDL_KEYDOWN:
if (ev.key.keysym.sym == SDLK_RETURN) {
printf("get text = %s\n", uart_rx_input.c_str());
uart_rx_input = "";
uart_rx_getchar('\n');
}
case SDL_KEYUP:
break; //key_handler(ev.key.keysym.scancode, ev.key.type == SDL_KEYDOWN); break;
case SDL_TEXTINPUT: uart_rx_input += ev.text.text; break;
case SDL_TEXTINPUT: uart_rx_getchar(ev.text.text[0]); break;
}
}

View File

@ -25,7 +25,7 @@ void nvboard_update() {
extern UART* uart;
extern int16_t uart_divisor_cnt;
if (unlikely((-- uart_divisor_cnt) < 0)) uart->check_tx();
if (unlikely((-- uart_divisor_cnt) < 0)) uart->tx_check();
static uint64_t last = 0;
static int cpf = 1; // count per frame

View File

@ -30,6 +30,18 @@ void Term::clear_screen() {
SDL_RenderFillRect(renderer, &region);
}
void Term::clear() {
while (lines.size() > 1) {
delete [] lines.back();
lines.pop_back();
}
memset(lines[0], ' ', w_in_char);
cursor_x = cursor_y = screen_y = 0;
clear_screen();
init_dirty(false);
set_redraw();
}
void Term::newline() {
cursor_x = 0;
cursor_y ++;
@ -68,6 +80,10 @@ void Term::feed_ch(uint8_t ch) {
if (cursor_x == w_in_char) newline();
}
void Term::feed_str(const char *s) {
while (*s != '\0') feed_ch(*(s ++));
}
bool Term::is_cursor_on_screen() {
return cursor_y >= screen_y && cursor_y < screen_y + h_in_char;
}

View File

@ -7,25 +7,30 @@
UART* uart = NULL;
int16_t uart_divisor_cnt = 0;
UART::UART(SDL_Renderer *rend, int cnt, int init_val, int ct, int x, int y, int w, int h):
Component(rend, cnt, init_val, ct),
state(0), divisor(16), need_update_gui(false) {
term = new Term(rend, x, y, w, h);
state(0), divisor(16), tx_update_gui(false) {
tx_term = new Term(rend, x, y, w, h);
rx_term = new Term(rend, x, y + h, w, 20);
uart_divisor_cnt = divisor - 1;
int len = pin_array[UART_TX].vector_len;
assert(len == 0 || len == 1); // either unbound or bound to 1 bit signal
p_tx = (uint8_t *)pin_array[UART_TX].ptr;
rx_term->feed_str(rx_input_prompt);
rx_input = "";
rx_update_gui = true;
}
UART::~UART() {
SDL_DestroyTexture(get_texture(0));
}
void UART::update_gui() {
term->update_gui();
void UART::update_gui() { // everything is done in update_state()
}
void UART::check_tx() {
void UART::tx_check() {
uart_divisor_cnt = divisor - 1;
uint8_t tx = *p_tx;
@ -38,24 +43,42 @@ void UART::check_tx() {
data = (tx << 7) | (data >> 1); // data bit
state ++;
} else if (state == 9) {
if (tx) {
term->feed_ch(data);
if (tx) { // stop bit
state = 0;
need_update_gui = true;
} // stop bit
tx_term->feed_ch(data);
tx_update_gui = true;
}
}
}
void UART::rx_getchar(uint8_t ch) {
if (ch == '\n') {
printf("Get RX input = %s\n", rx_input.c_str());
rx_term->clear();
rx_term->feed_str(rx_input_prompt);
rx_input = "";
}
else {
rx_input += ch;
rx_term->feed_ch(ch);
}
rx_update_gui = true;
}
void UART::update_state() {
if (need_update_gui) {
if (tx_update_gui) {
static uint64_t last = 0;
uint64_t now = nvboard_get_time();
if (now - last > 1000000 / UART_TX_FPS) {
last = now;
need_update_gui = false;
update_gui();
tx_update_gui = false;
tx_term->update_gui();
}
}
if (rx_update_gui) {
rx_update_gui = false;
rx_term->update_gui();
}
}
void UART::set_divisor(uint16_t d) {
@ -66,9 +89,13 @@ void init_uart(SDL_Renderer *renderer) {
int x = WINDOW_WIDTH / 2, y = 0, w = WINDOW_WIDTH / 2, h = WINDOW_HEIGHT / 2;
uart = new UART(renderer, 1, 0, UART_TYPE, x, y, w, h);
SDL_Rect *rect_ptr = new SDL_Rect;
*rect_ptr = (SDL_Rect){x, y, w, h};
*rect_ptr = (SDL_Rect){x, y + h, w, 10};
uart->set_rect(rect_ptr, 0);
uart->add_pin(UART_TX);
uart->add_pin(UART_RX);
add_component(uart);
}
void uart_rx_getchar(uint8_t ch) {
uart->rx_getchar(ch);
}