mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-20 07:25:06 +00:00
Compare commits
4 Commits
99bbe105eb
...
b4966c36f6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4966c36f6 | ||
|
|
c85c4da300 | ||
|
|
95f010d3f7 | ||
|
|
cc5050b7c6 |
@ -34,6 +34,7 @@ def parse_binding(file_path: str, binding_dirs: list[str]) -> Binding:
|
||||
includes.append(include)
|
||||
|
||||
# Parse local properties
|
||||
compatible = data.get('compatible', None)
|
||||
properties_raw = data.get('properties', {})
|
||||
for name, details in properties_raw.items():
|
||||
prop = BindingProperty(
|
||||
@ -43,9 +44,7 @@ def parse_binding(file_path: str, binding_dirs: list[str]) -> Binding:
|
||||
description=details.get('description', '').strip(),
|
||||
)
|
||||
properties_dict[name] = prop
|
||||
|
||||
filename = os.path.basename(file_path)
|
||||
compatible = filename.removesuffix(".yaml").removesuffix(".yml")
|
||||
return Binding(
|
||||
filename=filename,
|
||||
compatible=compatible,
|
||||
|
||||
@ -18,8 +18,10 @@ def get_device_identifier_safe(device: Device):
|
||||
|
||||
def get_device_type_name(device: Device, bindings: list[Binding]):
|
||||
device_binding = find_device_binding(device, bindings)
|
||||
if device_binding == None:
|
||||
if device_binding is None:
|
||||
raise Exception(f"Binding not found for {device.identifier}")
|
||||
if device_binding.compatible is None:
|
||||
raise Exception(f"Couldn't find compatible binding for {device.identifier}")
|
||||
compatible_safe = device_binding.compatible.split(",")[-1]
|
||||
return compatible_safe.replace("-", "_")
|
||||
|
||||
@ -101,7 +103,7 @@ def write_config(file, device: Device, bindings: list[Binding], type_name: str):
|
||||
file.write(f"{config_params_joined}\n")
|
||||
file.write("};\n\n")
|
||||
|
||||
def write_device_structs(file, device: Device, bindings: list[Binding], verbose: bool):
|
||||
def write_device_structs(file, device: Device, parent_device: Device, bindings: list[Binding], verbose: bool):
|
||||
if verbose:
|
||||
print(f"Writing device struct for '{device.identifier}'")
|
||||
# Assemble some pre-requisites
|
||||
@ -111,38 +113,38 @@ def write_device_structs(file, device: Device, bindings: list[Binding], verbose:
|
||||
raise Exception(f"Cannot find 'compatible' property for {device.identifier}")
|
||||
identifier = get_device_identifier_safe(device)
|
||||
config_variable_name = f"{identifier}_config"
|
||||
if parent_device is not None:
|
||||
parent_identifier = get_device_identifier_safe(parent_device)
|
||||
parent_value = f"&{parent_identifier}"
|
||||
else:
|
||||
parent_value = "NULL"
|
||||
# Write config struct
|
||||
write_config(file, device, bindings, type_name)
|
||||
# Write device struct
|
||||
file.write(f"static struct Device {identifier}" " = {\n")
|
||||
file.write(f"\t.name = \"{device.identifier}\",\n") # Use original name
|
||||
file.write(f"\t.config = (void*)&{config_variable_name},\n")
|
||||
file.write(f"\t.parent = {parent_value},\n")
|
||||
file.write("};\n\n")
|
||||
# Child devices
|
||||
for child_device in device.devices:
|
||||
write_device_structs(file, child_device, bindings, verbose)
|
||||
write_device_structs(file, child_device, device, bindings, verbose)
|
||||
|
||||
def write_device_init(file, device: Device, parent_device: Device, bindings: list[Binding], verbose: bool):
|
||||
def write_device_init(file, device: Device, bindings: list[Binding], verbose: bool):
|
||||
if verbose:
|
||||
print(f"Processing device init code for '{device.identifier}'")
|
||||
# Assemble some pre-requisites
|
||||
type_name = get_device_type_name(device, bindings)
|
||||
compatible_property = find_binding_property(device, "compatible")
|
||||
if compatible_property is None:
|
||||
raise Exception(f"Cannot find 'compatible' property for {device.identifier}")
|
||||
# Type & instance names
|
||||
identifier = get_device_identifier_safe(device)
|
||||
device_variable = identifier
|
||||
if parent_device is not None:
|
||||
parent_identifier = get_device_identifier_safe(parent_device)
|
||||
parent_value = f"&{parent_identifier}"
|
||||
else:
|
||||
parent_value = "NULL"
|
||||
# Write device struct
|
||||
file.write(f"\tif (init_builtin_device(&{device_variable}, \"{compatible_property.value}\", {parent_value}) != 0) return -1;\n")
|
||||
file.write(f"\tif (init_builtin_device(&{device_variable}, \"{compatible_property.value}\") != 0) return -1;\n")
|
||||
# Write children
|
||||
for child_device in device.devices:
|
||||
write_device_init(file, child_device, device, bindings, verbose)
|
||||
write_device_init(file, child_device, bindings, verbose)
|
||||
|
||||
def write_device_list_entry(file, device: Device):
|
||||
compatible_property = find_binding_property(device, "compatible")
|
||||
@ -164,11 +166,11 @@ def write_device_list(file, devices: list[Device]):
|
||||
def generate_devicetree_c(filename: str, items: list[object], bindings: list[Binding], verbose: bool):
|
||||
with open(filename, "w") as file:
|
||||
file.write(dedent('''\
|
||||
// Generated includes
|
||||
// Default headers
|
||||
#include <Tactility/Device.h>
|
||||
#include <Tactility/Driver.h>
|
||||
#include <Tactility/Log.h>
|
||||
// DTS includes
|
||||
// DTS headers
|
||||
'''))
|
||||
|
||||
# Write all headers first
|
||||
@ -180,7 +182,7 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin
|
||||
file.write(dedent('''\
|
||||
#define TAG LOG_TAG(devicetree)
|
||||
|
||||
static int init_builtin_device(struct Device* device, const char* compatible, struct Device* parent_device) {
|
||||
static int init_builtin_device(struct Device* device, const char* compatible) {
|
||||
struct Driver* driver = driver_find(compatible);
|
||||
if (driver == NULL) {
|
||||
LOG_E(TAG, "Can't find driver: %s", compatible);
|
||||
@ -188,7 +190,6 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin
|
||||
}
|
||||
device_construct(device);
|
||||
device_set_driver(device, driver);
|
||||
device_set_parent(device, parent_device);
|
||||
device_add(device);
|
||||
const int err = device_start(device);
|
||||
if (err != 0) {
|
||||
@ -203,13 +204,13 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin
|
||||
# Then write all devices
|
||||
for item in items:
|
||||
if type(item) is Device:
|
||||
write_device_structs(file, item, bindings, verbose)
|
||||
write_device_structs(file, item, None, bindings, verbose)
|
||||
# Init function body start
|
||||
file.write("int devices_builtin_init() {\n")
|
||||
# Init function body logic
|
||||
for item in items:
|
||||
if type(item) is Device:
|
||||
write_device_init(file, item, None, bindings, verbose)
|
||||
write_device_init(file, item, bindings, verbose)
|
||||
file.write("\treturn 0;\n")
|
||||
# Init function body end
|
||||
file.write("}\n")
|
||||
|
||||
@ -35,7 +35,7 @@ class BindingProperty:
|
||||
@dataclass
|
||||
class Binding:
|
||||
filename: str
|
||||
compatible: str
|
||||
compatible: list[str]
|
||||
description: str
|
||||
properties: list[BindingProperty]
|
||||
includes: list[str]
|
||||
|
||||
@ -32,7 +32,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
||||
"Firmware"
|
||||
"Devices/${TACTILITY_DEVICE_PROJECT}"
|
||||
"Drivers"
|
||||
"core"
|
||||
"TactilityKernel"
|
||||
"Tactility"
|
||||
"TactilityC"
|
||||
"TactilityCore"
|
||||
@ -75,13 +75,13 @@ if (NOT DEFINED ENV{ESP_IDF_VERSION})
|
||||
add_subdirectory(Tactility)
|
||||
add_subdirectory(TactilityCore)
|
||||
add_subdirectory(TactilityFreeRtos)
|
||||
add_subdirectory(TactilityKernel)
|
||||
add_subdirectory(Devices/simulator)
|
||||
add_subdirectory(Libraries/cJSON)
|
||||
add_subdirectory(Libraries/lv_screenshot)
|
||||
add_subdirectory(Libraries/QRCode)
|
||||
add_subdirectory(Libraries/minitar)
|
||||
add_subdirectory(Libraries/minmea)
|
||||
add_subdirectory(core)
|
||||
|
||||
# FreeRTOS
|
||||
set(FREERTOS_CONFIG_FILE_DIRECTORY ${PROJECT_SOURCE_DIR}/Devices/simulator/Source CACHE STRING "")
|
||||
|
||||
@ -20,6 +20,7 @@ Driver tlora_pager_driver = {
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.internal = { 0 }
|
||||
};
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
description: LilyGO T-Lora Pager
|
||||
|
||||
include: ["root.yaml"]
|
||||
|
||||
compatible: "lilygo,tlora-pager"
|
||||
|
||||
@ -7,7 +7,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
||||
idf_component_register(
|
||||
SRCS ${SOURCES}
|
||||
INCLUDE_DIRS "include/"
|
||||
REQUIRES core driver
|
||||
REQUIRES TactilityKernel driver
|
||||
)
|
||||
|
||||
else ()
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
description: ESP32 GPIO Controller
|
||||
|
||||
compatible: "espressif,esp32-gpio"
|
||||
|
||||
include: ["gpio-controller.yaml"]
|
||||
|
||||
@ -2,6 +2,8 @@ description: ESP32 GPIO Controller
|
||||
|
||||
include: ["i2c-controller.yaml"]
|
||||
|
||||
compatible: "espressif,esp32-i2c"
|
||||
|
||||
properties:
|
||||
port:
|
||||
type: int
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
dependencies:
|
||||
- core
|
||||
- TactilityKernel
|
||||
bindings: bindings
|
||||
|
||||
@ -112,6 +112,7 @@ Driver esp32_gpio_driver = {
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = (void*)&esp32_gpio_api,
|
||||
.device_type = nullptr,
|
||||
.internal = { 0 }
|
||||
};
|
||||
|
||||
|
||||
@ -84,6 +84,7 @@ Driver esp32_i2c_driver = {
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = (void*)&esp32_i2c_api,
|
||||
.device_type = &I2C_CONTROLLER_TYPE,
|
||||
.internal = { 0 }
|
||||
};
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
||||
idf_component_register(
|
||||
SRCS ${SOURCE_FILES}
|
||||
REQUIRES ${DEVICE_COMPONENTS}
|
||||
REQUIRES Tactility TactilityC core drivers-esp ${TACTILITY_DEVICE_PROJECT}
|
||||
REQUIRES Tactility TactilityC TactilityKernel drivers-esp ${TACTILITY_DEVICE_PROJECT}
|
||||
)
|
||||
|
||||
else ()
|
||||
@ -32,9 +32,9 @@ else ()
|
||||
PRIVATE Tactility
|
||||
PRIVATE TactilityCore
|
||||
PRIVATE TactilityFreeRtos
|
||||
PRIVATE TactilityKernel
|
||||
PRIVATE Simulator
|
||||
PRIVATE SDL2::SDL2-static SDL2-static
|
||||
PRIVATE core
|
||||
)
|
||||
|
||||
target_include_directories(FirmwareSim PRIVATE "${CMAKE_SOURCE_DIR}/Firmware/Generated")
|
||||
|
||||
@ -4,7 +4,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
||||
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||
|
||||
list(APPEND REQUIRES_LIST
|
||||
core
|
||||
TactilityKernel
|
||||
TactilityCore
|
||||
TactilityFreeRtos
|
||||
lvgl
|
||||
@ -72,12 +72,12 @@ else()
|
||||
PUBLIC cJSON
|
||||
PUBLIC TactilityFreeRtos
|
||||
PUBLIC TactilityCore
|
||||
PUBLIC TactilityKernel
|
||||
PUBLIC freertos_kernel
|
||||
PUBLIC lvgl
|
||||
PUBLIC lv_screenshot
|
||||
PUBLIC minmea
|
||||
PUBLIC minitar
|
||||
PUBLIC core
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
compatible: "root"
|
||||
|
||||
properties:
|
||||
model:
|
||||
required: true
|
||||
@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Driver.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <Tactility/Bus.h>
|
||||
#include <Tactility/concurrent/Mutex.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
@ -13,22 +14,26 @@ extern "C" {
|
||||
|
||||
struct Driver;
|
||||
|
||||
/** Enables discovering devices of the same type */
|
||||
struct DeviceType {
|
||||
/* Placeholder because empty structs have a different size with C vs C++ compilers */
|
||||
uint8_t _;
|
||||
};
|
||||
|
||||
/** Represents a piece of hardware */
|
||||
struct Device {
|
||||
/** The name of the device. Valid characters: a-z a-Z 0-9 - _ . */
|
||||
const char* name;
|
||||
/** The configuration data for the device's driver */
|
||||
void* config;
|
||||
/** The parent device that this device belongs to. Can be NULL, but only the root device should have a NULL parent. */
|
||||
struct Device* parent;
|
||||
/** Internal data */
|
||||
struct {
|
||||
/** The parent device that this device belongs to. Can be NULL, but only the root device should have a NULL parent. */
|
||||
struct Device* parent;
|
||||
/** Address of the API exposed by the device instance. */
|
||||
struct Driver* driver;
|
||||
/** The driver data for this device (e.g. a mutex) */
|
||||
void* driver_data;
|
||||
/** The bus that is owned by this device. This bus can contain child devices to make them discoverable. Can be NULL. */
|
||||
struct Bus* bus;
|
||||
/** The mutex for device operations */
|
||||
struct Mutex mutex;
|
||||
/** The device state */
|
||||
@ -134,18 +139,6 @@ static inline bool device_is_added(const struct Device* device) {
|
||||
return device->internal.state.added;
|
||||
}
|
||||
|
||||
static inline struct Bus* device_get_bus(const struct Device* device) {
|
||||
return device->internal.bus;
|
||||
}
|
||||
|
||||
static inline void device_set_bus(struct Device* device, struct Bus* bus) {
|
||||
device->internal.bus = bus;
|
||||
}
|
||||
|
||||
static inline const char* device_get_bus_name(const struct Device* device) {
|
||||
return device->internal.bus ? device->internal.bus->name : "";
|
||||
}
|
||||
|
||||
static inline void device_lock(struct Device* device) {
|
||||
mutex_lock(&device->internal.mutex);
|
||||
}
|
||||
@ -158,6 +151,18 @@ static inline void device_unlock(struct Device* device) {
|
||||
mutex_unlock(&device->internal.mutex);
|
||||
}
|
||||
|
||||
static inline const struct DeviceType* device_get_type(struct Device* device) {
|
||||
return device->internal.driver->device_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through all the known devices of a specific type
|
||||
* @param type the type to filter
|
||||
* @param callback_context the parameter to pass to the callback. NULL is valid.
|
||||
* @param on_device the function to call for each filtered device. return true to continue iterating or false to stop.
|
||||
*/
|
||||
void for_each_device_of_type(const struct DeviceType* type, void* callback_context, bool(*on_device)(struct Device* device, void* context));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/Bus.h>
|
||||
#include <Tactility/Device.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Device;
|
||||
struct DeviceType;
|
||||
|
||||
struct Driver {
|
||||
/** The driver name */
|
||||
const char* name;
|
||||
@ -18,6 +18,8 @@ struct Driver {
|
||||
int (*stop_device)(struct Device* dev);
|
||||
/** Contains the driver's functions */
|
||||
const void* api;
|
||||
/** Which type of devices this driver creates (can be NULL) */
|
||||
const struct DeviceType* device_type;
|
||||
/** Internal data */
|
||||
struct {
|
||||
/** Contains private data */
|
||||
@ -25,15 +27,19 @@ struct Driver {
|
||||
} internal;
|
||||
};
|
||||
|
||||
int driver_construct(struct Driver* drv);
|
||||
int driver_construct(struct Driver* driver);
|
||||
|
||||
int driver_destruct(struct Driver* drv);
|
||||
int driver_destruct(struct Driver* driver);
|
||||
|
||||
struct Driver* driver_find(const char* compatible);
|
||||
|
||||
int driver_bind(struct Driver* drv, struct Device* dev);
|
||||
int driver_bind(struct Driver* driver, struct Device* device);
|
||||
|
||||
int driver_unbind(struct Driver* drv, struct Device* dev);
|
||||
int driver_unbind(struct Driver* driver, struct Device* device);
|
||||
|
||||
static inline const struct DeviceType* driver_get_device_type(struct Driver* driver) {
|
||||
return driver->device_type;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@ -21,6 +21,8 @@ bool i2c_controller_write(struct Device* device, uint8_t address, const uint8_t*
|
||||
|
||||
bool i2c_controller_write_read(struct Device* device, uint8_t address, const uint8_t* write_data, size_t write_data_size, uint8_t* read_data, size_t read_data_size, TickType_t timeout);
|
||||
|
||||
extern const struct DeviceType I2C_CONTROLLER_TYPE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -85,16 +85,11 @@ void device_add(Device* device) {
|
||||
ledger_unlock();
|
||||
|
||||
// Add self to parent's children list
|
||||
auto* parent = device->internal.parent;
|
||||
auto* parent = device->parent;
|
||||
if (parent != nullptr) {
|
||||
device_add_child(parent, device);
|
||||
}
|
||||
|
||||
auto* bus = device->internal.bus;
|
||||
if (bus != nullptr) {
|
||||
bus_add_device(bus, device);
|
||||
}
|
||||
|
||||
device->internal.state.added = true;
|
||||
}
|
||||
|
||||
@ -108,13 +103,8 @@ bool device_remove(Device* device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto* bus = device->internal.bus;
|
||||
if (bus != nullptr) {
|
||||
bus_remove_device(bus, device);
|
||||
}
|
||||
|
||||
// Remove self from parent's children list
|
||||
auto* parent = device->internal.parent;
|
||||
auto* parent = device->parent;
|
||||
if (parent != nullptr) {
|
||||
device_remove_child(parent, device);
|
||||
}
|
||||
@ -138,11 +128,6 @@ failed_ledger_lookup:
|
||||
device_add_child(parent, device);
|
||||
}
|
||||
|
||||
// Re-add to bus
|
||||
if (bus != nullptr) {
|
||||
bus_add_device(bus, device);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -180,15 +165,6 @@ int device_stop(struct Device* device) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int result = driver_unbind(device->internal.driver, device);
|
||||
if (result != 0) {
|
||||
// Re-add to bus
|
||||
if (device->internal.bus != nullptr) {
|
||||
bus_add_device(device->internal.bus, device);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
device->internal.state.started = false;
|
||||
device->internal.state.start_result = 0;
|
||||
return 0;
|
||||
@ -196,7 +172,22 @@ int device_stop(struct Device* device) {
|
||||
|
||||
void device_set_parent(Device* device, Device* parent) {
|
||||
assert(!device->internal.state.started);
|
||||
device->internal.parent = parent;
|
||||
device->parent = parent;
|
||||
}
|
||||
|
||||
void for_each_device_of_type(const DeviceType* type, void* callback_context, bool(*on_device)(Device* device, void* context)) {
|
||||
ledger_lock();
|
||||
for (auto* device : ledger.devices) {
|
||||
auto* driver = device->internal.driver;
|
||||
if (driver != nullptr) {
|
||||
if (driver->device_type == type) {
|
||||
if (!on_device(device, callback_context)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ledger_unlock()
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@ -2,6 +2,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <Tactility/concurrent/Mutex.h>
|
||||
#include <Tactility/Device.h>
|
||||
#include <Tactility/Driver.h>
|
||||
#include <Tactility/Error.h>
|
||||
#include <Tactility/Log.h>
|
||||
@ -20,4 +20,6 @@ bool i2c_controller_write_read(Device* device, uint8_t address, const uint8_t* w
|
||||
return I2C_DRIVER_API(driver)->write_read(device, address, write_data, write_data_size, read_data, read_data_size, timeout);
|
||||
}
|
||||
|
||||
const struct DeviceType I2C_CONTROLLER_TYPE { 0 };
|
||||
|
||||
}
|
||||
@ -9,6 +9,7 @@ Driver root_driver = {
|
||||
.start_device = nullptr,
|
||||
.stop_device = nullptr,
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.internal = { 0 }
|
||||
};
|
||||
|
||||
@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Device;
|
||||
|
||||
/**
|
||||
* A bus contains a group of devices owned by a parent device.
|
||||
* It is used to make a group of devices discoverable.
|
||||
*
|
||||
* Example usage:
|
||||
* The "i2c0" bus is created by the i2c_controller driver when a device is started by a driver.
|
||||
* The postfix "0" means that it was the first device instance (at index 0).
|
||||
*/
|
||||
struct Bus {
|
||||
/** The name of the bus (e.g. "i2c0" or "spi1"). Valid characters: a-z a-Z 0-9 - _ . */
|
||||
const char* name;
|
||||
/** Internal data */
|
||||
struct {
|
||||
/** The device this bus belongs to */
|
||||
struct Device* parent_device;
|
||||
/** The bus' private data */
|
||||
void* data;
|
||||
} internal;
|
||||
};
|
||||
|
||||
// region Bus management
|
||||
|
||||
int bus_construct(struct Bus* bus);
|
||||
|
||||
int bus_destruct(struct Bus* bus);
|
||||
|
||||
struct Bus* bus_find(const char* name);
|
||||
|
||||
// endregion
|
||||
|
||||
// region Bus device management
|
||||
|
||||
int bus_add_device(struct Bus*, struct Device* dev);
|
||||
|
||||
void bus_remove_device(struct Bus*, struct Device* dev);
|
||||
|
||||
// endregion
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -1,115 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include <Tactility/concurrent/Mutex.h>
|
||||
#include <Tactility/Bus.h>
|
||||
#include <Tactility/Device.h>
|
||||
#include <Tactility/Driver.h>
|
||||
|
||||
/** Keeps track of all existing buses */
|
||||
struct BusLedger {
|
||||
std::vector<Bus*> buses = {};
|
||||
Mutex mutex {};
|
||||
|
||||
BusLedger() {
|
||||
mutex_construct(&mutex);
|
||||
}
|
||||
|
||||
~BusLedger() {
|
||||
mutex_destruct(&mutex);
|
||||
}
|
||||
};
|
||||
|
||||
/* Internal data for a Bus */
|
||||
struct BusData {
|
||||
std::vector<Device*> devices = {};
|
||||
std::vector<Driver*> drivers = {};
|
||||
Mutex mutex {};
|
||||
|
||||
BusData() {
|
||||
mutex_construct(&mutex);
|
||||
}
|
||||
|
||||
~BusData() {
|
||||
mutex_destruct(&mutex);
|
||||
}
|
||||
};
|
||||
|
||||
static BusLedger ledger;
|
||||
|
||||
#define ledger_lock() mutex_lock(&ledger.mutex);
|
||||
#define ledger_unlock() mutex_unlock(&ledger.mutex);
|
||||
|
||||
#define bus_lock(bus_data) mutex_lock(&bus_data->mutex);
|
||||
#define bus_unlock(bus_data) mutex_unlock(&bus_data->mutex);
|
||||
|
||||
#define BUS_INSTANCE_DATA(bus) ((struct BusData*)bus->internal.data)
|
||||
|
||||
extern "C" {
|
||||
|
||||
// region Bus management
|
||||
|
||||
static int bus_add(Bus* bus) {
|
||||
ledger_lock();
|
||||
ledger.buses.push_back(bus);
|
||||
ledger_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bus_remove(Bus* bus) {
|
||||
ledger_lock();
|
||||
const auto iterator = std::ranges::find(ledger.buses, bus);
|
||||
if (iterator != ledger.buses.end()) {
|
||||
ledger.buses.erase(iterator);
|
||||
}
|
||||
ledger_unlock();
|
||||
}
|
||||
|
||||
int bus_construct(Bus* bus) {
|
||||
bus->internal.data = new BusData();
|
||||
bus_add(bus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bus_destruct(Bus* bus) {
|
||||
delete BUS_INSTANCE_DATA(bus);
|
||||
bus_remove(bus);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Bus device management
|
||||
|
||||
Bus* bus_find(const char* name) {
|
||||
ledger_lock();
|
||||
const auto it = std::ranges::find_if(ledger.buses, [name](Bus* bus) {
|
||||
return strcmp(name, bus->name) == 0;
|
||||
});
|
||||
Bus* result = (it != ledger.buses.end()) ? *it : nullptr;
|
||||
ledger_unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
int bus_add_device(Bus* bus, Device* dev) {
|
||||
auto* bus_data = BUS_INSTANCE_DATA(bus);
|
||||
bus_lock(bus_data);
|
||||
bus_data->devices.push_back(dev);
|
||||
bus_unlock(bus_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bus_remove_device(Bus* bus, Device* dev) {
|
||||
auto* bus_data = BUS_INSTANCE_DATA(bus);
|
||||
bus_lock(bus_data);
|
||||
const auto iterator = std::ranges::find(bus_data->devices, dev);
|
||||
if (iterator != bus_data->devices.end()) {
|
||||
bus_data->devices.erase(iterator);
|
||||
}
|
||||
bus_unlock(bus_data);
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
} // extern "C"
|
||||
Loading…
x
Reference in New Issue
Block a user