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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ if(CONFIG_ARBITER)
${CMAKE_CURRENT_LIST_DIR}/lib/arbiter_accel.c
)

zephyr_library_sources_ifdef(CONFIG_ARBITER_EVENT_DRIVEN
${CMAKE_CURRENT_LIST_DIR}/lib/arbiter_event.c
)

zephyr_library_sources_ifdef(CONFIG_ARBITER_COMPOSE
${CMAKE_CURRENT_LIST_DIR}/lib/arbiter_compose.c
)

zephyr_library_sources_ifdef(CONFIG_ARBITER_STATE_MACHINE
${CMAKE_CURRENT_LIST_DIR}/lib/arbiter_state.c
)

zephyr_include_directories(${CMAKE_CURRENT_LIST_DIR}/include)

add_subdirectory_ifdef(CONFIG_ARBITER ${CMAKE_CURRENT_LIST_DIR}/subsys/arbiter)
Expand Down
141 changes: 141 additions & 0 deletions include/arbiter/arbiter_compose.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/* SPDX-License-Identifier: MIT */

#ifndef ARBITER_COMPOSE_H_
#define ARBITER_COMPOSE_H_

/**
* @defgroup arbiter_compose Multi-Model Composition (REQ-ARCH-037)
* @ingroup arbiter
* @{
* @brief Share facts across multiple models via a common fact bus.
*
* The fact bus holds a shared array of fact values. Each model is
* "attached" with a mapping table that translates bus fact indices
* to the model's own fact indices. ARBITER_compose_sync() pushes
* bus values into all attached contexts; ARBITER_compose_eval_all()
* evaluates every attached model in attachment order.
*
* All storage is pre-allocated — no malloc.
*/

#include <stdint.h>
#include <stdbool.h>
#include <arbiter/arbiter.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef CONFIG_ARBITER_MAX_MODELS
#define CONFIG_ARBITER_MAX_MODELS 4
#endif

#ifndef CONFIG_ARBITER_COMPOSE_MAX_BUS_FACTS
#define CONFIG_ARBITER_COMPOSE_MAX_BUS_FACTS 64
#endif

/** Maps one bus fact to a model fact. */
struct ARBITER_fact_mapping {
uint16_t bus_fact_id; /**< Index into the bus fact array. */
uint16_t model_fact_id; /**< Index into the model's own fact array. */
};

/** Per-attachment record (bus ↔ model link). */
struct ARBITER_compose_attachment {
struct ARBITER_ctx *ctx; /**< Model context. */
const struct ARBITER_fact_mapping *mapping; /**< Mapping table. */
uint16_t map_count; /**< Number of mappings. */
bool active; /**< Slot occupied? */
};

/** Shared fact bus. */
struct ARBITER_fact_bus {
struct ARBITER_fact_value *facts; /**< Shared fact array. */
uint16_t max_facts; /**< Capacity of facts[]. */

struct ARBITER_compose_attachment
attachments[CONFIG_ARBITER_MAX_MODELS]; /**< Attached models. */
uint16_t attachment_count; /**< Active attachments. */
};

/**
* @brief Initialize a fact bus with a pre-allocated fact array.
*
* @param bus Bus to initialize.
* @param facts Pre-allocated array of fact values.
* @param max_facts Capacity of facts[].
* @return ARBITER_OK on success, ARBITER_EINVAL if bus or facts is NULL.
*/
int ARBITER_compose_init(struct ARBITER_fact_bus *bus,
struct ARBITER_fact_value *facts,
uint16_t max_facts);

/**
* @brief Attach a model context to the bus.
*
* @param bus Initialized fact bus.
* @param ctx Model context to attach.
* @param mapping Array of bus-to-model fact mappings.
* @param map_count Number of entries in mapping[].
* @return ARBITER_OK on success, ARBITER_EOVERFLOW if no slots available.
*/
int ARBITER_compose_attach(struct ARBITER_fact_bus *bus,
struct ARBITER_ctx *ctx,
const struct ARBITER_fact_mapping *mapping,
uint16_t map_count);

/**
* @brief Detach a model context from the bus.
*
* @param bus Bus.
* @param ctx Context to detach.
* @return ARBITER_OK on success, ARBITER_EINVAL if not found.
*/
int ARBITER_compose_detach(struct ARBITER_fact_bus *bus,
struct ARBITER_ctx *ctx);

/**
* @brief Set a fact value on the bus.
*
* @param bus Initialized fact bus.
* @param fact_id Bus fact index.
* @param value Value to set.
* @return ARBITER_OK or ARBITER_ERANGE.
*/
int ARBITER_compose_set_fact(struct ARBITER_fact_bus *bus,
uint16_t fact_id, int32_t value);

/**
* @brief Push bus facts into all attached model contexts.
*
* For each attachment, iterates the mapping table and copies the bus
* fact values into the model context's fact_values[].
*
* @param bus Initialized fact bus.
* @return ARBITER_OK on success.
*/
int ARBITER_compose_sync(struct ARBITER_fact_bus *bus);

