mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-23 08:55:04 +00:00
Compare commits
No commits in common. "b4966c36f63f5ce00a76c1638908942b5517ce57" and "99bbe105eb8720e265ad50b3497aa0c98d737396" have entirely different histories.
b4966c36f6
...
99bbe105eb
@ -34,7 +34,6 @@ def parse_binding(file_path: str, binding_dirs: list[str]) -> Binding:
|
|||||||
includes.append(include)
|
includes.append(include)
|
||||||
|
|
||||||
# Parse local properties
|
# Parse local properties
|
||||||
compatible = data.get('compatible', None)
|
|
||||||
properties_raw = data.get('properties', {})
|
properties_raw = data.get('properties', {})
|
||||||
for name, details in properties_raw.items():
|
for name, details in properties_raw.items():
|
||||||
prop = BindingProperty(
|
prop = BindingProperty(
|
||||||
@ -44,7 +43,9 @@ def parse_binding(file_path: str, binding_dirs: list[str]) -> Binding:
|
|||||||
description=details.get('description', '').strip(),
|
description=details.get('description', '').strip(),
|
||||||
)
|
)
|
||||||
properties_dict[name] = prop
|
properties_dict[name] = prop
|
||||||
|
|
||||||
filename = os.path.basename(file_path)
|
filename = os.path.basename(file_path)
|
||||||
|
compatible = filename.removesuffix(".yaml").removesuffix(".yml")
|
||||||
return Binding(
|
return Binding(
|
||||||
filename=filename,
|
filename=filename,
|
||||||
compatible=compatible,
|
compatible=compatible,
|
||||||
|
|||||||
@ -18,10 +18,8 @@ def get_device_identifier_safe(device: Device):
|
|||||||
|
|
||||||
def get_device_type_name(device: Device, bindings: list[Binding]):
|
def get_device_type_name(device: Device, bindings: list[Binding]):
|
||||||
device_binding = find_device_binding(device, bindings)
|
device_binding = find_device_binding(device, bindings)
|
||||||
if device_binding is None:
|
if device_binding == None:
|
||||||
raise Exception(f"Binding not found for {device.identifier}")
|
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]
|
compatible_safe = device_binding.compatible.split(",")[-1]
|
||||||
return compatible_safe.replace("-", "_")
|
return compatible_safe.replace("-", "_")
|
||||||
|
|
||||||
@ -103,7 +101,7 @@ def write_config(file, device: Device, bindings: list[Binding], type_name: str):
|
|||||||
file.write(f"{config_params_joined}\n")
|
file.write(f"{config_params_joined}\n")
|
||||||
file.write("};\n\n")
|
file.write("};\n\n")
|
||||||
|
|
||||||
def write_device_structs(file, device: Device, parent_device: Device, bindings: list[Binding], verbose: bool):
|
def write_device_structs(file, device: Device, bindings: list[Binding], verbose: bool):
|
||||||
if verbose:
|
if verbose:
|
||||||
print(f"Writing device struct for '{device.identifier}'")
|
print(f"Writing device struct for '{device.identifier}'")
|
||||||
# Assemble some pre-requisites
|
# Assemble some pre-requisites
|
||||||
@ -113,38 +111,38 @@ def write_device_structs(file, device: Device, parent_device: Device, bindings:
|
|||||||
raise Exception(f"Cannot find 'compatible' property for {device.identifier}")
|
raise Exception(f"Cannot find 'compatible' property for {device.identifier}")
|
||||||
identifier = get_device_identifier_safe(device)
|
identifier = get_device_identifier_safe(device)
|
||||||
config_variable_name = f"{identifier}_config"
|
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 struct
|
||||||
write_config(file, device, bindings, type_name)
|
write_config(file, device, bindings, type_name)
|
||||||
# Write device struct
|
# Write device struct
|
||||||
file.write(f"static struct Device {identifier}" " = {\n")
|
file.write(f"static struct Device {identifier}" " = {\n")
|
||||||
file.write(f"\t.name = \"{device.identifier}\",\n") # Use original name
|
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.config = (void*)&{config_variable_name},\n")
|
||||||
file.write(f"\t.parent = {parent_value},\n")
|
|
||||||
file.write("};\n\n")
|
file.write("};\n\n")
|
||||||
# Child devices
|
# Child devices
|
||||||
for child_device in device.devices:
|
for child_device in device.devices:
|
||||||
write_device_structs(file, child_device, device, bindings, verbose)
|
write_device_structs(file, child_device, bindings, verbose)
|
||||||
|
|
||||||
def write_device_init(file, device: Device, bindings: list[Binding], verbose: bool):
|
def write_device_init(file, device: Device, parent_device: Device, bindings: list[Binding], verbose: bool):
|
||||||
if verbose:
|
if verbose:
|
||||||
print(f"Processing device init code for '{device.identifier}'")
|
print(f"Processing device init code for '{device.identifier}'")
|
||||||
# Assemble some pre-requisites
|
# Assemble some pre-requisites
|
||||||
|
type_name = get_device_type_name(device, bindings)
|
||||||
compatible_property = find_binding_property(device, "compatible")
|
compatible_property = find_binding_property(device, "compatible")
|
||||||
if compatible_property is None:
|
if compatible_property is None:
|
||||||
raise Exception(f"Cannot find 'compatible' property for {device.identifier}")
|
raise Exception(f"Cannot find 'compatible' property for {device.identifier}")
|
||||||
# Type & instance names
|
# Type & instance names
|
||||||
identifier = get_device_identifier_safe(device)
|
identifier = get_device_identifier_safe(device)
|
||||||
device_variable = identifier
|
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
|
# Write device struct
|
||||||
file.write(f"\tif (init_builtin_device(&{device_variable}, \"{compatible_property.value}\") != 0) return -1;\n")
|
file.write(f"\tif (init_builtin_device(&{device_variable}, \"{compatible_property.value}\", {parent_value}) != 0) return -1;\n")
|
||||||
# Write children
|
# Write children
|
||||||
for child_device in device.devices:
|
for child_device in device.devices:
|
||||||
write_device_init(file, child_device, bindings, verbose)
|
write_device_init(file, child_device, device, bindings, verbose)
|
||||||
|
|
||||||
def write_device_list_entry(file, device: Device):
|
def write_device_list_entry(file, device: Device):
|
||||||
compatible_property = find_binding_property(device, "compatible")
|
compatible_property = find_binding_property(device, "compatible")
|
||||||
@ -166,11 +164,11 @@ def write_device_list(file, devices: list[Device]):
|
|||||||
def generate_devicetree_c(filename: str, items: list[object], bindings: list[Binding], verbose: bool):
|
def generate_devicetree_c(filename: str, items: list[object], bindings: list[Binding], verbose: bool):
|
||||||
with open(filename, "w") as file:
|
with open(filename, "w") as file:
|
||||||
file.write(dedent('''\
|
file.write(dedent('''\
|
||||||
// Default headers
|
// Generated includes
|
||||||
#include <Tactility/Device.h>
|
#include <Tactility/Device.h>
|
||||||
#include <Tactility/Driver.h>
|
#include <Tactility/Driver.h>
|
||||||
#include <Tactility/Log.h>
|
#include <Tactility/Log.h>
|
||||||
// DTS headers
|
// DTS includes
|
||||||
'''))
|
'''))
|
||||||
|
|
||||||
# Write all headers first
|
# Write all headers first
|
||||||
@ -182,7 +180,7 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin
|
|||||||
file.write(dedent('''\
|
file.write(dedent('''\
|
||||||
#define TAG LOG_TAG(devicetree)
|
#define TAG LOG_TAG(devicetree)
|
||||||
|
|
||||||
static int init_builtin_device(struct Device* device, const char* compatible) {
|
static int init_builtin_device(struct Device* device, const char* compatible, struct Device* parent_device) {
|
||||||
struct Driver* driver = driver_find(compatible);
|
struct Driver* driver = driver_find(compatible);
|
||||||
if (driver == NULL) {
|
if (driver == NULL) {
|
||||||
LOG_E(TAG, "Can't find driver: %s", compatible);
|
LOG_E(TAG, "Can't find driver: %s", compatible);
|
||||||
@ -190,6 +188,7 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin
|
|||||||
}
|
}
|
||||||
device_construct(device);
|
device_construct(device);
|
||||||
device_set_driver(device, driver);
|
device_set_driver(device, driver);
|
||||||
|
device_set_parent(device, parent_device);
|
||||||
device_add(device);
|
device_add(device);
|
||||||
const int err = device_start(device);
|
const int err = device_start(device);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
@ -204,13 +203,13 @@ def generate_devicetree_c(filename: str, items: list[object], bindings: list[Bin
|
|||||||
# Then write all devices
|
# Then write all devices
|
||||||
for item in items:
|
for item in items:
|
||||||
if type(item) is Device:
|
if type(item) is Device:
|
||||||
write_device_structs(file, item, None, bindings, verbose)
|
write_device_structs(file, item, bindings, verbose)
|
||||||
# Init function body start
|
# Init function body start
|
||||||
file.write("int devices_builtin_init() {\n")
|
file.write("int devices_builtin_init() {\n")
|
||||||
# Init function body logic
|
# Init function body logic
|
||||||
for item in items:
|
for item in items:
|
||||||
if type(item) is Device:
|
if type(item) is Device:
|
||||||
write_device_init(file, item, bindings, verbose)
|
write_device_init(file, item, None, bindings, verbose)
|
||||||
file.write("\treturn 0;\n")
|
file.write("\treturn 0;\n")
|
||||||
# Init function body end
|
# Init function body end
|
||||||
file.write("}\n")
|
file.write("}\n")
|
||||||
|
|||||||
@ -35,7 +35,7 @@ class BindingProperty:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class Binding:
|
class Binding:
|
||||||
filename: str
|
filename: str
|
||||||
compatible: list[str]
|
compatible: str
|
||||||
description: str
|
description: str
|
||||||
properties: list[BindingProperty]
|
properties: list[BindingProperty]
|
||||||
includes: list[str]
|
includes: list[str]
|
||||||
|
|||||||
@ -32,7 +32,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
|||||||
"Firmware"
|
"Firmware"
|
||||||
"Devices/${TACTILITY_DEVICE_PROJECT}"
|
"Devices/${TACTILITY_DEVICE_PROJECT}"
|
||||||
"Drivers"
|
"Drivers"
|
||||||
"TactilityKernel"
|
"core"
|
||||||
"Tactility"
|
"Tactility"
|
||||||
"TactilityC"
|
"TactilityC"
|
||||||
"TactilityCore"
|
"TactilityCore"
|
||||||
@ -75,13 +75,13 @@ if (NOT DEFINED ENV{ESP_IDF_VERSION})
|
|||||||
add_subdirectory(Tactility)
|
add_subdirectory(Tactility)
|
||||||
add_subdirectory(TactilityCore)
|
add_subdirectory(TactilityCore)
|
||||||
add_subdirectory(TactilityFreeRtos)
|
add_subdirectory(TactilityFreeRtos)
|
||||||
add_subdirectory(TactilityKernel)
|
|
||||||
add_subdirectory(Devices/simulator)
|
add_subdirectory(Devices/simulator)
|
||||||
add_subdirectory(Libraries/cJSON)
|
add_subdirectory(Libraries/cJSON)
|
||||||
add_subdirectory(Libraries/lv_screenshot)
|
add_subdirectory(Libraries/lv_screenshot)
|
||||||
add_subdirectory(Libraries/QRCode)
|
add_subdirectory(Libraries/QRCode)
|
||||||
add_subdirectory(Libraries/minitar)
|
add_subdirectory(Libraries/minitar)
|
||||||
add_subdirectory(Libraries/minmea)
|
add_subdirectory(Libraries/minmea)
|
||||||
|
add_subdirectory(core)
|
||||||
|
|
||||||
# FreeRTOS
|
# FreeRTOS
|
||||||
set(FREERTOS_CONFIG_FILE_DIRECTORY ${PROJECT_SOURCE_DIR}/Devices/simulator/Source CACHE STRING "")
|
set(FREERTOS_CONFIG_FILE_DIRECTORY ${PROJECT_SOURCE_DIR}/Devices/simulator/Source CACHE STRING "")
|
||||||
|
|||||||
@ -20,7 +20,6 @@ Driver tlora_pager_driver = {
|
|||||||
.start_device = start,
|
.start_device = start,
|
||||||
.stop_device = stop,
|
.stop_device = stop,
|
||||||
.api = nullptr,
|
.api = nullptr,
|
||||||
.device_type = nullptr,
|
|
||||||
.internal = { 0 }
|
.internal = { 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
description: LilyGO T-Lora Pager
|
description: LilyGO T-Lora Pager
|
||||||
|
|
||||||
include: ["root.yaml"]
|
include: ["root.yaml"]
|
||||||
|
|
||||||
compatible: "lilygo,tlora-pager"
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
|||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS ${SOURCES}
|
SRCS ${SOURCES}
|
||||||
INCLUDE_DIRS "include/"
|
INCLUDE_DIRS "include/"
|
||||||
REQUIRES TactilityKernel driver
|
REQUIRES core driver
|
||||||
)
|
)
|
||||||
|
|
||||||
else ()
|
else ()
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
description: ESP32 GPIO Controller
|
description: ESP32 GPIO Controller
|
||||||
|
|
||||||
compatible: "espressif,esp32-gpio"
|
|
||||||
|
|
||||||
include: ["gpio-controller.yaml"]
|
include: ["gpio-controller.yaml"]
|
||||||
|
|||||||
@ -2,8 +2,6 @@ description: ESP32 GPIO Controller
|
|||||||
|
|
||||||
include: ["i2c-controller.yaml"]
|
include: ["i2c-controller.yaml"]
|
||||||
|
|
||||||
compatible: "espressif,esp32-i2c"
|
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
port:
|
port:
|
||||||
type: int
|
type: int
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
- TactilityKernel
|
- core
|
||||||
bindings: bindings
|
bindings: bindings
|
||||||
|
|||||||
@ -112,7 +112,6 @@ Driver esp32_gpio_driver = {
|
|||||||
.start_device = start,
|
.start_device = start,
|
||||||
.stop_device = stop,
|
.stop_device = stop,
|
||||||
.api = (void*)&esp32_gpio_api,
|
.api = (void*)&esp32_gpio_api,
|
||||||
.device_type = nullptr,
|
|
||||||
.internal = { 0 }
|
.internal = { 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -84,7 +84,6 @@ Driver esp32_i2c_driver = {
|
|||||||
.start_device = start,
|
.start_device = start,
|
||||||
.stop_device = stop,
|
.stop_device = stop,
|
||||||
.api = (void*)&esp32_i2c_api,
|
.api = (void*)&esp32_i2c_api,
|
||||||
.device_type = &I2C_CONTROLLER_TYPE,
|
|
||||||
.internal = { 0 }
|
.internal = { 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ if (DEFINED ENV{ESP_IDF_VERSION})
|
|||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS ${SOURCE_FILES}
|
SRCS ${SOURCE_FILES}
|
||||||
REQUIRES ${DEVICE_COMPONENTS}
|
REQUIRES ${DEVICE_COMPONENTS}
|
||||||
REQUIRES Tactility TactilityC TactilityKernel drivers-esp ${TACTILITY_DEVICE_PROJECT}
|
REQUIRES Tactility TactilityC core drivers-esp ${TACTILITY_DEVICE_PROJECT}
|
||||||
)
|
)
|
||||||
|
|
||||||
else ()
|
else ()
|
||||||
@ -32,9 +32,9 @@ else ()
|
|||||||
PRIVATE Tactility
|
PRIVATE Tactility
|
||||||
PRIVATE TactilityCore
|
PRIVATE TactilityCore
|
||||||
PRIVATE TactilityFreeRtos
|
PRIVATE TactilityFreeRtos
|
||||||
PRIVATE TactilityKernel
|
|
||||||
PRIVATE Simulator
|
PRIVATE Simulator
|
||||||
PRIVATE SDL2::SDL2-static SDL2-static
|
PRIVATE SDL2::SDL2-static SDL2-static
|
||||||
|
PRIVATE core
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(FirmwareSim PRIVATE "${CMAKE_SOURCE_DIR}/Firmware/Generated")
|
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*)
|
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
||||||
|
|
||||||
list(APPEND REQUIRES_LIST
|
list(APPEND REQUIRES_LIST
|
||||||
TactilityKernel
|
core
|
||||||
TactilityCore
|
TactilityCore
|
||||||
TactilityFreeRtos
|
TactilityFreeRtos
|
||||||
lvgl
|
lvgl
|
||||||
@ -72,12 +72,12 @@ else()
|
|||||||
PUBLIC cJSON
|
PUBLIC cJSON
|
||||||
PUBLIC TactilityFreeRtos
|
PUBLIC TactilityFreeRtos
|
||||||
PUBLIC TactilityCore
|
PUBLIC TactilityCore
|
||||||
PUBLIC TactilityKernel
|
|
||||||
PUBLIC freertos_kernel
|
PUBLIC freertos_kernel
|
||||||
PUBLIC lvgl
|
PUBLIC lvgl
|
||||||
PUBLIC lv_screenshot
|
PUBLIC lv_screenshot
|
||||||
PUBLIC minmea
|
PUBLIC minmea
|
||||||
PUBLIC minitar
|
PUBLIC minitar
|
||||||
|
PUBLIC core
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
compatible: "root"
|
|
||||||
|
|
||||||
properties:
|
properties:
|
||||||
model:
|
model:
|
||||||
required: true
|
required: true
|
||||||
49
core/include/Tactility/Bus.h
Normal file
49
core/include/Tactility/Bus.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#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,11 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Driver.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <Tactility/Bus.h>
|
||||||
#include <Tactility/concurrent/Mutex.h>
|
#include <Tactility/concurrent/Mutex.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@ -14,26 +13,22 @@ extern "C" {
|
|||||||
|
|
||||||
struct Driver;
|
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 */
|
/** Represents a piece of hardware */
|
||||||
struct Device {
|
struct Device {
|
||||||
/** The name of the device. Valid characters: a-z a-Z 0-9 - _ . */
|
/** The name of the device. Valid characters: a-z a-Z 0-9 - _ . */
|
||||||
const char* name;
|
const char* name;
|
||||||
/** The configuration data for the device's driver */
|
/** The configuration data for the device's driver */
|
||||||
void* config;
|
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 */
|
/** Internal data */
|
||||||
struct {
|
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. */
|
/** Address of the API exposed by the device instance. */
|
||||||
struct Driver* driver;
|
struct Driver* driver;
|
||||||
/** The driver data for this device (e.g. a mutex) */
|
/** The driver data for this device (e.g. a mutex) */
|
||||||
void* driver_data;
|
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 */
|
/** The mutex for device operations */
|
||||||
struct Mutex mutex;
|
struct Mutex mutex;
|
||||||
/** The device state */
|
/** The device state */
|
||||||
@ -139,6 +134,18 @@ static inline bool device_is_added(const struct Device* device) {
|
|||||||
return device->internal.state.added;
|
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) {
|
static inline void device_lock(struct Device* device) {
|
||||||
mutex_lock(&device->internal.mutex);
|
mutex_lock(&device->internal.mutex);
|
||||||
}
|
}
|
||||||
@ -151,18 +158,6 @@ static inline void device_unlock(struct Device* device) {
|
|||||||
mutex_unlock(&device->internal.mutex);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Tactility/Bus.h>
|
||||||
|
#include <Tactility/Device.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Device;
|
|
||||||
struct DeviceType;
|
|
||||||
|
|
||||||
struct Driver {
|
struct Driver {
|
||||||
/** The driver name */
|
/** The driver name */
|
||||||
const char* name;
|
const char* name;
|
||||||
@ -18,8 +18,6 @@ struct Driver {
|
|||||||
int (*stop_device)(struct Device* dev);
|
int (*stop_device)(struct Device* dev);
|
||||||
/** Contains the driver's functions */
|
/** Contains the driver's functions */
|
||||||
const void* api;
|
const void* api;
|
||||||
/** Which type of devices this driver creates (can be NULL) */
|
|
||||||
const struct DeviceType* device_type;
|
|
||||||
/** Internal data */
|
/** Internal data */
|
||||||
struct {
|
struct {
|
||||||
/** Contains private data */
|
/** Contains private data */
|
||||||
@ -27,19 +25,15 @@ struct Driver {
|
|||||||
} internal;
|
} internal;
|
||||||
};
|
};
|
||||||
|
|
||||||
int driver_construct(struct Driver* driver);
|
int driver_construct(struct Driver* drv);
|
||||||
|
|
||||||
int driver_destruct(struct Driver* driver);
|
int driver_destruct(struct Driver* drv);
|
||||||
|
|
||||||
struct Driver* driver_find(const char* compatible);
|
struct Driver* driver_find(const char* compatible);
|
||||||
|
|
||||||
int driver_bind(struct Driver* driver, struct Device* device);
|
int driver_bind(struct Driver* drv, struct Device* dev);
|
||||||
|
|
||||||
int driver_unbind(struct Driver* driver, struct Device* device);
|
int driver_unbind(struct Driver* drv, struct Device* dev);
|
||||||
|
|
||||||
static inline const struct DeviceType* driver_get_device_type(struct Driver* driver) {
|
|
||||||
return driver->device_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
@ -21,8 +21,6 @@ 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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
115
core/source/Bus.cpp
Normal file
115
core/source/Bus.cpp
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#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"
|
||||||
@ -85,11 +85,16 @@ void device_add(Device* device) {
|
|||||||
ledger_unlock();
|
ledger_unlock();
|
||||||
|
|
||||||
// Add self to parent's children list
|
// Add self to parent's children list
|
||||||
auto* parent = device->parent;
|
auto* parent = device->internal.parent;
|
||||||
if (parent != nullptr) {
|
if (parent != nullptr) {
|
||||||
device_add_child(parent, device);
|
device_add_child(parent, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* bus = device->internal.bus;
|
||||||
|
if (bus != nullptr) {
|
||||||
|
bus_add_device(bus, device);
|
||||||
|
}
|
||||||
|
|
||||||
device->internal.state.added = true;
|
device->internal.state.added = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,8 +108,13 @@ bool device_remove(Device* device) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* bus = device->internal.bus;
|
||||||
|
if (bus != nullptr) {
|
||||||
|
bus_remove_device(bus, device);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove self from parent's children list
|
// Remove self from parent's children list
|
||||||
auto* parent = device->parent;
|
auto* parent = device->internal.parent;
|
||||||
if (parent != nullptr) {
|
if (parent != nullptr) {
|
||||||
device_remove_child(parent, device);
|
device_remove_child(parent, device);
|
||||||
}
|
}
|
||||||
@ -128,6 +138,11 @@ failed_ledger_lookup:
|
|||||||
device_add_child(parent, device);
|
device_add_child(parent, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-add to bus
|
||||||
|
if (bus != nullptr) {
|
||||||
|
bus_add_device(bus, device);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,6 +180,15 @@ int device_stop(struct Device* device) {
|
|||||||
return 0;
|
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.started = false;
|
||||||
device->internal.state.start_result = 0;
|
device->internal.state.start_result = 0;
|
||||||
return 0;
|
return 0;
|
||||||
@ -172,22 +196,7 @@ int device_stop(struct Device* device) {
|
|||||||
|
|
||||||
void device_set_parent(Device* device, Device* parent) {
|
void device_set_parent(Device* device, Device* parent) {
|
||||||
assert(!device->internal.state.started);
|
assert(!device->internal.state.started);
|
||||||
device->parent = parent;
|
device->internal.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"
|
} // extern "C"
|
||||||
@ -2,7 +2,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <Tactility/concurrent/Mutex.h>
|
#include <Tactility/concurrent/Mutex.h>
|
||||||
#include <Tactility/Device.h>
|
|
||||||
#include <Tactility/Driver.h>
|
#include <Tactility/Driver.h>
|
||||||
#include <Tactility/Error.h>
|
#include <Tactility/Error.h>
|
||||||
#include <Tactility/Log.h>
|
#include <Tactility/Log.h>
|
||||||
@ -20,6 +20,4 @@ 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);
|
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,7 +9,6 @@ Driver root_driver = {
|
|||||||
.start_device = nullptr,
|
.start_device = nullptr,
|
||||||
.stop_device = nullptr,
|
.stop_device = nullptr,
|
||||||
.api = nullptr,
|
.api = nullptr,
|
||||||
.device_type = nullptr,
|
|
||||||
.internal = { 0 }
|
.internal = { 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user