Add Waveshare ESP32-S3-Touch-AMOLED-2.06 board port + Windows daemon fixes
- New board firmware/src/boards/waveshare_amoled_206/ (CO5300 410x502, FT3168 touch, AXP2101 PMU, QMI8658 IMU). PlatformIO env waveshare_amoled_206. CO5300_COL_OFFSET=22, fixed orientation, PWR button on GPIO10, FocalTech inline touch reader. - Windows daemon: fix advertised device name (Claude Controller -> Clawdmeter) to match firmware ble.cpp, and add CLAWDMETER_ADDRESS env fallback so it connects by address when the bonded HID device is not advertising (Windows keeps it HID-connected). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -23,7 +23,12 @@ import httpx
|
||||
from bleak import BleakClient, BleakScanner
|
||||
from bleak.exc import BleakError
|
||||
|
||||
DEVICE_NAME = "Claude Controller"
|
||||
DEVICE_NAME = "Clawdmeter" # must match firmware ble.cpp DEVICE_NAME
|
||||
# Optional direct-connect address. Once the device is bonded as a BLE HID
|
||||
# keyboard, Windows keeps it connected, so it stops advertising and an active
|
||||
# scan (find_device_by_name) never sees it. Setting CLAWDMETER_ADDRESS lets the
|
||||
# daemon connect straight to the bonded device by address via WinRT.
|
||||
DEVICE_ADDRESS = os.environ.get("CLAWDMETER_ADDRESS")
|
||||
SERVICE_UUID = "4c41555a-4465-7669-6365-000000000001"
|
||||
RX_CHAR_UUID = "4c41555a-4465-7669-6365-000000000002"
|
||||
REQ_CHAR_UUID = "4c41555a-4465-7669-6365-000000000004"
|
||||
@@ -162,7 +167,12 @@ async def scan_for_device():
|
||||
device = await BleakScanner.find_device_by_name(DEVICE_NAME, timeout=SCAN_TIMEOUT)
|
||||
if device:
|
||||
log(f"Found: {device.address}")
|
||||
return device # BLEDevice or None — NOT an address string
|
||||
return device # BLEDevice
|
||||
if DEVICE_ADDRESS:
|
||||
# Bonded device that's connected to Windows won't advertise — connect by address.
|
||||
log(f"Not advertising; connecting by bonded address {DEVICE_ADDRESS}")
|
||||
return DEVICE_ADDRESS # address string — BleakClient accepts it on WinRT
|
||||
return device # None
|
||||
|
||||
|
||||
class Session:
|
||||
@@ -324,7 +334,8 @@ async def connect_and_run(device, stop_event: asyncio.Event, tray_state=None) ->
|
||||
|
||||
Returns True if at least one successful write occurred.
|
||||
"""
|
||||
log(f"Connecting to {device.address}...")
|
||||
addr = device if isinstance(device, str) else device.address
|
||||
log(f"Connecting to {addr}...")
|
||||
# D-01: retry wrapper — defeats WinRT post-wake failure modes
|
||||
# (Could not get GATT services: Unreachable, stale is_connected).
|
||||
# Rebuild a fresh BleakClient each attempt (locked D-05 recipe).
|
||||
|
||||
@@ -111,6 +111,63 @@ lib_deps =
|
||||
h2zero/NimBLE-Arduino@^2.1.1
|
||||
|
||||
|
||||
[env:waveshare_amoled_206]
|
||||
; Waveshare ESP32-S3-Touch-AMOLED-2.06 watch kit. 410x502 CO5300 + FT3168
|
||||
; touch + AXP2101 PMU + QMI8658 IMU. 32MB flash / 8MB OPI PSRAM. No IO
|
||||
; expander (reset lines are direct GPIOs), fixed orientation.
|
||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.38-1/platform-espressif32.zip
|
||||
board = esp32-s3-devkitc-1
|
||||
framework = arduino
|
||||
board_build.arduino.memory_type = qio_opi
|
||||
board_upload.flash_size = 16MB
|
||||
board_upload.maximum_size = 16777216
|
||||
board_build.partitions = default_16MB.csv
|
||||
upload_speed = 921600
|
||||
monitor_speed = 115200
|
||||
|
||||
build_src_filter =
|
||||
+<*>
|
||||
-<boards/>
|
||||
+<boards/waveshare_amoled_206/>
|
||||
|
||||
build_flags =
|
||||
-DBOARD_AMOLED_206
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DXPOWERS_CHIP_AXP2101
|
||||
; NimBLE config — peripheral, 2 simultaneous connections so the OS can
|
||||
; hold the HID link while the daemon holds the data-service connection.
|
||||
-DCONFIG_BT_NIMBLE_ROLE_BROADCASTER=1
|
||||
-DCONFIG_BT_NIMBLE_ROLE_PERIPHERAL=1
|
||||
-DCONFIG_BT_NIMBLE_ROLE_CENTRAL=0
|
||||
-DCONFIG_BT_NIMBLE_ROLE_OBSERVER=0
|
||||
-DCONFIG_BT_NIMBLE_MAX_CONNECTIONS=2
|
||||
; LVGL config via build flags
|
||||
-DLV_CONF_SKIP
|
||||
-DLV_COLOR_DEPTH=16
|
||||
-DLV_USE_LOG=0
|
||||
-DLV_USE_BAR=1
|
||||
-DLV_USE_LABEL=1
|
||||
-DLV_USE_ARC=1
|
||||
-DLV_USE_BTN=1
|
||||
-DLV_USE_LINE=1
|
||||
-DLV_USE_OBJ=1
|
||||
-DLV_USE_IMG=1
|
||||
-DLV_USE_IMAGE=1
|
||||
-DLV_USE_ANIMIMG=0
|
||||
-DLV_TICK_CUSTOM=1
|
||||
-DLV_USE_SNAPSHOT=1
|
||||
|
||||
lib_deps =
|
||||
; 1.6.4+ ships Arduino_CO5300 in mainline
|
||||
moononournation/GFX Library for Arduino@^1.6.4
|
||||
lewisxhe/SensorLib@^0.2.6
|
||||
lewisxhe/XPowersLib@^0.2.7
|
||||
lvgl/lvgl@^9.2.0
|
||||
bblanchon/ArduinoJson@^7.0.0
|
||||
h2zero/NimBLE-Arduino@^2.1.1
|
||||
|
||||
|
||||
[env:waveshare_amoled_216_c6]
|
||||
; C6 sibling of the AMOLED-2.16. Same panel/touch/PMU/IMU, no PSRAM,
|
||||
; single-core RISC-V, BLE 5.3 only (no classic BT). If the build fails
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
// Waveshare ESP32-S3-Touch-AMOLED-2.06 — rectangular AMOLED smartwatch kit.
|
||||
// 410x502 CO5300 + FT3168 touch + AXP2101 PMU + QMI8658 IMU + PCF85063 RTC.
|
||||
// No IO expander: display/touch reset lines are direct ESP32 GPIOs.
|
||||
// IMU is present (initialized for I2C bus health) but rotation is disabled —
|
||||
// the panel is non-square and the kit mounts in a fixed orientation.
|
||||
|
||||
#define BOARD_NAME "Waveshare AMOLED 2.06"
|
||||
|
||||
// ---- Display geometry (portrait, non-square) ----
|
||||
#define LCD_WIDTH 410
|
||||
#define LCD_HEIGHT 502
|
||||
|
||||
// ---- QSPI display pins (CO5300) ----
|
||||
// Same data lines as the 2.16 board, but SCLK and RESET differ.
|
||||
#define LCD_CS 12
|
||||
#define LCD_SCLK 11 // 2.06: GPIO11 (2.16 board used GPIO38)
|
||||
#define LCD_SDIO0 4
|
||||
#define LCD_SDIO1 5
|
||||
#define LCD_SDIO2 6
|
||||
#define LCD_SDIO3 7
|
||||
#define LCD_RESET 8 // direct GPIO (2.16 used GPIO2)
|
||||
#define LCD_TE 13 // tearing-effect line (unused by GFX driver)
|
||||
|
||||
// CO5300 GRAM is wider than the 410px active area, so the visible image needs
|
||||
// a horizontal start offset. 22 verified for this panel (matches the value used
|
||||
// by other 2.06 firmwares; eliminates the uninitialized green band on the right).
|
||||
#define CO5300_COL_OFFSET 22
|
||||
|
||||
// ---- I2C bus (touch + PMU + IMU + RTC all share one bus) ----
|
||||
#define IIC_SDA 15
|
||||
#define IIC_SCL 14
|
||||
|
||||
// ---- Touch (FT3168 via minimal inline FocalTech-style I2C reader) ----
|
||||
#define TP_INT 38
|
||||
#define TP_RST 9 // direct GPIO (active LOW)
|
||||
#define FT3168_ADDR 0x38
|
||||
|
||||
// ---- PMU ----
|
||||
#define AXP2101_ADDR 0x34
|
||||
|
||||
// ---- Buttons ----
|
||||
#define BTN_BACK_GPIO 0 // BOOT — primary, Space (PTT)
|
||||
#define BTN_PWR_GPIO 10 // PWR side button — cycle screens / animations
|
||||
// PWR polarity: assumed active LOW with internal pull-up (button to GND, like
|
||||
// BOOT). If the screen-cycle button never registers, flip BTN_PWR_ACTIVE_LOW.
|
||||
#define BTN_PWR_ACTIVE_LOW 1
|
||||
|
||||
// ---- Capability flags ----
|
||||
#define BOARD_HAS_SECONDARY_BUTTON 0 // only BOOT via input_hal; PWR via power_hal
|
||||
#define BOARD_HAS_ROTATION 0 // non-square panel, fixed orientation
|
||||
#define BOARD_HAS_IMU 1 // present + initialized, rotation off
|
||||
#define BOARD_HAS_BATTERY 1
|
||||
#define BOARD_HAS_IO_EXPANDER 0
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "board.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
// AMOLED-2.06 has no IO expander — display and touch reset lines are direct
|
||||
// ESP32 GPIOs. We bring up the shared I2C bus and release both reset lines
|
||||
// before any display/touch HAL call runs.
|
||||
//
|
||||
// Display power: on this kit the AMOLED rail is supplied by the AXP2101 PMU
|
||||
// (the "DSI_PWR_EN" net on the schematic sits on the PMIC, not an ESP32 pin),
|
||||
// matching the AMOLED-2.16 sibling which lights up with no explicit rail
|
||||
// poke after pmu.begin(). If the panel stays dark on first flash, enable the
|
||||
// AXP rails in power.cpp (see the commented block there).
|
||||
extern "C" void board_init(void) {
|
||||
Wire.begin(IIC_SDA, IIC_SCL);
|
||||
|
||||
// Release the touch controller from reset (active LOW). The display's own
|
||||
// reset is driven by the Arduino_GFX CO5300 driver via LCD_RESET.
|
||||
pinMode(TP_RST, OUTPUT);
|
||||
digitalWrite(TP_RST, LOW);
|
||||
delay(5);
|
||||
digitalWrite(TP_RST, HIGH);
|
||||
delay(50);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "../../hal/board_caps.h"
|
||||
#include "board.h"
|
||||
|
||||
static const BoardCaps caps = {
|
||||
.name = BOARD_NAME,
|
||||
.width = LCD_WIDTH,
|
||||
.height = LCD_HEIGHT,
|
||||
.button_count = 1,
|
||||
.has_rotation = false,
|
||||
.has_battery = true,
|
||||
.has_imu = true,
|
||||
};
|
||||
|
||||
const BoardCaps& board_caps(void) { return caps; }
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "../../hal/display_hal.h"
|
||||
#include "board.h"
|
||||
#include <Arduino.h>
|
||||
#include <Arduino_GFX_Library.h>
|
||||
|
||||
// AMOLED-2.06 is fixed at 0° (non-square 410x502 panel — the 2.16 board's CPU
|
||||
// strip-rotation assumes a square panel and can't be reused here). No rot_buf.
|
||||
//
|
||||
// Display driver is the CO5300 (same controller family as the 2.16 board).
|
||||
// Reset is a direct GPIO (LCD_RESET), so the GFX driver owns it. The CO5300's
|
||||
// active area starts partway into the controller GRAM, so it gets a column
|
||||
// offset to center the image (CO5300_COL_OFFSET — verify on hardware).
|
||||
|
||||
static Arduino_DataBus* bus = nullptr;
|
||||
static Arduino_CO5300* gfx = nullptr;
|
||||
|
||||
void display_hal_init(void) {
|
||||
bus = new Arduino_ESP32QSPI(
|
||||
LCD_CS, LCD_SCLK, LCD_SDIO0, LCD_SDIO1, LCD_SDIO2, LCD_SDIO3);
|
||||
// CO5300: (bus, rst, rotation, w, h, col_off1, row_off1, col_off2, row_off2)
|
||||
gfx = new Arduino_CO5300(
|
||||
bus, LCD_RESET, 0 /* no rotation */,
|
||||
LCD_WIDTH, LCD_HEIGHT, CO5300_COL_OFFSET, 0, 0, 0);
|
||||
}
|
||||
|
||||
void display_hal_begin(void) {
|
||||
gfx->begin();
|
||||
gfx->fillScreen(0x0000);
|
||||
gfx->setBrightness(200);
|
||||
}
|
||||
|
||||
void display_hal_set_brightness(uint8_t level) {
|
||||
if (gfx) gfx->setBrightness(level);
|
||||
}
|
||||
|
||||
void display_hal_fill_screen(uint16_t color) {
|
||||
if (gfx) gfx->fillScreen(color);
|
||||
}
|
||||
|
||||
void display_hal_draw_bitmap(int32_t x, int32_t y, int32_t w, int32_t h,
|
||||
const uint16_t* pixels) {
|
||||
if (gfx) gfx->draw16bitRGBBitmap(x, y, (uint16_t*)pixels, w, h);
|
||||
}
|
||||
|
||||
void display_hal_tick(void) {
|
||||
// No rotation handling needed on this board.
|
||||
}
|
||||
|
||||
// CO5300 requires even-aligned flush regions.
|
||||
void display_hal_round_area(int32_t* x1, int32_t* y1, int32_t* x2, int32_t* y2) {
|
||||
*x1 = *x1 & ~1;
|
||||
*y1 = *y1 & ~1;
|
||||
*x2 = *x2 | 1;
|
||||
*y2 = *y2 | 1;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "../../hal/imu_hal.h"
|
||||
#include "board.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <SensorQMI8658.hpp>
|
||||
|
||||
// AMOLED-2.06 ships with QMI8658 populated, but the panel is non-square and
|
||||
// mounts in a fixed orientation, so rotation is disabled. We initialize the
|
||||
// device anyway to keep the shared I2C bus healthy, but always report 0.
|
||||
|
||||
static SensorQMI8658 imu;
|
||||
|
||||
void imu_hal_init(void) {
|
||||
if (!imu.begin(Wire, QMI8658_L_SLAVE_ADDRESS, IIC_SDA, IIC_SCL)) {
|
||||
Serial.println("QMI8658 init failed");
|
||||
return;
|
||||
}
|
||||
Serial.println("QMI8658 init OK (rotation disabled on this board)");
|
||||
}
|
||||
|
||||
void imu_hal_tick(void) {
|
||||
// No-op — rotation is disabled.
|
||||
}
|
||||
|
||||
uint8_t imu_hal_rotation_quadrant(void) { return 0; }
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "../../hal/input_hal.h"
|
||||
#include "board.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
// AMOLED-2.06 exposes the BOOT button as the primary HID input. The PWR side
|
||||
// button is handled in power_hal (BTN_PWR_GPIO). No secondary button.
|
||||
|
||||
void input_hal_init(void) {
|
||||
pinMode(BTN_BACK_GPIO, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
bool input_hal_is_held(InputButton btn) {
|
||||
switch (btn) {
|
||||
case INPUT_BTN_PRIMARY:
|
||||
return digitalRead(BTN_BACK_GPIO) == LOW;
|
||||
case INPUT_BTN_SECONDARY:
|
||||
return false; // not present on this board
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "../../hal/power_hal.h"
|
||||
#include "board.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <XPowersLib.h>
|
||||
|
||||
// AXP2101 provides battery monitoring. The PWR side button on this kit is a
|
||||
// direct ESP32 GPIO (BTN_PWR_GPIO), not the AXP PKEY, so we poll it and
|
||||
// synthesize the same three edges the AXP IRQ path produces on the 2.16 board:
|
||||
// short — fired on release if the hold was shorter than PWR_LONG_MS
|
||||
// long — fired once when a hold crosses PWR_LONG_MS
|
||||
// release — fired on every release edge
|
||||
// This keeps the hold-to-pair gesture logic in main.cpp board-agnostic.
|
||||
|
||||
#define BATTERY_POLL_MS 2000
|
||||
#define CHARGING_POLL_MS 500
|
||||
#define PWR_POLL_MS 50
|
||||
#define PWR_LONG_MS 1500 // hold threshold, mirrors the AXP LONG IRQ
|
||||
|
||||
#if BTN_PWR_ACTIVE_LOW
|
||||
#define PWR_IS_DOWN(level) ((level) == LOW)
|
||||
#else
|
||||
#define PWR_IS_DOWN(level) ((level) == HIGH)
|
||||
#endif
|
||||
|
||||
static XPowersPMU pmu;
|
||||
|
||||
static int cached_pct = -1;
|
||||
static bool cached_charging = false;
|
||||
static bool cached_vbus = false;
|
||||
static bool pwr_pressed_flag = false;
|
||||
static bool pwr_long_flag = false;
|
||||
static bool pwr_released_flag = false;
|
||||
static bool last_pwr_down = false; // edge detector for BTN_PWR_GPIO
|
||||
static uint32_t pwr_press_started_ms = 0;
|
||||
static bool pwr_long_fired = false;
|
||||
static uint32_t last_battery_ms = 0;
|
||||
static uint32_t last_charging_ms = 0;
|
||||
static uint32_t last_pwr_ms = 0;
|
||||
|
||||
void power_hal_init(void) {
|
||||
if (!pmu.begin(Wire, AXP2101_ADDR, IIC_SDA, IIC_SCL)) {
|
||||
Serial.println("AXP2101 init failed");
|
||||
return;
|
||||
}
|
||||
Serial.println("AXP2101 init OK");
|
||||
|
||||
pmu.enableBattDetection();
|
||||
pmu.enableBattVoltageMeasure();
|
||||
|
||||
// ---- OPTIONAL: explicit AMOLED rail enable ----------------------------
|
||||
// The 2.16 sibling lights up without this, so it's left off by default.
|
||||
// If the panel stays DARK on first flash, the display rail isn't powered.
|
||||
// Uncomment and set the channels/voltages to match the Waveshare 2.06
|
||||
// schematic (typical AXP2101 AMOLED kits use the ALDO/BLDO rails):
|
||||
//
|
||||
// pmu.setALDO1Voltage(1800); pmu.enableALDO1(); // panel logic 1.8V
|
||||
// pmu.setBLDO1Voltage(3300); pmu.enableBLDO1(); // panel/touch 3.3V
|
||||
// pmu.setBLDO2Voltage(3300); pmu.enableBLDO2();
|
||||
// delay(50);
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// PWR button is a direct GPIO on this board.
|
||||
pinMode(BTN_PWR_GPIO, BTN_PWR_ACTIVE_LOW ? INPUT_PULLUP : INPUT_PULLDOWN);
|
||||
|
||||
cached_charging = pmu.isCharging();
|
||||
cached_vbus = pmu.isVbusIn();
|
||||
cached_pct = pmu.getBatteryPercent();
|
||||
}
|
||||
|
||||
void power_hal_tick(void) {
|
||||
uint32_t now = millis();
|
||||
|
||||
if (now - last_charging_ms >= CHARGING_POLL_MS) {
|
||||
last_charging_ms = now;
|
||||
cached_charging = pmu.isCharging();
|
||||
cached_vbus = pmu.isVbusIn();
|
||||
}
|
||||
if (now - last_battery_ms >= BATTERY_POLL_MS) {
|
||||
last_battery_ms = now;
|
||||
cached_pct = pmu.getBatteryPercent();
|
||||
}
|
||||
if (now - last_pwr_ms >= PWR_POLL_MS) {
|
||||
last_pwr_ms = now;
|
||||
bool pwr_down = PWR_IS_DOWN(digitalRead(BTN_PWR_GPIO));
|
||||
if (pwr_down && !last_pwr_down) { // press begins
|
||||
pwr_press_started_ms = now;
|
||||
pwr_long_fired = false;
|
||||
} else if (pwr_down && last_pwr_down) { // held
|
||||
if (!pwr_long_fired && (now - pwr_press_started_ms >= PWR_LONG_MS)) {
|
||||
pwr_long_flag = true;
|
||||
pwr_long_fired = true;
|
||||
}
|
||||
} else if (!pwr_down && last_pwr_down) { // release
|
||||
pwr_released_flag = true;
|
||||
if (!pwr_long_fired) pwr_pressed_flag = true; // short press
|
||||
}
|
||||
last_pwr_down = pwr_down;
|
||||
}
|
||||
}
|
||||
|
||||
int power_hal_battery_pct(void) { return cached_pct; }
|
||||
bool power_hal_is_charging(void) { return cached_charging; }
|
||||
bool power_hal_is_vbus_in(void) { return cached_vbus; }
|
||||
|
||||
bool power_hal_pwr_pressed(void) {
|
||||
if (pwr_pressed_flag) { pwr_pressed_flag = false; return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool power_hal_pwr_long_pressed(void) {
|
||||
if (pwr_long_flag) { pwr_long_flag = false; return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool power_hal_pwr_released(void) {
|
||||
if (pwr_released_flag) { pwr_released_flag = false; return true; }
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "../../hal/touch_hal.h"
|
||||
#include "board.h"
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
|
||||
// Minimal capacitive-touch reader for the FT3168 (FocalTech). Same data layout
|
||||
// as the FT3168 on the AMOLED-1.8 board, so we reuse the inline reader instead
|
||||
// of vendoring the GPLv3 Arduino_DriveBus library.
|
||||
// reg 0x02: low nibble = active finger count
|
||||
// reg 0x03 / 0x04: X1 high (low nibble) + X1 low
|
||||
// reg 0x05 / 0x06: Y1 high (low nibble) + Y1 low
|
||||
//
|
||||
// Axis orientation: started with no swap/mirror (matches the portrait FT3168
|
||||
// on the 1.8 board). If touch coordinates come out flipped/swapped on this
|
||||
// panel, mirror/swap them in touch_read_into_shared_state() below.
|
||||
|
||||
static volatile bool touch_data_ready = false;
|
||||
static volatile bool touch_pressed = false;
|
||||
static volatile uint16_t touch_x = 0;
|
||||
static volatile uint16_t touch_y = 0;
|
||||
|
||||
static void IRAM_ATTR touch_isr(void) {
|
||||
touch_data_ready = true;
|
||||
}
|
||||
|
||||
static void touch_read_into_shared_state(void) {
|
||||
Wire.beginTransmission(FT3168_ADDR);
|
||||
Wire.write(0x02);
|
||||
if (Wire.endTransmission(false) != 0) { touch_pressed = false; return; }
|
||||
if (Wire.requestFrom((uint8_t)FT3168_ADDR, (uint8_t)5) != 5) { touch_pressed = false; return; }
|
||||
uint8_t fingers = Wire.read() & 0x0F;
|
||||
uint8_t xH = Wire.read();
|
||||
uint8_t xL = Wire.read();
|
||||
uint8_t yH = Wire.read();
|
||||
uint8_t yL = Wire.read();
|
||||
if (fingers == 0 || fingers > 5) {
|
||||
touch_pressed = false;
|
||||
return;
|
||||
}
|
||||
touch_x = ((uint16_t)(xH & 0x0F) << 8) | xL;
|
||||
touch_y = ((uint16_t)(yH & 0x0F) << 8) | yL;
|
||||
touch_pressed = true;
|
||||
}
|
||||
|
||||
void touch_hal_init(void) {
|
||||
// FT3168 power-mode register 0xA5 = 0x00: active scanning.
|
||||
Wire.beginTransmission(FT3168_ADDR);
|
||||
Wire.write(0xA5);
|
||||
Wire.write(0x00);
|
||||
Wire.endTransmission();
|
||||
|
||||
// Verify the controller answers (FT3168 chip-id is reg 0xA0).
|
||||
Wire.beginTransmission(FT3168_ADDR);
|
||||
Wire.write(0xA0);
|
||||
if (Wire.endTransmission(false) == 0 && Wire.requestFrom((uint8_t)FT3168_ADDR, (uint8_t)1) == 1) {
|
||||
Serial.printf("Touch FT3168 ID=0x%02X (addr 0x%02X)\n", Wire.read(), FT3168_ADDR);
|
||||
} else {
|
||||
Serial.printf("Touch FT3168 ID read failed (addr 0x%02X)\n", FT3168_ADDR);
|
||||
}
|
||||
|
||||
pinMode(TP_INT, INPUT_PULLUP);
|
||||
attachInterrupt(TP_INT, touch_isr, FALLING);
|
||||
Serial.println("Touch attached on INT pin");
|
||||
}
|
||||
|
||||
void touch_hal_read(uint16_t* x, uint16_t* y, bool* pressed) {
|
||||
if (touch_data_ready) {
|
||||
touch_data_ready = false;
|
||||
touch_read_into_shared_state();
|
||||
}
|
||||
*x = touch_x;
|
||||
*y = touch_y;
|
||||
*pressed = touch_pressed;
|
||||
}
|
||||
Reference in New Issue
Block a user