From a7362dc14bca1233eb34b41aefebe9cfb22684ac Mon Sep 17 00:00:00 2001 From: "info@mode42.com" Date: Fri, 7 Aug 2026 18:09:58 +0000 Subject: Initial push --- firmware/s1224/src/common/display.c | 187 ++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 firmware/s1224/src/common/display.c (limited to 'firmware/s1224/src/common/display.c') diff --git a/firmware/s1224/src/common/display.c b/firmware/s1224/src/common/display.c new file mode 100644 index 0000000..e2875be --- /dev/null +++ b/firmware/s1224/src/common/display.c @@ -0,0 +1,187 @@ +/* + * HD44780 LCD via PCF8574 I2C backpack + USB mirror. + * SPDX-License-Identifier: GPL-3.0-or-later + */ +#include "display.h" +#include "board_pins.h" +#include "config.h" +#include "status.h" +#include "sense.h" +#include "ptt.h" +#include "hardware/i2c.h" +#include "pico/stdlib.h" +#include +#include +#include + +/* PCF8574 bit map (common backpack): P0=RS P1=RW P2=E P3=BL P4-7=D4-D7 */ +#define LCD_RS 0x01 +#define LCD_RW 0x02 +#define LCD_EN 0x04 +#define LCD_BL 0x08 + +static bool g_lcd; +static uint8_t g_addr = I2C_LCD_ADDR_DEFAULT; +static char g_last_l0[17]; +static char g_last_l1[17]; + +static bool i2c_write_u8(uint8_t addr, uint8_t v) +{ + return i2c_write_blocking(i2c0, addr, &v, 1, false) >= 0; +} + +static bool i2c_probe(uint8_t addr) +{ + uint8_t b = 0; + return i2c_write_blocking(i2c0, addr, &b, 1, false) >= 0; +} + +static void lcd_write4(uint8_t nibble, uint8_t mode) +{ + uint8_t data = (uint8_t)((nibble & 0xF0) | LCD_BL | mode); + i2c_write_u8(g_addr, (uint8_t)(data | LCD_EN)); + sleep_us(1); + i2c_write_u8(g_addr, (uint8_t)(data & (uint8_t)~LCD_EN)); + sleep_us(50); +} + +static void lcd_send(uint8_t value, uint8_t mode) +{ + lcd_write4((uint8_t)(value & 0xF0), mode); + lcd_write4((uint8_t)((value << 4) & 0xF0), mode); +} + +static void lcd_cmd(uint8_t c) +{ + lcd_send(c, 0); +} + +static void lcd_data(uint8_t c) +{ + lcd_send(c, LCD_RS); +} + +static void lcd_set_cursor(uint8_t col, uint8_t row) +{ + static const uint8_t row_addr[] = {0x00, 0x40, 0x14, 0x54}; + if (row > 1) { + row = 1; + } + lcd_cmd((uint8_t)(0x80 | (row_addr[row] + col))); +} + +static void lcd_print_line(uint8_t row, const char *s) +{ + char buf[17]; + size_t n = strlen(s); + if (n > 16) { + n = 16; + } + memset(buf, ' ', 16); + memcpy(buf, s, n); + buf[16] = '\0'; + lcd_set_cursor(0, row); + for (int i = 0; i < 16; i++) { + lcd_data((uint8_t)buf[i]); + } +} + +static bool lcd_init_seq(uint8_t addr) +{ + g_addr = addr; + sleep_ms(50); + lcd_write4(0x30, 0); + sleep_ms(5); + lcd_write4(0x30, 0); + sleep_us(150); + lcd_write4(0x30, 0); + sleep_us(150); + lcd_write4(0x20, 0); /* 4-bit */ + lcd_cmd(0x28); /* 2 line, 5x8 */ + lcd_cmd(0x0C); /* display on, cursor off */ + lcd_cmd(0x06); /* entry mode */ + lcd_cmd(0x01); /* clear */ + sleep_ms(2); + return true; +} + +void display_init(void) +{ + g_lcd = false; + g_last_l0[0] = '\0'; + g_last_l1[0] = '\0'; + + uint8_t addrs[] = {0x27, 0x3F}; + for (unsigned i = 0; i < sizeof(addrs); i++) { + if (i2c_probe(addrs[i])) { + if (lcd_init_seq(addrs[i])) { + g_lcd = true; + if (config_unsolicited_ok()) { + printf("LCD: HD44780 @ 0x%02X\r\n", addrs[i]); + } + return; + } + } + } + if (config_unsolicited_ok()) { + printf("LCD: none — USB status only\r\n"); + } +} + +bool display_present(void) +{ + return g_lcd; +} + +void display_show(const char *line) +{ + if (!line) { + return; + } + if (g_lcd) { + lcd_print_line(0, line); + } +} + +void display_update(void) +{ + const s1224_config_t *cfg = config_get(); + char l0[17]; + char l1[17]; + + s1224_state_t st = status_get(); + if (st == S1224_STATE_FAULT) { + snprintf(l0, sizeof(l0), "%.16s", cfg->fault); + } else if (ptt_get()) { + snprintf(l0, sizeof(l0), "%.16s", cfg->sending); + } else if (st == S1224_STATE_STARTING) { + snprintf(l0, sizeof(l0), "%.16s", cfg->starting); + } else { + /* Power/ready on line 0 */ + snprintf(l0, sizeof(l0), "%.16s", cfg->ready); + } + + /* Line 1: Signal + Packet from sense */ + bool sig = sense_signal_active(); + bool pkt = sense_packet_active(); + if (sig && pkt) { + snprintf(l1, sizeof(l1), "%.7s %.7s", cfg->signal, cfg->packet); + } else if (sig) { + snprintf(l1, sizeof(l1), "%.16s", cfg->signal); + } else if (pkt) { + snprintf(l1, sizeof(l1), "%.16s", cfg->packet); + } else { + snprintf(l1, sizeof(l1), "%.16s", cfg->power); + } + + if (strcmp(l0, g_last_l0) != 0 || strcmp(l1, g_last_l1) != 0) { + strncpy(g_last_l0, l0, sizeof(g_last_l0)); + strncpy(g_last_l1, l1, sizeof(g_last_l1)); + g_last_l0[16] = '\0'; + g_last_l1[16] = '\0'; + if (g_lcd) { + lcd_print_line(0, l0); + lcd_print_line(1, l1); + } + } +} -- cgit v1.3.1