Implement device management (#199)

- Added `tt::hal::Device` and functions (de)register devices and search for them.
- Refactored apps: `Power` and `Display` settings apps now use the device API to find devices.
- Implemented the new API for all existing drivers for all devices, including the simulator.
- Updated HAL Configuration to return `std::shared_ptr` instead of raw pointers.
- Added test project for headless tests and implemented tests for the new code.
This commit is contained in:
Ken Van Hoeylandt
2025-02-02 15:16:51 +01:00
committed by GitHub
parent c87200a80d
commit cff0605b0a
54 changed files with 655 additions and 109 deletions
@@ -12,8 +12,8 @@ typedef bool (*InitLvgl)();
class Display;
class Keyboard;
typedef Display* (*CreateDisplay)();
typedef Keyboard* (*CreateKeyboard)();
typedef std::shared_ptr<Display> (*CreateDisplay)();
typedef std::shared_ptr<Keyboard> (*CreateKeyboard)();
typedef std::shared_ptr<Power> (*CreatePower)();
struct Configuration {
@@ -0,0 +1,83 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
namespace tt::hal {
/**
* Base class for HAL-related devices.
*/
class Device {
public:
enum class Type {
I2c,
Display,
Touch,
SdCard,
Keyboard,
Power
};
typedef uint32_t Id;
private:
Id id;
public:
Device();
virtual ~Device() = default;
Id getId() const { return id; }
/** The type of device. */
virtual Type getType() const = 0;
/** The part number or hardware name e.g. TdeckTouch, TdeckDisplay, BQ24295, etc. */
virtual std::string getName() const = 0;
/** A short description of what this device does.
* e.g. "USB charging controller with I2C interface."
*/
virtual std::string getDescription() const = 0;
};
/**
* Adds a device to the registry.
* @warning This will leak memory if you want to destroy a device and don't call deregisterDevice()!
*/
void registerDevice(const std::shared_ptr<Device>& device);
/** Remove a device from the registry. */
void deregisterDevice(const std::shared_ptr<Device>& device);
/** Find a device in the registry by its name. */
std::shared_ptr<Device> _Nullable findDevice(std::string name);
/** Find a device in the registry by its identifier. */
std::shared_ptr<Device> _Nullable findDevice(Device::Id id);
/** Find 0, 1 or more devices in the registry by type. */
std::vector<std::shared_ptr<Device>> findDevices(Device::Type type);
/** Get a copy of the entire device registry in its current state. */
std::vector<std::shared_ptr<Device>> getDevices();
template<class DeviceType>
std::shared_ptr<DeviceType> findFirstDevice(Device::Type type) {
auto devices = findDevices(type);
if (devices.empty()) {
return {};
} else {
auto& first = devices[0];
return std::static_pointer_cast<DeviceType>(first);
}
}
}
@@ -1,13 +1,19 @@
#pragma once
#include "lvgl.h"
#include "Device.h"
#include <lvgl.h>
namespace tt::hal {
class Touch;
class Display {
class Display : public Device {
public:
Type getType() const override { return Type::Display; }
virtual bool start() = 0;
virtual bool stop() = 0;
@@ -15,7 +21,7 @@ public:
virtual bool isPoweredOn() const { return true; }
virtual bool supportsPowerControl() const { return false; }
virtual Touch* _Nullable createTouch() = 0;
virtual std::shared_ptr<Touch> _Nullable createTouch() = 0;
/** Set a value in the range [0, 255] */
virtual void setBacklightDuty(uint8_t backlightDuty) { /* NO-OP */ }
@@ -1,13 +1,19 @@
#pragma once
#include "lvgl.h"
#include "Device.h"
#include <lvgl.h>
namespace tt::hal {
class Display;
class Keyboard {
class Keyboard : public Device {
public:
Type getType() const override { return Type::Keyboard; }
virtual bool start(lv_display_t* display) = 0;
virtual bool stop() = 0;
virtual bool isAttached() const = 0;
@@ -1,15 +1,18 @@
#pragma once
#include "Device.h"
#include <cstdint>
namespace tt::hal {
class Power{
class Power : public Device {
public:
Power() = default;
virtual ~Power() = default;
~Power() override = default;
Type getType() const override { return Type::Power; }
enum class MetricType {
IsCharging, // bool
@@ -1,5 +1,7 @@
#pragma once
#include "Device.h"
#include <Tactility/TactilityCore.h>
namespace tt::hal {
@@ -7,8 +9,10 @@ namespace tt::hal {
#define TT_SDCARD_MOUNT_NAME "sdcard"
#define TT_SDCARD_MOUNT_POINT "/sdcard"
class SdCard {
class SdCard : public Device {
public:
enum class State {
Mounted,
Unmounted,
@@ -22,11 +26,15 @@ public:
};
private:
MountBehaviour mountBehaviour;
public:
explicit SdCard(MountBehaviour mountBehaviour) : mountBehaviour(mountBehaviour) {}
virtual ~SdCard() = default;
virtual ~SdCard() override = default;
Type getType() const final { return Type::SdCard; };
virtual bool mount(const char* mountPath) = 0;
virtual bool unmount() = 0;
@@ -70,6 +70,9 @@ public:
config(std::move(config))
{}
std::string getName() const final { return "SD Card"; }
std::string getDescription() const final { return "SD card via SPI interface"; }
bool mount(const char* mountPath) override;
bool unmount() override;
State getState() const override;
@@ -1,14 +1,19 @@
#pragma once
#include "lvgl.h"
#include "Device.h"
#include <lvgl.h>
namespace tt::hal {
class Display;
class Touch {
class Touch : public Device {
public:
Type getType() const override { return Type::SdCard; }
virtual bool start(lv_display_t* display) = 0;
virtual bool stop() = 0;
@@ -1,6 +1,9 @@
#pragma once
#include "./I2c.h"
#include "I2c.h"
#include "../Device.h"
namespace tt::hal::i2c {
/**
* Represents an I2C peripheral at a specific port and address.
@@ -8,7 +11,7 @@
*
* All read and write calls are thread-safe.
*/
class I2cDevice {
class I2cDevice : public Device {
protected:
@@ -17,6 +20,8 @@ protected:
static constexpr TickType_t DEFAULT_TIMEOUT = 1000 / portTICK_PERIOD_MS;
Type getType() const override { return Type::I2c; }
bool readRegister8(uint8_t reg, uint8_t& result) const;
bool writeRegister8(uint8_t reg, uint8_t value) const;
bool readRegister12(uint8_t reg, float& out) const;
@@ -26,7 +31,10 @@ protected:
bool bitOff(uint8_t reg, uint8_t bitmask) const;
bool bitOnByIndex(uint8_t reg, uint8_t index) const { return bitOn(reg, 1 << index); }
bool bitOffByIndex(uint8_t reg, uint8_t index) const { return bitOff(reg, 1 << index); }
public:
explicit I2cDevice(i2c_port_t port, uint32_t address) : port(port), address(address) {}
};
}