Replaces the build-flag-driven #ifdef sprawl (~30 blocks across 6 files)
with a small HAL in firmware/src/hal/ and per-board folders under
firmware/src/boards/. Shared code (main.cpp, ui.cpp, splash.cpp) no
longer contains a single `#ifdef BOARD_*` — optional features are
guarded by BoardCaps (runtime) and BOARD_HAS_* macros (compile-time,
inside the board's own files).
Why: lets community contributors port to new ESP32 + AMOLED + touch
combos by dropping in a boards/<name>/ folder + a PlatformIO env,
without touching shared files. See docs/porting/adding-a-board.md.
Highlights:
- New HAL: display_hal, touch_hal, input_hal, power_hal, imu_hal,
board_caps. Each board provides display.cpp, touch.cpp, input.cpp,
power.cpp, imu.cpp, caps.cpp, board_init.cpp + private hardware
drivers (e.g. io_expander.{h,cpp} on AMOLED-1.8).
- PlatformIO build_src_filter selects each board's folder per env.
- ui.cpp picks fonts and layout from board_caps() via compute_layout()
with screen-height breakpoints (>= 460 → large, else compact).
- splash.cpp computes CELL = min(W,H)/20 — responsive instead of two
hardcoded values.
- idle.cpp (from #24) rewired through display_hal + power_hal — no
longer depends on the deleted display_cfg.h / power.h.
- power_hal gains power_hal_is_vbus_in() for idle's
IDLE_SLEEP_WHEN_CHARGING gate.
- boards/template/ + docs/porting/{adding-a-board,hal-contract,
capability-flags}.md to bootstrap new ports.
- display_cfg.h, power.{h,cpp}, imu.{h,cpp}, io_expander.{h,cpp}
deleted from src/ root (moved into boards/<name>/ or hal/).
Verification: both `pio run -e waveshare_amoled_216` and
`pio run -e waveshare_amoled_18` succeed unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
66 lines
1.8 KiB
C++
66 lines
1.8 KiB
C++
#include "io_expander.h"
|
|
#include "board.h"
|
|
#include <Arduino.h>
|
|
#include <Wire.h>
|
|
|
|
// XCA9554/PCA9554 register map
|
|
#define IOX_REG_INPUT 0x00
|
|
#define IOX_REG_OUTPUT 0x01
|
|
#define IOX_REG_POLARITY 0x02
|
|
#define IOX_REG_CONFIG 0x03 // 1 = input, 0 = output
|
|
|
|
// EXIO0..2 are outputs (reset lines + audio amp). Everything else is input.
|
|
// Bit layout: 0bIIIIIOOO = 0xF8
|
|
#define IOX_CONFIG_MASK 0xF8
|
|
// All three outputs HIGH = resets released, amp enabled.
|
|
#define IOX_OUTPUT_DEFAULT 0x07
|
|
|
|
static uint8_t output_state = 0x00;
|
|
|
|
static bool write_reg(uint8_t reg, uint8_t val) {
|
|
Wire.beginTransmission(XCA9554_ADDR);
|
|
Wire.write(reg);
|
|
Wire.write(val);
|
|
return Wire.endTransmission() == 0;
|
|
}
|
|
|
|
static bool read_reg(uint8_t reg, uint8_t& val) {
|
|
Wire.beginTransmission(XCA9554_ADDR);
|
|
Wire.write(reg);
|
|
if (Wire.endTransmission(false) != 0) return false;
|
|
if (Wire.requestFrom(XCA9554_ADDR, (uint8_t)1) != 1) return false;
|
|
val = Wire.read();
|
|
return true;
|
|
}
|
|
|
|
bool io_expander_init(void) {
|
|
if (!write_reg(IOX_REG_CONFIG, IOX_CONFIG_MASK)) {
|
|
Serial.println("XCA9554 init failed (config)");
|
|
return false;
|
|
}
|
|
// Hold display + touch in reset.
|
|
output_state = 0x00;
|
|
write_reg(IOX_REG_OUTPUT, output_state);
|
|
delay(20);
|
|
// Release resets and enable audio amp output line.
|
|
output_state = IOX_OUTPUT_DEFAULT;
|
|
write_reg(IOX_REG_OUTPUT, output_state);
|
|
delay(20);
|
|
Serial.println("XCA9554 init OK");
|
|
return true;
|
|
}
|
|
|
|
void io_expander_set(uint8_t pin, bool high) {
|
|
if (pin > 7) return;
|
|
if (high) output_state |= (1u << pin);
|
|
else output_state &= ~(1u << pin);
|
|
write_reg(IOX_REG_OUTPUT, output_state);
|
|
}
|
|
|
|
bool io_expander_get(uint8_t pin) {
|
|
if (pin > 7) return false;
|
|
uint8_t v = 0;
|
|
if (!read_reg(IOX_REG_INPUT, v)) return false;
|
|
return (v & (1u << pin)) != 0;
|
|
}
|