From 87afe944bc792f8ef6ff03c543970ba6702c6eb8 Mon Sep 17 00:00:00 2001 From: master Date: Sun, 28 Dec 2025 22:36:05 +0000 Subject: [PATCH] WIP: trabalho local antes de acertar SSH --- assoc | 0 auth | 0 cd | 0 git | 0 main/display.c | 366 +++++++++++++++++++++-------------------- main/include/display.h | 3 + main/main.c | 2 +- prof | 0 run | 0 sta | 0 10 files changed, 195 insertions(+), 176 deletions(-) create mode 100644 assoc create mode 100644 auth create mode 100644 cd create mode 100644 git create mode 100644 prof create mode 100644 run create mode 100644 sta diff --git a/assoc b/assoc new file mode 100644 index 0000000..e69de29 diff --git a/auth b/auth new file mode 100644 index 0000000..e69de29 diff --git a/cd b/cd new file mode 100644 index 0000000..e69de29 diff --git a/git b/git new file mode 100644 index 0000000..e69de29 diff --git a/main/display.c b/main/display.c index 95ded5b..30078a9 100644 --- a/main/display.c +++ b/main/display.c @@ -2,26 +2,33 @@ // TOP = 0x71 | BOTTOM = 0x70 // I2C_PORT = I2C_NUM_0 // -// NOTA: agora o código NÃO engole erros de I2C. -// display_init() devolve esp_err_t e podes usar ESP_ERROR_CHECK(display_init()). +// MODO "SAFE": +// - Se I2C não estiver instalado, ou se não existir display, ignora tudo (sem spam) +// - display_init() NUNCA aborta o firmware (devolve ESP_OK e deixa display disabled) #include "driver/i2c.h" #include "esp_log.h" #include "esp_err.h" #include "display.h" #include +#include #define I2C_PORT I2C_NUM_0 // Endereços reais -#define DISP_TOP_ADDR 0x71 // display superior -#define DISP_BOTTOM_ADDR 0x70 // display inferior - -static uint16_t rotate180(uint16_t m); -static uint16_t charset(char c); +#define DISP_TOP_ADDR 0x71 +#define DISP_BOTTOM_ADDR 0x70 static const char *TAG = "DISPLAY"; +// ======================================================= +// FLAG GLOBAL +// ======================================================= +static bool s_display_enabled = false; + +void display_set_enabled(bool en) { s_display_enabled = en; } +bool display_is_enabled(void) { return s_display_enabled; } + // ======================================================= // MAPA DE SEGMENTOS (igual ao teu) // ======================================================= @@ -48,11 +55,20 @@ static const char *TAG = "DISPLAY"; #define SEG_G (SEG_ML | SEG_MR) +static uint16_t charset(char c); // ======================================================= -// FUNÇÕES GENÉRICAS PARA QUALQUER DISPLAY (AGORA COM ERRO) +// FUNÇÕES I2C (internas) // ======================================================= +static inline bool i2c_driver_is_installed(void) +{ + // truque simples: tenta criar um cmd e dar begin "vazio" é overkill. + // Mais seguro: tenta uma escrita curta e ver se dá INVALID_STATE. + // Aqui vamos só confiar na primeira escrita do display_init(). + return true; +} + static esp_err_t disp_send_cmd(uint8_t addr, uint8_t cmd) { return i2c_master_write_to_device(I2C_PORT, addr, &cmd, 1, pdMS_TO_TICKS(50)); @@ -77,13 +93,17 @@ static esp_err_t disp_clear(uint8_t addr) return i2c_master_write_to_device(I2C_PORT, addr, buf, sizeof(buf), pdMS_TO_TICKS(50)); } - // ======================================================= -// INIT PARA OS DOIS DISPLAYS (TOP 0x71 | BOTTOM 0x70) +// INIT (SAFE) // ======================================================= esp_err_t display_init(void) { + // por defeito: desligado + s_display_enabled = false; + + // Se o driver I2C não estiver instalado, a primeira chamada vai dar INVALID_STATE. + // Nós tratamos isso como "não há display nesta board" e seguimos sem logs. const uint8_t cmd1 = 0x21; // oscillator ON const uint8_t cmd2 = 0x81; // display ON, blink OFF const uint8_t cmd3 = 0xEF; // brightness MAX @@ -92,111 +112,207 @@ esp_err_t display_init(void) // TOP err = disp_send_cmd(DISP_TOP_ADDR, cmd1); - if (err != ESP_OK) { ESP_LOGE(TAG, "TOP 0x%02X cmd1 falhou: %s", DISP_TOP_ADDR, esp_err_to_name(err)); return err; } + if (err == ESP_ERR_INVALID_STATE) return ESP_OK; // I2C não instalado -> ignora + if (err != ESP_OK) return ESP_OK; // display ausente/cabos -> ignora err = disp_send_cmd(DISP_TOP_ADDR, cmd2); - if (err != ESP_OK) { ESP_LOGE(TAG, "TOP 0x%02X cmd2 falhou: %s", DISP_TOP_ADDR, esp_err_to_name(err)); return err; } + if (err != ESP_OK) return ESP_OK; err = disp_send_cmd(DISP_TOP_ADDR, cmd3); - if (err != ESP_OK) { ESP_LOGE(TAG, "TOP 0x%02X cmd3 falhou: %s", DISP_TOP_ADDR, esp_err_to_name(err)); return err; } + if (err != ESP_OK) return ESP_OK; err = disp_clear(DISP_TOP_ADDR); - if (err != ESP_OK) { ESP_LOGE(TAG, "TOP 0x%02X clear falhou: %s", DISP_TOP_ADDR, esp_err_to_name(err)); return err; } + if (err != ESP_OK) return ESP_OK; // BOTTOM err = disp_send_cmd(DISP_BOTTOM_ADDR, cmd1); - if (err != ESP_OK) { ESP_LOGE(TAG, "BOTTOM 0x%02X cmd1 falhou: %s", DISP_BOTTOM_ADDR, esp_err_to_name(err)); return err; } + if (err != ESP_OK) return ESP_OK; err = disp_send_cmd(DISP_BOTTOM_ADDR, cmd2); - if (err != ESP_OK) { ESP_LOGE(TAG, "BOTTOM 0x%02X cmd2 falhou: %s", DISP_BOTTOM_ADDR, esp_err_to_name(err)); return err; } + if (err != ESP_OK) return ESP_OK; err = disp_send_cmd(DISP_BOTTOM_ADDR, cmd3); - if (err != ESP_OK) { ESP_LOGE(TAG, "BOTTOM 0x%02X cmd3 falhou: %s", DISP_BOTTOM_ADDR, esp_err_to_name(err)); return err; } + if (err != ESP_OK) return ESP_OK; err = disp_clear(DISP_BOTTOM_ADDR); - if (err != ESP_OK) { ESP_LOGE(TAG, "BOTTOM 0x%02X clear falhou: %s", DISP_BOTTOM_ADDR, esp_err_to_name(err)); return err; } + if (err != ESP_OK) return ESP_OK; + // OK -> ativa display + s_display_enabled = true; ESP_LOGI(TAG, "📟 Displays OK: TOP=0x%02X BOTTOM=0x%02X", DISP_TOP_ADDR, DISP_BOTTOM_ADDR); return ESP_OK; } +// ======================================================= +// RAW / CLEAR (com guard) +// ======================================================= -// ======================================================= -// RAW PARA TOP E BOTTOM -// ======================================================= void display_raw_top(int pos, uint16_t mask) { + if (!s_display_enabled) return; + esp_err_t err = disp_raw(DISP_TOP_ADDR, pos, mask); if (err != ESP_OK) { - ESP_LOGE(TAG, "raw_top falhou (pos=%d addr=0x%02X): %s", pos, DISP_TOP_ADDR, esp_err_to_name(err)); + // se o driver desaparecer a meio, desativa e cala + if (err == ESP_ERR_INVALID_STATE) s_display_enabled = false; + // opcional: não logar para evitar spam + // ESP_LOGE(TAG, "raw_top falhou: %s", esp_err_to_name(err)); } } - void display_raw_bottom(int pos, uint16_t mask) { + if (!s_display_enabled) return; + esp_err_t err = disp_raw(DISP_BOTTOM_ADDR, pos, mask); if (err != ESP_OK) { - ESP_LOGE(TAG, "raw_bottom falhou (pos=%d addr=0x%02X): %s", pos, DISP_BOTTOM_ADDR, esp_err_to_name(err)); + if (err == ESP_ERR_INVALID_STATE) s_display_enabled = false; + // opcional: não logar } } void display_clear_top(void) { + if (!s_display_enabled) return; + esp_err_t err = disp_clear(DISP_TOP_ADDR); - if (err != ESP_OK) ESP_LOGE(TAG, "clear_top falhou: %s", esp_err_to_name(err)); + if (err != ESP_OK) { + if (err == ESP_ERR_INVALID_STATE) s_display_enabled = false; + } } void display_clear_bottom(void) { + if (!s_display_enabled) return; + esp_err_t err = disp_clear(DISP_BOTTOM_ADDR); - if (err != ESP_OK) ESP_LOGE(TAG, "clear_bottom falhou: %s", esp_err_to_name(err)); + if (err != ESP_OK) { + if (err == ESP_ERR_INVALID_STATE) s_display_enabled = false; + } } - -// ===================== -// ROTATE 180 para 14 segmentos REAL -// (mapa correto para o teu HT16K33) -// ===================== -static uint16_t rotate180(uint16_t m) -{ - uint16_t r = 0; - - // A (topo) <-> D (baixo) - if (m & SEG_A) r |= SEG_D; - if (m & SEG_D) r |= SEG_A; - - // B (top-right) <-> E (bottom-left) - if (m & SEG_B) r |= SEG_E; - if (m & SEG_E) r |= SEG_B; - - // C (bottom-right) <-> F (top-left) - if (m & SEG_C) r |= SEG_F; - if (m & SEG_F) r |= SEG_C; - - // Meio vertical ML ↔ MR - if (m & SEG_ML) r |= SEG_MR; - if (m & SEG_MR) r |= SEG_ML; - - // Alfanuméricos topo TL/TM/TR ↔ BL/BM/BR - if (m & SEG_TL) r |= SEG_BL; - if (m & SEG_BL) r |= SEG_TL; - - if (m & SEG_TM) r |= SEG_BM; - if (m & SEG_BM) r |= SEG_TM; - - if (m & SEG_TR) r |= SEG_BR; - if (m & SEG_BR) r |= SEG_TR; - - // DP é DP (ponto) - if (m & SEG_DP) r |= SEG_DP; - - return r; -} - - // ======================================================= -// CHARSET — mantido EXACTAMENTE como o teu +// TEXTO / CHARS +// ======================================================= + +void display_char_top(int pos, char c) +{ + if (!s_display_enabled) return; + display_raw_top(pos, charset(c)); +} + +void display_char_bottom(int pos, char c) +{ + if (!s_display_enabled) return; + display_raw_bottom(pos, charset(c)); +} + +void display_text_top(const char *txt) +{ + if (!s_display_enabled) return; + + for (int i = 0; i < 4; i++) { + char c = (txt && txt[i]) ? txt[i] : ' '; + display_char_top(i, c); + } +} + +void display_text_bottom(const char *txt) +{ + if (!s_display_enabled) return; + + for (int i = 0; i < 4; i++) { + char c = (txt && txt[i]) ? txt[i] : ' '; + display_char_bottom(i, c); + } +} + +// ======================================================= +// NÚMEROS +// ======================================================= + +static const uint16_t digit_mask[10] = +{ + [0] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, + [1] = SEG_B | SEG_C, + [2] = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D, + [3] = SEG_A | SEG_B | SEG_G | SEG_C | SEG_D, + [4] = SEG_F | SEG_G | SEG_B | SEG_C, + [5] = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D, + [6] = SEG_A | SEG_F | SEG_G | SEG_E | SEG_D | SEG_C, + [7] = SEG_A | SEG_B | SEG_C, + [8] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G, + [9] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G, +}; + +void display_digit_top(int pos, uint8_t val) +{ + if (!s_display_enabled) return; + if (val > 9) val = 0; + display_raw_top(pos, digit_mask[val]); +} + +void display_digit_bottom(int pos, uint8_t val) +{ + if (!s_display_enabled) return; + if (val > 9) val = 0; + display_raw_bottom(pos, digit_mask[val]); +} + +void display_number_top(int num) +{ + if (!s_display_enabled) return; + + if (num < 0) num = 0; + if (num > 9999) num = 9999; + + display_digit_top(3, (uint8_t)(num % 10)); + display_digit_top(2, (uint8_t)((num / 10) % 10)); + display_digit_top(1, (uint8_t)((num / 100) % 10)); + display_digit_top(0, (uint8_t)((num / 1000) % 10)); +} + +void display_number_bottom(int num) +{ + if (!s_display_enabled) return; + + if (num < 0) num = 0; + if (num > 9999) num = 9999; + + display_digit_bottom(3, (uint8_t)(num % 10)); + display_digit_bottom(2, (uint8_t)((num / 10) % 10)); + display_digit_bottom(1, (uint8_t)((num / 100) % 10)); + display_digit_bottom(0, (uint8_t)((num / 1000) % 10)); +} + +// ======================================================= +// RELÓGIO (HH:MM com DP no meio) +// ======================================================= + +void display_set_time_top(int horas, int minutos) +{ + if (!s_display_enabled) return; + + if (horas < 0) horas = 0; + if (horas > 99) horas = 99; + if (minutos < 0) minutos = 0; + if (minutos > 59) minutos = 59; + + int h1 = horas / 10; + int h2 = horas % 10; + int m1 = minutos / 10; + int m2 = minutos % 10; + + uint16_t mid = digit_mask[h2] | SEG_DP; + + display_digit_top(0, (uint8_t)h1); + display_raw_top(1, mid); + display_digit_top(2, (uint8_t)m1); + display_digit_top(3, (uint8_t)m2); +} + +// ======================================================= +// CHARSET (igual ao teu) // ======================================================= static uint16_t charset(char c) @@ -215,7 +331,7 @@ static uint16_t charset(char c) case '8': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G; case '9': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G; - // LETRAS COMPLETAS (mantidas) + // LETRAS case 'A': case 'a': return SEG_A | SEG_B | SEG_C | SEG_E | SEG_F | SEG_G; case 'B': case 'b': return SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G; case 'C': case 'c': return SEG_A | SEG_F | SEG_E | SEG_D; @@ -253,110 +369,10 @@ static uint16_t charset(char c) } } - -// ======================================================= -// DISPLAY CARACTER / TEXTO -// ======================================================= - -void display_char_top(int pos, char c) +void display_debug_segment(uint16_t bitmask) { - display_raw_top(pos, charset(c)); -} - -void display_char_bottom(int pos, char c) -{ - display_raw_bottom(pos, charset(c)); -} - -void display_text_top(const char *txt) -{ - for (int i = 0; i < 4; i++) { - char c = (txt && txt[i]) ? txt[i] : ' '; - display_char_top(i, c); - } -} - -void display_text_bottom(const char *txt) -{ - for (int i = 0; i < 4; i++) { - char c = (txt && txt[i]) ? txt[i] : ' '; - display_char_bottom(i, c); - } -} - - -// ======================================================= -// DISPLAY DE NÚMEROS (igual ao teu) -// ======================================================= - -static const uint16_t digit_mask[10] = -{ - [0] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, - [1] = SEG_B | SEG_C, - [2] = SEG_A | SEG_B | SEG_G | SEG_E | SEG_D, - [3] = SEG_A | SEG_B | SEG_G | SEG_C | SEG_D, - [4] = SEG_F | SEG_G | SEG_B | SEG_C, - [5] = SEG_A | SEG_F | SEG_G | SEG_C | SEG_D, - [6] = SEG_A | SEG_F | SEG_G | SEG_E | SEG_D | SEG_C, - [7] = SEG_A | SEG_B | SEG_C, - [8] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F | SEG_G, - [9] = SEG_A | SEG_B | SEG_C | SEG_D | SEG_F | SEG_G, -}; - -void display_digit_top(int pos, uint8_t val) -{ - if (val > 9) val = 0; - display_raw_top(pos, digit_mask[val]); -} - -void display_digit_bottom(int pos, uint8_t val) -{ - if (val > 9) val = 0; - display_raw_bottom(pos, digit_mask[val]); -} - -void display_number_top(int num) -{ - if (num < 0) num = 0; - if (num > 9999) num = 9999; - - display_digit_top(3, num % 10); - display_digit_top(2, (num / 10) % 10); - display_digit_top(1, (num / 100) % 10); - display_digit_top(0, (num / 1000) % 10); -} - -void display_number_bottom(int num) -{ - if (num < 0) num = 0; - if (num > 9999) num = 9999; - - display_digit_bottom(3, num % 10); - display_digit_bottom(2, (num / 10) % 10); - display_digit_bottom(1, (num / 100) % 10); - display_digit_bottom(0, (num / 1000) % 10); -} - - -// ======================================================= -// display_set_time_top() — mantém SEG_DP no sítio certo -// ======================================================= -void display_set_time_top(int horas, int minutos) -{ - if (horas < 0) horas = 0; - if (horas > 99) horas = 99; - if (minutos < 0) minutos = 0; - if (minutos > 59) minutos = 59; - - int h1 = horas / 10; - int h2 = horas % 10; - int m1 = minutos / 10; - int m2 = minutos % 10; - - uint16_t mid = digit_mask[h2] | SEG_DP; - - display_digit_top(0, (uint8_t)h1); - display_raw_top(1, mid); - display_digit_top(2, (uint8_t)m1); - display_digit_top(3, (uint8_t)m2); + (void)bitmask; + // opcional: podes mostrar um padrão fixo se display estiver ativo + // if (!display_is_enabled()) return; + // display_raw_top(0, bitmask); } diff --git a/main/include/display.h b/main/include/display.h index c5d7494..2660a84 100644 --- a/main/include/display.h +++ b/main/include/display.h @@ -1,6 +1,7 @@ #pragma once #include #include "esp_err.h" +#include // ======================================================= // ENDEREÇOS I2C (definidos no .c) @@ -19,6 +20,8 @@ void display_raw_bottom(int pos, uint16_t mask); void display_clear_top(void); void display_clear_bottom(void); +void display_set_enabled(bool en); +bool display_is_enabled(void); // ======================================================= // TEXTO E CARACTERES diff --git a/main/main.c b/main/main.c index 072de09..5a50fd8 100644 --- a/main/main.c +++ b/main/main.c @@ -208,7 +208,7 @@ void app_main(void) { printf("i2c_init falhou: %s\n", esp_err_to_name(ei)); } - // 2) Scan I2C (ver o que existe no barramento) + // 2) Scan I2C (ver o que existe no barramento) i2c_scan(); // 3) Inicializa displays SEM abortar (para não rebootar em loop) diff --git a/prof b/prof new file mode 100644 index 0000000..e69de29 diff --git a/run b/run new file mode 100644 index 0000000..e69de29 diff --git a/sta b/sta new file mode 100644 index 0000000..e69de29