Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,3 @@
[submodule "Libraries/cJSON/cJSON"]
path = Libraries/cJSON/cJSON
url = https://github.com/DaveGamble/cJSON.git
[submodule "Libraries/esp_epaper"]
path = Libraries/esp_epaper
url = https://github.com/NellowTCS/esp_epaper.git
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ else ()
add_compile_definitions(CONFIG_TT_LAUNCHER_APP_ID="tactility.launcher")
add_compile_definitions(CONFIG_TT_AUTO_START_APP_ID="")
add_compile_definitions(CONFIG_TT_USER_DATA_LOCATION_INTERNAL)
add_compile_definitions(CONFIG_TT_LVGL_STATUSBAR_COLORS_INVERTED=false)

endif ()

project(Tactility)
Expand Down
2 changes: 1 addition & 1 deletion Devices/cl32/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "source"
REQUIRES TactilityKernel
REQUIRES TactilityKernel tca8418-module
)
48 changes: 4 additions & 44 deletions Devices/cl32/cl32.dts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <tactility/bindings/esp32_sdspi.h>
#include <tactility/bindings/esp32_wifi.h>

#include <bindings/tca8418.h>
#include <bindings/bm8563.h>
#include <bindings/esp_epaper.h>

Expand All @@ -26,56 +25,17 @@
status = "disabled";
};

// Top Stemma/Qwiic port 1 shares this bus with the keyboard and RTC (SDA: pin 1 <-> SCL: pin 2).
// External I2C devices on that port are reachable via i2c0.
// Top Stemma/Qwiic port 1 shares this bus with the RTC (SDA: pin 1 <-> SCL: pin 2). External
// I2C devices on that port are reachable via i2c0. The tca8418 keyboard (revision 2 hardware)
// and power-supply chip (revision 3 hardware) are mutually exclusive on this bus and are
// created dynamically based on hardware detection - see cl32_detect.cpp.
i2c0 {
compatible = "espressif,esp32-i2c-master";
port = <I2C_NUM_0>;
clock-frequency = <100000>;
pin-sda = <&gpio0 1 GPIO_FLAG_PULL_UP>;
pin-scl = <&gpio0 2 GPIO_FLAG_PULL_UP>;

keyboard {
compatible = "ti,tca8418";
reg = <0x34>;
rows = <8>;
columns = <10>;
keymap-lc = [
37 49 50 51 52 53 54 55 56 0 // % 1 2 3 4 5 6 7 8
57 48 8 91 93 43 34 39 27 0 // 9 0 BKSP [ ] + " ' EXIT
9 113 119 101 114 116 121 117 105 0 // TAB q w e r t y u i
111 112 13 40 41 45 59 58 3 0 // o p ENTER ( ) - ; : STOP
0 97 115 100 102 103 104 106 107 0 // a s d f g h j k
108 17 35 123 125 42 44 46 2 0 // l UP # { } * , . MENU
122 120 99 118 98 32 32 110 109 0 // z x c v b n m
20 18 19 60 62 47 92 61 13 0 // LEFT DOWN RIGHT < > / \ = RUN
];
keymap-uc = [
37 49 50 51 52 53 54 55 56 0 // % 1 2 3 4 5 6 7 8
57 48 8 91 93 43 34 39 27 0 // 9 0 BKSP [ ] + " ' EXIT
9 81 87 69 82 84 89 85 73 0 // TAB Q W E R T Y U I
79 80 13 40 41 45 59 58 3 0 // O P ENTER ( ) - ; : STOP
0 65 83 68 70 71 72 74 75 0 // A S D F G H J K
76 17 35 123 125 42 44 46 2 0 // L UP # { } * , . MENU
90 88 67 86 66 32 32 78 77 0 // Z X C V B N M
20 18 19 60 62 47 92 61 13 0 // LEFT DOWN RIGHT < > / \ = RUN
];
keymap-sy = [
37 49 50 51 52 53 54 55 56 0 // % 1 2 3 4 5 6 7 8
57 48 8 91 93 43 34 39 27 0 // 9 0 BKSP [ ] + " ' EXIT
9 113 119 101 114 116 121 117 105 0 // TAB q w e r t y u i
111 112 13 40 41 45 59 58 3 0 // o p ENTER ( ) - ; : STOP
0 97 115 100 102 103 104 106 107 0 // a s d f g h j k
108 17 35 123 125 42 44 46 2 0 // l UP # { } * , . MENU
122 120 99 118 98 32 32 110 109 0 // z x c v b n m
20 18 19 60 62 47 92 61 13 0 // LEFT DOWN RIGHT < > / \ = RUN
];
shift-row = <4>;
shift-col = <0>;
sym-row = <5>;
sym-col = <8>;
};

rtc: bm8563 {
compatible = "belling,bm8563";
reg = <0x51>;
Expand Down
4 changes: 4 additions & 0 deletions Devices/cl32/device.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ display.dpi=139

lvgl.colorDepth=8
lvgl.theme=Mono
lvgl.uiDensity=compact
lvgl.statusbarColorsInverted=true

cdn.warningMessage=Only hardware revision 0.2 and 0.3 are supported for now!
156 changes: 156 additions & 0 deletions Devices/cl32/source/cl32_detect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
// SPDX-License-Identifier: Apache-2.0
#include "cl32_detect.h"

#include "cl32_v2_keyboard.h"
#include "cl32_v3_keyboard.h"
#include "cl32_v2.h"
#include "cl32_v3.h"
#include "cl32_v4.h"
#include "cl32_v4_keyboard.h"
#include "cl32_v4_power.h"

#include <tactility/device.h>
#include <tactility/device_listener.h>
#include <tactility/drivers/i2c_controller.h>
#include <tactility/log.h>

#include <cstring>

constexpr auto* TAG = "cl32-detect";

// Revision 2 and 3 boards are both plain tca8418 keyboards (different physical key layouts) with
// no core chip. Revision 4 boards have the core chip (power + keyboard) at CL32_V4_CORE_I2C_ADDRESS.
static Cl32HardwareRevision cl32_revision = Cl32HardwareRevision::Unknown;

static Device cl32_v4_power_device {};
static bool cl32_v4_power_created = false;

// The probe-once latch for on_i2c0_started(). File-scope (not function-local) so
// cl32_teardown_devices() can reset it for a later start/probe cycle.
static bool did_probe = false;

static void create_v2_devices(Device* i2c0) {
cl32_create_keyboard(i2c0);
}

static void create_v3_devices(Device* i2c0) {
cl32_v3_create_keyboard(i2c0);
}

static bool create_v4_power_device(Device* i2c0) {
cl32_v4_power_device = Device { .address = 0, .name = "cl32-v4-power", .config = nullptr, .parent = nullptr, .flags = 0, .internal = nullptr };

error_t error = device_construct(&cl32_v4_power_device);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to construct cl32-v4-power: %s", error_to_string(error));
return false;
}

device_set_parent(&cl32_v4_power_device, i2c0);
device_set_driver(&cl32_v4_power_device, &cl32_v4_power_driver);

error = device_add(&cl32_v4_power_device);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to add cl32-v4-power: %s", error_to_string(error));
device_destruct(&cl32_v4_power_device);
return false;
}

error = device_start(&cl32_v4_power_device);
if (error != ERROR_NONE) {
LOG_E(TAG, "Failed to start cl32-v4-power: %s", error_to_string(error));
device_remove(&cl32_v4_power_device);
device_destruct(&cl32_v4_power_device);
return false;
}

return true;
}