/**
* @brief Evaluate all attached models in attachment order.
*
* For each attached model, takes a snapshot, evaluates, and stores
* the result. Caller must provide arrays of at least
* bus->attachment_count entries.
*
* @param bus Initialized fact bus.
* @param results Pre-allocated array for results (one per attached model).
* @param traces Pre-allocated array for traces (one per model, NULL entries OK).
* @return ARBITER_OK on success.
*/
int ARBITER_compose_eval_all(struct ARBITER_fact_bus *bus,
struct ARBITER_result *results,
struct ARBITER_trace *traces);

/** @} */

#ifdef __cplusplus
}
#endif

#endif /* ARBITER_COMPOSE_H_ */
118 changes: 118 additions & 0 deletions include/arbiter/arbiter_event.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/* SPDX-License-Identifier: MIT */

#ifndef ARBITER_EVENT_H_
#define ARBITER_EVENT_H_

/**
* @defgroup arbiter_event Event-Driven Evaluation (REQ-ARCH-036)
* @ingroup arbiter
* @{
* @brief Watch facts for changes and trigger evaluation only when needed.
*
* Instead of polling on a fixed period, the event subsystem lets callers
* mark specific facts as "watched". When a watched fact changes, a
* pending flag is set. The runtime thread (or application) can check
* ARBITER_event_pending() and skip evaluation cycles when nothing has
* changed — saving CPU on idle periods.
*
* Implementation uses static bitmasks — no dynamic allocation.
* For models with <= 32 facts a single uint32_t pair is used.
* For larger models a uint8_t byte-array is used (1 bit per fact).
*/

#include <stdint.h>
#include <stdbool.h>
#include <arbiter/arbiter.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef CONFIG_ARBITER_MAX_FACTS
#define CONFIG_ARBITER_MAX_FACTS 64
#endif

/** Number of bytes needed to hold one bit per fact. */
#define ARBITER_EVENT_MASK_BYTES \
((CONFIG_ARBITER_MAX_FACTS + 7u) / 8u)

/** Event tracking state — embedded in or alongside an ARBITER_ctx. */
struct ARBITER_event_ctx {
#if CONFIG_ARBITER_MAX_FACTS <= 32
uint32_t watched; /**< Bitmask of watched fact ids. */
uint32_t pending; /**< Bitmask of changed watched facts. */
#else
uint8_t watched[ARBITER_EVENT_MASK_BYTES];
uint8_t pending[ARBITER_EVENT_MASK_BYTES];
#endif
bool any_pending; /**< Fast flag: true if any bit in pending is set. */
};

/**
* @brief Initialize event tracking for a context.
*
* Clears all watched and pending flags.
*
* @param ectx Event context to initialize.
* @return ARBITER_OK on success, ARBITER_EINVAL if ectx is NULL.
*/
int ARBITER_event_init(struct ARBITER_event_ctx *ectx);

/**
* @brief Mark a fact as watched.
*
* @param ectx Event context.
* @param fact_id Fact index (0-based, < CONFIG_ARBITER_MAX_FACTS).
* @return ARBITER_OK on success, ARBITER_ERANGE if fact_id out of range.
*/
int ARBITER_watch_fact(struct ARBITER_event_ctx *ectx, uint16_t fact_id);

/**
* @brief Remove a fact from the watch set.
*
* Also clears any pending flag for that fact.
*
* @param ectx Event context.
* @param fact_id Fact index.
* @return ARBITER_OK on success, ARBITER_ERANGE if fact_id out of range.
*/
int ARBITER_unwatch_fact(struct ARBITER_event_ctx *ectx, uint16_t fact_id);

/**
* @brief Notify that a fact has changed.
*
* If the fact is watched, sets its pending bit and the fast flag.
* If the fact is not watched, this is a no-op.
*
* @param ectx Event context.
* @param fact_id Fact index.
* @return ARBITER_OK on success, ARBITER_ERANGE if fact_id out of range.
*/
int ARBITER_notify_fact_changed(struct ARBITER_event_ctx *ectx,
uint16_t fact_id);

/**
* @brief Check whether any watched fact has changed since last clear.
*
* @param ectx Event context.
* @return true if at least one watched fact has a pending change.
*/
bool ARBITER_event_pending(const struct ARBITER_event_ctx *ectx);

/**
* @brief Clear all pending flags.
*
* Typically called after a successful evaluation cycle.
*
* @param ectx Event context.
* @return ARBITER_OK on success, ARBITER_EINVAL if ectx is NULL.
*/
int ARBITER_event_clear(struct ARBITER_event_ctx *ectx);

/** @} */

#ifdef __cplusplus
}
#endif

#endif /* ARBITER_EVENT_H_ */
Loading
Loading