Files
t-embed-insecam-widget/main/board.c
T
Juli 65a391940b insecam desk widget for the LilyGO T-Embed
ESP-IDF 5.5 + LVGL 9 firmware that plays random public cameras from
insecam.org on the T-Embed's 320x170 screen, live MJPEG where available,
a new camera every 20 seconds. Knob steps through cameras, LED ring shows
the countdown. Auto-detects the original vs CC1101 board, reuses Wi-Fi
credentials from NVS and falls back to a captive-portal setup hotspot.
2026-09-17 00:38:09 +02:00

96 lines
3.3 KiB
C

#include "board.h"
#include "sdkconfig.h"
#include "driver/gpio.h"
#include "driver/i2c_master.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
static const char *TAG = "board";
static const board_t tembed = {
.variant = BOARD_TEMBED, .name = "T-Embed",
.pwr_en = 46,
.lcd_mosi = 11, .lcd_miso = -1, .lcd_sclk = 12, .lcd_cs = 10, .lcd_dc = 13, .lcd_rst = 9, .lcd_bl = 15,
.lcd_bgr = false,
.enc_a = 2, .enc_b = 1, .enc_btn = 0, .user_key = -1,
.led_ws2812 = false, .led_clk = 45, .led_data = 42, .led_count = 7,
.i2c_sda = 18, .i2c_scl = 8,
.spi_other_cs = {-1, -1, -1},
};
static const board_t tembed_cc1101 = {
.variant = BOARD_TEMBED_CC1101, .name = "T-Embed CC1101",
.pwr_en = 15,
.lcd_mosi = 9, .lcd_miso = 10, .lcd_sclk = 11, .lcd_cs = 41, .lcd_dc = 16, .lcd_rst = -1, .lcd_bl = 21,
.lcd_bgr = true,
.enc_a = 4, .enc_b = 5, .enc_btn = 0, .user_key = 6,
.led_ws2812 = true, .led_clk = -1, .led_data = 14, .led_count = 8,
.i2c_sda = 8, .i2c_scl = 18,
.spi_other_cs = {13, 12, 44}, // SD, CC1101, nRF24
};
const board_t *board = &tembed;
static void drive_high(int pin)
{
if (pin < 0) return;
gpio_config_t io = {.pin_bit_mask = 1ULL << pin, .mode = GPIO_MODE_OUTPUT};
gpio_config(&io);
gpio_set_level(pin, 1);
}
// Probe a list of 7-bit addresses on a temporary I2C bus; true if any ACKs.
static bool i2c_any_present(int sda, int scl, const uint8_t *addrs, int n)
{
i2c_master_bus_config_t cfg = {
.i2c_port = -1, .sda_io_num = sda, .scl_io_num = scl,
.clk_source = I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true,
};
i2c_master_bus_handle_t bus;
if (i2c_new_master_bus(&cfg, &bus) != ESP_OK) return false;
bool found = false;
for (int i = 0; i < n && !found; i++) {
if (i2c_master_probe(bus, addrs[i], 20) == ESP_OK) {
ESP_LOGI(TAG, "I2C device 0x%02x answered on SDA%d/SCL%d", addrs[i], sda, scl);
found = true;
}
}
i2c_del_master_bus(bus);
return found;
}
static const board_t *detect(void)
{
#if CONFIG_TEMBED_VARIANT_ORIGINAL
return &tembed;
#elif CONFIG_TEMBED_VARIANT_CC1101
return &tembed_cc1101;
#else
// Both boards' power latches are set before probing so the codec is up.
static const uint8_t cc1101_chips[] = {0x55, 0x6b, 0x24}; // BQ27220, BQ25896, PN532
static const uint8_t original_chips[] = {0x40, 0x41, 0x42, 0x43}; // ES7210 (AD1/AD0 straps)
if (i2c_any_present(tembed_cc1101.i2c_sda, tembed_cc1101.i2c_scl, cc1101_chips, sizeof cc1101_chips))
return &tembed_cc1101;
if (i2c_any_present(tembed.i2c_sda, tembed.i2c_scl, original_chips, sizeof original_chips))
return &tembed;
ESP_LOGW(TAG, "no known I2C device found on either pin map; assuming original T-Embed");
return &tembed;
#endif
}
void board_init(void)
{
// Power latches of both variants (GPIO46 original, GPIO15 CC1101). Harmless on the
// other board: GPIO15 is the original's backlight, GPIO46 the CC1101's I2S clock.
drive_high(tembed.pwr_en);
drive_high(tembed_cc1101.pwr_en);
vTaskDelay(pdMS_TO_TICKS(50));
board = detect();
ESP_LOGI(TAG, "board: %s", board->name);
for (int i = 0; i < 3; i++) drive_high(board->spi_other_cs[i]);
}