static void create_v4_devices(Device* i2c0) {
cl32_v4_create_keyboard(i2c0);
cl32_v4_power_created = create_v4_power_device(i2c0);
}

// Stops, removes and destructs cl32_v4_power_device if it was successfully created.
// cl32_v4_power_driver's own stop() tears down its power-supply child device.
static void destroy_v4_power_device() {
if (!cl32_v4_power_created) {
return;
}
device_stop(&cl32_v4_power_device);
device_remove(&cl32_v4_power_device);
device_destruct(&cl32_v4_power_device);
cl32_v4_power_created = false;
}

static Cl32HardwareRevision cl32_detect(Device* i2c0) {
uint8_t probe_value = 0;
if (i2c_controller_register8_get(i2c0, CL32_V4_CORE_I2C_ADDRESS, CL32_V4_KEYBOARD_PROBE_REGISTER, &probe_value, CL32_V4_CORE_TIMEOUT) == ERROR_NONE) {
LOG_I(TAG, "Detected V4 hardware by V4 keyboard presence");
return Cl32HardwareRevision::Revision4;
}

if (i2c_controller_has_device_at_address(i2c0, CL32_V3_FUEL_GAUGE_I2C_ADDRESS, CL32_V3_TIMEOUT) == ERROR_NONE) {
LOG_I(TAG, "Detected V3 hardware by MAX17048G fuel gauge presence");
return Cl32HardwareRevision::Revision3;
}

LOG_I(TAG, "No core chip or fuel gauge detected, assuming revision 2 hardware");
return Cl32HardwareRevision::Revision2;
Comment thread
KenVanHoeylandt marked this conversation as resolved.
}

// Fires for every device's start/stop in the system.
static void on_i2c0_started(Device* device, DeviceEvent event, void* context) {
(void)context;

if (did_probe || event != DEVICE_EVENT_STARTED || strcmp(device->name, "i2c0") != 0) {
return;
}
did_probe = true;

cl32_revision = cl32_detect(device);

switch (cl32_revision) {
case Cl32HardwareRevision::Revision2:
create_v2_devices(device);
break;
case Cl32HardwareRevision::Revision3:
create_v3_devices(device);
break;
case Cl32HardwareRevision::Revision4:
create_v4_devices(device);
break;
default:
LOG_W(TAG, "Unknown/unsupported hardware revision");
break;
}
}

Cl32HardwareRevision cl32_hardware_revision() {
return cl32_revision;
}

void cl32_teardown_devices() {
// Revision 2/3 keyboards bind the shared ti,tca8418 driver (owned by tca8418-module), so they
// don't block cl32_module's own driver destruction - torn down anyway for symmetry and so a
// later start can recreate them cleanly.
cl32_destroy_keyboard();
cl32_v3_destroy_keyboard();

// Revision 4 devices bind cl32-owned drivers (cl32_v4_keyboard_driver, cl32_v4_power_driver).
// Must be torn down before cl32_module's driver-removal loop runs, or driver_destruct() finds
// a started device still using the driver and fails.
cl32_v4_destroy_keyboard();
destroy_v4_power_device();

did_probe = false;
}

void cl32_power_detect_start() {
device_listener_add(on_i2c0_started, nullptr);
}

void cl32_power_detect_stop() {
device_listener_remove(on_i2c0_started);
}
16 changes: 16 additions & 0 deletions Devices/cl32/source/cl32_detect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

enum class Cl32HardwareRevision {
Unknown,
Revision2,
Revision3,
Revision4,
};

Cl32HardwareRevision cl32_hardware_revision();

void cl32_power_detect_start();
void cl32_power_detect_stop();

/** Stops, removes and destructs the devices for the relevant hardware revision. */
void cl32_teardown_devices();
4 changes: 4 additions & 0 deletions Devices/cl32/source/cl32_v2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#pragma once

#include <cstdint>

Loading
Loading