mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-06-19 04:15:06 +00:00
Grove driver, I2C migrations, bugfixes and docs (#532)
This commit is contained in:
parent
8dabda2b5b
commit
a35c88c8fd
3
.gitignore
vendored
3
.gitignore
vendored
@ -23,3 +23,6 @@ dependencies.lock
|
|||||||
sdkconfig.board.*.dev
|
sdkconfig.board.*.dev
|
||||||
|
|
||||||
.tactility/
|
.tactility/
|
||||||
|
|
||||||
|
.caveman.json
|
||||||
|
.ai/mcp
|
||||||
@ -3,11 +3,15 @@
|
|||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
#include <RgbDisplay.h>
|
#include <RgbDisplay.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
// Note for future changes: Reset pin is 41 and interrupt pin is 40
|
// Note for future changes: Reset pin is 41 and interrupt pin is 40
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
800,
|
800,
|
||||||
480
|
480
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,10 +3,14 @@
|
|||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <Ili934xDisplay.h>
|
#include <Ili934xDisplay.h>
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
LCD_HORIZONTAL_RESOLUTION,
|
LCD_HORIZONTAL_RESOLUTION,
|
||||||
LCD_VERTICAL_RESOLUTION
|
LCD_VERTICAL_RESOLUTION
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,10 +3,14 @@
|
|||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
#include <St7796Display.h>
|
#include <St7796Display.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
LCD_HORIZONTAL_RESOLUTION,
|
LCD_HORIZONTAL_RESOLUTION,
|
||||||
LCD_VERTICAL_RESOLUTION
|
LCD_VERTICAL_RESOLUTION
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
#include <driver/gpio.h>
|
#include <driver/gpio.h>
|
||||||
#include <esp_err.h>
|
#include <esp_err.h>
|
||||||
@ -221,8 +223,10 @@ lvgl_port_display_rgb_cfg_t St7701Display::getLvglPortDisplayRgbConfig(esp_lcd_p
|
|||||||
|
|
||||||
std::shared_ptr<tt::hal::touch::TouchDevice> St7701Display::getTouchDevice() {
|
std::shared_ptr<tt::hal::touch::TouchDevice> St7701Display::getTouchDevice() {
|
||||||
if (touchDevice == nullptr) {
|
if (touchDevice == nullptr) {
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
480,
|
480,
|
||||||
480
|
480
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,12 +3,16 @@
|
|||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
#include <RgbDisplay.h>
|
#include <RgbDisplay.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
// Note for future changes: Reset pin is 38 and interrupt pin is 18
|
// Note for future changes: Reset pin is 38 and interrupt pin is 18
|
||||||
// or INT = NC, schematic and other info floating around is kinda conflicting...
|
// or INT = NC, schematic and other info floating around is kinda conflicting...
|
||||||
|
auto* i2c = device_find_by_name("i2c_internal");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
800,
|
800,
|
||||||
480
|
480
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,10 +3,14 @@
|
|||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
#include <Ili9488Display.h>
|
#include <Ili9488Display.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
320,
|
320,
|
||||||
480
|
480
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,12 +2,16 @@
|
|||||||
|
|
||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <RgbDisplay.h>
|
#include <RgbDisplay.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
// Note for future changes: Reset pin is 38 and interrupt pin is 18
|
// Note for future changes: Reset pin is 38 and interrupt pin is 18
|
||||||
// or INT = NC, schematic and other info floating around is kinda conflicting...
|
// or INT = NC, schematic and other info floating around is kinda conflicting...
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
800,
|
800,
|
||||||
480
|
480
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,12 +3,16 @@
|
|||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
#include <RgbDisplay.h>
|
#include <RgbDisplay.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
// Note for future changes: Reset pin is 38 and interrupt pin is 18
|
// Note for future changes: Reset pin is 38 and interrupt pin is 18
|
||||||
// or INT = NC, schematic and other info floating around is kinda conflicting...
|
// or INT = NC, schematic and other info floating around is kinda conflicting...
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
800,
|
800,
|
||||||
480
|
480
|
||||||
);
|
);
|
||||||
|
|||||||
@ -5,21 +5,22 @@
|
|||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/Mutex.h>
|
#include <Tactility/Mutex.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
constexpr auto LCD_PIN_RESET = GPIO_NUM_0; // Match P4 EV board reset line
|
constexpr auto LCD_PIN_RESET = GPIO_NUM_0; // Match P4 EV board reset line
|
||||||
constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_23;
|
constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_23;
|
||||||
constexpr auto LCD_HORIZONTAL_RESOLUTION = 1024;
|
constexpr auto LCD_HORIZONTAL_RESOLUTION = 1024;
|
||||||
constexpr auto LCD_VERTICAL_RESOLUTION = 600;
|
constexpr auto LCD_VERTICAL_RESOLUTION = 600;
|
||||||
|
|
||||||
constexpr auto TOUCH_I2C_PORT = I2C_NUM_0;
|
|
||||||
constexpr auto TOUCH_I2C_SDA = GPIO_NUM_7;
|
|
||||||
constexpr auto TOUCH_I2C_SCL = GPIO_NUM_8;
|
|
||||||
constexpr auto TOUCH_PIN_RESET = GPIO_NUM_NC;
|
constexpr auto TOUCH_PIN_RESET = GPIO_NUM_NC;
|
||||||
constexpr auto TOUCH_PIN_INTERRUPT = GPIO_NUM_NC;
|
constexpr auto TOUCH_PIN_INTERRUPT = GPIO_NUM_NC;
|
||||||
|
|
||||||
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
|
auto* i2c = device_find_by_name("i2c_internal");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
TOUCH_I2C_PORT,
|
i2c,
|
||||||
LCD_HORIZONTAL_RESOLUTION,
|
LCD_HORIZONTAL_RESOLUTION,
|
||||||
LCD_VERTICAL_RESOLUTION,
|
LCD_VERTICAL_RESOLUTION,
|
||||||
false, // swapXY
|
false, // swapXY
|
||||||
|
|||||||
@ -3,12 +3,16 @@
|
|||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
#include <RgbDisplay.h>
|
#include <RgbDisplay.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
// Note for future changes: Reset pin is 38 and interrupt pin is 18
|
// Note for future changes: Reset pin is 38 and interrupt pin is 18
|
||||||
// or INT = NC, schematic and other info floating around is kinda conflicting...
|
// or INT = NC, schematic and other info floating around is kinda conflicting...
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
800,
|
800,
|
||||||
480
|
480
|
||||||
);
|
);
|
||||||
|
|||||||
@ -7,16 +7,20 @@
|
|||||||
|
|
||||||
#include <Tactility/hal/Configuration.h>
|
#include <Tactility/hal/Configuration.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
bool initBoot();
|
bool initBoot();
|
||||||
|
|
||||||
using namespace tt::hal;
|
using namespace tt::hal;
|
||||||
|
|
||||||
static std::vector<std::shared_ptr<tt::hal::Device>> createDevices() {
|
static std::vector<std::shared_ptr<tt::hal::Device>> createDevices() {
|
||||||
|
auto* i2c_internal = device_find_by_name("i2c0");
|
||||||
|
check(i2c_internal);
|
||||||
return {
|
return {
|
||||||
createPower(),
|
createPower(),
|
||||||
createDisplay(),
|
createDisplay(),
|
||||||
std::make_shared<TdeckKeyboard>(),
|
std::make_shared<TdeckKeyboard>(i2c_internal),
|
||||||
std::make_shared<KeyboardBacklightDevice>(),
|
std::make_shared<KeyboardBacklightDevice>(),
|
||||||
std::make_shared<TrackballDevice>(),
|
std::make_shared<TrackballDevice>(),
|
||||||
createSdCard()
|
createSdCard()
|
||||||
|
|||||||
@ -58,7 +58,7 @@ bool initBoot() {
|
|||||||
std::vector<tt::hal::gps::GpsConfiguration> gps_configurations;
|
std::vector<tt::hal::gps::GpsConfiguration> gps_configurations;
|
||||||
gps_service->getGpsConfigurations(gps_configurations);
|
gps_service->getGpsConfigurations(gps_configurations);
|
||||||
if (gps_configurations.empty()) {
|
if (gps_configurations.empty()) {
|
||||||
if (gps_service->addGpsConfiguration(tt::hal::gps::GpsConfiguration {.uartName = "uart1", .baudRate = 38400, .model = tt::hal::gps::GpsModel::UBLOX10})) {
|
if (gps_service->addGpsConfiguration(tt::hal::gps::GpsConfiguration {.uartName = "uart0", .baudRate = 38400, .model = tt::hal::gps::GpsModel::UBLOX10})) {
|
||||||
LOGGER.info("Configured internal GPS");
|
LOGGER.info("Configured internal GPS");
|
||||||
} else {
|
} else {
|
||||||
LOGGER.error("Failed to configure internal GPS");
|
LOGGER.error("Failed to configure internal GPS");
|
||||||
|
|||||||
@ -3,10 +3,14 @@
|
|||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
#include <St7789Display.h>
|
#include <St7789Display.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
240,
|
240,
|
||||||
320,
|
320,
|
||||||
true,
|
true,
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#include "KeyboardBacklight.h"
|
#include "KeyboardBacklight.h"
|
||||||
#include <KeyboardBacklight/KeyboardBacklight.h> // Driver
|
#include <KeyboardBacklight/KeyboardBacklight.h> // Driver
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
|
||||||
#include <Tactility/settings/KeyboardSettings.h>
|
#include <Tactility/settings/KeyboardSettings.h>
|
||||||
|
|
||||||
// TODO: Add Mutex and consider refactoring into a class
|
// TODO: Add Mutex and consider refactoring into a class
|
||||||
|
|||||||
@ -1,24 +1,18 @@
|
|||||||
#include "TdeckKeyboard.h"
|
#include "TdeckKeyboard.h"
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
|
||||||
#include <driver/i2c.h>
|
|
||||||
#include <lvgl.h>
|
|
||||||
#include <Tactility/settings/KeyboardSettings.h>
|
|
||||||
#include <Tactility/settings/DisplaySettings.h>
|
|
||||||
#include <Tactility/hal/display/DisplayDevice.h>
|
|
||||||
#include <tactility/hal/Device.h>
|
|
||||||
#include <Tactility/Logger.h>
|
|
||||||
#include <KeyboardBacklight/KeyboardBacklight.h>
|
#include <KeyboardBacklight/KeyboardBacklight.h>
|
||||||
|
#include <Tactility/Logger.h>
|
||||||
|
#include <Tactility/hal/display/DisplayDevice.h>
|
||||||
|
#include <Tactility/settings/DisplaySettings.h>
|
||||||
|
#include <Tactility/settings/KeyboardSettings.h>
|
||||||
|
#include <lvgl.h>
|
||||||
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
|
|
||||||
using tt::hal::findFirstDevice;
|
using tt::hal::findFirstDevice;
|
||||||
|
|
||||||
static const auto LOGGER = tt::Logger("TdeckKeyboard");
|
static const auto LOGGER = tt::Logger("TdeckKeyboard");
|
||||||
|
|
||||||
constexpr auto TDECK_KEYBOARD_I2C_BUS_HANDLE = I2C_NUM_0;
|
constexpr uint8_t TDECK_KEYBOARD_SLAVE_ADDRESS = 0x55;
|
||||||
constexpr auto TDECK_KEYBOARD_SLAVE_ADDRESS = 0x55;
|
|
||||||
|
|
||||||
static bool keyboard_i2c_read(uint8_t* output) {
|
|
||||||
return tt::hal::i2c::masterRead(TDECK_KEYBOARD_I2C_BUS_HANDLE, TDECK_KEYBOARD_SLAVE_ADDRESS, output, 1, 100 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The callback simulates press and release events, because the T-Deck
|
* The callback simulates press and release events, because the T-Deck
|
||||||
@ -37,7 +31,8 @@ static void keyboard_read_callback(lv_indev_t* indev, lv_indev_data_t* data) {
|
|||||||
data->key = 0;
|
data->key = 0;
|
||||||
data->state = LV_INDEV_STATE_RELEASED;
|
data->state = LV_INDEV_STATE_RELEASED;
|
||||||
|
|
||||||
if (keyboard_i2c_read(&read_buffer)) {
|
auto* keyboard = static_cast<TdeckKeyboard*>(lv_indev_get_user_data(indev));
|
||||||
|
if (i2c_controller_read(keyboard->getI2cController(), TDECK_KEYBOARD_SLAVE_ADDRESS, &read_buffer, 1, 100 / portTICK_PERIOD_MS) == ERROR_NONE) {
|
||||||
if (read_buffer == 0 && read_buffer != last_buffer) {
|
if (read_buffer == 0 && read_buffer != last_buffer) {
|
||||||
if (LOGGER.isLoggingDebug()) {
|
if (LOGGER.isLoggingDebug()) {
|
||||||
LOGGER.debug("Released {}", last_buffer);
|
LOGGER.debug("Released {}", last_buffer);
|
||||||
@ -91,5 +86,5 @@ bool TdeckKeyboard::stopLvgl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TdeckKeyboard::isAttached() const {
|
bool TdeckKeyboard::isAttached() const {
|
||||||
return tt::hal::i2c::masterHasDeviceAtAddress(TDECK_KEYBOARD_I2C_BUS_HANDLE, TDECK_KEYBOARD_SLAVE_ADDRESS, 100);
|
return i2c_controller_has_device_at_address(i2cController, TDECK_KEYBOARD_SLAVE_ADDRESS, 100) == ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Tactility/hal/keyboard/KeyboardDevice.h>
|
#include <Tactility/hal/keyboard/KeyboardDevice.h>
|
||||||
#include <Tactility/TactilityCore.h>
|
|
||||||
|
struct Device;
|
||||||
|
|
||||||
class TdeckKeyboard final : public tt::hal::keyboard::KeyboardDevice {
|
class TdeckKeyboard final : public tt::hal::keyboard::KeyboardDevice {
|
||||||
|
|
||||||
|
::Device* i2cController;
|
||||||
lv_indev_t* deviceHandle = nullptr;
|
lv_indev_t* deviceHandle = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
explicit TdeckKeyboard(::Device* i2cController) : i2cController(i2cController) {}
|
||||||
|
|
||||||
std::string getName() const override { return "T-Deck Keyboard"; }
|
std::string getName() const override { return "T-Deck Keyboard"; }
|
||||||
std::string getDescription() const override { return "I2C keyboard"; }
|
std::string getDescription() const override { return "I2C keyboard"; }
|
||||||
|
|
||||||
|
::Device* getI2cController() const { return i2cController; }
|
||||||
|
|
||||||
bool startLvgl(lv_display_t* display) override;
|
bool startLvgl(lv_display_t* display) override;
|
||||||
bool stopLvgl() override;
|
bool stopLvgl() override;
|
||||||
bool isAttached() const override;
|
bool isAttached() const override;
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@ -30,15 +31,6 @@
|
|||||||
pin-scl = <&gpio0 8 GPIO_FLAG_NONE>;
|
pin-scl = <&gpio0 8 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_external: i2c1 {
|
|
||||||
compatible = "espressif,esp32-i2c";
|
|
||||||
status = "disabled";
|
|
||||||
port = <I2C_NUM_1>;
|
|
||||||
clock-frequency = <400000>;
|
|
||||||
pin-sda = <&gpio0 43 GPIO_FLAG_NONE>;
|
|
||||||
pin-scl = <&gpio0 44 GPIO_FLAG_NONE>;
|
|
||||||
};
|
|
||||||
|
|
||||||
i2s0 {
|
i2s0 {
|
||||||
compatible = "espressif,esp32-i2s";
|
compatible = "espressif,esp32-i2s";
|
||||||
port = <I2S_NUM_0>;
|
port = <I2S_NUM_0>;
|
||||||
@ -55,7 +47,7 @@
|
|||||||
pin-sclk = <&gpio0 40 GPIO_FLAG_NONE>;
|
pin-sclk = <&gpio0 40 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
uart1 {
|
uart0 {
|
||||||
compatible = "espressif,esp32-uart";
|
compatible = "espressif,esp32-uart";
|
||||||
port = <UART_NUM_1>;
|
port = <UART_NUM_1>;
|
||||||
pin-tx = <&gpio0 43 GPIO_FLAG_NONE>;
|
pin-tx = <&gpio0 43 GPIO_FLAG_NONE>;
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "devices/TpagerKeyboard.h"
|
#include "devices/TpagerKeyboard.h"
|
||||||
#include "devices/TpagerPower.h"
|
#include "devices/TpagerPower.h"
|
||||||
#include <driver/gpio.h>
|
#include <driver/gpio.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
#include <Tactility/hal/Configuration.h>
|
#include <Tactility/hal/Configuration.h>
|
||||||
#include <Bq25896.h>
|
#include <Bq25896.h>
|
||||||
@ -14,17 +15,18 @@ bool tpagerInit();
|
|||||||
using namespace tt::hal;
|
using namespace tt::hal;
|
||||||
|
|
||||||
static DeviceVector createDevices() {
|
static DeviceVector createDevices() {
|
||||||
auto bq27220 = std::make_shared<Bq27220>(I2C_NUM_0);
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
auto bq27220 = std::make_shared<Bq27220>(i2c);
|
||||||
auto power = std::make_shared<TpagerPower>(bq27220);
|
auto power = std::make_shared<TpagerPower>(bq27220);
|
||||||
|
|
||||||
auto tca8418 = std::make_shared<Tca8418>(I2C_NUM_0);
|
auto tca8418 = std::make_shared<Tca8418>(i2c);
|
||||||
auto keyboard = std::make_shared<TpagerKeyboard>(tca8418);
|
auto keyboard = std::make_shared<TpagerKeyboard>(tca8418);
|
||||||
|
|
||||||
return std::vector<std::shared_ptr<tt::hal::Device>> {
|
return std::vector<std::shared_ptr<tt::hal::Device>> {
|
||||||
tca8418,
|
tca8418,
|
||||||
std::make_shared<Bq25896>(I2C_NUM_0),
|
std::make_shared<Bq25896>(i2c),
|
||||||
bq27220,
|
bq27220,
|
||||||
std::make_shared<Drv2605>(I2C_NUM_0),
|
std::make_shared<Drv2605>(i2c),
|
||||||
power,
|
power,
|
||||||
createTpagerSdCard(),
|
createTpagerSdCard(),
|
||||||
createDisplay(),
|
createDisplay(),
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
#include "TpagerKeyboard.h"
|
#include "TpagerKeyboard.h"
|
||||||
|
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
|
|
||||||
#include <driver/i2c.h>
|
#include <driver/i2c.h>
|
||||||
@ -156,7 +155,7 @@ bool TpagerKeyboard::stopLvgl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TpagerKeyboard::isAttached() const {
|
bool TpagerKeyboard::isAttached() const {
|
||||||
return tt::hal::i2c::masterHasDeviceAtAddress(keypad->getPort(), keypad->getAddress(), 100);
|
return i2c_controller_has_device_at_address(keypad->getController(), keypad->getAddress(), 100) == ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TpagerKeyboard::initBacklight(gpio_num_t pin, uint32_t frequencyHz, ledc_timer_t timer, ledc_channel_t channel) {
|
bool TpagerKeyboard::initBacklight(gpio_num_t pin, uint32_t frequencyHz, ledc_timer_t timer, ledc_channel_t channel) {
|
||||||
|
|||||||
@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
static const auto LOGGER = tt::Logger("TpagerPower");
|
static const auto LOGGER = tt::Logger("TpagerPower");
|
||||||
|
|
||||||
constexpr auto TPAGER_GAUGE_I2C_BUS_HANDLE = I2C_NUM_0;
|
|
||||||
|
|
||||||
TpagerPower::~TpagerPower() {}
|
TpagerPower::~TpagerPower() {}
|
||||||
|
|
||||||
bool TpagerPower::supportsMetric(MetricType type) const {
|
bool TpagerPower::supportsMetric(MetricType type) const {
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "devices/CardputerPower.h"
|
#include "devices/CardputerPower.h"
|
||||||
#include <driver/gpio.h>
|
#include <driver/gpio.h>
|
||||||
|
|
||||||
|
#include <tactility/device.h>
|
||||||
#include <Tactility/hal/Configuration.h>
|
#include <Tactility/hal/Configuration.h>
|
||||||
|
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
@ -16,7 +17,7 @@ static bool initBoot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static DeviceVector createDevices() {
|
static DeviceVector createDevices() {
|
||||||
auto tca8418 = std::make_shared<Tca8418>(I2C_NUM_0);
|
auto tca8418 = std::make_shared<Tca8418>(device_find_by_name("i2c_internal"));
|
||||||
return {
|
return {
|
||||||
createSdCard(),
|
createSdCard(),
|
||||||
createDisplay(),
|
createDisplay(),
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
#include "CardputerKeyboard.h"
|
#include "CardputerKeyboard.h"
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
|
|
||||||
constexpr auto* TAG = "CardputerKeyb";
|
constexpr auto* TAG = "CardputerKeyb";
|
||||||
|
|
||||||
constexpr auto BACKLIGHT = GPIO_NUM_46;
|
|
||||||
|
|
||||||
constexpr auto KB_ROWS = 14;
|
constexpr auto KB_ROWS = 14;
|
||||||
constexpr auto KB_COLS = 4;
|
constexpr auto KB_COLS = 4;
|
||||||
|
|
||||||
@ -151,5 +149,5 @@ bool CardputerKeyboard::stopLvgl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CardputerKeyboard::isAttached() const {
|
bool CardputerKeyboard::isAttached() const {
|
||||||
return tt::hal::i2c::masterHasDeviceAtAddress(keypad->getPort(), keypad->getAddress(), 100);
|
return i2c_controller_has_device_at_address(keypad->getController(), keypad->getAddress(), 100) == ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@ -36,12 +37,14 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_port_a {
|
port_a: grove0 {
|
||||||
compatible = "espressif,esp32-i2c";
|
compatible = "espressif,esp32-grove";
|
||||||
port = <I2C_NUM_1>;
|
defaultMode = <GROVE_MODE_I2C>;
|
||||||
clock-frequency = <400000>;
|
pinSdaRx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||||
pin-sda = <&gpio0 2 GPIO_FLAG_NONE>;
|
pinSclTx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||||
pin-scl = <&gpio0 1 GPIO_FLAG_NONE>;
|
uartPort = <UART_NUM_1>;
|
||||||
|
i2cPort = <I2C_NUM_1>;
|
||||||
|
i2cClockFrequency = <400000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
display_spi: spi0 {
|
display_spi: spi0 {
|
||||||
@ -68,12 +71,4 @@
|
|||||||
pin-data-out = <&gpio0 42 GPIO_FLAG_NONE>;
|
pin-data-out = <&gpio0 42 GPIO_FLAG_NONE>;
|
||||||
pin-data-in = <&gpio0 46 GPIO_FLAG_NONE>;
|
pin-data-in = <&gpio0 46 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
uart_port_a: uart1 {
|
|
||||||
compatible = "espressif,esp32-uart";
|
|
||||||
status = "disabled";
|
|
||||||
port = <UART_NUM_1>;
|
|
||||||
pin-tx = <&gpio0 1 GPIO_FLAG_NONE>;
|
|
||||||
pin-rx = <&gpio0 2 GPIO_FLAG_NONE>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@ -22,12 +23,14 @@
|
|||||||
gpio-count = <49>;
|
gpio-count = <49>;
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_port_a {
|
port_a: grove0 {
|
||||||
compatible = "espressif,esp32-i2c";
|
compatible = "espressif,esp32-grove";
|
||||||
port = <I2C_NUM_0>;
|
defaultMode = <GROVE_MODE_I2C>;
|
||||||
clock-frequency = <400000>;
|
pinSdaRx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||||
pin-sda = <&gpio0 2 GPIO_FLAG_NONE>;
|
pinSclTx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||||
pin-scl = <&gpio0 1 GPIO_FLAG_NONE>;
|
uartPort = <UART_NUM_1>;
|
||||||
|
i2cPort = <I2C_NUM_0>;
|
||||||
|
i2cClockFrequency = <400000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
display_spi: spi0 {
|
display_spi: spi0 {
|
||||||
@ -55,12 +58,4 @@
|
|||||||
pin-data-out = <&gpio0 42 GPIO_FLAG_NONE>;
|
pin-data-out = <&gpio0 42 GPIO_FLAG_NONE>;
|
||||||
pin-data-in = <&gpio0 46 GPIO_FLAG_NONE>;
|
pin-data-in = <&gpio0 46 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
uart_port_a: uart1 {
|
|
||||||
compatible = "espressif,esp32-uart";
|
|
||||||
status = "disabled";
|
|
||||||
port = <UART_NUM_1>;
|
|
||||||
pin-tx = <&gpio0 1 GPIO_FLAG_NONE>;
|
|
||||||
pin-rx = <&gpio0 2 GPIO_FLAG_NONE>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
#include <Axp192.h>
|
#include <Axp192.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
static std::shared_ptr<Axp192> axp192 = nullptr;
|
static std::shared_ptr<Axp192> axp192 = nullptr;
|
||||||
|
|
||||||
std::shared_ptr<Axp192> createAxp192() {
|
std::shared_ptr<Axp192> createAxp192() {
|
||||||
assert(axp192 == nullptr);
|
assert(axp192 == nullptr);
|
||||||
auto configuration = std::make_unique<Axp192::Configuration>(I2C_NUM_0);
|
auto configuration = std::make_unique<Axp192::Configuration>(device_find_by_name("i2c_internal"));
|
||||||
axp192 = std::make_shared<Axp192>(std::move(configuration));
|
axp192 = std::make_shared<Axp192>(std::move(configuration));
|
||||||
return axp192;
|
return axp192;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@ -37,12 +38,14 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_port_a {
|
port_a: grove0 {
|
||||||
compatible = "espressif,esp32-i2c";
|
compatible = "espressif,esp32-grove";
|
||||||
port = <I2C_NUM_1>;
|
defaultMode = <GROVE_MODE_I2C>;
|
||||||
clock-frequency = <400000>;
|
pinSdaRx = <&gpio0 32 GPIO_FLAG_NONE>;
|
||||||
pin-sda = <&gpio0 32 GPIO_FLAG_NONE>;
|
pinSclTx = <&gpio0 33 GPIO_FLAG_NONE>;
|
||||||
pin-scl = <&gpio0 33 GPIO_FLAG_NONE>;
|
uartPort = <UART_NUM_1>;
|
||||||
|
i2cPort = <I2C_NUM_1>;
|
||||||
|
i2cClockFrequency = <400000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
spi0 {
|
spi0 {
|
||||||
@ -63,12 +66,4 @@
|
|||||||
pin-data-out = <&gpio0 2 GPIO_FLAG_NONE>;
|
pin-data-out = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||||
pin-data-in = <&gpio0 34 GPIO_FLAG_NONE>;
|
pin-data-in = <&gpio0 34 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
uart_port_a: uart1 {
|
|
||||||
compatible = "espressif,esp32-uart";
|
|
||||||
status = "disabled";
|
|
||||||
port = <UART_NUM_1>;
|
|
||||||
pin-tx = <&gpio0 33 GPIO_FLAG_NONE>;
|
|
||||||
pin-rx = <&gpio0 32 GPIO_FLAG_NONE>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -146,8 +146,9 @@ bool initPowerControl() {
|
|||||||
bool initBoot() {
|
bool initBoot() {
|
||||||
LOGGER.info("initBoot()");
|
LOGGER.info("initBoot()");
|
||||||
|
|
||||||
axp2101 = std::make_shared<Axp2101>(I2C_NUM_0);
|
auto controller = device_find_by_name("i2c_internal");
|
||||||
aw9523 = std::make_shared<Aw9523>(I2C_NUM_0);
|
axp2101 = std::make_shared<Axp2101>(controller);
|
||||||
|
aw9523 = std::make_shared<Aw9523>(controller);
|
||||||
|
|
||||||
return initPowerControl() && initGpioExpander();
|
return initPowerControl() && initGpioExpander();
|
||||||
}
|
}
|
||||||
@ -4,14 +4,17 @@
|
|||||||
#include <Ft5x06Touch.h>
|
#include <Ft5x06Touch.h>
|
||||||
#include <Ili934xDisplay.h>
|
#include <Ili934xDisplay.h>
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
|
||||||
|
#include <tactility/check.h>
|
||||||
|
|
||||||
static const auto LOGGER = tt::Logger("CoreS3Display");
|
static const auto LOGGER = tt::Logger("CoreS3Display");
|
||||||
|
|
||||||
static void setBacklightDuty(uint8_t backlightDuty) {
|
static void setBacklightDuty(uint8_t backlightDuty) {
|
||||||
const uint8_t voltage = 20 + ((8 * backlightDuty) / 255); // [0b00000, 0b11100] - under 20 is too dark
|
const uint8_t voltage = 20 + ((8 * backlightDuty) / 255); // [0b00000, 0b11100] - under 20 is too dark
|
||||||
// TODO: Refactor to use Axp2102 driver subproject. Reference: https://github.com/m5stack/M5Unified/blob/b8cfec7fed046242da7f7b8024a4e92004a51ff7/src/utility/AXP2101_Class.cpp#L42
|
// TODO: Refactor to use Axp2102 driver subproject. Reference: https://github.com/m5stack/M5Unified/blob/b8cfec7fed046242da7f7b8024a4e92004a51ff7/src/utility/AXP2101_Class.cpp#L42
|
||||||
if (!tt::hal::i2c::masterWriteRegister(I2C_NUM_0, AXP2101_ADDRESS, 0x99, &voltage, 1, 1000)) { // Sets DLD01
|
auto controller = device_find_by_name("i2c_internal");
|
||||||
|
check(controller);
|
||||||
|
if (i2c_controller_write_register(controller, AXP2101_ADDRESS, 0x99, &voltage, 1, 1000) != ERROR_NONE) { // Sets DLD01
|
||||||
LOGGER.error("Failed to set display backlight voltage");
|
LOGGER.error("Failed to set display backlight voltage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@ -42,30 +43,34 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_port_a {
|
port_a: grove0 {
|
||||||
compatible = "espressif,esp32-i2c";
|
compatible = "espressif,esp32-grove";
|
||||||
port = <I2C_NUM_1>;
|
defaultMode = <GROVE_MODE_I2C>;
|
||||||
clock-frequency = <400000>;
|
pinSdaRx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||||
pin-sda = <&gpio0 2 GPIO_FLAG_NONE>;
|
pinSclTx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||||
pin-scl = <&gpio0 1 GPIO_FLAG_NONE>;
|
uartPort = <UART_NUM_1>;
|
||||||
|
i2cPort = <I2C_NUM_1>;
|
||||||
|
i2cClockFrequency = <400000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_port_b {
|
port_b: grove1 {
|
||||||
compatible = "espressif,esp32-i2c";
|
compatible = "espressif,esp32-grove";
|
||||||
status = "disabled";
|
defaultMode = <GROVE_MODE_UART>;
|
||||||
port = <I2C_NUM_1>;
|
pinSdaRx = <&gpio0 9 GPIO_FLAG_NONE>;
|
||||||
clock-frequency = <400000>;
|
pinSclTx = <&gpio0 8 GPIO_FLAG_NONE>;
|
||||||
pin-sda = <&gpio0 9 GPIO_FLAG_NONE>;
|
uartPort = <UART_NUM_1>;
|
||||||
pin-scl = <&gpio0 8 GPIO_FLAG_NONE>;
|
i2cPort = <I2C_NUM_1>;
|
||||||
|
i2cClockFrequency = <400000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_port_c {
|
port_c: grove2 {
|
||||||
compatible = "espressif,esp32-i2c";
|
compatible = "espressif,esp32-grove";
|
||||||
status = "disabled";
|
defaultMode = <GROVE_MODE_UART>;
|
||||||
port = <I2C_NUM_1>;
|
pinSdaRx = <&gpio0 17 GPIO_FLAG_NONE>;
|
||||||
clock-frequency = <400000>;
|
pinSclTx = <&gpio0 18 GPIO_FLAG_NONE>;
|
||||||
pin-sda = <&gpio0 18 GPIO_FLAG_NONE>;
|
uartPort = <UART_NUM_2>;
|
||||||
pin-scl = <&gpio0 17 GPIO_FLAG_NONE>;
|
i2cPort = <I2C_NUM_1>;
|
||||||
|
i2cClockFrequency = <400000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
spi0 {
|
spi0 {
|
||||||
@ -89,12 +94,4 @@
|
|||||||
pin-data-in = <&gpio0 14 GPIO_FLAG_NONE>;
|
pin-data-in = <&gpio0 14 GPIO_FLAG_NONE>;
|
||||||
pin-mclk = <&gpio0 0 GPIO_FLAG_NONE>;
|
pin-mclk = <&gpio0 0 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
uart_port_a: uart1 {
|
|
||||||
compatible = "espressif,esp32-uart";
|
|
||||||
status = "disabled";
|
|
||||||
port = <UART_NUM_1>;
|
|
||||||
pin-tx = <&gpio0 1 GPIO_FLAG_NONE>;
|
|
||||||
pin-rx = <&gpio0 2 GPIO_FLAG_NONE>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <EpdiyDisplayHelper.h>
|
#include <EpdiyDisplayHelper.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
|
auto* i2c = device_find_by_name("i2c_internal");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
540,
|
540,
|
||||||
960,
|
960,
|
||||||
true, // swapXy
|
true, // swapXy
|
||||||
|
|||||||
@ -231,7 +231,7 @@ bool initBoot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Keep Axp2101 C++ wrapper alive for Axp2101Power (backlight + battery)
|
// Keep Axp2101 C++ wrapper alive for Axp2101Power (backlight + battery)
|
||||||
axp2101 = std::make_shared<Axp2101>(I2C_NUM_0);
|
axp2101 = std::make_shared<Axp2101>(i2c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,13 +4,16 @@
|
|||||||
#include <Ft6x36Touch.h>
|
#include <Ft6x36Touch.h>
|
||||||
#include <Ili934xDisplay.h>
|
#include <Ili934xDisplay.h>
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
|
||||||
|
#include <tactility/check.h>
|
||||||
|
|
||||||
static const auto LOGGER = tt::Logger("StackChanDisplay");
|
static const auto LOGGER = tt::Logger("StackChanDisplay");
|
||||||
|
|
||||||
static void setBacklightDuty(uint8_t backlightDuty) {
|
static void setBacklightDuty(uint8_t backlightDuty) {
|
||||||
const uint8_t voltage = 20 + ((8 * backlightDuty) / 255); // [0b00000, 0b11100]
|
const uint8_t voltage = 20 + ((8 * backlightDuty) / 255); // [0b00000, 0b11100]
|
||||||
if (!tt::hal::i2c::masterWriteRegister(I2C_NUM_0, AXP2101_ADDRESS, 0x99, &voltage, 1, 1000)) {
|
auto controller = device_find_by_name("i2c_internal");
|
||||||
|
check(controller);
|
||||||
|
if (i2c_controller_write_register(controller, AXP2101_ADDRESS, 0x99, &voltage, 1, 1000) != ERROR_NONE) { // Sets DLD01
|
||||||
LOGGER.error("Failed to set display backlight voltage");
|
LOGGER.error("Failed to set display backlight voltage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_ble.h>
|
#include <tactility/bindings/esp32_ble.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
|
#include <tactility/bindings/esp32_grove.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
@ -67,30 +68,43 @@
|
|||||||
// TODO: BMM150 magnetometer @ 0x10 — accessible only via BMI270 aux I2C
|
// TODO: BMM150 magnetometer @ 0x10 — accessible only via BMI270 aux I2C
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_port_a {
|
// TODO: Servo UART (SCS9009, 1 Mbaud) — TX=GPIO6, RX=GPIO7
|
||||||
compatible = "espressif,esp32-i2c";
|
uart_port_a: uart1 {
|
||||||
port = <I2C_NUM_1>;
|
compatible = "espressif,esp32-uart";
|
||||||
clock-frequency = <400000>;
|
status = "disabled";
|
||||||
pin-sda = <&gpio0 2 GPIO_FLAG_NONE>;
|
port = <UART_NUM_1>;
|
||||||
pin-scl = <&gpio0 1 GPIO_FLAG_NONE>;
|
pin-tx = <&gpio0 6 GPIO_FLAG_NONE>;
|
||||||
|
pin-rx = <&gpio0 7 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_port_b {
|
port_a: grove0 {
|
||||||
compatible = "espressif,esp32-i2c";
|
compatible = "espressif,esp32-grove";
|
||||||
status = "disabled";
|
defaultMode = <GROVE_MODE_I2C>;
|
||||||
port = <I2C_NUM_1>;
|
pinSdaRx = <&gpio0 2 GPIO_FLAG_NONE>;
|
||||||
clock-frequency = <400000>;
|
pinSclTx = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||||
pin-sda = <&gpio0 9 GPIO_FLAG_NONE>;
|
uartPort = <UART_NUM_2>;
|
||||||
pin-scl = <&gpio0 8 GPIO_FLAG_NONE>;
|
i2cPort = <I2C_NUM_1>;
|
||||||
|
i2cClockFrequency = <400000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_port_c {
|
port_b: grove1 {
|
||||||
compatible = "espressif,esp32-i2c";
|
compatible = "espressif,esp32-grove";
|
||||||
status = "disabled";
|
defaultMode = <GROVE_MODE_UART>;
|
||||||
port = <I2C_NUM_1>;
|
pinSdaRx = <&gpio0 9 GPIO_FLAG_NONE>;
|
||||||
clock-frequency = <400000>;
|
pinSclTx = <&gpio0 8 GPIO_FLAG_NONE>;
|
||||||
pin-sda = <&gpio0 18 GPIO_FLAG_NONE>;
|
uartPort = <UART_NUM_2>;
|
||||||
pin-scl = <&gpio0 17 GPIO_FLAG_NONE>;
|
i2cPort = <I2C_NUM_1>;
|
||||||
|
i2cClockFrequency = <400000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
port_c: grove2 {
|
||||||
|
compatible = "espressif,esp32-grove";
|
||||||
|
defaultMode = <GROVE_MODE_DISABLED>;
|
||||||
|
pinSdaRx = <&gpio0 17 GPIO_FLAG_NONE>;
|
||||||
|
pinSclTx = <&gpio0 18 GPIO_FLAG_NONE>;
|
||||||
|
uartPort = <UART_NUM_2>;
|
||||||
|
i2cPort = <I2C_NUM_1>;
|
||||||
|
i2cClockFrequency = <400000>;
|
||||||
};
|
};
|
||||||
|
|
||||||
spi0 {
|
spi0 {
|
||||||
@ -111,13 +125,4 @@
|
|||||||
pin-data-in = <&gpio0 14 GPIO_FLAG_NONE>;
|
pin-data-in = <&gpio0 14 GPIO_FLAG_NONE>;
|
||||||
pin-mclk = <&gpio0 0 GPIO_FLAG_NONE>;
|
pin-mclk = <&gpio0 0 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Servo UART (SCS9009, 1 Mbaud) — TX=GPIO6, RX=GPIO7
|
|
||||||
uart_port_a: uart1 {
|
|
||||||
compatible = "espressif,esp32-uart";
|
|
||||||
status = "disabled";
|
|
||||||
port = <UART_NUM_1>;
|
|
||||||
pin-tx = <&gpio0 1 GPIO_FLAG_NONE>;
|
|
||||||
pin-rx = <&gpio0 2 GPIO_FLAG_NONE>;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
#include <Axp192.h>
|
#include <Axp192.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
static std::shared_ptr<Axp192> axp192 = nullptr;
|
static std::shared_ptr<Axp192> axp192 = nullptr;
|
||||||
|
|
||||||
std::shared_ptr<Axp192> createAxp192() {
|
std::shared_ptr<Axp192> createAxp192() {
|
||||||
assert(axp192 == nullptr);
|
assert(axp192 == nullptr);
|
||||||
auto configuration = std::make_unique<Axp192::Configuration>(I2C_NUM_0);
|
auto configuration = std::make_unique<Axp192::Configuration>(device_find_by_name("i2c_internal"));
|
||||||
axp192 = std::make_shared<Axp192>(std::move(configuration));
|
axp192 = std::make_shared<Axp192>(std::move(configuration));
|
||||||
return axp192;
|
return axp192;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
#include <tactility/drivers/i2c_controller.h>
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
|
|
||||||
#include <Tactility/hal/Configuration.h>
|
#include <Tactility/hal/Configuration.h>
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
|
||||||
|
|
||||||
using namespace tt::hal;
|
using namespace tt::hal;
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,8 @@
|
|||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/hal/gpio/Gpio.h>
|
#include <Tactility/hal/gpio/Gpio.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
#include <freertos/FreeRTOS.h>
|
#include <freertos/FreeRTOS.h>
|
||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
|
|
||||||
@ -19,8 +21,10 @@ constexpr auto LCD_PIN_RESET = GPIO_NUM_NC;
|
|||||||
constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_22;
|
constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_22;
|
||||||
|
|
||||||
static std::shared_ptr<tt::hal::touch::TouchDevice> createGt911Touch() {
|
static std::shared_ptr<tt::hal::touch::TouchDevice> createGt911Touch() {
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
720,
|
720,
|
||||||
1280,
|
1280,
|
||||||
false, // swapXY
|
false, // swapXY
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "UnPhoneFeatures.h"
|
#include "UnPhoneFeatures.h"
|
||||||
|
#include <tactility/device.h>
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/LogMessages.h>
|
#include <Tactility/LogMessages.h>
|
||||||
#include <Tactility/Preferences.h>
|
#include <Tactility/Preferences.h>
|
||||||
@ -160,7 +161,7 @@ static bool unPhonePowerOn() {
|
|||||||
bootStats.printInfo();
|
bootStats.printInfo();
|
||||||
bootStats.notifyBootStart();
|
bootStats.notifyBootStart();
|
||||||
|
|
||||||
bq24295 = std::make_shared<Bq24295>(I2C_NUM_0);
|
bq24295 = std::make_shared<Bq24295>(device_find_by_name("i2c_internal"));
|
||||||
|
|
||||||
unPhoneFeatures = std::make_shared<UnPhoneFeatures>(bq24295);
|
unPhoneFeatures = std::make_shared<UnPhoneFeatures>(bq24295);
|
||||||
|
|
||||||
|
|||||||
@ -2,12 +2,16 @@
|
|||||||
|
|
||||||
#include <Gt911Touch.h>
|
#include <Gt911Touch.h>
|
||||||
#include <RgbDisplay.h>
|
#include <RgbDisplay.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
|
||||||
// Note for future changes: Reset pin is 38 and interrupt pin is 18
|
// Note for future changes: Reset pin is 38 and interrupt pin is 18
|
||||||
// or INT = NC, schematic and other info floating around is kinda conflicting...
|
// or INT = NC, schematic and other info floating around is kinda conflicting...
|
||||||
|
auto* i2c = device_find_by_name("i2c0");
|
||||||
|
check(i2c);
|
||||||
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
auto configuration = std::make_unique<Gt911Touch::Configuration>(
|
||||||
I2C_NUM_0,
|
i2c,
|
||||||
800,
|
800,
|
||||||
480
|
480
|
||||||
);
|
);
|
||||||
|
|||||||
145
Documentation/README.md
Normal file
145
Documentation/README.md
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
Tactility is an operating system for the ESP32 microcontroller family. It runs on 40+ supported devices (CYD boards, LilyGO, M5Stack, Elecrow, etc.) and includes a desktop simulator. Built with C++23, ESP-IDF, LVGL, and FreeRTOS.
|
||||||
|
|
||||||
|
## Build Commands
|
||||||
|
|
||||||
|
### Simulator (Linux/macOS, no ESP-IDF needed)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B buildsim -G Ninja
|
||||||
|
ninja -C buildsim # build firmware + tests
|
||||||
|
./buildsim/Firmware/Tactility # run simulator
|
||||||
|
```
|
||||||
|
|
||||||
|
### ESP32 firmware
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python device.py <device-id> # generate sdkconfig for device (e.g. lilygo-tdeck)
|
||||||
|
python device.py <device-id> --dev # dev mode: force 4MB partition table
|
||||||
|
idf.py build # build firmware
|
||||||
|
idf.py flash monitor # flash and monitor
|
||||||
|
```
|
||||||
|
|
||||||
|
Device IDs are the folder names under `Devices/` (e.g. `lilygo-tdeck`, `m5stack-cores3`, `cyd-2432s028r`).
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
Tests use Doctest and run on simulator (POSIX) target only:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B buildsim -G Ninja
|
||||||
|
ninja -C buildsim build-tests
|
||||||
|
cd buildsim && ctest # run all tests
|
||||||
|
./buildsim/Tests/TactilityCore/TactilityCoreTests # run a single test suite
|
||||||
|
./buildsim/Tests/TactilityKernel/TactilityKernelTests
|
||||||
|
./buildsim/Tests/Tactility/TactilityTests
|
||||||
|
./buildsim/Tests/TactilityFreeRtos/TactilityFreeRtosTests
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Layer Stack (bottom to top)
|
||||||
|
|
||||||
|
- **TactilityKernel** — C API kernel: device/driver/module lifecycle, concurrency primitives (thread, mutex, timer, dispatcher), filesystem, logging. Header convention: `<tactility/*.h>` (lowercase snake_case).
|
||||||
|
- **TactilityCore** — Former kernel subproject. Deprecated, replaced by TactilityKernel. Contains C++ utilities: Bundle (key-value data), string helpers, file I/O, crypto. Header convention: `<Tactility/*.h>` (UpperCamelCase).
|
||||||
|
- **TactilityFreeRtos** — Thin C++ wrappers around FreeRTOS primitives.
|
||||||
|
- **Tactility** — Main OS layer: app framework, service framework, HAL (deprecated, replaced by TactilityKernel), LVGL integration, networking and services (Wi-Fi, BLE, NTP, ESP-NOW), settings, i18n.
|
||||||
|
- **TactilityC** — C bindings (`tt_*.h`) for TactilityCore and Tactility subprojects, used by side-loaded ELF apps on ESP32. Deprecated, replaced by TactilityKernel.
|
||||||
|
- **Firmware** — Entry point (`app_main`).
|
||||||
|
|
||||||
|
### Device/Driver/Module System (kernel layer, C API)
|
||||||
|
|
||||||
|
The kernel uses a Linux-inspired device model:
|
||||||
|
|
||||||
|
- **Module** (`struct Module`): loadable unit that registers drivers and hardware. Lifecycle: `module_construct` → `module_add` → `module_start`. Each device board and platform is a module.
|
||||||
|
- **Driver** (`struct Driver`): binds to devices via `compatible` strings (like devicetree). Has `start_device`/`stop_device` callbacks and an `api` pointer for type-specific operations.
|
||||||
|
- **Device** (`struct Device`): represents hardware. Lifecycle: `device_construct` → `device_add` → `device_start`. Has a parent-child tree, driver binding, and locking.
|
||||||
|
- **DeviceType** (`struct DeviceType`): enables discovering devices by category (e.g. `DISPLAY_TYPE`, `TOUCH_TYPE`, `UART_CONTROLLER_TYPE`).
|
||||||
|
|
||||||
|
Devices are defined via **devicetree** `.dts` files in each `Devices/<id>/` folder. A custom devicetree compiler (`Buildscripts/DevicetreeCompiler/compile.py`) generates C code from these files. Each device folder also has a `devicetree.yaml` specifying dependencies and the `.dts` file.
|
||||||
|
|
||||||
|
### App Framework
|
||||||
|
|
||||||
|
Apps implement `tt::app::App` (or just provide callbacks). Each app has an `AppManifest` with `appId`, `appName`, `appCategory`, and a factory function `createApp`. Apps are registered at startup in `Tactility.cpp`. External apps can be loaded from SD card via `manifest.properties` files, or side-loaded as ELF binaries on ESP32.
|
||||||
|
|
||||||
|
### Service Framework
|
||||||
|
|
||||||
|
Services implement `tt::service::Service` with a `ServiceManifest`. Services are long-running background processes (GUI, Wi-Fi, loader, statusbar, GPS, etc.).
|
||||||
|
|
||||||
|
### HAL Layer
|
||||||
|
|
||||||
|
#### Deprecated HAL
|
||||||
|
|
||||||
|
Located in Tactility folder.
|
||||||
|
|
||||||
|
`tt::hal::Configuration` is declared per-device board (in `Devices/<id>/Source/Configuration.cpp`). It provides `initBoot` for early hardware setup and `createDevices` to instantiate HAL device wrappers (display, touch, power, keyboard, etc.).
|
||||||
|
|
||||||
|
#### Current HAL
|
||||||
|
|
||||||
|
Located in TactilityKernel. Based on Linux driver subsystems.
|
||||||
|
|
||||||
|
#### Driver
|
||||||
|
|
||||||
|
A driver generally consists of:
|
||||||
|
- Registration of driver in parent module (optional)
|
||||||
|
- YAML bindings in the `bindings/` folder
|
||||||
|
- An `#include` that is used in the `.dts` file. The include is in `[projectname]/bindings/[drivername].h`
|
||||||
|
- The driver implementation: a `.cpp` and `.h` file. The implementation is C++, but the header exposes pure C functions.
|
||||||
|
|
||||||
|
Drivers can be stored in:
|
||||||
|
- TactilityKernel
|
||||||
|
- A subproject in Platforms/ folder
|
||||||
|
- A subproject in Devices/ folder
|
||||||
|
- A subproject in Drivers/ folder. This is a kernel module. Naming is lower case and postfixed with `-module`
|
||||||
|
|
||||||
|
#### Kernel Modules
|
||||||
|
|
||||||
|
Projects that are kernel modules:
|
||||||
|
|
||||||
|
1. Declare a `struct Module`
|
||||||
|
2. Contain a `devicetree.yaml` file that declares a list of dependencies (for parsing the devicetree) and specifies the bindings folder that contains the drivers' YAML definitions. For example:
|
||||||
|
```yaml
|
||||||
|
dependencies:
|
||||||
|
- TactilityKernel
|
||||||
|
bindings: bindings
|
||||||
|
```
|
||||||
|
|
||||||
|
### Platform Abstraction
|
||||||
|
|
||||||
|
- `Platforms/platform-esp32/` — ESP-IDF specific implementations
|
||||||
|
- `Platforms/platform-posix/` — POSIX simulator implementations (SDL for display)
|
||||||
|
|
||||||
|
### Build System
|
||||||
|
|
||||||
|
The `tactility_add_module()` CMake macro (in `Buildscripts/module.cmake`) wraps ESP-IDF's `idf_component_register` on ESP32 and standard `add_library` on POSIX, allowing the same source to build for both targets.
|
||||||
|
|
||||||
|
`device.py` reads `Devices/<id>/device.properties` and generates the `sdkconfig` file with all necessary ESP-IDF config (target chip, flash size, SPIRAM, LVGL fonts, Bluetooth, USB, etc.).
|
||||||
|
|
||||||
|
### LVGL
|
||||||
|
|
||||||
|
User interfaces should scale well for everything between very large (e.g. 1280x720) and small (e.g. 135x240) displays. Vertical and horizontal layouts are supported.
|
||||||
|
|
||||||
|
## Coding Style
|
||||||
|
|
||||||
|
Two conventions coexist; which one to use depends on the project layer:
|
||||||
|
|
||||||
|
- **C code** (TactilityKernel, drivers): `lower_snake_case` for files, functions, variables. `UpperCamelCase` for types. Files in `source/`, `include/`, `private/` directories.
|
||||||
|
- **C++ code** (TactilityCore, Tactility, apps, services): `UpperCamelCase` for files and types. `lowerCamelCase` for functions. Files in `Source/`, `Include/`, `Private/` directories.
|
||||||
|
|
||||||
|
Formatting is enforced by `.clang-format` (LLVM-based, 4-space indent, no column limit).
|
||||||
|
Never throw exceptions — use return types for error handling. Use `enum class` over plain `enum`.
|
||||||
|
Don't do null checks: caller is responsible for passing valid data.
|
||||||
|
Pointers are expected to be non-null unless documented otherwise.
|
||||||
|
|
||||||
|
## Key Conventions
|
||||||
|
|
||||||
|
- `#ifdef ESP_PLATFORM` guards ESP32-specific code; the simulator uses POSIX equivalents.
|
||||||
|
- The `Drivers/` directory contains hardware drivers (display controllers, touch controllers, PMICs, etc.) — each is its own CMake component.
|
||||||
|
- `Modules/` contains cross-cutting modules: `hal-device-module` (device lifecycle) and `lvgl-module` (LVGL task management).
|
||||||
|
- `Data/system/` and `Data/data/` are flashed as FAT filesystem images on ESP32.
|
||||||
|
- Translations are in `Translations/` as CSV files, generated via `generate.py`.
|
||||||
@ -8,7 +8,7 @@ class Aw9523 : public tt::hal::i2c::I2cDevice {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit Aw9523(i2c_port_t port) : I2cDevice(port, AW9523_ADDRESS) {}
|
explicit Aw9523(::Device* controller) : I2cDevice(controller, AW9523_ADDRESS) {}
|
||||||
|
|
||||||
std::string getName() const final { return "AW9523"; }
|
std::string getName() const final { return "AW9523"; }
|
||||||
std::string getDescription() const final { return "GPIO expander with LED driver and I2C interface."; }
|
std::string getDescription() const final { return "GPIO expander with LED driver and I2C interface."; }
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <axp192/axp192.h>
|
#include <axp192/axp192.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
#include <Tactility/hal/power/PowerDevice.h>
|
#include <Tactility/hal/power/PowerDevice.h>
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ class Axp192 final : public tt::hal::power::PowerDevice {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
struct Configuration {
|
struct Configuration {
|
||||||
i2c_port_t port;
|
::Device* controller;
|
||||||
TickType_t readTimeout = 50 / portTICK_PERIOD_MS;
|
TickType_t readTimeout = 50 / portTICK_PERIOD_MS;
|
||||||
TickType_t writeTimeout = 50 / portTICK_PERIOD_MS;
|
TickType_t writeTimeout = 50 / portTICK_PERIOD_MS;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
#include "Axp192.h"
|
#include "Axp192.h"
|
||||||
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
|
|
||||||
constexpr auto TAG = "Axp192Power";
|
constexpr auto TAG = "Axp192Power";
|
||||||
|
|
||||||
int32_t Axp192::i2cRead(void* handle, uint8_t address, uint8_t reg, uint8_t* buffer, uint16_t size) {
|
int32_t Axp192::i2cRead(void* handle, uint8_t address, uint8_t reg, uint8_t* buffer, uint16_t size) {
|
||||||
const auto* device = static_cast<Axp192*>(handle);
|
const auto* device = static_cast<Axp192*>(handle);
|
||||||
if (tt::hal::i2c::masterReadRegister(device->configuration->port, address, reg, buffer, size, device->configuration->readTimeout)) {
|
if (i2c_controller_read_register(device->configuration->controller, address, reg, buffer, size, device->configuration->readTimeout) == ERROR_NONE) {
|
||||||
return AXP192_OK;
|
return AXP192_OK;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
@ -13,7 +14,7 @@ int32_t Axp192::i2cRead(void* handle, uint8_t address, uint8_t reg, uint8_t* buf
|
|||||||
|
|
||||||
int32_t Axp192::i2cWrite(void* handle, uint8_t address, uint8_t reg, const uint8_t* buffer, uint16_t size) {
|
int32_t Axp192::i2cWrite(void* handle, uint8_t address, uint8_t reg, const uint8_t* buffer, uint16_t size) {
|
||||||
const auto* device = static_cast<Axp192*>(handle);
|
const auto* device = static_cast<Axp192*>(handle);
|
||||||
if (tt::hal::i2c::masterWriteRegister(device->configuration->port, address, reg, buffer, size, device->configuration->writeTimeout)) {
|
if (i2c_controller_write_register(device->configuration->controller, address, reg, buffer, size, device->configuration->writeTimeout) == ERROR_NONE) {
|
||||||
return AXP192_OK;
|
return AXP192_OK;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@ -54,5 +54,5 @@ bool Axp2101::getVBusVoltage(float& out) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Axp2101::setRegisters(uint8_t* bytePairs, size_t bytePairsSize) const {
|
bool Axp2101::setRegisters(uint8_t* bytePairs, size_t bytePairsSize) const {
|
||||||
return tt::hal::i2c::masterWriteRegisterArray(port, address, bytePairs, bytePairsSize, DEFAULT_TIMEOUT);
|
return i2c_controller_write_register_array(controller, address, bytePairs, bytePairsSize, DEFAULT_TIMEOUT) == ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,7 @@ public:
|
|||||||
CHARGE_STATUS_STANDBY = 0b00
|
CHARGE_STATUS_STANDBY = 0b00
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Axp2101(i2c_port_t port) : I2cDevice(port, AXP2101_ADDRESS) {}
|
explicit Axp2101(::Device* controller) : I2cDevice(controller, AXP2101_ADDRESS) {}
|
||||||
|
|
||||||
std::string getName() const override { return "AXP2101"; }
|
std::string getName() const override { return "AXP2101"; }
|
||||||
std::string getDescription() const override { return "Power management with I2C interface."; }
|
std::string getDescription() const override { return "Power management with I2C interface."; }
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public:
|
|||||||
Enabled160s = 0b110000
|
Enabled160s = 0b110000
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit Bq24295(i2c_port_t port) : I2cDevice(port, BQ24295_ADDRESS) {}
|
explicit Bq24295(::Device* controller) : I2cDevice(controller, BQ24295_ADDRESS) {}
|
||||||
|
|
||||||
bool getWatchDogTimer(WatchDogTimer& out) const;
|
bool getWatchDogTimer(WatchDogTimer& out) const;
|
||||||
bool setWatchDogTimer(WatchDogTimer in) const;
|
bool setWatchDogTimer(WatchDogTimer in) const;
|
||||||
|
|||||||
@ -8,7 +8,7 @@ class Bq25896 final : public tt::hal::i2c::I2cDevice {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit Bq25896(i2c_port_t port) : I2cDevice(port, BQ25896_ADDRESS) {
|
explicit Bq25896(::Device* controller) : I2cDevice(controller, BQ25896_ADDRESS) {
|
||||||
powerOn();
|
powerOn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -89,7 +89,7 @@ public:
|
|||||||
|
|
||||||
std::string getDescription() const override { return "I2C-controlled CEDV battery fuel gauge"; }
|
std::string getDescription() const override { return "I2C-controlled CEDV battery fuel gauge"; }
|
||||||
|
|
||||||
explicit Bq27220(i2c_port_t port) : I2cDevice(port, BQ27220_ADDRESS), accessKey(0xFFFFFFFF) {}
|
explicit Bq27220(::Device* controller) : I2cDevice(controller, BQ27220_ADDRESS), accessKey(0xFFFFFFFF) {}
|
||||||
|
|
||||||
bool configureCapacity(uint16_t designCapacity, uint16_t fullChargeCapacity);
|
bool configureCapacity(uint16_t designCapacity, uint16_t fullChargeCapacity);
|
||||||
bool getVoltage(uint16_t &value);
|
bool getVoltage(uint16_t &value);
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
static const auto LOGGER = tt::Logger("DRV2605");
|
static const auto LOGGER = tt::Logger("DRV2605");
|
||||||
|
|
||||||
Drv2605::Drv2605(i2c_port_t port, bool autoPlayStartupBuzz) : I2cDevice(port, ADDRESS), autoPlayStartupBuzz(autoPlayStartupBuzz) {
|
Drv2605::Drv2605(::Device* controller, bool autoPlayStartupBuzz) : I2cDevice(controller, ADDRESS), autoPlayStartupBuzz(autoPlayStartupBuzz) {
|
||||||
check(init(), "Initialize DRV2605");
|
check(init(), "Initialize DRV2605");
|
||||||
|
|
||||||
if (autoPlayStartupBuzz) {
|
if (autoPlayStartupBuzz) {
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class Drv2605 : public tt::hal::i2c::I2cDevice {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit Drv2605(i2c_port_t port, bool autoPlayStartupBuzz = true);
|
explicit Drv2605(::Device* controller, bool autoPlayStartupBuzz = true);
|
||||||
|
|
||||||
std::string getName() const final { return "DRV2605"; }
|
std::string getName() const final { return "DRV2605"; }
|
||||||
std::string getDescription() const final { return "Haptic driver for ERM/LRA with waveform library & auto-resonance tracking"; }
|
std::string getDescription() const final { return "Haptic driver for ERM/LRA with waveform library & auto-resonance tracking"; }
|
||||||
|
|||||||
@ -1,31 +1,43 @@
|
|||||||
#include "Gt911Touch.h"
|
#include "Gt911Touch.h"
|
||||||
|
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
|
||||||
|
|
||||||
|
#include <esp_lcd_io_i2c.h>
|
||||||
#include <esp_lcd_touch_gt911.h>
|
#include <esp_lcd_touch_gt911.h>
|
||||||
#include <esp_err.h>
|
#include <esp_err.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/drivers/esp32_i2c.h>
|
||||||
|
#include <tactility/drivers/esp32_i2c_master.h>
|
||||||
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
|
|
||||||
static const auto LOGGER = tt::Logger("GT911");
|
static const auto LOGGER = tt::Logger("GT911");
|
||||||
|
|
||||||
bool Gt911Touch::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
|
bool Gt911Touch::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
|
||||||
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
|
esp_lcd_panel_io_i2c_config_t io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
|
||||||
|
|
||||||
/**
|
auto* i2c = configuration->i2cController;
|
||||||
* When the interrupt pin is low, the address is 0x5D. Otherwise it is 0x14.
|
|
||||||
* There is not reset pin, and the current driver fails when you only specify the interrupt pin.
|
if (i2c_controller_has_device_at_address(i2c, ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS, pdMS_TO_TICKS(10)) == ERROR_NONE) {
|
||||||
* Because of that, we don't use the interrupt pin and we'll simply scan the bus instead:
|
|
||||||
*/
|
|
||||||
if (tt::hal::i2c::masterHasDeviceAtAddress(configuration->port, ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS)) {
|
|
||||||
io_config.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS;
|
io_config.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS;
|
||||||
} else if (tt::hal::i2c::masterHasDeviceAtAddress(configuration->port, ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP)) {
|
} else if (i2c_controller_has_device_at_address(i2c, ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP, pdMS_TO_TICKS(10)) == ERROR_NONE) {
|
||||||
io_config.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP;
|
io_config.dev_addr = ESP_LCD_TOUCH_IO_I2C_GT911_ADDRESS_BACKUP;
|
||||||
} else {
|
} else {
|
||||||
LOGGER.error("No device found on I2C bus");
|
LOGGER.error("No device found on I2C bus");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return esp_lcd_new_panel_io_i2c(configuration->port, &io_config, &outHandle) == ESP_OK;
|
auto* driver = device_get_driver(i2c);
|
||||||
|
if (driver_is_compatible(driver, "espressif,esp32-i2c")) {
|
||||||
|
auto port = static_cast<const Esp32I2cConfig*>(i2c->config)->port;
|
||||||
|
return esp_lcd_new_panel_io_i2c_v1(port, &io_config, &outHandle) == ESP_OK;
|
||||||
|
} else if (driver_is_compatible(driver, "espressif,esp32-i2c-master")) {
|
||||||
|
auto bus = esp32_i2c_master_get_bus_handle(i2c);
|
||||||
|
return esp_lcd_new_panel_io_i2c_v2(bus, &io_config, &outHandle) == ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.error("Unsupported I2C driver");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Gt911Touch::createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& configuration, esp_lcd_touch_handle_t& panelHandle) {
|
bool Gt911Touch::createTouchHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_touch_config_t& configuration, esp_lcd_touch_handle_t& panelHandle) {
|
||||||
|
|||||||
@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
#include <Tactility/hal/touch/TouchDevice.h>
|
#include <Tactility/hal/touch/TouchDevice.h>
|
||||||
#include <Tactility/TactilityCore.h>
|
#include <Tactility/TactilityCore.h>
|
||||||
#include <driver/i2c.h>
|
|
||||||
|
|
||||||
#include <EspLcdTouch.h>
|
#include <EspLcdTouch.h>
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
|
||||||
class Gt911Touch final : public EspLcdTouch {
|
class Gt911Touch final : public EspLcdTouch {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -14,7 +15,7 @@ public:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
Configuration(
|
Configuration(
|
||||||
i2c_port_t port,
|
::Device* i2cController,
|
||||||
uint16_t xMax,
|
uint16_t xMax,
|
||||||
uint16_t yMax,
|
uint16_t yMax,
|
||||||
bool swapXy = false,
|
bool swapXy = false,
|
||||||
@ -24,7 +25,7 @@ public:
|
|||||||
gpio_num_t pinInterrupt = GPIO_NUM_NC,
|
gpio_num_t pinInterrupt = GPIO_NUM_NC,
|
||||||
unsigned int pinResetLevel = 0,
|
unsigned int pinResetLevel = 0,
|
||||||
unsigned int pinInterruptLevel = 0
|
unsigned int pinInterruptLevel = 0
|
||||||
) : port(port),
|
) : i2cController(i2cController),
|
||||||
xMax(xMax),
|
xMax(xMax),
|
||||||
yMax(yMax),
|
yMax(yMax),
|
||||||
swapXy(swapXy),
|
swapXy(swapXy),
|
||||||
@ -36,7 +37,7 @@ public:
|
|||||||
pinInterruptLevel(pinInterruptLevel)
|
pinInterruptLevel(pinInterruptLevel)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
i2c_port_t port;
|
::Device* i2cController;
|
||||||
uint16_t xMax;
|
uint16_t xMax;
|
||||||
uint16_t yMax;
|
uint16_t yMax;
|
||||||
bool swapXy;
|
bool swapXy;
|
||||||
|
|||||||
@ -45,7 +45,7 @@ public:
|
|||||||
|
|
||||||
std::string getDescription() const final { return "I2C-controlled keyboard scan IC"; }
|
std::string getDescription() const final { return "I2C-controlled keyboard scan IC"; }
|
||||||
|
|
||||||
explicit Tca8418(i2c_port_t port) : I2cDevice(port, TCA8418_ADDRESS) {
|
explicit Tca8418(::Device* controller) : I2cDevice(controller, TCA8418_ADDRESS) {
|
||||||
delta_micros = 0;
|
delta_micros = 0;
|
||||||
last_update_micros = 0;
|
last_update_micros = 0;
|
||||||
this_update_micros = 0;
|
this_update_micros = 0;
|
||||||
|
|||||||
29
Platforms/platform-esp32/bindings/espressif,esp32-grove.yaml
Normal file
29
Platforms/platform-esp32/bindings/espressif,esp32-grove.yaml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
description: ESP32 Grove Port
|
||||||
|
|
||||||
|
compatible: "espressif,esp32-grove"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
defaultMode:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: "One of enum Esp32GroveMode"
|
||||||
|
pinSdaRx:
|
||||||
|
type: phandle-array
|
||||||
|
required: true
|
||||||
|
description: SDA (I2C) or RX (UART) pin
|
||||||
|
pinSclTx:
|
||||||
|
type: phandle-array
|
||||||
|
required: true
|
||||||
|
description: SCL (I2C) or TX (UART) pin
|
||||||
|
uartPort:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: UART port number
|
||||||
|
i2cPort:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: I2C port number
|
||||||
|
i2cClockFrequency:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: I2C clock frequency
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tactility/bindings/bindings.h>
|
||||||
|
#include <tactility/drivers/esp32_grove.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEFINE_DEVICETREE(esp32_grove, struct Esp32GroveConfig)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <driver/uart.h>
|
||||||
|
#include <hal/i2c_types.h>
|
||||||
|
#include <tactility/drivers/gpio.h>
|
||||||
|
#include <tactility/drivers/grove.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Esp32GroveConfig {
|
||||||
|
enum GroveMode defaultMode;
|
||||||
|
struct GpioPinSpec pinSdaRx;
|
||||||
|
struct GpioPinSpec pinSclTx;
|
||||||
|
uart_port_t uartPort;
|
||||||
|
i2c_port_t i2cPort;
|
||||||
|
uint32_t i2cClockFrequency;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -2,12 +2,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <tactility/drivers/gpio.h>
|
#include <tactility/drivers/gpio.h>
|
||||||
#include <driver/i2c_types.h>
|
#include <driver/i2c_master.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
|
||||||
struct Esp32I2cMasterConfig {
|
struct Esp32I2cMasterConfig {
|
||||||
i2c_port_num_t port;
|
i2c_port_num_t port;
|
||||||
uint32_t clockFrequency;
|
uint32_t clockFrequency;
|
||||||
@ -16,6 +18,8 @@ struct Esp32I2cMasterConfig {
|
|||||||
struct GpioPinSpec pinScl;
|
struct GpioPinSpec pinScl;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
i2c_master_bus_handle_t esp32_i2c_master_get_bus_handle(struct Device* device);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
228
Platforms/platform-esp32/source/drivers/esp32_grove.cpp
Normal file
228
Platforms/platform-esp32/source/drivers/esp32_grove.cpp
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/drivers/esp32_grove.h>
|
||||||
|
#include <tactility/drivers/esp32_i2c.h>
|
||||||
|
#include <tactility/drivers/esp32_i2c_master.h>
|
||||||
|
#include <tactility/drivers/esp32_uart.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#define TAG "esp32_grove"
|
||||||
|
|
||||||
|
struct Esp32GroveInternal {
|
||||||
|
Device* child_device = nullptr;
|
||||||
|
void* child_config = nullptr;
|
||||||
|
char* child_name = nullptr;
|
||||||
|
GroveMode current_mode = GROVE_MODE_DISABLED;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GET_CONFIG(device) ((const struct Esp32GroveConfig*)device->config)
|
||||||
|
#define GET_DATA(device) ((struct Esp32GroveInternal*)device_get_driver_data(device))
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static error_t stop_child(Device* device) {
|
||||||
|
auto* data = GET_DATA(device);
|
||||||
|
if (!data) return ERROR_NONE;
|
||||||
|
|
||||||
|
if (data->child_device) {
|
||||||
|
if (data->child_device->internal) {
|
||||||
|
if (device_is_added(data->child_device)) {
|
||||||
|
if (device_is_ready(data->child_device)) {
|
||||||
|
if (device_stop(data->child_device) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "%s: failed to stop child device", device->name);
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (device_remove(data->child_device) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "%s: failed to remove child device", device->name);
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check(device_destruct(data->child_device) == ERROR_NONE);
|
||||||
|
}
|
||||||
|
delete data->child_device;
|
||||||
|
data->child_device = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->child_config) {
|
||||||
|
if (data->current_mode == GROVE_MODE_UART) {
|
||||||
|
delete static_cast<Esp32UartConfig*>(data->child_config);
|
||||||
|
} else if (data->current_mode == GROVE_MODE_I2C) {
|
||||||
|
delete static_cast<Esp32I2cMasterConfig*>(data->child_config);
|
||||||
|
}
|
||||||
|
data->child_config = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] data->child_name;
|
||||||
|
data->child_name = nullptr;
|
||||||
|
|
||||||
|
data->current_mode = GROVE_MODE_DISABLED;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t start_child(Device* device, GroveMode mode) {
|
||||||
|
const auto* config = GET_CONFIG(device);
|
||||||
|
auto* data = GET_DATA(device);
|
||||||
|
|
||||||
|
if (mode == GROVE_MODE_DISABLED) {
|
||||||
|
LOG_I(TAG, "%s: Grove port disabled", device->name);
|
||||||
|
data->current_mode = GROVE_MODE_DISABLED;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->child_device = new(std::nothrow) Device();
|
||||||
|
if (!data->child_device) {
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
std::memset(data->child_device, 0, sizeof(Device));
|
||||||
|
|
||||||
|
size_t name_len = std::strlen(device->name) + 10;
|
||||||
|
data->child_name = new(std::nothrow) char[name_len];
|
||||||
|
if (!data->child_name) {
|
||||||
|
delete data->child_device;
|
||||||
|
data->child_device = nullptr;
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->child_device->parent = device;
|
||||||
|
const char* compatible = nullptr;
|
||||||
|
|
||||||
|
if (mode == GROVE_MODE_UART) {
|
||||||
|
// Device name
|
||||||
|
std::snprintf(data->child_name, name_len, "%s_uart", device->name);
|
||||||
|
data->child_device->name = data->child_name;
|
||||||
|
// Device config
|
||||||
|
auto* uart_cfg = new(std::nothrow) struct Esp32UartConfig();
|
||||||
|
if (!uart_cfg) {
|
||||||
|
delete[] data->child_name;
|
||||||
|
data->child_name = nullptr;
|
||||||
|
delete data->child_device;
|
||||||
|
data->child_device = nullptr;
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
std::memset(uart_cfg, 0, sizeof(Esp32UartConfig));
|
||||||
|
uart_cfg->port = config->uartPort;
|
||||||
|
uart_cfg->pin_tx = config->pinSclTx;
|
||||||
|
uart_cfg->pin_rx = config->pinSdaRx;
|
||||||
|
uart_cfg->pin_cts = GPIO_PIN_SPEC_NONE;
|
||||||
|
uart_cfg->pin_rts = GPIO_PIN_SPEC_NONE;
|
||||||
|
data->child_config = uart_cfg;
|
||||||
|
compatible = "espressif,esp32-uart";
|
||||||
|
LOG_I(TAG, "%s: starting UART mode on port %d", device->name, (int)uart_cfg->port);
|
||||||
|
} else if (mode == GROVE_MODE_I2C) {
|
||||||
|
// Device name
|
||||||
|
std::snprintf(data->child_name, name_len, "%s_i2c", device->name);
|
||||||
|
data->child_device->name = data->child_name;
|
||||||
|
// Device config
|
||||||
|
auto* i2c_cfg = new (std::nothrow) struct Esp32I2cMasterConfig();
|
||||||
|
if (!i2c_cfg) {
|
||||||
|
delete[] data->child_name;
|
||||||
|
data->child_name = nullptr;
|
||||||
|
delete data->child_device;
|
||||||
|
data->child_device = nullptr;
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
std::memset(i2c_cfg, 0, sizeof(Esp32I2cMasterConfig));
|
||||||
|
i2c_cfg->port = static_cast<i2c_port_num_t>(config->i2cPort);
|
||||||
|
i2c_cfg->clockFrequency = config->i2cClockFrequency;
|
||||||
|
i2c_cfg->pinSda = config->pinSdaRx;
|
||||||
|
i2c_cfg->pinScl = config->pinSclTx;
|
||||||
|
// New driver seems to require pull-up setting
|
||||||
|
i2c_cfg->pinSda.flags |= GPIO_FLAG_PULL_UP;
|
||||||
|
i2c_cfg->pinScl.flags |= GPIO_FLAG_PULL_UP;
|
||||||
|
i2c_cfg->clkSource = 0; // Default
|
||||||
|
data->child_config = i2c_cfg;
|
||||||
|
compatible = "espressif,esp32-i2c-master";
|
||||||
|
LOG_I(TAG, "%s: starting I2C mode on port %d", device->name, (int)config->i2cPort);
|
||||||
|
} else {
|
||||||
|
LOG_E(TAG, "%s: unknown mode %d", device->name, mode);
|
||||||
|
if (data->child_name != nullptr) {
|
||||||
|
delete[] data->child_name;
|
||||||
|
data->child_name = nullptr;
|
||||||
|
}
|
||||||
|
delete data->child_device;
|
||||||
|
data->child_device = nullptr;
|
||||||
|
return ERROR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->child_device->config = data->child_config;
|
||||||
|
|
||||||
|
error_t err = device_construct_add_start(data->child_device, compatible);
|
||||||
|
if (err != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "%s: failed to start child device: %d", device->name, err);
|
||||||
|
stop_child(device);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->current_mode = mode;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t start_device(Device* device) {
|
||||||
|
const auto* config = GET_CONFIG(device);
|
||||||
|
|
||||||
|
auto* data = new(std::nothrow) Esp32GroveInternal();
|
||||||
|
if (!data) return ERROR_OUT_OF_MEMORY;
|
||||||
|
device_set_driver_data(device, data);
|
||||||
|
|
||||||
|
if (start_child(device, config->defaultMode) != ERROR_NONE) {
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
delete data;
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t stop_device(Device* device) {
|
||||||
|
auto* data = GET_DATA(device);
|
||||||
|
if (!data) return ERROR_NONE;
|
||||||
|
|
||||||
|
stop_child(device);
|
||||||
|
delete data;
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t esp32_grove_set_mode(Device* device, enum GroveMode mode) {
|
||||||
|
auto* data = GET_DATA(device);
|
||||||
|
if (data->current_mode == mode) return ERROR_NONE;
|
||||||
|
|
||||||
|
error_t err = stop_child(device);
|
||||||
|
if (err != ERROR_NONE) return err;
|
||||||
|
|
||||||
|
return start_child(device, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t esp32_grove_get_mode(Device* device, enum GroveMode* mode) {
|
||||||
|
auto* data = GET_DATA(device);
|
||||||
|
*mode = data->current_mode;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GroveApi esp32_grove_api = {
|
||||||
|
.set_mode = esp32_grove_set_mode,
|
||||||
|
.get_mode = esp32_grove_get_mode
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Module platform_esp32_module;
|
||||||
|
|
||||||
|
Driver esp32_grove_driver = {
|
||||||
|
.name = "esp32_grove",
|
||||||
|
.compatible = (const char*[]) { "espressif,esp32-grove", nullptr },
|
||||||
|
.start_device = start_device,
|
||||||
|
.stop_device = stop_device,
|
||||||
|
.api = &esp32_grove_api,
|
||||||
|
.device_type = &GROVE_TYPE,
|
||||||
|
.owner = &platform_esp32_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
@ -308,4 +308,8 @@ Driver esp32_i2c_master_driver = {
|
|||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
i2c_master_bus_handle_t esp32_i2c_master_get_bus_handle(Device* device) {
|
||||||
|
return GET_DATA(device)->bus_handle;
|
||||||
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@ -71,9 +71,7 @@ static error_t start_device(struct Device* device) {
|
|||||||
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
.intr_flags = ESP_INTR_FLAG_LEVEL1,
|
||||||
.enum_filter_cb = nullptr,
|
.enum_filter_cb = nullptr,
|
||||||
.fifo_settings_custom = {},
|
.fifo_settings_custom = {},
|
||||||
#if CONFIG_IDF_TARGET_ESP32P4
|
|
||||||
.peripheral_map = cfg->peripheral_map,
|
.peripheral_map = cfg->peripheral_map,
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
esp_err_t ret = usb_host_install(&host_cfg);
|
esp_err_t ret = usb_host_install(&host_cfg);
|
||||||
|
|||||||
@ -20,6 +20,7 @@ extern Driver esp32_sdmmc_driver;
|
|||||||
#endif
|
#endif
|
||||||
extern Driver esp32_spi_driver;
|
extern Driver esp32_spi_driver;
|
||||||
extern Driver esp32_uart_driver;
|
extern Driver esp32_uart_driver;
|
||||||
|
extern Driver esp32_grove_driver;
|
||||||
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||||
extern Driver esp32_bluetooth_driver;
|
extern Driver esp32_bluetooth_driver;
|
||||||
extern Driver esp32_ble_serial_driver;
|
extern Driver esp32_ble_serial_driver;
|
||||||
@ -45,6 +46,7 @@ static error_t start() {
|
|||||||
#endif
|
#endif
|
||||||
check(driver_construct_add(&esp32_spi_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_spi_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_uart_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_uart_driver) == ERROR_NONE);
|
||||||
|
check(driver_construct_add(&esp32_grove_driver) == ERROR_NONE);
|
||||||
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
#if defined(CONFIG_BT_NIMBLE_ENABLED)
|
||||||
check(driver_construct_add(&esp32_bluetooth_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_bluetooth_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_ble_serial_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_ble_serial_driver) == ERROR_NONE);
|
||||||
@ -84,6 +86,7 @@ static error_t stop() {
|
|||||||
#endif
|
#endif
|
||||||
check(driver_remove_destruct(&esp32_spi_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_spi_driver) == ERROR_NONE);
|
||||||
check(driver_remove_destruct(&esp32_uart_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_uart_driver) == ERROR_NONE);
|
||||||
|
check(driver_remove_destruct(&esp32_grove_driver) == ERROR_NONE);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,64 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "./I2cCompat.h"
|
|
||||||
#include "Tactility/Lock.h"
|
|
||||||
|
|
||||||
#include <Tactility/freertoscompat/RTOS.h>
|
|
||||||
|
|
||||||
#include <climits>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace tt::hal::i2c {
|
|
||||||
|
|
||||||
constexpr TickType_t defaultTimeout = 10 / portTICK_PERIOD_MS;
|
|
||||||
|
|
||||||
enum class Status {
|
|
||||||
Started,
|
|
||||||
Stopped,
|
|
||||||
Unknown
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Start the bus for the specified port. */
|
|
||||||
bool start(i2c_port_t port);
|
|
||||||
|
|
||||||
/** Stop the bus for the specified port. */
|
|
||||||
bool stop(i2c_port_t port);
|
|
||||||
|
|
||||||
/** @return true if the bus is started */
|
|
||||||
bool isStarted(i2c_port_t port);
|
|
||||||
|
|
||||||
/** @return name or nullptr */
|
|
||||||
const char* getName(i2c_port_t port);
|
|
||||||
|
|
||||||
/** Read bytes in master mode. */
|
|
||||||
bool masterRead(i2c_port_t port, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout = defaultTimeout);
|
|
||||||
|
|
||||||
/** Read bytes from the specified register in master mode. */
|
|
||||||
bool masterReadRegister(i2c_port_t port, uint8_t address, uint8_t reg, uint8_t* data, size_t dataSize, TickType_t timeout = defaultTimeout);
|
|
||||||
|
|
||||||
/** Write bytes in master mode. */
|
|
||||||
bool masterWrite(i2c_port_t port, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout = defaultTimeout);
|
|
||||||
|
|
||||||
/** Write bytes to a register in master mode */
|
|
||||||
bool masterWriteRegister(i2c_port_t port, uint8_t address, uint8_t reg, const uint8_t* data, uint16_t dataSize, TickType_t timeout = defaultTimeout);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write multiple values to multiple registers in master mode.
|
|
||||||
* The input is as follows: { register1, value1, register2, value2, ... }
|
|
||||||
* @return false if any of the write operations failed
|
|
||||||
*/
|
|
||||||
bool masterWriteRegisterArray(i2c_port_t port, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout = defaultTimeout);
|
|
||||||
|
|
||||||
/** Write bytes and then read the response bytes in master mode*/
|
|
||||||
bool masterWriteRead(i2c_port_t port, uint8_t address, const uint8_t* writeData, size_t writeDataSize, uint8_t* readData, size_t readDataSize, TickType_t timeout = defaultTimeout);
|
|
||||||
|
|
||||||
/** @return true when a device is detected at the specified address */
|
|
||||||
bool masterHasDeviceAtAddress(i2c_port_t port, uint8_t address, TickType_t timeout = defaultTimeout);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The lock for the specified bus.
|
|
||||||
* This can be used when calling native I2C functionality outside of Tactility.
|
|
||||||
*/
|
|
||||||
Lock& getLock(i2c_port_t port);
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
|
||||||
|
|
||||||
#include <hal/i2c_types.h>
|
|
||||||
#include <driver/i2c.h>
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
enum i2c_port_t {
|
|
||||||
I2C_NUM_0 = 0,
|
|
||||||
I2C_NUM_1,
|
|
||||||
LP_I2C_NUM_0,
|
|
||||||
I2C_NUM_MAX,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum i2c_mode_t {
|
|
||||||
I2C_MODE_MASTER,
|
|
||||||
I2C_MODE_MAX,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct i2c_config_t {
|
|
||||||
i2c_mode_t mode;
|
|
||||||
int sda_io_num;
|
|
||||||
int scl_io_num;
|
|
||||||
bool sda_pullup_en;
|
|
||||||
bool scl_pullup_en;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
uint32_t clk_speed;
|
|
||||||
} master;
|
|
||||||
};
|
|
||||||
uint32_t clk_flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <tactility/hal/Device.h>
|
#include <tactility/hal/Device.h>
|
||||||
#include "I2c.h"
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
|
|
||||||
namespace tt::hal::i2c {
|
namespace tt::hal::i2c {
|
||||||
|
|
||||||
@ -10,12 +10,13 @@ namespace tt::hal::i2c {
|
|||||||
* It helps to read and write registers.
|
* It helps to read and write registers.
|
||||||
*
|
*
|
||||||
* All read and write calls are thread-safe.
|
* All read and write calls are thread-safe.
|
||||||
|
* @deprecated Use the device API from the Kernel project
|
||||||
*/
|
*/
|
||||||
class I2cDevice : public Device {
|
class I2cDevice : public Device {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
i2c_port_t port;
|
::Device* controller;
|
||||||
uint8_t address;
|
uint8_t address;
|
||||||
|
|
||||||
static constexpr TickType_t DEFAULT_TIMEOUT = 1000 / portTICK_PERIOD_MS;
|
static constexpr TickType_t DEFAULT_TIMEOUT = 1000 / portTICK_PERIOD_MS;
|
||||||
@ -36,11 +37,11 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit I2cDevice(i2c_port_t port, uint32_t address) : port(port), address(address) {}
|
explicit I2cDevice(::Device* controller, uint32_t address) : controller(controller), address(address) {}
|
||||||
|
|
||||||
Type getType() const override { return Type::I2c; }
|
Type getType() const override { return Type::I2c; }
|
||||||
|
|
||||||
i2c_port_t getPort() const { return port; }
|
::Device* getController() const { return controller; }
|
||||||
|
|
||||||
uint8_t getAddress() const { return address; }
|
uint8_t getAddress() const { return address; }
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,12 +3,14 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
|
||||||
namespace tt::app::i2cscanner {
|
namespace tt::app::i2cscanner {
|
||||||
|
|
||||||
std::string getAddressText(uint8_t address);
|
std::string getAddressText(uint8_t address);
|
||||||
|
|
||||||
std::string getPortNamesForDropdown();
|
std::string getPortNamesForDropdown();
|
||||||
|
|
||||||
bool getActivePortAtIndex(int32_t index, int32_t& out);
|
bool getActivePortAtIndex(int32_t index, struct Device** out);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,6 @@
|
|||||||
#include <Tactility/LogMessages.h>
|
#include <Tactility/LogMessages.h>
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/MountPoints.h>
|
#include <Tactility/MountPoints.h>
|
||||||
#include <Tactility/Paths.h>
|
|
||||||
#include <Tactility/app/AppManifestParsing.h>
|
#include <Tactility/app/AppManifestParsing.h>
|
||||||
#include <Tactility/app/AppRegistration.h>
|
#include <Tactility/app/AppRegistration.h>
|
||||||
#include <Tactility/file/File.h>
|
#include <Tactility/file/File.h>
|
||||||
@ -27,6 +26,7 @@
|
|||||||
#include <Tactility/settings/TimePrivate.h>
|
#include <Tactility/settings/TimePrivate.h>
|
||||||
|
|
||||||
#include <tactility/concurrent/thread.h>
|
#include <tactility/concurrent/thread.h>
|
||||||
|
#include <tactility/drivers/grove.h>
|
||||||
#include <tactility/drivers/uart_controller.h>
|
#include <tactility/drivers/uart_controller.h>
|
||||||
#include <tactility/filesystem/file_system.h>
|
#include <tactility/filesystem/file_system.h>
|
||||||
#include <tactility/hal_device_module.h>
|
#include <tactility/hal_device_module.h>
|
||||||
@ -94,6 +94,7 @@ namespace app {
|
|||||||
namespace files { extern const AppManifest manifest; }
|
namespace files { extern const AppManifest manifest; }
|
||||||
namespace fileselection { extern const AppManifest manifest; }
|
namespace fileselection { extern const AppManifest manifest; }
|
||||||
namespace gpssettings { extern const AppManifest manifest; }
|
namespace gpssettings { extern const AppManifest manifest; }
|
||||||
|
namespace grovesettings { extern const AppManifest manifest; }
|
||||||
namespace i2cscanner { extern const AppManifest manifest; }
|
namespace i2cscanner { extern const AppManifest manifest; }
|
||||||
namespace imageviewer { extern const AppManifest manifest; }
|
namespace imageviewer { extern const AppManifest manifest; }
|
||||||
namespace inputdialog { extern const AppManifest manifest; }
|
namespace inputdialog { extern const AppManifest manifest; }
|
||||||
@ -187,7 +188,11 @@ static void registerInternalApps() {
|
|||||||
addAppManifest(app::chat::manifest);
|
addAppManifest(app::chat::manifest);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (device_exists_of_type(&UART_CONTROLLER_TYPE)) {
|
if (device_exists_of_type(&GROVE_TYPE)) {
|
||||||
|
addAppManifest(app::grovesettings::manifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device_exists_of_type(&UART_CONTROLLER_TYPE) || device_exists_of_type(&GROVE_TYPE)) {
|
||||||
addAppManifest(app::addgps::manifest);
|
addAppManifest(app::addgps::manifest);
|
||||||
addAppManifest(app::gpssettings::manifest);
|
addAppManifest(app::gpssettings::manifest);
|
||||||
}
|
}
|
||||||
|
|||||||
79
Tactility/Source/app/grovesettings/GroveSettings.cpp
Normal file
79
Tactility/Source/app/grovesettings/GroveSettings.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <lvgl.h>
|
||||||
|
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/drivers/grove.h>
|
||||||
|
#include <tactility/lvgl_icon_shared.h>
|
||||||
|
|
||||||
|
#include <Tactility/Tactility.h>
|
||||||
|
#include <Tactility/lvgl/Toolbar.h>
|
||||||
|
|
||||||
|
namespace tt::app::grovesettings {
|
||||||
|
|
||||||
|
class GroveSettingsApp final : public App {
|
||||||
|
|
||||||
|
std::vector<::Device*> devices;
|
||||||
|
|
||||||
|
void collectDevices() {
|
||||||
|
devices.clear();
|
||||||
|
device_for_each_of_type(&GROVE_TYPE, &devices, [](auto* device, auto* context) {
|
||||||
|
auto* vec = static_cast<std::vector<::Device*>*>(context);
|
||||||
|
vec->push_back(device);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onModeChanged(lv_event_t* e) {
|
||||||
|
auto* device = static_cast<::Device*>(lv_event_get_user_data(e));
|
||||||
|
auto* dropdown = static_cast<lv_obj_t*>(lv_event_get_target(e));
|
||||||
|
auto mode = static_cast<GroveMode>(lv_dropdown_get_selected(dropdown));
|
||||||
|
grove_set_mode(device, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void onShow(AppContext& app, lv_obj_t* parent) override {
|
||||||
|
collectDevices();
|
||||||
|
|
||||||
|
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||||
|
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
|
||||||
|
|
||||||
|
lvgl::toolbar_create(parent, app);
|
||||||
|
|
||||||
|
auto* main_wrapper = lv_obj_create(parent);
|
||||||
|
lv_obj_set_flex_flow(main_wrapper, LV_FLEX_FLOW_COLUMN);
|
||||||
|
lv_obj_set_width(main_wrapper, LV_PCT(100));
|
||||||
|
lv_obj_set_flex_grow(main_wrapper, 1);
|
||||||
|
|
||||||
|
for (auto* device : devices) {
|
||||||
|
auto* row = lv_obj_create(main_wrapper);
|
||||||
|
lv_obj_set_size(row, LV_PCT(100), LV_SIZE_CONTENT);
|
||||||
|
lv_obj_set_style_pad_all(row, 0, LV_STATE_DEFAULT);
|
||||||
|
lv_obj_set_style_border_width(row, 0, LV_STATE_DEFAULT);
|
||||||
|
|
||||||
|
auto* label = lv_label_create(row);
|
||||||
|
lv_label_set_text(label, device->name);
|
||||||
|
lv_obj_align(label, LV_ALIGN_LEFT_MID, 0, 0);
|
||||||
|
|
||||||
|
auto* dropdown = lv_dropdown_create(row);
|
||||||
|
lv_dropdown_set_options(dropdown, "Disabled\nUART\nI2C");
|
||||||
|
lv_obj_align(dropdown, LV_ALIGN_RIGHT_MID, 0, 0);
|
||||||
|
|
||||||
|
GroveMode current = GROVE_MODE_DISABLED;
|
||||||
|
grove_get_mode(device, ¤t);
|
||||||
|
lv_dropdown_set_selected(dropdown, static_cast<uint32_t>(current));
|
||||||
|
|
||||||
|
lv_obj_add_event_cb(dropdown, onModeChanged, LV_EVENT_VALUE_CHANGED, device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const AppManifest manifest = {
|
||||||
|
.appId = "GroveSettings",
|
||||||
|
.appName = "Grove",
|
||||||
|
.appIcon = LVGL_ICON_SHARED_CABLE,
|
||||||
|
.appCategory = Category::Settings,
|
||||||
|
.createApp = create<GroveSettingsApp>
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
#include "Tactility/app/i2cscanner/I2cHelpers.h"
|
#include "Tactility/app/i2cscanner/I2cHelpers.h"
|
||||||
|
|
||||||
#include <Tactility/StringUtils.h>
|
#include <Tactility/StringUtils.h>
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
|
||||||
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -19,31 +20,36 @@ std::string getAddressText(uint8_t address) {
|
|||||||
|
|
||||||
std::string getPortNamesForDropdown() {
|
std::string getPortNamesForDropdown() {
|
||||||
std::vector<std::string> config_names;
|
std::vector<std::string> config_names;
|
||||||
for (int port = 0; port < I2C_NUM_MAX; ++port) {
|
device_for_each_of_type(&I2C_CONTROLLER_TYPE, &config_names, [](auto* device, auto* context) {
|
||||||
auto native_port = static_cast<i2c_port_t>(port);
|
auto* names = static_cast<std::vector<std::string>*>(context);
|
||||||
if (hal::i2c::isStarted(native_port)) {
|
if (device_is_ready(device)) {
|
||||||
auto* name = hal::i2c::getName(native_port);
|
names->push_back(device->name);
|
||||||
if (name != nullptr) {
|
|
||||||
config_names.push_back(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
return string::join(config_names, "\n");
|
return string::join(config_names, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getActivePortAtIndex(int32_t index, int32_t& out) {
|
bool getActivePortAtIndex(int32_t index, struct Device** out) {
|
||||||
int current_index = -1;
|
struct Context {
|
||||||
for (int port = 0; port < I2C_NUM_MAX; ++port) {
|
int32_t targetIndex;
|
||||||
auto native_port = static_cast<i2c_port_t>(port);
|
int32_t currentIndex;
|
||||||
if (hal::i2c::isStarted(native_port)) {
|
struct Device* foundDevice;
|
||||||
current_index++;
|
} context = { index, 0, nullptr };
|
||||||
if (current_index == index) {
|
|
||||||
out = port;
|
device_for_each_of_type(&I2C_CONTROLLER_TYPE, &context, [](auto* device, auto* ctx) {
|
||||||
return true;
|
auto* c = static_cast<Context*>(ctx);
|
||||||
}
|
if (device_is_ready(device)) {
|
||||||
}
|
if (c->currentIndex == c->targetIndex) {
|
||||||
}
|
c->foundDevice = device;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
c->currentIndex++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
*out = context.foundDevice;
|
||||||
|
return context.foundDevice != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
#include <Tactility/app/i2cscanner/I2cScannerPrivate.h>
|
#include <Tactility/app/i2cscanner/I2cScannerPrivate.h>
|
||||||
#include <Tactility/app/i2cscanner/I2cHelpers.h>
|
#include <Tactility/app/i2cscanner/I2cHelpers.h>
|
||||||
|
|
||||||
#include <Tactility/Assets.h>
|
|
||||||
#include <Tactility/app/AppContext.h>
|
#include <Tactility/app/AppContext.h>
|
||||||
#include <Tactility/hal/i2c/I2cDevice.h>
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/LogMessages.h>
|
#include <Tactility/LogMessages.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
@ -33,7 +32,7 @@ class I2cScannerApp final : public App {
|
|||||||
std::unique_ptr<Timer> scanTimer = nullptr;
|
std::unique_ptr<Timer> scanTimer = nullptr;
|
||||||
// State
|
// State
|
||||||
ScanState scanState = ScanStateInitial;
|
ScanState scanState = ScanStateInitial;
|
||||||
i2c_port_t port = I2C_NUM_0;
|
struct Device* portDevice = nullptr;
|
||||||
std::vector<uint8_t> scannedAddresses;
|
std::vector<uint8_t> scannedAddresses;
|
||||||
// Widgets
|
// Widgets
|
||||||
lv_obj_t* scanButtonLabelWidget = nullptr;
|
lv_obj_t* scanButtonLabelWidget = nullptr;
|
||||||
@ -47,14 +46,13 @@ class I2cScannerApp final : public App {
|
|||||||
|
|
||||||
static void onSelectBusCallback(lv_event_t* event);
|
static void onSelectBusCallback(lv_event_t* event);
|
||||||
static void onPressScanCallback(lv_event_t* event);
|
static void onPressScanCallback(lv_event_t* event);
|
||||||
static void onScanTimerCallback();
|
|
||||||
|
|
||||||
void onSelectBus(lv_event_t* event);
|
void onSelectBus(lv_event_t* event);
|
||||||
void onPressScan(lv_event_t* event);
|
void onPressScan(lv_event_t* event);
|
||||||
void onScanTimer();
|
void onScanTimer();
|
||||||
|
|
||||||
bool shouldStopScanTimer();
|
bool shouldStopScanTimer();
|
||||||
bool getPort(i2c_port_t* outPort);
|
bool getPort(struct Device** outPort);
|
||||||
bool addAddressToList(uint8_t address);
|
bool addAddressToList(uint8_t address);
|
||||||
bool hasScanThread();
|
bool hasScanThread();
|
||||||
void startScanning();
|
void startScanning();
|
||||||
@ -140,8 +138,10 @@ void I2cScannerApp::onShow(AppContext& app, lv_obj_t* parent) {
|
|||||||
lv_obj_add_flag(scan_list, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(scan_list, LV_OBJ_FLAG_HIDDEN);
|
||||||
scanListWidget = scan_list;
|
scanListWidget = scan_list;
|
||||||
|
|
||||||
int32_t first_port;
|
struct Device* dummy;
|
||||||
if (getActivePortAtIndex(0, first_port)) {
|
if (getActivePortAtIndex(selected_bus, &dummy)) {
|
||||||
|
selectBus(selected_bus);
|
||||||
|
} else if (getActivePortAtIndex(0, &dummy)) {
|
||||||
lv_dropdown_set_selected(port_dropdown, 0);
|
lv_dropdown_set_selected(port_dropdown, 0);
|
||||||
selectBus(0);
|
selectBus(0);
|
||||||
}
|
}
|
||||||
@ -184,9 +184,9 @@ void I2cScannerApp::onPressScanCallback(lv_event_t* event) {
|
|||||||
|
|
||||||
// endregion Callbacks
|
// endregion Callbacks
|
||||||
|
|
||||||
bool I2cScannerApp::getPort(i2c_port_t* outPort) {
|
bool I2cScannerApp::getPort(struct Device** outPort) {
|
||||||
if (mutex.lock(100 / portTICK_PERIOD_MS)) {
|
if (mutex.lock(100 / portTICK_PERIOD_MS)) {
|
||||||
*outPort = this->port;
|
*outPort = this->portDevice;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -219,21 +219,21 @@ bool I2cScannerApp::shouldStopScanTimer() {
|
|||||||
void I2cScannerApp::onScanTimer() {
|
void I2cScannerApp::onScanTimer() {
|
||||||
logger.info("Scan thread started");
|
logger.info("Scan thread started");
|
||||||
|
|
||||||
i2c_port_t safe_port;
|
Device* safe_port;
|
||||||
if (!getPort(&safe_port)) {
|
if (!getPort(&safe_port)) {
|
||||||
logger.error("Failed to get I2C port");
|
logger.error("Failed to get I2C port");
|
||||||
onScanTimerFinished();
|
onScanTimerFinished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hal::i2c::isStarted(safe_port)) {
|
if (!device_is_ready(safe_port)) {
|
||||||
logger.error("I2C port not started");
|
logger.error("I2C port not started");
|
||||||
onScanTimerFinished();
|
onScanTimerFinished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t address = 0; address < 128; ++address) {
|
for (uint8_t address = 0; address < 128; ++address) {
|
||||||
if (hal::i2c::masterHasDeviceAtAddress(safe_port, address, 10 / portTICK_PERIOD_MS)) {
|
if (i2c_controller_has_device_at_address(safe_port, address, 10 / portTICK_PERIOD_MS) == ERROR_NONE) {
|
||||||
logger.info("Found device at address 0x{:02X}", address);
|
logger.info("Found device at address 0x{:02X}", address);
|
||||||
if (!shouldStopScanTimer()) {
|
if (!shouldStopScanTimer()) {
|
||||||
addAddressToList(address);
|
addAddressToList(address);
|
||||||
@ -305,14 +305,14 @@ void I2cScannerApp::onSelectBus(lv_event_t* event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void I2cScannerApp::selectBus(int32_t selected) {
|
void I2cScannerApp::selectBus(int32_t selected) {
|
||||||
int32_t found_port;
|
struct Device* found_device;
|
||||||
if (!getActivePortAtIndex(selected, found_port)) {
|
if (!getActivePortAtIndex(selected, &found_device)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mutex.lock(100 / portTICK_PERIOD_MS)) {
|
if (mutex.lock(100 / portTICK_PERIOD_MS)) {
|
||||||
scannedAddresses.clear();
|
scannedAddresses.clear();
|
||||||
port = static_cast<i2c_port_t>(found_port);
|
portDevice = found_device;
|
||||||
scanState = ScanStateInitial;
|
scanState = ScanStateInitial;
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
}
|
}
|
||||||
@ -334,16 +334,6 @@ void I2cScannerApp::onPressScan(lv_event_t* event) {
|
|||||||
updateViews();
|
updateViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool findDeviceName(const std::vector<std::shared_ptr<hal::i2c::I2cDevice>>& devices, i2c_port_t port, uint8_t address, std::string& outName) {
|
|
||||||
for (auto& device : devices) {
|
|
||||||
if (device->getPort() == port && device->getAddress() == address) {
|
|
||||||
outName = device->getName();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void I2cScannerApp::updateViews() {
|
void I2cScannerApp::updateViews() {
|
||||||
if (mutex.lock(100 / portTICK_PERIOD_MS)) {
|
if (mutex.lock(100 / portTICK_PERIOD_MS)) {
|
||||||
if (scanState == ScanStateScanning) {
|
if (scanState == ScanStateScanning) {
|
||||||
@ -358,19 +348,11 @@ void I2cScannerApp::updateViews() {
|
|||||||
if (scanState == ScanStateStopped) {
|
if (scanState == ScanStateStopped) {
|
||||||
lv_obj_remove_flag(scanListWidget, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_remove_flag(scanListWidget, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
auto devices = hal::findDevices<hal::i2c::I2cDevice>(hal::Device::Type::I2c);
|
|
||||||
|
|
||||||
if (!scannedAddresses.empty()) {
|
if (!scannedAddresses.empty()) {
|
||||||
for (auto address: scannedAddresses) {
|
for (auto address: scannedAddresses) {
|
||||||
std::string address_text = getAddressText(address);
|
std::string address_text = getAddressText(address);
|
||||||
std::string device_name;
|
|
||||||
if (findDeviceName(devices, port, address, device_name)) {
|
|
||||||
auto text = std::format("{} - {}", address_text, device_name);
|
|
||||||
lv_list_add_text(scanListWidget, text.c_str());
|
|
||||||
} else {
|
|
||||||
lv_list_add_text(scanListWidget, address_text.c_str());
|
lv_list_add_text(scanListWidget, address_text.c_str());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
lv_list_add_text(scanListWidget, "No devices found");
|
lv_list_add_text(scanListWidget, "No devices found");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,111 +0,0 @@
|
|||||||
#include <Tactility/hal/i2c/I2c.h>
|
|
||||||
|
|
||||||
#include <Tactility/Logger.h>
|
|
||||||
#include <Tactility/Mutex.h>
|
|
||||||
|
|
||||||
#include <tactility/check.h>
|
|
||||||
#include <tactility/drivers/i2c_controller.h>
|
|
||||||
#include <tactility/time.h>
|
|
||||||
|
|
||||||
#ifdef ESP_PLATFORM
|
|
||||||
#include <tactility/drivers/esp32_i2c.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace tt::hal::i2c {
|
|
||||||
|
|
||||||
class NoLock final : public tt::Lock {
|
|
||||||
bool lock(TickType_t timeout) const override { return true; }
|
|
||||||
void unlock() const override { /* NO-OP */ }
|
|
||||||
};
|
|
||||||
|
|
||||||
static NoLock NO_LOCK;
|
|
||||||
|
|
||||||
Device* findDevice(i2c_port_t port) {
|
|
||||||
#ifdef ESP_PLATFORM
|
|
||||||
struct Params {
|
|
||||||
i2c_port_t port;
|
|
||||||
Device* device;
|
|
||||||
};
|
|
||||||
|
|
||||||
Params params = {
|
|
||||||
.port = port,
|
|
||||||
.device = nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
device_for_each_of_type(&I2C_CONTROLLER_TYPE, ¶ms, [](auto* device, auto* context) {
|
|
||||||
auto* params_ptr = (Params*)context;
|
|
||||||
auto* driver = device_get_driver(device);
|
|
||||||
if (driver == nullptr) return true;
|
|
||||||
if (!driver_is_compatible(driver, "espressif,esp32-i2c")) return true;
|
|
||||||
auto* config = static_cast<const Esp32I2cConfig*>(device->config);
|
|
||||||
if (config->port != params_ptr->port) return true;
|
|
||||||
// Found it, stop iterating
|
|
||||||
params_ptr->device = device;
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
return params.device;
|
|
||||||
#else
|
|
||||||
return nullptr;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isStarted(i2c_port_t port) {
|
|
||||||
auto* device = findDevice(port);
|
|
||||||
if (device == nullptr) return false;
|
|
||||||
return device_is_ready(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* getName(i2c_port_t port) {
|
|
||||||
auto* device = findDevice(port);
|
|
||||||
if (device == nullptr) return nullptr;
|
|
||||||
return device->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool masterRead(i2c_port_t port, uint8_t address, uint8_t* data, size_t dataSize, TickType_t timeout) {
|
|
||||||
auto* device = findDevice(port);
|
|
||||||
if (device == nullptr) return false;
|
|
||||||
return i2c_controller_read(device, address, data, dataSize, timeout) == ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool masterReadRegister(i2c_port_t port, uint8_t address, uint8_t reg, uint8_t* data, size_t dataSize, TickType_t timeout) {
|
|
||||||
auto* device = findDevice(port);
|
|
||||||
if (device == nullptr) return false;
|
|
||||||
return i2c_controller_read_register(device, address, reg, data, dataSize, timeout) == ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool masterWrite(i2c_port_t port, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
|
||||||
auto* device = findDevice(port);
|
|
||||||
if (device == nullptr) return false;
|
|
||||||
return i2c_controller_write(device, address, data, dataSize, timeout) == ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool masterWriteRegister(i2c_port_t port, uint8_t address, uint8_t reg, const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
|
||||||
auto* device = findDevice(port);
|
|
||||||
if (device == nullptr) return false;
|
|
||||||
return i2c_controller_write_register(device, address, reg, data, dataSize, timeout) == ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool masterWriteRegisterArray(i2c_port_t port, uint8_t address, const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
|
||||||
auto* device = findDevice(port);
|
|
||||||
if (device == nullptr) return false;
|
|
||||||
return i2c_controller_write_register_array(device, address, data, dataSize, timeout) == ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool masterWriteRead(i2c_port_t port, uint8_t address, const uint8_t* writeData, size_t writeDataSize, uint8_t* readData, size_t readDataSize, TickType_t timeout) {
|
|
||||||
auto* device = findDevice(port);
|
|
||||||
if (device == nullptr) return false;
|
|
||||||
return i2c_controller_write_read(device, address, writeData, writeDataSize, readData, readDataSize, timeout) == ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool masterHasDeviceAtAddress(i2c_port_t port, uint8_t address, TickType_t timeout) {
|
|
||||||
auto* device = findDevice(port);
|
|
||||||
if (device == nullptr) return false;
|
|
||||||
return i2c_controller_has_device_at_address(device, address, timeout) == ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Lock& getLock(i2c_port_t port) {
|
|
||||||
return NO_LOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
@ -5,24 +5,24 @@
|
|||||||
namespace tt::hal::i2c {
|
namespace tt::hal::i2c {
|
||||||
|
|
||||||
bool I2cDevice::read(uint8_t* data, size_t dataSize, TickType_t timeout) {
|
bool I2cDevice::read(uint8_t* data, size_t dataSize, TickType_t timeout) {
|
||||||
return masterRead(port, address, data, dataSize, timeout);
|
return i2c_controller_read(controller, address, data, dataSize, timeout) == ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2cDevice::write(const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
bool I2cDevice::write(const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
||||||
return masterWrite(port, address, data, dataSize, timeout);
|
return i2c_controller_write(controller, address, data, dataSize, timeout) == ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2cDevice::writeRead(const uint8_t* writeData, size_t writeDataSize, uint8_t* readData, size_t readDataSize, TickType_t timeout) {
|
bool I2cDevice::writeRead(const uint8_t* writeData, size_t writeDataSize, uint8_t* readData, size_t readDataSize, TickType_t timeout) {
|
||||||
return masterWriteRead(port, address, writeData, writeDataSize, readData, readDataSize, timeout);
|
return i2c_controller_write_read(controller, address, writeData, writeDataSize, readData, readDataSize, timeout) == ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2cDevice::writeRegister(uint8_t reg, const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
bool I2cDevice::writeRegister(uint8_t reg, const uint8_t* data, uint16_t dataSize, TickType_t timeout) {
|
||||||
return masterWriteRegister(port, address, reg, data, dataSize, timeout);
|
return i2c_controller_write_register(controller, address, reg, data, dataSize, timeout) == ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2cDevice::readRegister12(uint8_t reg, float& out) const {
|
bool I2cDevice::readRegister12(uint8_t reg, float& out) const {
|
||||||
std::uint8_t data[2] = {0};
|
std::uint8_t data[2] = {0};
|
||||||
if (masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT)) {
|
if (i2c_controller_read_register(controller, address, reg, data, 2, DEFAULT_TIMEOUT) == ERROR_NONE) {
|
||||||
out = (data[0] & 0x0F) << 8 | data[1];
|
out = (data[0] & 0x0F) << 8 | data[1];
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -32,7 +32,7 @@ bool I2cDevice::readRegister12(uint8_t reg, float& out) const {
|
|||||||
|
|
||||||
bool I2cDevice::readRegister14(uint8_t reg, float& out) const {
|
bool I2cDevice::readRegister14(uint8_t reg, float& out) const {
|
||||||
std::uint8_t data[2] = {0};
|
std::uint8_t data[2] = {0};
|
||||||
if (masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT)) {
|
if (i2c_controller_read_register(controller, address, reg, data, 2, DEFAULT_TIMEOUT) == ERROR_NONE) {
|
||||||
out = (data[0] & 0x3F) << 8 | data[1];
|
out = (data[0] & 0x3F) << 8 | data[1];
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -42,7 +42,7 @@ bool I2cDevice::readRegister14(uint8_t reg, float& out) const {
|
|||||||
|
|
||||||
bool I2cDevice::readRegister16(uint8_t reg, uint16_t& out) const {
|
bool I2cDevice::readRegister16(uint8_t reg, uint16_t& out) const {
|
||||||
std::uint8_t data[2] = {0};
|
std::uint8_t data[2] = {0};
|
||||||
if (masterReadRegister(port, address, reg, data, 2, DEFAULT_TIMEOUT)) {
|
if (i2c_controller_read_register(controller, address, reg, data, 2, DEFAULT_TIMEOUT) == ERROR_NONE) {
|
||||||
out = data[0] << 8 | data[1];
|
out = data[0] << 8 | data[1];
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -51,11 +51,11 @@ bool I2cDevice::readRegister16(uint8_t reg, uint16_t& out) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool I2cDevice::readRegister8(uint8_t reg, uint8_t& result) const {
|
bool I2cDevice::readRegister8(uint8_t reg, uint8_t& result) const {
|
||||||
return masterWriteRead(port, address, ®, 1, &result, 1, DEFAULT_TIMEOUT);
|
return i2c_controller_write_read(controller, address, ®, 1, &result, 1, DEFAULT_TIMEOUT) == ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2cDevice::writeRegister8(uint8_t reg, uint8_t value) const {
|
bool I2cDevice::writeRegister8(uint8_t reg, uint8_t value) const {
|
||||||
return masterWriteRegister(port, address, reg, &value, 1, DEFAULT_TIMEOUT);
|
return i2c_controller_write_register(controller, address, reg, &value, 1, DEFAULT_TIMEOUT) == ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2cDevice::bitOn(uint8_t reg, uint8_t bitmask) const {
|
bool I2cDevice::bitOn(uint8_t reg, uint8_t bitmask) const {
|
||||||
|
|||||||
58
TactilityKernel/include/tactility/drivers/grove.h
Normal file
58
TactilityKernel/include/tactility/drivers/grove.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/error.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Grove Port modes
|
||||||
|
*/
|
||||||
|
enum GroveMode {
|
||||||
|
GROVE_MODE_DISABLED = 0,
|
||||||
|
GROVE_MODE_UART = 1,
|
||||||
|
GROVE_MODE_I2C = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief API for Grove drivers.
|
||||||
|
*
|
||||||
|
* The grove driver is meant for external interfaces with two wires that can be used as UART, I2C or GPIO as needed.
|
||||||
|
* It can be used with the Grove connector, but also with others such as Stemma QT.
|
||||||
|
*/
|
||||||
|
struct GroveApi {
|
||||||
|
/**
|
||||||
|
* @brief Sets the Grove port mode.
|
||||||
|
* @param[in] device the Grove device
|
||||||
|
* @param[in] mode the new mode
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*set_mode)(struct Device* device, enum GroveMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current Grove port mode.
|
||||||
|
* @param[in] device the Grove device
|
||||||
|
* @param[out] mode pointer to store the current mode
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*get_mode)(struct Device* device, enum GroveMode* mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the Grove port mode using the specified device.
|
||||||
|
*/
|
||||||
|
error_t grove_set_mode(struct Device* device, enum GroveMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current Grove port mode using the specified device.
|
||||||
|
*/
|
||||||
|
error_t grove_get_mode(struct Device* device, enum GroveMode* mode);
|
||||||
|
|
||||||
|
extern const struct DeviceType GROVE_TYPE;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
23
TactilityKernel/source/drivers/grove.cpp
Normal file
23
TactilityKernel/source/drivers/grove.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <tactility/drivers/grove.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
|
||||||
|
#define GROVE_DRIVER_API(driver) ((struct GroveApi*)driver->api)
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
error_t grove_set_mode(struct Device* device, enum GroveMode mode) {
|
||||||
|
const auto* driver = device_get_driver(device);
|
||||||
|
return GROVE_DRIVER_API(driver)->set_mode(device, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t grove_get_mode(struct Device* device, enum GroveMode* mode) {
|
||||||
|
const auto* driver = device_get_driver(device);
|
||||||
|
return GROVE_DRIVER_API(driver)->get_mode(device, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct DeviceType GROVE_TYPE {
|
||||||
|
.name = "grove"
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user