Compare commits
2
Commits
f47299b939
...
ce9af6382e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce9af6382e | ||
|
|
d21f7ad4e4 |
@@ -1,4 +1,4 @@
|
||||
idf_component_register(SRCS "app_ui.c"
|
||||
idf_component_register(SRCS "app_ui.c" "app_ui_color.c"
|
||||
INCLUDE_DIRS "include" "."
|
||||
REQUIRES ui_cmd app_machine app_process
|
||||
PRIV_REQUIRES hal_display)
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include "app_process.h"
|
||||
#include "hal_display.h"
|
||||
|
||||
void app_ui_draw_color_chrome(machine_state_t st);
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -192,6 +194,7 @@ void app_ui_draw(void)
|
||||
draw_program_select();
|
||||
break;
|
||||
}
|
||||
app_ui_draw_color_chrome(st);
|
||||
hal_display_flush();
|
||||
s_dirty = false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
#include "app_ui.h"
|
||||
#include "app_machine.h"
|
||||
#include "hal_display.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
bool app_ui_touch_to_key(int x, int y, char *out_key)
|
||||
{
|
||||
if (out_key == NULL) {
|
||||
return false;
|
||||
}
|
||||
machine_state_t st = app_machine_state();
|
||||
const int w = HAL_DISPLAY_PX_W;
|
||||
const int h = HAL_DISPLAY_PX_H;
|
||||
const int sk = HAL_DISPLAY_SOFTKEY_H;
|
||||
|
||||
if (x < 0 || y < 0 || x >= w || y >= h) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (st == ST_RUNNING || st == ST_COMPLETE) {
|
||||
if (y >= h - sk) {
|
||||
*out_key = 'X';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (st == ST_STOPPED) {
|
||||
if (y >= h - sk) {
|
||||
*out_key = (x < w / 2) ? 'E' : 'X';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (st == ST_IDLE) {
|
||||
/* 2x3 process grid matching ProgramSelect labels. */
|
||||
int col = (x < w / 2) ? 0 : 1;
|
||||
int row = y / (h / 3);
|
||||
if (row > 2) {
|
||||
row = 2;
|
||||
}
|
||||
/* left: 1,2,3 right: 4,5,6 */
|
||||
int id = row + col * 3;
|
||||
*out_key = (char)('1' + id);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (st == ST_ARMED) {
|
||||
if (y >= h - sk) {
|
||||
*out_key = (x < w / 2) ? 'E' : 'X';
|
||||
return true;
|
||||
}
|
||||
*out_key = 'E';
|
||||
return true;
|
||||
}
|
||||
|
||||
/* STEP_SELECT: strips for U/D/L/R, body Ent */
|
||||
if (y < 40) {
|
||||
*out_key = 'U';
|
||||
return true;
|
||||
}
|
||||
if (y >= h - sk) {
|
||||
*out_key = 'D';
|
||||
return true;
|
||||
}
|
||||
if (x < 80) {
|
||||
*out_key = 'L';
|
||||
return true;
|
||||
}
|
||||
if (x >= w - 80) {
|
||||
*out_key = 'R';
|
||||
return true;
|
||||
}
|
||||
*out_key = 'E';
|
||||
return true;
|
||||
}
|
||||
|
||||
void app_ui_draw_color_chrome(machine_state_t st)
|
||||
{
|
||||
switch (st) {
|
||||
case ST_RUNNING:
|
||||
case ST_COMPLETE:
|
||||
hal_display_softkey(0, 1, "STOP");
|
||||
break;
|
||||
case ST_STOPPED:
|
||||
hal_display_softkey(0, 2, "RESUME");
|
||||
hal_display_softkey(1, 2, "BACK");
|
||||
break;
|
||||
case ST_ARMED:
|
||||
hal_display_softkey(0, 2, "START");
|
||||
hal_display_softkey(1, 2, "QUIT");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,9 @@ void app_ui_on_event(const ui_evt_t *ev);
|
||||
void app_ui_draw(void);
|
||||
bool app_ui_is_dirty(void);
|
||||
|
||||
/* Map colour-panel touch to the same raw keys as the WROOM keypad. */
|
||||
bool app_ui_touch_to_key(int x, int y, char *out_key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
#include "board.h"
|
||||
|
||||
/*
|
||||
* JC4827W543C pin lock (community 480x272 NV3041A + GT911).
|
||||
*
|
||||
* Display NV3041A QSPI:
|
||||
* CS 45
|
||||
* SCK 47
|
||||
* D0 21
|
||||
* D1 48
|
||||
* D2 40
|
||||
* D3 39
|
||||
* BL 1
|
||||
*
|
||||
* GT911 I2C:
|
||||
* SDA 8
|
||||
* SCL 4
|
||||
* INT 3
|
||||
* RST 38
|
||||
* addr 0x5D
|
||||
*
|
||||
* Motor:
|
||||
* EN GPIO_NUM_NC — no spare header pin documented for EN.
|
||||
* STEP/DIR not assigned. Do not steal QSPI or GT911 pins.
|
||||
* Agitation may remain on WROOM until a spare is proven.
|
||||
*/
|
||||
|
||||
const char *board_name(void)
|
||||
{
|
||||
return "jc4827w543";
|
||||
@@ -14,3 +39,16 @@ int board_motor_en_disable_level(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
gpio_num_t board_pin_lcd_cs(void) { return (gpio_num_t)45; }
|
||||
gpio_num_t board_pin_lcd_sck(void) { return (gpio_num_t)47; }
|
||||
gpio_num_t board_pin_lcd_d0(void) { return (gpio_num_t)21; }
|
||||
gpio_num_t board_pin_lcd_d1(void) { return (gpio_num_t)48; }
|
||||
gpio_num_t board_pin_lcd_d2(void) { return (gpio_num_t)40; }
|
||||
gpio_num_t board_pin_lcd_d3(void) { return (gpio_num_t)39; }
|
||||
gpio_num_t board_pin_lcd_bl(void) { return (gpio_num_t)1; }
|
||||
|
||||
gpio_num_t board_pin_tp_sda(void) { return (gpio_num_t)8; }
|
||||
gpio_num_t board_pin_tp_scl(void) { return (gpio_num_t)4; }
|
||||
gpio_num_t board_pin_tp_int(void) { return (gpio_num_t)3; }
|
||||
gpio_num_t board_pin_tp_rst(void) { return (gpio_num_t)38; }
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
#pragma once
|
||||
#include "driver/gpio.h"
|
||||
|
||||
const char *board_name(void);
|
||||
gpio_num_t board_pin_motor_en(void);
|
||||
int board_motor_en_disable_level(void);
|
||||
|
||||
gpio_num_t board_pin_lcd_cs(void);
|
||||
gpio_num_t board_pin_lcd_sck(void);
|
||||
gpio_num_t board_pin_lcd_d0(void);
|
||||
gpio_num_t board_pin_lcd_d1(void);
|
||||
gpio_num_t board_pin_lcd_d2(void);
|
||||
gpio_num_t board_pin_lcd_d3(void);
|
||||
gpio_num_t board_pin_lcd_bl(void);
|
||||
|
||||
gpio_num_t board_pin_tp_sda(void);
|
||||
gpio_num_t board_pin_tp_scl(void);
|
||||
gpio_num_t board_pin_tp_int(void);
|
||||
gpio_num_t board_pin_tp_rst(void);
|
||||
|
||||
@@ -11,6 +11,9 @@ if(IDF_TARGET STREQUAL "esp32")
|
||||
${CMAKE_CURRENT_LIST_DIR}/../third_party/LiquidCrystal_I2C/include
|
||||
)
|
||||
list(APPEND priv_req board_wroom espressif__arduino-esp32)
|
||||
elseif(IDF_TARGET STREQUAL "esp32s3")
|
||||
list(APPEND srcs hal_display_nv3041a.c)
|
||||
list(APPEND priv_req board_jc4827w543 esp_lcd)
|
||||
else()
|
||||
list(APPEND srcs stub/hal_display.c)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
/* Public-domain 5x7 glyphs for ASCII 32..126. */
|
||||
static const uint8_t font5x7[95][7] = {
|
||||
{0,0,0,0,0,0,0},
|
||||
{0x04,0x04,0x04,0x04,0x04,0x00,0x04},
|
||||
{0x0A,0x0A,0x0A,0,0,0,0},
|
||||
{0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A},
|
||||
{0x04,0x0F,0x14,0x0E,0x05,0x1E,0x04},
|
||||
{0x18,0x19,0x02,0x04,0x08,0x13,0x03},
|
||||
{0x08,0x14,0x14,0x08,0x15,0x12,0x0D},
|
||||
{0x04,0x04,0x08,0,0,0,0},
|
||||
{0x02,0x04,0x08,0x08,0x08,0x04,0x02},
|
||||
{0x08,0x04,0x02,0x02,0x02,0x04,0x08},
|
||||
{0x00,0x04,0x15,0x0E,0x15,0x04,0x00},
|
||||
{0x00,0x04,0x04,0x1F,0x04,0x04,0x00},
|
||||
{0,0,0,0,0,0x04,0x08},
|
||||
{0,0,0,0x1F,0,0,0},
|
||||
{0,0,0,0,0,0,0x04},
|
||||
{0x01,0x02,0x04,0x08,0x10,0,0},
|
||||
{0x0E,0x11,0x13,0x15,0x19,0x11,0x0E},
|
||||
{0x04,0x0C,0x04,0x04,0x04,0x04,0x0E},
|
||||
{0x0E,0x11,0x01,0x02,0x04,0x08,0x1F},
|
||||
{0x1F,0x02,0x04,0x02,0x01,0x11,0x0E},
|
||||
{0x02,0x06,0x0A,0x12,0x1F,0x02,0x02},
|
||||
{0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E},
|
||||
{0x06,0x08,0x10,0x1E,0x11,0x11,0x0E},
|
||||
{0x1F,0x01,0x02,0x04,0x08,0x08,0x08},
|
||||
{0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E},
|
||||
{0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C},
|
||||
{0,0x04,0,0,0x04,0,0},
|
||||
{0,0x04,0,0,0x04,0x04,0x08},
|
||||
{0x02,0x04,0x08,0x10,0x08,0x04,0x02},
|
||||
{0,0,0x1F,0,0x1F,0,0},
|
||||
{0x08,0x04,0x02,0x01,0x02,0x04,0x08},
|
||||
{0x0E,0x11,0x01,0x02,0x04,0x00,0x04},
|
||||
{0x0E,0x11,0x17,0x15,0x17,0x10,0x0E},
|
||||
{0x0E,0x11,0x11,0x1F,0x11,0x11,0x11},
|
||||
{0x1E,0x11,0x11,0x1E,0x11,0x11,0x1E},
|
||||
{0x0E,0x11,0x10,0x10,0x10,0x11,0x0E},
|
||||
{0x1C,0x12,0x11,0x11,0x11,0x12,0x1C},
|
||||
{0x1F,0x10,0x10,0x1E,0x10,0x10,0x1F},
|
||||
{0x1F,0x10,0x10,0x1E,0x10,0x10,0x10},
|
||||
{0x0E,0x11,0x10,0x17,0x11,0x11,0x0F},
|
||||
{0x11,0x11,0x11,0x1F,0x11,0x11,0x11},
|
||||
{0x0E,0x04,0x04,0x04,0x04,0x04,0x0E},
|
||||
{0x07,0x02,0x02,0x02,0x02,0x12,0x0C},
|
||||
{0x11,0x12,0x14,0x18,0x14,0x12,0x11},
|
||||
{0x10,0x10,0x10,0x10,0x10,0x10,0x1F},
|
||||
{0x11,0x1B,0x15,0x15,0x11,0x11,0x11},
|
||||
{0x11,0x19,0x15,0x13,0x11,0x11,0x11},
|
||||
{0x0E,0x11,0x11,0x11,0x11,0x11,0x0E},
|
||||
{0x1E,0x11,0x11,0x1E,0x10,0x10,0x10},
|
||||
{0x0E,0x11,0x11,0x11,0x15,0x12,0x0D},
|
||||
{0x1E,0x11,0x11,0x1E,0x14,0x12,0x11},
|
||||
{0x0F,0x10,0x10,0x0E,0x01,0x01,0x1E},
|
||||
{0x1F,0x04,0x04,0x04,0x04,0x04,0x04},
|
||||
{0x11,0x11,0x11,0x11,0x11,0x11,0x0E},
|
||||
{0x11,0x11,0x11,0x11,0x11,0x0A,0x04},
|
||||
{0x11,0x11,0x11,0x15,0x15,0x1B,0x11},
|
||||
{0x11,0x11,0x0A,0x04,0x0A,0x11,0x11},
|
||||
{0x11,0x11,0x0A,0x04,0x04,0x04,0x04},
|
||||
{0x1F,0x01,0x02,0x04,0x08,0x10,0x1F},
|
||||
{0x0E,0x08,0x08,0x08,0x08,0x08,0x0E},
|
||||
{0x10,0x08,0x04,0x02,0x01,0,0},
|
||||
{0x0E,0x02,0x02,0x02,0x02,0x02,0x0E},
|
||||
{0x04,0x0A,0x11,0,0,0,0},
|
||||
{0,0,0,0,0,0,0x1F},
|
||||
{0x08,0x04,0x02,0,0,0,0},
|
||||
{0,0,0x0E,0x01,0x0F,0x11,0x0F},
|
||||
{0x10,0x10,0x1E,0x11,0x11,0x11,0x1E},
|
||||
{0,0,0x0E,0x10,0x10,0x11,0x0E},
|
||||
{0x01,0x01,0x0F,0x11,0x11,0x11,0x0F},
|
||||
{0,0,0x0E,0x11,0x1F,0x10,0x0E},
|
||||
{0x06,0x08,0x08,0x1E,0x08,0x08,0x08},
|
||||
{0,0,0x0F,0x11,0x11,0x0F,0x01,},
|
||||
{0x10,0x10,0x1E,0x11,0x11,0x11,0x11},
|
||||
{0x04,0,0x0C,0x04,0x04,0x04,0x0E},
|
||||
{0x02,0,0x06,0x02,0x02,0x02,0x12},
|
||||
{0x10,0x10,0x12,0x14,0x18,0x14,0x12},
|
||||
{0x0C,0x04,0x04,0x04,0x04,0x04,0x0E},
|
||||
{0,0,0x1A,0x15,0x15,0x15,0x15},
|
||||
{0,0,0x1E,0x11,0x11,0x11,0x11},
|
||||
{0,0,0x0E,0x11,0x11,0x11,0x0E},
|
||||
{0,0,0x1E,0x11,0x11,0x1E,0x10},
|
||||
{0,0,0x0F,0x11,0x11,0x0F,0x01},
|
||||
{0,0,0x16,0x19,0x10,0x10,0x10},
|
||||
{0,0,0x0F,0x10,0x0E,0x01,0x1E},
|
||||
{0x08,0x08,0x1E,0x08,0x08,0x08,0x06},
|
||||
{0,0,0x11,0x11,0x11,0x11,0x0F},
|
||||
{0,0,0x11,0x11,0x11,0x0A,0x04},
|
||||
{0,0,0x11,0x15,0x15,0x15,0x0A},
|
||||
{0,0,0x11,0x0A,0x04,0x0A,0x11},
|
||||
{0,0,0x11,0x11,0x0F,0x01,0x0E},
|
||||
{0,0,0x1F,0x02,0x04,0x08,0x1F},
|
||||
{0x02,0x04,0x04,0x08,0x04,0x04,0x02},
|
||||
{0x04,0x04,0x04,0x04,0x04,0x04,0x04},
|
||||
{0x08,0x04,0x04,0x02,0x04,0x04,0x08},
|
||||
{0x00,0x00,0x08,0x15,0x02,0x00,0x00},
|
||||
};
|
||||
@@ -89,3 +89,10 @@ extern "C" void hal_display_glyph_thermo(int col, int row)
|
||||
extern "C" void hal_display_flush(void)
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void hal_display_softkey(int slot, int slots, const char *label)
|
||||
{
|
||||
(void)slot;
|
||||
(void)slots;
|
||||
(void)label;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
#include "hal_display.h"
|
||||
#include "font5x7.h"
|
||||
#include "board.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_lcd_panel_io.h"
|
||||
#include "esp_lcd_panel_commands.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#define LCD_HOST SPI2_HOST
|
||||
#define LCD_H HAL_DISPLAY_PX_H
|
||||
#define LCD_W HAL_DISPLAY_PX_W
|
||||
|
||||
#define COL_BG 0x18E3
|
||||
#define COL_FG 0xFFFF
|
||||
#define COL_ACC 0xF800
|
||||
#define COL_BTN 0x39E7
|
||||
#define COL_BTNT 0xFFFF
|
||||
|
||||
static const char *TAG = "disp-s3";
|
||||
|
||||
static esp_lcd_panel_io_handle_t s_io;
|
||||
static uint16_t *s_fb;
|
||||
static bool s_inited;
|
||||
static bool s_dirty;
|
||||
|
||||
static uint16_t swap565(uint16_t c)
|
||||
{
|
||||
return (uint16_t)((c >> 8) | (c << 8));
|
||||
}
|
||||
|
||||
static void fb_fill(uint16_t color)
|
||||
{
|
||||
if (s_fb == NULL) {
|
||||
return;
|
||||
}
|
||||
uint16_t c = swap565(color);
|
||||
for (int i = 0; i < LCD_W * LCD_H; i++) {
|
||||
s_fb[i] = c;
|
||||
}
|
||||
s_dirty = true;
|
||||
}
|
||||
|
||||
static void fb_pixel(int x, int y, uint16_t color)
|
||||
{
|
||||
if (s_fb == NULL || x < 0 || y < 0 || x >= LCD_W || y >= LCD_H) {
|
||||
return;
|
||||
}
|
||||
s_fb[y * LCD_W + x] = swap565(color);
|
||||
}
|
||||
|
||||
static void fb_fill_rect(int x, int y, int w, int h, uint16_t color)
|
||||
{
|
||||
if (s_fb == NULL) {
|
||||
return;
|
||||
}
|
||||
if (x < 0) {
|
||||
w += x;
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0) {
|
||||
h += y;
|
||||
y = 0;
|
||||
}
|
||||
if (x + w > LCD_W) {
|
||||
w = LCD_W - x;
|
||||
}
|
||||
if (y + h > LCD_H) {
|
||||
h = LCD_H - y;
|
||||
}
|
||||
uint16_t c = swap565(color);
|
||||
for (int yy = 0; yy < h; yy++) {
|
||||
uint16_t *row = &s_fb[(y + yy) * LCD_W + x];
|
||||
for (int xx = 0; xx < w; xx++) {
|
||||
row[xx] = c;
|
||||
}
|
||||
}
|
||||
s_dirty = true;
|
||||
}
|
||||
|
||||
static void fb_char(int x, int y, char ch, uint16_t fg, int scale)
|
||||
{
|
||||
if (ch < 32 || ch > 126) {
|
||||
ch = '?';
|
||||
}
|
||||
const uint8_t *g = font5x7[ch - 32];
|
||||
for (int row = 0; row < 7; row++) {
|
||||
uint8_t bits = g[row];
|
||||
for (int col = 0; col < 5; col++) {
|
||||
if (bits & (0x10 >> col)) {
|
||||
fb_fill_rect(x + col * scale, y + row * scale, scale, scale, fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fb_str(int x, int y, const char *s, uint16_t fg, int scale)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return;
|
||||
}
|
||||
int cx = x;
|
||||
while (*s) {
|
||||
fb_char(cx, y, *s, fg, scale);
|
||||
cx += 6 * scale;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
static void lcd_cmd(uint8_t cmd, const uint8_t *data, size_t len)
|
||||
{
|
||||
if (s_io == NULL) {
|
||||
return;
|
||||
}
|
||||
uint32_t packed = ((uint32_t)0x02 << 24) | ((uint32_t)cmd << 8);
|
||||
esp_lcd_panel_io_tx_param(s_io, packed, data, len);
|
||||
}
|
||||
|
||||
static void lcd_window(int x0, int y0, int x1, int y1)
|
||||
{
|
||||
uint8_t cas[4] = { (uint8_t)(x0 >> 8), (uint8_t)x0, (uint8_t)(x1 >> 8), (uint8_t)x1 };
|
||||
uint8_t ras[4] = { (uint8_t)(y0 >> 8), (uint8_t)y0, (uint8_t)(y1 >> 8), (uint8_t)y1 };
|
||||
lcd_cmd(LCD_CMD_CASET, cas, 4);
|
||||
lcd_cmd(LCD_CMD_RASET, ras, 4);
|
||||
}
|
||||
|
||||
static void lcd_init_panel(void)
|
||||
{
|
||||
/* Vendor bring-up for NV3041A-01 480x272. Commands are public datasheet/community. */
|
||||
static const uint8_t seq[][3] = {
|
||||
{0xFF, 0xA5, 1},
|
||||
{0x36, 0x00, 1},
|
||||
{0x3A, 0x01, 1},
|
||||
{0x41, 0x03, 1},
|
||||
{0x44, 0x15, 1},
|
||||
{0x45, 0x15, 1},
|
||||
{0x7D, 0x03, 1},
|
||||
{0xC1, 0xBB, 1},
|
||||
{0xC2, 0x05, 1},
|
||||
{0xC3, 0x10, 1},
|
||||
{0xC6, 0x3E, 1},
|
||||
{0xC7, 0x25, 1},
|
||||
{0xC8, 0x11, 1},
|
||||
{0xC9, 0x20, 1},
|
||||
{0x7A, 0x51, 1},
|
||||
{0x6F, 0x2D, 1},
|
||||
{0x78, 0x4B, 1},
|
||||
{0x70, 0x07, 1},
|
||||
{0x71, 0x05, 1},
|
||||
};
|
||||
lcd_cmd(LCD_CMD_SWRESET, NULL, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
lcd_cmd(LCD_CMD_SLPOUT, NULL, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(120));
|
||||
for (size_t i = 0; i < sizeof(seq) / sizeof(seq[0]); i++) {
|
||||
uint8_t d = seq[i][1];
|
||||
lcd_cmd(seq[i][0], &d, seq[i][2]);
|
||||
}
|
||||
lcd_cmd(LCD_CMD_DISPON, NULL, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
}
|
||||
|
||||
void hal_display_init(void)
|
||||
{
|
||||
if (s_inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpio_config_t bl = {
|
||||
.pin_bit_mask = 1ULL << board_pin_lcd_bl(),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
gpio_config(&bl);
|
||||
gpio_set_level(board_pin_lcd_bl(), 1);
|
||||
|
||||
spi_bus_config_t buscfg = {
|
||||
.sclk_io_num = board_pin_lcd_sck(),
|
||||
.data0_io_num = board_pin_lcd_d0(),
|
||||
.data1_io_num = board_pin_lcd_d1(),
|
||||
.data2_io_num = board_pin_lcd_d2(),
|
||||
.data3_io_num = board_pin_lcd_d3(),
|
||||
.max_transfer_sz = LCD_W * 40 * sizeof(uint16_t),
|
||||
};
|
||||
esp_err_t err = spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "spi_bus_initialize %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
esp_lcd_panel_io_spi_config_t io_config = {
|
||||
.cs_gpio_num = board_pin_lcd_cs(),
|
||||
.dc_gpio_num = -1,
|
||||
.spi_mode = 0,
|
||||
.pclk_hz = 40 * 1000 * 1000,
|
||||
.trans_queue_depth = 4,
|
||||
.lcd_cmd_bits = 32,
|
||||
.lcd_param_bits = 8,
|
||||
.flags = {
|
||||
.quad_mode = 1,
|
||||
},
|
||||
};
|
||||
err = esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)LCD_HOST, &io_config, &s_io);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "panel_io %s", esp_err_to_name(err));
|
||||
s_io = NULL;
|
||||
} else {
|
||||
lcd_init_panel();
|
||||
}
|
||||
|
||||
s_fb = heap_caps_malloc((size_t)LCD_W * LCD_H * sizeof(uint16_t),
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (s_fb == NULL) {
|
||||
s_fb = heap_caps_malloc((size_t)LCD_W * LCD_H * sizeof(uint16_t), MALLOC_CAP_8BIT);
|
||||
}
|
||||
if (s_fb == NULL) {
|
||||
ESP_LOGE(TAG, "no framebuffer");
|
||||
}
|
||||
fb_fill(COL_BG);
|
||||
s_inited = true;
|
||||
ESP_LOGI(TAG, "NV3041A QSPI %dx%d CS=%d SCK=%d D0=%d",
|
||||
LCD_W, LCD_H, (int)board_pin_lcd_cs(), (int)board_pin_lcd_sck(),
|
||||
(int)board_pin_lcd_d0());
|
||||
}
|
||||
|
||||
void hal_display_clear(void)
|
||||
{
|
||||
fb_fill(COL_BG);
|
||||
}
|
||||
|
||||
void hal_display_text(int col, int row, const char *s)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return;
|
||||
}
|
||||
if (col < 0) {
|
||||
col = 0;
|
||||
}
|
||||
if (row < 0 || row >= HAL_DISPLAY_ROWS) {
|
||||
return;
|
||||
}
|
||||
int x = col * HAL_DISPLAY_CELL_W + 4;
|
||||
int y = 8 + row * HAL_DISPLAY_CELL_H;
|
||||
/* clip 20 columns */
|
||||
char buf[HAL_DISPLAY_COLS + 1];
|
||||
int n = 0;
|
||||
while (s[n] && n < HAL_DISPLAY_COLS - col && n < HAL_DISPLAY_COLS) {
|
||||
buf[n] = s[n];
|
||||
n++;
|
||||
}
|
||||
buf[n] = 0;
|
||||
fb_fill_rect(x, y, n * HAL_DISPLAY_CELL_W, HAL_DISPLAY_CELL_H - 4, COL_BG);
|
||||
fb_str(x, y + 6, buf, COL_FG, 3);
|
||||
}
|
||||
|
||||
void hal_display_glyph_thermo(int col, int row)
|
||||
{
|
||||
int x = col * HAL_DISPLAY_CELL_W + 8;
|
||||
int y = 8 + row * HAL_DISPLAY_CELL_H + 4;
|
||||
fb_fill_rect(x + 6, y, 6, 14, COL_ACC);
|
||||
fb_fill_rect(x + 3, y + 14, 12, 10, COL_ACC);
|
||||
}
|
||||
|
||||
void hal_display_softkey(int slot, int slots, const char *label)
|
||||
{
|
||||
if (slots < 1) {
|
||||
slots = 1;
|
||||
}
|
||||
if (slot < 0 || slot >= slots) {
|
||||
return;
|
||||
}
|
||||
int w = LCD_W / slots;
|
||||
int x = slot * w + 4;
|
||||
int y = LCD_H - HAL_DISPLAY_SOFTKEY_H + 4;
|
||||
int bw = w - 8;
|
||||
int bh = HAL_DISPLAY_SOFTKEY_H - 8;
|
||||
fb_fill_rect(x, y, bw, bh, COL_BTN);
|
||||
if (label != NULL) {
|
||||
int scale = 3;
|
||||
int tw = (int)strlen(label) * 6 * scale;
|
||||
int tx = x + (bw - tw) / 2;
|
||||
int ty = y + (bh - 7 * scale) / 2;
|
||||
if (tx < x) {
|
||||
tx = x + 4;
|
||||
}
|
||||
fb_str(tx, ty, label, COL_BTNT, scale);
|
||||
}
|
||||
}
|
||||
|
||||
void hal_display_flush(void)
|
||||
{
|
||||
if (!s_dirty || s_fb == NULL || s_io == NULL) {
|
||||
s_dirty = false;
|
||||
return;
|
||||
}
|
||||
lcd_window(0, 0, LCD_W - 1, LCD_H - 1);
|
||||
const int chunk_rows = 16;
|
||||
for (int y = 0; y < LCD_H; y += chunk_rows) {
|
||||
int rows = chunk_rows;
|
||||
if (y + rows > LCD_H) {
|
||||
rows = LCD_H - y;
|
||||
}
|
||||
uint32_t packed = ((uint32_t)0x32 << 24) | ((uint32_t)LCD_CMD_RAMWR << 8);
|
||||
esp_lcd_panel_io_tx_color(s_io, packed, &s_fb[y * LCD_W],
|
||||
(size_t)rows * LCD_W * sizeof(uint16_t));
|
||||
}
|
||||
s_dirty = false;
|
||||
}
|
||||
@@ -4,11 +4,24 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HAL_DISPLAY_COLS 20
|
||||
#define HAL_DISPLAY_ROWS 4
|
||||
|
||||
/* Colour panel geometry (S3). 2004 ignores pixel APIs. */
|
||||
#define HAL_DISPLAY_PX_W 480
|
||||
#define HAL_DISPLAY_PX_H 272
|
||||
#define HAL_DISPLAY_CELL_W 24
|
||||
#define HAL_DISPLAY_CELL_H 32
|
||||
#define HAL_DISPLAY_SOFTKEY_H 48
|
||||
|
||||
void hal_display_init(void);
|
||||
void hal_display_clear(void);
|
||||
void hal_display_text(int col, int row, const char *s); /* clip to 20 cols */
|
||||
void hal_display_glyph_thermo(int col, int row);
|
||||
void hal_display_flush(void); /* no-op on 2004 */
|
||||
void hal_display_flush(void);
|
||||
|
||||
/* Softkey chrome; no-op on 2004. slot in [0, slots). */
|
||||
void hal_display_softkey(int slot, int slots, const char *label);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -14,3 +14,10 @@ void hal_display_glyph_thermo(int col, int row)
|
||||
(void)row;
|
||||
}
|
||||
void hal_display_flush(void) {}
|
||||
|
||||
void hal_display_softkey(int slot, int slots, const char *label)
|
||||
{
|
||||
(void)slot;
|
||||
(void)slots;
|
||||
(void)label;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ if(IDF_TARGET STREQUAL "esp32")
|
||||
${CMAKE_CURRENT_LIST_DIR}/../third_party/Keypad/include
|
||||
)
|
||||
list(APPEND priv_req board_wroom espressif__arduino-esp32)
|
||||
elseif(IDF_TARGET STREQUAL "esp32s3")
|
||||
list(APPEND srcs hal_input_gt911.c)
|
||||
list(APPEND priv_req board_jc4827w543)
|
||||
else()
|
||||
list(APPEND srcs stub/hal_input.c)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
#include "hal_input.h"
|
||||
#include <string.h>
|
||||
#include "board.h"
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#define TP_I2C I2C_NUM_0
|
||||
#define TP_ADDR 0x5D
|
||||
#define GT_REG_STAT 0x814E
|
||||
#define GT_REG_PT0 0x8150
|
||||
|
||||
static const char *TAG = "gt911";
|
||||
|
||||
static bool s_have;
|
||||
static ui_raw_touch_t s_last;
|
||||
static uint8_t s_prev_stat;
|
||||
|
||||
static esp_err_t tp_write(uint16_t reg, const uint8_t *data, size_t n)
|
||||
{
|
||||
uint8_t buf[8];
|
||||
if (n + 2 > sizeof(buf)) {
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
buf[0] = (uint8_t)(reg >> 8);
|
||||
buf[1] = (uint8_t)reg;
|
||||
if (n && data) {
|
||||
memcpy(buf + 2, data, n);
|
||||
}
|
||||
return i2c_master_write_to_device(TP_I2C, TP_ADDR, buf, n + 2, pdMS_TO_TICKS(50));
|
||||
}
|
||||
|
||||
static esp_err_t tp_read(uint16_t reg, uint8_t *data, size_t n)
|
||||
{
|
||||
uint8_t addr[2] = { (uint8_t)(reg >> 8), (uint8_t)reg };
|
||||
return i2c_master_write_read_device(TP_I2C, TP_ADDR, addr, 2, data, n, pdMS_TO_TICKS(50));
|
||||
}
|
||||
|
||||
void hal_input_init(void)
|
||||
{
|
||||
gpio_config_t io = {
|
||||
.pin_bit_mask = (1ULL << board_pin_tp_rst()) | (1ULL << board_pin_tp_int()),
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
};
|
||||
gpio_config(&io);
|
||||
gpio_set_level(board_pin_tp_int(), 0);
|
||||
gpio_set_level(board_pin_tp_rst(), 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
gpio_set_level(board_pin_tp_rst(), 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
io.mode = GPIO_MODE_INPUT;
|
||||
io.pin_bit_mask = 1ULL << board_pin_tp_int();
|
||||
gpio_config(&io);
|
||||
|
||||
i2c_config_t conf = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = board_pin_tp_sda(),
|
||||
.scl_io_num = board_pin_tp_scl(),
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = 400000,
|
||||
};
|
||||
i2c_param_config(TP_I2C, &conf);
|
||||
i2c_driver_install(TP_I2C, conf.mode, 0, 0, 0);
|
||||
ESP_LOGI(TAG, "GT911 addr=0x5D SDA=%d SCL=%d RST=%d INT=%d",
|
||||
(int)board_pin_tp_sda(), (int)board_pin_tp_scl(),
|
||||
(int)board_pin_tp_rst(), (int)board_pin_tp_int());
|
||||
}
|
||||
|
||||
bool hal_input_pop_key(ui_raw_key_t *out)
|
||||
{
|
||||
(void)out;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hal_input_pop_touch(ui_raw_touch_t *out)
|
||||
{
|
||||
uint8_t stat = 0;
|
||||
if (tp_read(GT_REG_STAT, &stat, 1) != ESP_OK) {
|
||||
return false;
|
||||
}
|
||||
if ((stat & 0x80) == 0) {
|
||||
return false;
|
||||
}
|
||||
uint8_t n = stat & 0x0F;
|
||||
uint8_t raw[8];
|
||||
if (n > 0 && tp_read(GT_REG_PT0, raw, 8) == ESP_OK) {
|
||||
int16_t x = (int16_t)(raw[0] | ((uint16_t)raw[1] << 8));
|
||||
int16_t y = (int16_t)(raw[2] | ((uint16_t)raw[3] << 8));
|
||||
uint8_t zero = 0;
|
||||
tp_write(GT_REG_STAT, &zero, 1);
|
||||
/* Edge: report once per contact start. */
|
||||
if (s_prev_stat == 0) {
|
||||
s_last.x = x;
|
||||
s_last.y = y;
|
||||
s_prev_stat = n;
|
||||
if (out) {
|
||||
*out = s_last;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
s_prev_stat = n;
|
||||
return false;
|
||||
}
|
||||
uint8_t zero = 0;
|
||||
tp_write(GT_REG_STAT, &zero, 1);
|
||||
s_prev_stat = 0;
|
||||
(void)s_have;
|
||||
return false;
|
||||
}
|
||||
@@ -42,3 +42,9 @@ extern "C" bool hal_input_pop_key(ui_raw_key_t *out)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool hal_input_pop_touch(ui_raw_touch_t *out)
|
||||
{
|
||||
(void)out;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -10,8 +11,14 @@ typedef struct {
|
||||
char key;
|
||||
} ui_raw_key_t;
|
||||
|
||||
typedef struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} ui_raw_touch_t;
|
||||
|
||||
void hal_input_init(void);
|
||||
bool hal_input_pop_key(ui_raw_key_t *out); /* nonblocking */
|
||||
bool hal_input_pop_touch(ui_raw_touch_t *out); /* nonblocking; S3 only */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -7,3 +7,9 @@ bool hal_input_pop_key(ui_raw_key_t *out)
|
||||
(void)out;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hal_input_pop_touch(ui_raw_touch_t *out)
|
||||
{
|
||||
(void)out;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ If blocked: stop, commit nothing broken, write `BLOCKED:` at top of the phase fi
|
||||
| P04 | `refactor/P04-gitea-ci.md` | `.gitea/workflows/ci.yml` live | DONE |
|
||||
| P05 | `refactor/P05-hal-wroom-motion.md` | WROOM motor/temp/audio HAL | DONE |
|
||||
| P06 | `refactor/P06-ui-wroom-cutover.md` | 2004 UI + keypad + Stop/Resume cutover | DONE |
|
||||
| P07 | `refactor/P07-board-s3-ui.md` | JC4827W543 display+GT911+STOP | BLOCKED |
|
||||
| P07 | `refactor/P07-board-s3-ui.md` | JC4827W543 display+GT911+STOP | DONE |
|
||||
| P08 | `refactor/P08-idf-debt.md` | Replace Arduino drivers (RMT etc.) | TODO |
|
||||
|
||||
P04 Notes: merge_bin uses `${{ gitea.sha }}` (not `github.sha`); runner unverified (no Actions run).
|
||||
@@ -48,7 +48,7 @@ P05 Notes: Arduino-esp32 ~3.2.1 (3.1.x requires IDF <5.4) + IDF v5.4; AccelStepp
|
||||
|
||||
P06 Notes: WROOM input_task dual-path stop (hal_motor_request_stop then CMD_STOP). Legacy startingMenu unlinked from IDF. Notes=`hw smoke pending`.
|
||||
|
||||
P07 Notes: BLOCKED — S3 display+GT911+STOP not started this session. P06 landed; P07 not implemented. Hw unflashed.
|
||||
P07 Notes: custom NV3041A QSPI + GT911; shared app_ui text grid + colour softkeys; EN=NC. idf.py not run here (no IDF_PATH). host ctest green. Hw unflashed.
|
||||
|
||||
## Dependency
|
||||
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
# P07 — JC4827W543 display + GT911 + STOP
|
||||
|
||||
STATUS: BLOCKED
|
||||
STATUS: DONE
|
||||
DEPENDS: P06
|
||||
|
||||
BLOCKED: P06 `app_ui` + WROOM cutover missing on `refactor/esp-idf-modular-ui` @ `0b1d14d`.
|
||||
|
||||
Required and absent:
|
||||
- `components/app_ui` (five-screen contract P07 must colour-adapt)
|
||||
- `components/hal_display` / `hal_display_text` cell grid
|
||||
- `components/hal_input`
|
||||
- WROOM 2004 + keypad Stop/Resume cutover (`ui_task` / `input_task`)
|
||||
|
||||
P06 STATUS remains BLOCKED. Protocol: P07 requires P06 screen contract.
|
||||
Do not implement P01–P06 in this session. No NV3041A/GT911 HAL, colour adapter, or STOP hit-test landed.
|
||||
VERIFY not run (nothing to build for this phase). Hw smoke: unflashed.
|
||||
Custom-draw NV3041A + GT911 colour adapter for the five P06 screens.
|
||||
Touch STOP = `hal_motor_request_stop()` then CMD_STOP via the same key map as Esc.
|
||||
Motor EN remains GPIO_NUM_NC (no spare header pin documented). No STEP/DIR.
|
||||
No LVGL. Hw smoke: unflashed.
|
||||
|
||||
READ: this file, `docs/TARGET_ARCHITECTURE.md` dual-board + UI strategy, vendor pin notes below
|
||||
OUT: LVGL in `app_machine`; changing recipes; assigning WROOM STEP/DIR onto S3 without a pin table comment; pumps
|
||||
@@ -65,7 +58,7 @@ Hardware S3: ProgramSelect visible, tap process, Running shows name/remaining/te
|
||||
|
||||
## DoD
|
||||
|
||||
- [ ] Same commands as keypad
|
||||
- [ ] No lv types in machine/process/cmd headers
|
||||
- [ ] WROOM firmware unchanged in behaviour
|
||||
- [ ] STATUS→DONE
|
||||
- [x] Same commands as keypad
|
||||
- [x] No lv types in machine/process/cmd headers
|
||||
- [x] WROOM firmware unchanged in behaviour
|
||||
- [x] STATUS→DONE
|
||||
|
||||
@@ -16,6 +16,8 @@ idf_component_register(SRCS "main.c"
|
||||
|
||||
if(IDF_TARGET STREQUAL "esp32")
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE AUTOFILM_BOARD_WROOM=1)
|
||||
elseif(IDF_TARGET STREQUAL "esp32s3")
|
||||
target_compile_definitions(${COMPONENT_LIB} PRIVATE AUTOFILM_BOARD_S3=1)
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
|
||||
+11
-2
@@ -29,7 +29,7 @@
|
||||
|
||||
static const char *TAG = "app";
|
||||
|
||||
#ifdef AUTOFILM_BOARD_WROOM
|
||||
#if defined(AUTOFILM_BOARD_WROOM) || defined(AUTOFILM_BOARD_S3)
|
||||
static QueueHandle_t s_cmdq;
|
||||
|
||||
extern void autofilm_temp_tick(void);
|
||||
@@ -110,6 +110,13 @@ static void input_task(void *arg)
|
||||
while (hal_input_pop_key(&raw)) {
|
||||
map_and_post_key(raw.key);
|
||||
}
|
||||
ui_raw_touch_t touch;
|
||||
while (hal_input_pop_touch(&touch)) {
|
||||
char key;
|
||||
if (app_ui_touch_to_key(touch.x, touch.y, &key)) {
|
||||
map_and_post_key(key);
|
||||
}
|
||||
}
|
||||
esp_task_wdt_reset();
|
||||
vTaskDelay(period);
|
||||
}
|
||||
@@ -165,7 +172,9 @@ static void temp_task(void *arg)
|
||||
(void)arg;
|
||||
esp_task_wdt_add(NULL);
|
||||
for (;;) {
|
||||
#ifdef AUTOFILM_BOARD_WROOM
|
||||
autofilm_temp_tick();
|
||||
#endif
|
||||
float c = 0.0f;
|
||||
bool ok = (hal_temp_read_c(&c) == ESP_OK);
|
||||
app_machine_on_temp(ok ? c : 0.0f, ok);
|
||||
@@ -201,7 +210,7 @@ void app_main(void)
|
||||
hal_audio_init();
|
||||
app_machine_init();
|
||||
|
||||
#ifdef AUTOFILM_BOARD_WROOM
|
||||
#if defined(AUTOFILM_BOARD_WROOM) || defined(AUTOFILM_BOARD_S3)
|
||||
hal_display_init();
|
||||
hal_input_init();
|
||||
app_ui_init();
|
||||
|
||||
Reference in New Issue
Block a user