temphummon/firmware/main/bitprobe.c
temphummon dev b5cf59b39a Complete icon map: Bluetooth (f13 bit3) and battery (f13 bit4) with °C composition
- probed f[13] on blank panel: bit3=Bluetooth, bit4=battery icon,
  0x05=°C, 0x06=°F, bits5-7 unused
- combos verified live: 0x0D (°C+BT), 0x15 (°C+bat), 0x1D (°C+BT+bat)
- add ICON_* constants to temphummon.c; restore as active build
- update PROJECT_MEMORY.md with complete f[13] icon table
2026-09-24 17:56:39 +00:00

218 lines
6.7 KiB
C

/**
* iconfinder2 — ESP32-H2 Zero + 1.9" Segment E-Paper (IST7134 via I²C)
*
* Hunt the BLUETOOTH and BATTERY icons specifically.
* Per user: they are at the "3rd and 4th position on the 13th bit" —
* i.e. frame byte 13 (the °C/°F byte), bits 3 and 4.
*
* We probe byte 13 bits 0..7 one at a time on a BLANK panel so any icon is
* unmistakable. (We already know: bit0+bit2 = °C letter; bit1 = black
* control, so it's guarded.)
*
* Wiring (GPIO4→SDA, GPIO5→SCL, GPIO10→RST, GPIO11→BUSY, 3V3→VCC, GND→GND)
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2c_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_timer.h"
#define PIN_SDA GPIO_NUM_4
#define PIN_SCL GPIO_NUM_5
#define PIN_RST GPIO_NUM_10
#define PIN_BUSY GPIO_NUM_11
#define PIN_BOOT GPIO_NUM_9
#define FRAME_LEN 15
#define ADVANCE_MODE 1
#define AUTO_HOLD_MS 3000
#define BOOT_TIMEOUT_MS 0
static i2c_master_bus_handle_t bus;
static i2c_master_dev_handle_t cmd_dev, dat_dev;
static void epd_reset(void)
{
gpio_set_level(PIN_RST, 1); vTaskDelay(pdMS_TO_TICKS(200));
gpio_set_level(PIN_RST, 0); vTaskDelay(pdMS_TO_TICKS(20));
gpio_set_level(PIN_RST, 1); vTaskDelay(pdMS_TO_TICKS(200));
}
static void epd_wait_busy(void)
{
while (gpio_get_level(PIN_BUSY) == 0) vTaskDelay(pdMS_TO_TICKS(1));
vTaskDelay(pdMS_TO_TICKS(10));
}
static void epd_lut_GC(void)
{
uint8_t lut[] = {0x82, 0x20, 0x00, 0xA0, 0x80, 0x40, 0x63};
i2c_master_transmit(cmd_dev, lut, sizeof(lut), pdMS_TO_TICKS(100));
}
static void epd_lut_DU_WB(void)
{
uint8_t lut[] = {0x82, 0x80, 0x00, 0xC0, 0x80, 0x80, 0x62};
i2c_master_transmit(cmd_dev, lut, sizeof(lut), pdMS_TO_TICKS(100));
}
static void epd_temperature(void)
{
uint8_t a[] = {0x7E, 0x81, 0xB4};
i2c_master_transmit(cmd_dev, a, sizeof(a), pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(10));
uint8_t b[] = {0xE7, 0x0E};
i2c_master_transmit(cmd_dev, b, sizeof(b), pdMS_TO_TICKS(100));
}
static void epd_init(void)
{
epd_reset();
vTaskDelay(pdMS_TO_TICKS(100));
uint8_t p[] = {0x2B, 0xA7, 0xE0};
i2c_master_transmit(cmd_dev, p, sizeof(p), pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(10));
epd_temperature();
}
static void epd_write(const uint8_t *frame, uint8_t extra_byte)
{
uint8_t w[] = {0xAC, 0x2B, 0x40, 0xA9, 0xA8};
i2c_master_transmit(cmd_dev, w, sizeof(w), pdMS_TO_TICKS(100));
i2c_master_transmit(dat_dev, frame, FRAME_LEN, pdMS_TO_TICKS(100));
i2c_master_transmit(dat_dev, &extra_byte, 1, pdMS_TO_TICKS(100));
uint8_t d[] = {0xAB, 0xAA, 0xAF};
i2c_master_transmit(cmd_dev, d, sizeof(d), pdMS_TO_TICKS(100));
epd_wait_busy();
uint8_t s[] = {0xAE, 0x28, 0xAD};
i2c_master_transmit(cmd_dev, s, sizeof(s), pdMS_TO_TICKS(100));
}
/* Show byte13 with ONLY the given bit set (blank elsewhere). */
static void show_b13(uint8_t value, int tag, const char *note)
{
uint8_t f[FRAME_LEN];
memset(f, 0, FRAME_LEN);
f[13] = value;
ESP_LOGI("icon2", "T%d: f[13]=0x%02x (%s)", tag, value, note);
uint8_t off[FRAME_LEN];
memset(off, 0, FRAME_LEN);
epd_lut_GC();
epd_write(off, 0x00);
epd_lut_DU_WB();
epd_write(f, 0x00);
}
static void boot_init(void)
{
gpio_config_t bc = {
.pin_bit_mask = (1ULL << PIN_BOOT), .mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&bc);
}
static void wait_for_advance(void)
{
if (ADVANCE_MODE == 0) { vTaskDelay(pdMS_TO_TICKS(AUTO_HOLD_MS)); return; }
ESP_LOGI("icon2", "press BOOT to advance next...");
int64_t t_start = esp_timer_get_time();
for (;;) {
if (gpio_get_level(PIN_BOOT) == 0) {
vTaskDelay(pdMS_TO_TICKS(30));
while (gpio_get_level(PIN_BOOT) == 0) vTaskDelay(pdMS_TO_TICKS(10));
vTaskDelay(pdMS_TO_TICKS(30));
break;
}
if (BOOT_TIMEOUT_MS > 0 &&
esp_timer_get_time() - t_start > BOOT_TIMEOUT_MS * 1000LL) {
ESP_LOGW("icon2", "no BOOT press in %d ms", BOOT_TIMEOUT_MS);
break;
}
vTaskDelay(pdMS_TO_TICKS(20));
}
}
void app_main(void)
{
i2c_master_bus_config_t bc = {
.i2c_port = -1, .sda_io_num = PIN_SDA, .scl_io_num = PIN_SCL,
.clk_source = I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = 1,
};
ESP_ERROR_CHECK(i2c_new_master_bus(&bc, &bus));
i2c_device_config_t cc = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = 0x3C, .scl_speed_hz = 100000,
};
i2c_device_config_t dc = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = 0x3D, .scl_speed_hz = 100000,
};
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus, &cc, &cmd_dev));
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus, &dc, &dat_dev));
gpio_config_t rc = {
.pin_bit_mask = (1ULL << PIN_RST), .mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&rc); gpio_set_level(PIN_RST, 1);
gpio_config_t busy_cfg = {
.pin_bit_mask = (1ULL << PIN_BUSY), .mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_DISABLE, .pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&busy_cfg);
boot_init();
epd_init();
ESP_LOGI("icon2", "== Probe f[13] bits for Bluetooth (3) & power (4) icons ==");
/* Single bits of byte 13 (skip bit1 = known black control). */
show_b13(0x01, 1, "bit0 (C stroke)");
wait_for_advance();
show_b13(0x02, 2, "bit1 (SKIPPED-guard, black ctrl)");
wait_for_advance(); // just wait, we already know it blackens
show_b13(0x04, 3, "bit2 (C stroke)");
wait_for_advance();
show_b13(0x08, 4, "bit3 = BLUETOOTH?");
wait_for_advance();
show_b13(0x10, 5, "bit4 = POWER/BATTERY?");
wait_for_advance();
show_b13(0x20, 6, "bit5");
wait_for_advance();
show_b13(0x40, 7, "bit6");
wait_for_advance();
show_b13(0x80, 8, "bit7");
wait_for_advance();
/* Combo reference: full °C (0x05) and, if icons exist, try adding them. */
show_b13(0x05, 9, "0x05 = °C full");
wait_for_advance();
show_b13(0x05 | 0x08, 10, "0x0D = °C + BT?");
wait_for_advance();
show_b13(0x05 | 0x10, 11, "0x15 = °C + bat?");
wait_for_advance();
show_b13(0x05 | 0x08 | 0x10, 12, "0x1D = °C + BT + bat?");
wait_for_advance();
ESP_LOGI("icon2", "== Done. ==");
uint8_t off[FRAME_LEN];
memset(off, 0, FRAME_LEN);
epd_lut_DU_WB();
epd_write(off, 0x00);
while (1) vTaskDelay(pdMS_TO_TICKS(1000));
}