829 lines
42 KiB
C
829 lines
42 KiB
C
#include "sim_hal.h"
|
|
|
|
#include <math.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
typedef struct {
|
|
uint32_t used;
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
sim_hal_value value;
|
|
} pin_entry;
|
|
|
|
typedef struct {
|
|
uint32_t used;
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
sim_hal_value value;
|
|
} param_entry;
|
|
|
|
typedef struct {
|
|
uint32_t used;
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
uint32_t period;
|
|
} thread_entry;
|
|
|
|
typedef struct {
|
|
uint32_t used;
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
uint32_t thread;
|
|
uint32_t calls;
|
|
uint32_t fail;
|
|
uint32_t component_index;
|
|
uint32_t component_kind;
|
|
} function_entry;
|
|
|
|
typedef struct {
|
|
uint32_t used;
|
|
char instance[SIM_HAL_NAME_CAPACITY];
|
|
char type[SIM_HAL_NAME_CAPACITY];
|
|
uint32_t kind;
|
|
uint32_t function_index;
|
|
double memory[4];
|
|
uint32_t flags[4];
|
|
} component_entry;
|
|
|
|
typedef struct {
|
|
uint32_t used;
|
|
uint32_t source;
|
|
uint32_t target;
|
|
} link_entry;
|
|
|
|
enum {
|
|
SIM_HAL_COMPONENT_NONE = 0,
|
|
SIM_HAL_COMPONENT_COREXY = 1,
|
|
SIM_HAL_COMPONENT_CONSTANT,
|
|
SIM_HAL_COMPONENT_AND2,
|
|
SIM_HAL_COMPONENT_OR2,
|
|
SIM_HAL_COMPONENT_XOR2,
|
|
SIM_HAL_COMPONENT_NOT,
|
|
SIM_HAL_COMPONENT_ABS,
|
|
SIM_HAL_COMPONENT_ABS_S32,
|
|
SIM_HAL_COMPONENT_ABS_S64,
|
|
SIM_HAL_COMPONENT_LOWPASS,
|
|
SIM_HAL_COMPONENT_DDT,
|
|
SIM_HAL_COMPONENT_INTEG,
|
|
SIM_HAL_COMPONENT_MUX2,
|
|
SIM_HAL_COMPONENT_SUM2,
|
|
SIM_HAL_COMPONENT_MULT2,
|
|
SIM_HAL_COMPONENT_DIV2,
|
|
SIM_HAL_COMPONENT_HYPOT,
|
|
SIM_HAL_COMPONENT_NEAR,
|
|
SIM_HAL_COMPONENT_COMP,
|
|
SIM_HAL_COMPONENT_INVERT,
|
|
SIM_HAL_COMPONENT_EDGE,
|
|
SIM_HAL_COMPONENT_TOGGLE,
|
|
SIM_HAL_COMPONENT_ESTOP_LATCH
|
|
};
|
|
|
|
typedef struct {
|
|
uint32_t tick;
|
|
pin_entry pins[SIM_HAL_PIN_CAPACITY];
|
|
param_entry params[SIM_HAL_PARAM_CAPACITY];
|
|
thread_entry threads[SIM_HAL_THREAD_CAPACITY];
|
|
function_entry functions[SIM_HAL_FUNCTION_CAPACITY];
|
|
component_entry components[SIM_HAL_COMPONENT_CAPACITY];
|
|
link_entry links[256U];
|
|
} hal_state;
|
|
|
|
static hal_state state;
|
|
|
|
static int valid_name(const char *name) {
|
|
return name != NULL && name[0] != '\0' && strlen(name) < SIM_HAL_NAME_CAPACITY;
|
|
}
|
|
|
|
static int find_pin(const char *name) {
|
|
uint32_t index;
|
|
for (index = 0; index < SIM_HAL_PIN_CAPACITY; ++index) {
|
|
if (state.pins[index].used && strcmp(state.pins[index].name, name) == 0) return (int)index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int find_param(const char *name) {
|
|
uint32_t index;
|
|
for (index = 0; index < SIM_HAL_PARAM_CAPACITY; ++index) {
|
|
if (state.params[index].used && strcmp(state.params[index].name, name) == 0) return (int)index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int find_thread(const char *name) {
|
|
uint32_t index;
|
|
for (index = 0; index < SIM_HAL_THREAD_CAPACITY; ++index) {
|
|
if (state.threads[index].used && strcmp(state.threads[index].name, name) == 0) return (int)index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int find_function(const char *name) {
|
|
uint32_t index;
|
|
for (index = 0; index < SIM_HAL_FUNCTION_CAPACITY; ++index) {
|
|
if (state.functions[index].used && strcmp(state.functions[index].name, name) == 0) return (int)index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int find_component(const char *instance) {
|
|
uint32_t index;
|
|
for (index = 0; index < SIM_HAL_COMPONENT_CAPACITY; ++index) {
|
|
if (state.components[index].used && strcmp(state.components[index].instance, instance) == 0) return (int)index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int finite_value(sim_hal_value value) {
|
|
return value.type != SIM_HAL_FLOAT || isfinite((double)value.value.real);
|
|
}
|
|
|
|
static int type_from_name(const char *name, uint32_t *type) {
|
|
if (name == NULL || type == NULL) return 0;
|
|
if (strcmp(name, "bit") == 0) *type = SIM_HAL_BIT;
|
|
else if (strcmp(name, "s32") == 0 || strcmp(name, "signed") == 0) *type = SIM_HAL_S32;
|
|
else if (strcmp(name, "u32") == 0 || strcmp(name, "unsigned") == 0) *type = SIM_HAL_U32;
|
|
else if (strcmp(name, "float") == 0) *type = SIM_HAL_FLOAT;
|
|
else return 0;
|
|
return 1;
|
|
}
|
|
|
|
void sim_hal_reset(void) {
|
|
memset(&state, 0, sizeof(state));
|
|
}
|
|
|
|
int32_t sim_hal_register_pin(const char *name, uint32_t type) {
|
|
uint32_t index;
|
|
if (!valid_name(name) || type < SIM_HAL_BIT || type > SIM_HAL_FLOAT) return SIM_HAL_ERR_ARGUMENT;
|
|
if (find_pin(name) >= 0) return SIM_HAL_ERR_DUPLICATE;
|
|
for (index = 0; index < SIM_HAL_PIN_CAPACITY; ++index) {
|
|
if (!state.pins[index].used) {
|
|
state.pins[index].used = 1;
|
|
strcpy(state.pins[index].name, name);
|
|
state.pins[index].value.type = type;
|
|
return SIM_HAL_OK;
|
|
}
|
|
}
|
|
return SIM_HAL_ERR_FULL;
|
|
}
|
|
|
|
int32_t sim_hal_set_pin(const char *name, sim_hal_value value) {
|
|
int index = find_pin(name);
|
|
if (index < 0) return SIM_HAL_ERR_NOT_FOUND;
|
|
if (value.type != state.pins[index].value.type) return SIM_HAL_ERR_TYPE;
|
|
if (value.type == SIM_HAL_BIT && value.value.bit > 1U) return SIM_HAL_ERR_RANGE;
|
|
if (!finite_value(value)) return SIM_HAL_ERR_RANGE;
|
|
state.pins[index].value = value;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
int32_t sim_hal_set_pin_scalar(const char *name, uint32_t type, double value) {
|
|
sim_hal_value scalar = {0};
|
|
scalar.type = type;
|
|
if (type == SIM_HAL_BIT) scalar.value.bit = value != 0.0;
|
|
else if (type == SIM_HAL_S32) scalar.value.s32 = (int32_t)value;
|
|
else if (type == SIM_HAL_U32) scalar.value.u32 = (uint32_t)value;
|
|
else if (type == SIM_HAL_FLOAT) scalar.value.real = (float)value;
|
|
else return SIM_HAL_ERR_TYPE;
|
|
return sim_hal_set_pin(name, scalar);
|
|
}
|
|
|
|
int32_t sim_hal_get_pin(const char *name, sim_hal_value *out) {
|
|
int index = find_pin(name);
|
|
if (index < 0 || out == NULL) return index < 0 ? SIM_HAL_ERR_NOT_FOUND : SIM_HAL_ERR_ARGUMENT;
|
|
*out = state.pins[index].value;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
int32_t sim_hal_set_param(const char *name, sim_hal_value value) {
|
|
int index = find_param(name);
|
|
if (index < 0) return SIM_HAL_ERR_NOT_FOUND;
|
|
if (value.type != state.params[index].value.type) return SIM_HAL_ERR_TYPE;
|
|
if (value.type == SIM_HAL_BIT && value.value.bit > 1U) return SIM_HAL_ERR_RANGE;
|
|
if (!finite_value(value)) return SIM_HAL_ERR_RANGE;
|
|
state.params[index].value = value;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
int32_t sim_hal_set_param_scalar(const char *name, uint32_t type, double value) {
|
|
sim_hal_value scalar = {0};
|
|
scalar.type = type;
|
|
if (type == SIM_HAL_BIT) scalar.value.bit = value != 0.0;
|
|
else if (type == SIM_HAL_S32) scalar.value.s32 = (int32_t)value;
|
|
else if (type == SIM_HAL_U32) scalar.value.u32 = (uint32_t)value;
|
|
else if (type == SIM_HAL_FLOAT) scalar.value.real = (float)value;
|
|
else return SIM_HAL_ERR_TYPE;
|
|
return sim_hal_set_param(name, scalar);
|
|
}
|
|
|
|
int32_t sim_hal_get_param(const char *name, sim_hal_value *out) {
|
|
int index = find_param(name);
|
|
if (index < 0 || out == NULL) return index < 0 ? SIM_HAL_ERR_NOT_FOUND : SIM_HAL_ERR_ARGUMENT;
|
|
*out = state.params[index].value;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
int32_t sim_hal_connect(const char *source, const char *target) {
|
|
int source_index = find_pin(source);
|
|
int target_index = find_pin(target);
|
|
uint32_t link_index;
|
|
if (source_index < 0 || target_index < 0) return SIM_HAL_ERR_NOT_FOUND;
|
|
if (state.pins[source_index].value.type != state.pins[target_index].value.type) return SIM_HAL_ERR_CONNECTION;
|
|
for (link_index = 0; link_index < 256U; ++link_index) {
|
|
if (state.links[link_index].used && state.links[link_index].source == (uint32_t)source_index && state.links[link_index].target == (uint32_t)target_index) return SIM_HAL_ERR_DUPLICATE;
|
|
}
|
|
for (link_index = 0; link_index < 256U; ++link_index) {
|
|
if (!state.links[link_index].used) {
|
|
state.links[link_index].used = 1U;
|
|
state.links[link_index].source = (uint32_t)source_index;
|
|
state.links[link_index].target = (uint32_t)target_index;
|
|
break;
|
|
}
|
|
}
|
|
if (link_index == 256U) return SIM_HAL_ERR_FULL;
|
|
state.pins[target_index].value = state.pins[source_index].value;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
int32_t sim_hal_register_thread(const char *name, uint32_t period_ticks) {
|
|
uint32_t index;
|
|
if (!valid_name(name) || period_ticks == 0U || period_ticks > 1000000U) return SIM_HAL_ERR_RANGE;
|
|
if (find_thread(name) >= 0) return SIM_HAL_ERR_DUPLICATE;
|
|
for (index = 0; index < SIM_HAL_THREAD_CAPACITY; ++index) {
|
|
if (!state.threads[index].used) {
|
|
state.threads[index].used = 1;
|
|
strcpy(state.threads[index].name, name);
|
|
state.threads[index].period = period_ticks;
|
|
return SIM_HAL_OK;
|
|
}
|
|
}
|
|
return SIM_HAL_ERR_FULL;
|
|
}
|
|
|
|
int32_t sim_hal_register_function(const char *thread, const char *name) {
|
|
uint32_t index;
|
|
int thread_index = find_thread(thread);
|
|
if (thread_index < 0) return SIM_HAL_ERR_NOT_FOUND;
|
|
if (!valid_name(name)) return SIM_HAL_ERR_ARGUMENT;
|
|
if (find_function(name) >= 0) return SIM_HAL_ERR_DUPLICATE;
|
|
for (index = 0; index < SIM_HAL_FUNCTION_CAPACITY; ++index) {
|
|
if (!state.functions[index].used) {
|
|
state.functions[index].used = 1;
|
|
strcpy(state.functions[index].name, name);
|
|
state.functions[index].thread = (uint32_t)thread_index;
|
|
return SIM_HAL_OK;
|
|
}
|
|
}
|
|
return SIM_HAL_ERR_FULL;
|
|
}
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
uint32_t type;
|
|
} component_pin_spec;
|
|
|
|
typedef struct {
|
|
const char *name;
|
|
uint32_t type;
|
|
sim_hal_value initial;
|
|
} component_param_spec;
|
|
|
|
typedef struct {
|
|
uint32_t kind;
|
|
const component_pin_spec *pins;
|
|
uint32_t pin_count;
|
|
const component_param_spec *params;
|
|
uint32_t param_count;
|
|
} component_spec;
|
|
|
|
static const component_pin_spec pins_corexy[] = {
|
|
{"j0-motor-pos-cmd", SIM_HAL_FLOAT}, {"j1-motor-pos-cmd", SIM_HAL_FLOAT},
|
|
{"alpha-cmd", SIM_HAL_FLOAT}, {"beta-cmd", SIM_HAL_FLOAT},
|
|
{"alpha-fb", SIM_HAL_FLOAT}, {"beta-fb", SIM_HAL_FLOAT},
|
|
{"j0-motor-pos-fb", SIM_HAL_FLOAT}, {"j1-motor-pos-fb", SIM_HAL_FLOAT}
|
|
};
|
|
static const component_pin_spec pins_bit2[] = {
|
|
{"in0", SIM_HAL_BIT}, {"in1", SIM_HAL_BIT}, {"out", SIM_HAL_BIT}
|
|
};
|
|
static const component_pin_spec pins_bit1[] = {{"in", SIM_HAL_BIT}, {"out", SIM_HAL_BIT}};
|
|
static const component_pin_spec pins_abs[] = {
|
|
{"in", SIM_HAL_FLOAT}, {"out", SIM_HAL_FLOAT}, {"sign", SIM_HAL_BIT},
|
|
{"is-positive", SIM_HAL_BIT}, {"is-negative", SIM_HAL_BIT}
|
|
};
|
|
static const component_pin_spec pins_abs_s32[] = {
|
|
{"in", SIM_HAL_S32}, {"out", SIM_HAL_S32}, {"sign", SIM_HAL_BIT},
|
|
{"is-positive", SIM_HAL_BIT}, {"is-negative", SIM_HAL_BIT}
|
|
};
|
|
static const component_pin_spec pins_float2[] = {
|
|
{"in0", SIM_HAL_FLOAT}, {"in1", SIM_HAL_FLOAT}, {"out", SIM_HAL_FLOAT}
|
|
};
|
|
static const component_pin_spec pins_lowpass[] = {
|
|
{"in", SIM_HAL_FLOAT}, {"out", SIM_HAL_FLOAT}, {"load", SIM_HAL_BIT}
|
|
};
|
|
static const component_pin_spec pins_ddt[] = {{"in", SIM_HAL_FLOAT}, {"out", SIM_HAL_FLOAT}};
|
|
static const component_pin_spec pins_integ[] = {
|
|
{"in", SIM_HAL_FLOAT}, {"gain", SIM_HAL_FLOAT}, {"out", SIM_HAL_FLOAT},
|
|
{"reset", SIM_HAL_BIT}, {"max", SIM_HAL_FLOAT}, {"min", SIM_HAL_FLOAT}
|
|
};
|
|
static const component_pin_spec pins_mux2[] = {
|
|
{"sel", SIM_HAL_BIT}, {"out", SIM_HAL_FLOAT}, {"in1", SIM_HAL_FLOAT}, {"in0", SIM_HAL_FLOAT}
|
|
};
|
|
static const component_pin_spec pins_sum2[] = {
|
|
{"in0", SIM_HAL_FLOAT}, {"in1", SIM_HAL_FLOAT}, {"out", SIM_HAL_FLOAT}
|
|
};
|
|
static const component_pin_spec pins_hypot[] = {
|
|
{"in0", SIM_HAL_FLOAT}, {"in1", SIM_HAL_FLOAT}, {"in2", SIM_HAL_FLOAT}, {"out", SIM_HAL_FLOAT}
|
|
};
|
|
static const component_pin_spec pins_near[] = {
|
|
{"in1", SIM_HAL_FLOAT}, {"in2", SIM_HAL_FLOAT}, {"out", SIM_HAL_BIT}
|
|
};
|
|
static const component_pin_spec pins_comp[] = {
|
|
{"in0", SIM_HAL_FLOAT}, {"in1", SIM_HAL_FLOAT}, {"out", SIM_HAL_BIT}, {"equal", SIM_HAL_BIT}
|
|
};
|
|
static const component_pin_spec pins_edge[] = {
|
|
{"in", SIM_HAL_BIT}, {"out", SIM_HAL_BIT}, {"out-invert", SIM_HAL_BIT}
|
|
};
|
|
static const component_pin_spec pins_estop[] = {
|
|
{"ok-in", SIM_HAL_BIT}, {"fault-in", SIM_HAL_BIT}, {"reset", SIM_HAL_BIT},
|
|
{"ok-out", SIM_HAL_BIT}, {"fault-out", SIM_HAL_BIT}, {"watchdog", SIM_HAL_BIT}
|
|
};
|
|
static const component_pin_spec pins_constant[] = {{"out", SIM_HAL_FLOAT}};
|
|
static const component_pin_spec pins_invert[] = {{"in", SIM_HAL_FLOAT}, {"out", SIM_HAL_FLOAT}};
|
|
static const component_pin_spec pins_toggle[] = {{"in", SIM_HAL_BIT}, {"out", SIM_HAL_BIT}};
|
|
|
|
static const component_param_spec param_constant[] = {
|
|
{"value", SIM_HAL_FLOAT, {SIM_HAL_FLOAT, {.real = 0.0f}}}
|
|
};
|
|
static const component_param_spec param_lowpass[] = {
|
|
{"gain", SIM_HAL_FLOAT, {SIM_HAL_FLOAT, {.real = 0.0f}}}
|
|
};
|
|
static const component_param_spec param_sum2[] = {
|
|
{"gain0", SIM_HAL_FLOAT, {SIM_HAL_FLOAT, {.real = 1.0f}}},
|
|
{"gain1", SIM_HAL_FLOAT, {SIM_HAL_FLOAT, {.real = 1.0f}}},
|
|
{"offset", SIM_HAL_FLOAT, {SIM_HAL_FLOAT, {.real = 0.0f}}}
|
|
};
|
|
static const component_param_spec param_div2[] = {
|
|
{"deadband", SIM_HAL_FLOAT, {SIM_HAL_FLOAT, {.real = 0.0f}}}
|
|
};
|
|
static const component_param_spec param_near[] = {
|
|
{"scale", SIM_HAL_FLOAT, {SIM_HAL_FLOAT, {.real = 1.0f}}},
|
|
{"difference", SIM_HAL_FLOAT, {SIM_HAL_FLOAT, {.real = 0.0f}}}
|
|
};
|
|
static const component_param_spec param_comp[] = {
|
|
{"hyst", SIM_HAL_FLOAT, {SIM_HAL_FLOAT, {.real = 0.0f}}}
|
|
};
|
|
static const component_param_spec param_invert[] = {
|
|
{"deadband", SIM_HAL_FLOAT, {SIM_HAL_FLOAT, {.real = 0.0f}}}
|
|
};
|
|
static const component_param_spec param_edge[] = {
|
|
{"both", SIM_HAL_BIT, {SIM_HAL_BIT, {.bit = 0U}}},
|
|
{"in-edge", SIM_HAL_BIT, {SIM_HAL_BIT, {.bit = 1U}}},
|
|
{"out-width-ns", SIM_HAL_S32, {SIM_HAL_S32, {.s32 = 0}}},
|
|
{"time-left-ns", SIM_HAL_S32, {SIM_HAL_S32, {.s32 = 0}}},
|
|
{"last-in", SIM_HAL_BIT, {SIM_HAL_BIT, {.bit = 0U}}}
|
|
};
|
|
static const component_param_spec param_toggle[] = {
|
|
{"debounce", SIM_HAL_U32, {SIM_HAL_U32, {.u32 = 2U}}}
|
|
};
|
|
|
|
static int component_spec_for(const char *type, component_spec *out) {
|
|
if (type == NULL || out == NULL) return 0;
|
|
memset(out, 0, sizeof(*out));
|
|
#define SPEC(kind_value, pin_array) do { out->kind = (kind_value); out->pins = (pin_array); out->pin_count = (uint32_t)(sizeof(pin_array) / sizeof((pin_array)[0])); return 1; } while (0)
|
|
if (strcmp(type, "corexy_by_hal") == 0) SPEC(SIM_HAL_COMPONENT_COREXY, pins_corexy);
|
|
if (strcmp(type, "constant") == 0) { out->kind = SIM_HAL_COMPONENT_CONSTANT; out->pins = pins_constant; out->pin_count = 1U; out->params = param_constant; out->param_count = 1U; return 1; }
|
|
if (strcmp(type, "and2") == 0) SPEC(SIM_HAL_COMPONENT_AND2, pins_bit2);
|
|
if (strcmp(type, "or2") == 0) SPEC(SIM_HAL_COMPONENT_OR2, pins_bit2);
|
|
if (strcmp(type, "xor2") == 0) SPEC(SIM_HAL_COMPONENT_XOR2, pins_bit2);
|
|
if (strcmp(type, "not") == 0 || strcmp(type, "invert_bit") == 0) SPEC(SIM_HAL_COMPONENT_NOT, pins_bit1);
|
|
if (strcmp(type, "abs") == 0) SPEC(SIM_HAL_COMPONENT_ABS, pins_abs);
|
|
if (strcmp(type, "abs_s32") == 0) SPEC(SIM_HAL_COMPONENT_ABS_S32, pins_abs_s32);
|
|
if (strcmp(type, "lowpass") == 0) { out->kind = SIM_HAL_COMPONENT_LOWPASS; out->pins = pins_lowpass; out->pin_count = 3U; out->params = param_lowpass; out->param_count = 1U; return 1; }
|
|
if (strcmp(type, "ddt") == 0) SPEC(SIM_HAL_COMPONENT_DDT, pins_ddt);
|
|
if (strcmp(type, "integ") == 0) SPEC(SIM_HAL_COMPONENT_INTEG, pins_integ);
|
|
if (strcmp(type, "mux2") == 0) SPEC(SIM_HAL_COMPONENT_MUX2, pins_mux2);
|
|
if (strcmp(type, "sum2") == 0) { out->kind = SIM_HAL_COMPONENT_SUM2; out->pins = pins_sum2; out->pin_count = 3U; out->params = param_sum2; out->param_count = 3U; return 1; }
|
|
if (strcmp(type, "mult2") == 0) SPEC(SIM_HAL_COMPONENT_MULT2, pins_float2);
|
|
if (strcmp(type, "div2") == 0) { out->kind = SIM_HAL_COMPONENT_DIV2; out->pins = pins_float2; out->pin_count = 3U; out->params = param_div2; out->param_count = 1U; return 1; }
|
|
if (strcmp(type, "hypot") == 0) SPEC(SIM_HAL_COMPONENT_HYPOT, pins_hypot);
|
|
if (strcmp(type, "near") == 0) { out->kind = SIM_HAL_COMPONENT_NEAR; out->pins = pins_near; out->pin_count = 3U; out->params = param_near; out->param_count = 2U; return 1; }
|
|
if (strcmp(type, "comp") == 0) { out->kind = SIM_HAL_COMPONENT_COMP; out->pins = pins_comp; out->pin_count = 4U; out->params = param_comp; out->param_count = 1U; return 1; }
|
|
if (strcmp(type, "invert") == 0) { out->kind = SIM_HAL_COMPONENT_INVERT; out->pins = pins_invert; out->pin_count = 2U; out->params = param_invert; out->param_count = 1U; return 1; }
|
|
if (strcmp(type, "edge") == 0) { out->kind = SIM_HAL_COMPONENT_EDGE; out->pins = pins_edge; out->pin_count = 3U; out->params = param_edge; out->param_count = 5U; return 1; }
|
|
if (strcmp(type, "toggle") == 0) { out->kind = SIM_HAL_COMPONENT_TOGGLE; out->pins = pins_toggle; out->pin_count = 2U; out->params = param_toggle; out->param_count = 1U; return 1; }
|
|
if (strcmp(type, "estop_latch") == 0) SPEC(SIM_HAL_COMPONENT_ESTOP_LATCH, pins_estop);
|
|
#undef SPEC
|
|
return 0;
|
|
}
|
|
|
|
static int32_t qualified_name(const char *instance, const char *suffix, char *out) {
|
|
size_t left;
|
|
size_t right;
|
|
if (!valid_name(instance) || suffix == NULL || out == NULL) return SIM_HAL_ERR_ARGUMENT;
|
|
left = strlen(instance); right = strlen(suffix);
|
|
if (left + 1U + right >= SIM_HAL_NAME_CAPACITY) return SIM_HAL_ERR_RANGE;
|
|
memcpy(out, instance, left); out[left] = '.'; memcpy(out + left + 1U, suffix, right + 1U);
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
static int32_t register_param_internal(const char *name, sim_hal_value value) {
|
|
uint32_t index;
|
|
if (!valid_name(name) || !finite_value(value)) return SIM_HAL_ERR_ARGUMENT;
|
|
if (find_param(name) >= 0) return SIM_HAL_ERR_DUPLICATE;
|
|
for (index = 0; index < SIM_HAL_PARAM_CAPACITY; ++index) {
|
|
if (!state.params[index].used) {
|
|
state.params[index].used = 1U;
|
|
strcpy(state.params[index].name, name);
|
|
state.params[index].value = value;
|
|
return SIM_HAL_OK;
|
|
}
|
|
}
|
|
return SIM_HAL_ERR_FULL;
|
|
}
|
|
|
|
static void component_initialize_defaults(const component_entry *component);
|
|
|
|
int32_t sim_hal_register_component(const char *instance, const char *type, const char *thread) {
|
|
component_spec spec;
|
|
hal_state before;
|
|
char qualified[SIM_HAL_NAME_CAPACITY];
|
|
uint32_t index;
|
|
int component_index;
|
|
int function_index;
|
|
int32_t result;
|
|
if (!valid_name(instance) || !valid_name(type) || !valid_name(thread)) return SIM_HAL_ERR_ARGUMENT;
|
|
if (!component_spec_for(type, &spec)) return SIM_HAL_ERR_REAL_EXCLUDED;
|
|
if (find_component(instance) >= 0 || find_function(instance) >= 0) return SIM_HAL_ERR_DUPLICATE;
|
|
if (find_thread(thread) < 0) return SIM_HAL_ERR_NOT_FOUND;
|
|
memcpy(&before, &state, sizeof(state));
|
|
component_index = -1;
|
|
for (index = 0; index < SIM_HAL_COMPONENT_CAPACITY; ++index) {
|
|
if (!state.components[index].used) { component_index = (int)index; break; }
|
|
}
|
|
if (component_index < 0) return SIM_HAL_ERR_FULL;
|
|
state.components[component_index].used = 1U;
|
|
strcpy(state.components[component_index].instance, instance);
|
|
strcpy(state.components[component_index].type, type);
|
|
state.components[component_index].kind = spec.kind;
|
|
state.components[component_index].function_index = 0U;
|
|
for (index = 0; index < spec.pin_count; ++index) {
|
|
result = qualified_name(instance, spec.pins[index].name, qualified);
|
|
if (result != SIM_HAL_OK || (result = sim_hal_register_pin(qualified, spec.pins[index].type)) != SIM_HAL_OK) { memcpy(&state, &before, sizeof(state)); return result; }
|
|
}
|
|
for (index = 0; index < spec.param_count; ++index) {
|
|
result = qualified_name(instance, spec.params[index].name, qualified);
|
|
if (result != SIM_HAL_OK || (result = register_param_internal(qualified, spec.params[index].initial)) != SIM_HAL_OK) { memcpy(&state, &before, sizeof(state)); return result; }
|
|
}
|
|
result = sim_hal_register_function(thread, instance);
|
|
if (result != SIM_HAL_OK) { memcpy(&state, &before, sizeof(state)); return result; }
|
|
function_index = find_function(instance);
|
|
state.components[component_index].function_index = (uint32_t)function_index;
|
|
state.functions[function_index].component_index = (uint32_t)component_index;
|
|
state.functions[function_index].component_kind = spec.kind;
|
|
component_initialize_defaults(&state.components[component_index]);
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
static int32_t corexy_pin_names(const char *component, char names[8][SIM_HAL_NAME_CAPACITY]) {
|
|
static const char *suffixes[8] = {
|
|
".j0-motor-pos-cmd", ".j1-motor-pos-cmd", ".alpha-cmd", ".beta-cmd",
|
|
".alpha-fb", ".beta-fb", ".j0-motor-pos-fb", ".j1-motor-pos-fb",
|
|
};
|
|
uint32_t index;
|
|
if (!valid_name(component)) return SIM_HAL_ERR_ARGUMENT;
|
|
for (index = 0; index < 8; ++index) {
|
|
size_t prefix = strlen(component);
|
|
size_t suffix = strlen(suffixes[index]);
|
|
if (prefix + suffix >= SIM_HAL_NAME_CAPACITY) return SIM_HAL_ERR_RANGE;
|
|
memcpy(names[index], component, prefix);
|
|
memcpy(names[index] + prefix, suffixes[index], suffix + 1);
|
|
}
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
int32_t sim_hal_register_corexy_by_hal(const char *component, const char *thread) {
|
|
char names[8][SIM_HAL_NAME_CAPACITY];
|
|
uint32_t index;
|
|
int32_t result;
|
|
if (component == NULL || thread == NULL) return SIM_HAL_ERR_ARGUMENT;
|
|
result = corexy_pin_names(component, names);
|
|
if (result != SIM_HAL_OK) return result;
|
|
for (index = 0; index < 8; ++index) {
|
|
if (find_pin(names[index]) >= 0) return SIM_HAL_ERR_DUPLICATE;
|
|
}
|
|
if (find_function(component) >= 0) return SIM_HAL_ERR_DUPLICATE;
|
|
for (index = 0; index < 8; ++index) {
|
|
result = sim_hal_register_pin(names[index], SIM_HAL_FLOAT);
|
|
if (result != SIM_HAL_OK) return result;
|
|
}
|
|
result = sim_hal_register_function(thread, component);
|
|
if (result != SIM_HAL_OK) return result;
|
|
state.functions[find_function(component)].component_index = UINT32_MAX;
|
|
state.functions[find_function(component)].component_kind = SIM_HAL_COMPONENT_COREXY;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
static int32_t float_pin(const char *name, float *value) {
|
|
sim_hal_value pin = {0};
|
|
int32_t result = sim_hal_get_pin(name, &pin);
|
|
if (result != SIM_HAL_OK) return result;
|
|
if (pin.type != SIM_HAL_FLOAT) return SIM_HAL_ERR_TYPE;
|
|
*value = pin.value.real;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
static int32_t set_float_pin(const char *name, float value) {
|
|
sim_hal_value pin = {SIM_HAL_FLOAT, {.real = value}};
|
|
return sim_hal_set_pin(name, pin);
|
|
}
|
|
|
|
int32_t sim_hal_corexy_transform(const char *component) {
|
|
char names[8][SIM_HAL_NAME_CAPACITY];
|
|
float j0_cmd, j1_cmd, alpha_fb, beta_fb;
|
|
int32_t result = corexy_pin_names(component, names);
|
|
if (result != SIM_HAL_OK) return result;
|
|
result = float_pin(names[0], &j0_cmd); if (result != SIM_HAL_OK) return result;
|
|
result = float_pin(names[1], &j1_cmd); if (result != SIM_HAL_OK) return result;
|
|
result = float_pin(names[4], &alpha_fb); if (result != SIM_HAL_OK) return result;
|
|
result = float_pin(names[5], &beta_fb); if (result != SIM_HAL_OK) return result;
|
|
result = set_float_pin(names[2], 0.5f * (j0_cmd + j1_cmd)); if (result != SIM_HAL_OK) return result;
|
|
result = set_float_pin(names[3], 0.5f * (j0_cmd - j1_cmd)); if (result != SIM_HAL_OK) return result;
|
|
result = set_float_pin(names[6], alpha_fb + beta_fb); if (result != SIM_HAL_OK) return result;
|
|
return set_float_pin(names[7], alpha_fb - beta_fb);
|
|
}
|
|
|
|
static int32_t component_pin_name(const component_entry *component, const char *suffix, char out[SIM_HAL_NAME_CAPACITY]) {
|
|
return qualified_name(component->instance, suffix, out);
|
|
}
|
|
|
|
static int32_t component_float_pin(const component_entry *component, const char *suffix, float *value) {
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
sim_hal_value pin = {0};
|
|
int32_t result = component_pin_name(component, suffix, name);
|
|
if (result != SIM_HAL_OK) return result;
|
|
result = sim_hal_get_pin(name, &pin);
|
|
if (result != SIM_HAL_OK) return result;
|
|
if (pin.type != SIM_HAL_FLOAT || !finite_value(pin)) return SIM_HAL_ERR_TYPE;
|
|
*value = pin.value.real;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
static int32_t component_bit_pin(const component_entry *component, const char *suffix, uint32_t *value) {
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
sim_hal_value pin = {0};
|
|
int32_t result = component_pin_name(component, suffix, name);
|
|
if (result != SIM_HAL_OK) return result;
|
|
result = sim_hal_get_pin(name, &pin);
|
|
if (result != SIM_HAL_OK) return result;
|
|
if (pin.type != SIM_HAL_BIT) return SIM_HAL_ERR_TYPE;
|
|
*value = pin.value.bit;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
static int32_t component_s32_pin(const component_entry *component, const char *suffix, int32_t *value) {
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
sim_hal_value pin = {0};
|
|
int32_t result = component_pin_name(component, suffix, name);
|
|
if (result != SIM_HAL_OK) return result;
|
|
result = sim_hal_get_pin(name, &pin);
|
|
if (result != SIM_HAL_OK) return result;
|
|
if (pin.type != SIM_HAL_S32) return SIM_HAL_ERR_TYPE;
|
|
*value = pin.value.s32;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
static int32_t component_write_float(const component_entry *component, const char *suffix, float value) {
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
int32_t result = component_pin_name(component, suffix, name);
|
|
if (result != SIM_HAL_OK) return result;
|
|
return sim_hal_set_pin(name, (sim_hal_value){SIM_HAL_FLOAT, {.real = value}});
|
|
}
|
|
|
|
static int32_t component_write_bit(const component_entry *component, const char *suffix, uint32_t value) {
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
int32_t result = component_pin_name(component, suffix, name);
|
|
if (result != SIM_HAL_OK) return result;
|
|
return sim_hal_set_pin(name, (sim_hal_value){SIM_HAL_BIT, {.bit = value ? 1U : 0U}});
|
|
}
|
|
|
|
static int32_t component_write_s32(const component_entry *component, const char *suffix, int32_t value) {
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
int32_t result = component_pin_name(component, suffix, name);
|
|
if (result != SIM_HAL_OK) return result;
|
|
return sim_hal_set_pin(name, (sim_hal_value){SIM_HAL_S32, {.s32 = value}});
|
|
}
|
|
|
|
static int32_t component_float_param(const component_entry *component, const char *suffix, float *value) {
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
sim_hal_value param = {0};
|
|
int32_t result = component_pin_name(component, suffix, name);
|
|
if (result != SIM_HAL_OK) return result;
|
|
result = sim_hal_get_param(name, ¶m);
|
|
if (result != SIM_HAL_OK) return result;
|
|
if (param.type != SIM_HAL_FLOAT || !finite_value(param)) return SIM_HAL_ERR_TYPE;
|
|
*value = param.value.real;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
static int32_t component_bit_param(const component_entry *component, const char *suffix, uint32_t *value) {
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
sim_hal_value param = {0};
|
|
int32_t result = component_pin_name(component, suffix, name);
|
|
if (result != SIM_HAL_OK) return result;
|
|
result = sim_hal_get_param(name, ¶m);
|
|
if (result != SIM_HAL_OK) return result;
|
|
if (param.type != SIM_HAL_BIT) return SIM_HAL_ERR_TYPE;
|
|
*value = param.value.bit;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
static int32_t component_s32_param(const component_entry *component, const char *suffix, int32_t *value) {
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
sim_hal_value param = {0};
|
|
int32_t result = component_pin_name(component, suffix, name);
|
|
if (result != SIM_HAL_OK) return result;
|
|
result = sim_hal_get_param(name, ¶m);
|
|
if (result != SIM_HAL_OK) return result;
|
|
if (param.type != SIM_HAL_S32) return SIM_HAL_ERR_TYPE;
|
|
*value = param.value.s32;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
static int32_t component_write_bit_param(const component_entry *component, const char *suffix, uint32_t value) {
|
|
char name[SIM_HAL_NAME_CAPACITY];
|
|
int32_t result = component_pin_name(component, suffix, name);
|
|
if (result != SIM_HAL_OK) return result;
|
|
return sim_hal_set_param(name, (sim_hal_value){SIM_HAL_BIT, {.bit = value ? 1U : 0U}});
|
|
}
|
|
|
|
static void component_initialize_defaults(const component_entry *component) {
|
|
if (component->kind == SIM_HAL_COMPONENT_INTEG) {
|
|
(void)component_write_float(component, "gain", 1.0f);
|
|
(void)component_write_float(component, "max", 1.0e20f);
|
|
(void)component_write_float(component, "min", -1.0e20f);
|
|
} else if (component->kind == SIM_HAL_COMPONENT_ESTOP_LATCH) {
|
|
(void)component_write_bit(component, "ok-in", 1U);
|
|
(void)component_write_bit(component, "fault-in", 0U);
|
|
(void)component_write_bit(component, "ok-out", 0U);
|
|
(void)component_write_bit(component, "fault-out", 1U);
|
|
}
|
|
}
|
|
|
|
static int32_t component_step(component_entry *component) {
|
|
float a, b, c, value;
|
|
uint32_t bit, other;
|
|
int32_t integer;
|
|
int32_t result;
|
|
if (component->kind == SIM_HAL_COMPONENT_COREXY) return sim_hal_corexy_transform(component->instance);
|
|
switch (component->kind) {
|
|
case SIM_HAL_COMPONENT_CONSTANT:
|
|
result = component_float_param(component, "value", &value); if (result != SIM_HAL_OK) return result;
|
|
return component_write_float(component, "out", value);
|
|
case SIM_HAL_COMPONENT_AND2: case SIM_HAL_COMPONENT_OR2: case SIM_HAL_COMPONENT_XOR2:
|
|
result = component_bit_pin(component, "in0", &bit); if (result != SIM_HAL_OK) return result;
|
|
result = component_bit_pin(component, "in1", &other); if (result != SIM_HAL_OK) return result;
|
|
value = (float)(component->kind == SIM_HAL_COMPONENT_AND2 ? (bit && other) : component->kind == SIM_HAL_COMPONENT_OR2 ? (bit || other) : (bit != other));
|
|
return component_write_bit(component, "out", value != 0.0f);
|
|
case SIM_HAL_COMPONENT_NOT:
|
|
result = component_bit_pin(component, "in", &bit); if (result != SIM_HAL_OK) return result;
|
|
return component_write_bit(component, "out", !bit);
|
|
case SIM_HAL_COMPONENT_ABS:
|
|
result = component_float_pin(component, "in", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_write_float(component, "out", fabsf(a)); if (result != SIM_HAL_OK) return result;
|
|
result = component_write_bit(component, "sign", a < 0.0f); if (result != SIM_HAL_OK) return result;
|
|
result = component_write_bit(component, "is-positive", a > 0.000001f); if (result != SIM_HAL_OK) return result;
|
|
return component_write_bit(component, "is-negative", a < -0.000001f);
|
|
case SIM_HAL_COMPONENT_ABS_S32: case SIM_HAL_COMPONENT_ABS_S64:
|
|
result = component_s32_pin(component, "in", &integer); if (result != SIM_HAL_OK) return result;
|
|
if (integer == INT32_MIN) return SIM_HAL_ERR_RANGE;
|
|
result = component_write_s32(component, "out", integer < 0 ? -integer : integer); if (result != SIM_HAL_OK) return result;
|
|
result = component_write_bit(component, "sign", integer < 0); if (result != SIM_HAL_OK) return result;
|
|
result = component_write_bit(component, "is-positive", integer > 0); if (result != SIM_HAL_OK) return result;
|
|
return component_write_bit(component, "is-negative", integer < 0);
|
|
case SIM_HAL_COMPONENT_LOWPASS:
|
|
result = component_float_pin(component, "in", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "out", &b); if (result != SIM_HAL_OK) return result;
|
|
result = component_bit_pin(component, "load", &bit); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_param(component, "gain", &c); if (result != SIM_HAL_OK) return result;
|
|
return component_write_float(component, "out", bit ? a : b + (a - b) * c);
|
|
case SIM_HAL_COMPONENT_DDT:
|
|
result = component_float_pin(component, "in", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_write_float(component, "out", (float)(a - component->memory[0]));
|
|
component->memory[0] = a; return result;
|
|
case SIM_HAL_COMPONENT_INTEG:
|
|
result = component_float_pin(component, "in", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "gain", &b); if (result != SIM_HAL_OK) return result;
|
|
result = component_bit_pin(component, "reset", &bit); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "max", &c); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "min", &value); if (result != SIM_HAL_OK) return result;
|
|
if (bit) component->memory[0] = 0.0; else component->memory[0] += (double)a * (double)b;
|
|
if (component->memory[0] > c) component->memory[0] = c;
|
|
if (component->memory[0] < value) component->memory[0] = value;
|
|
return component_write_float(component, "out", (float)component->memory[0]);
|
|
case SIM_HAL_COMPONENT_MUX2:
|
|
result = component_bit_pin(component, "sel", &bit); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, bit ? "in1" : "in0", &a); if (result != SIM_HAL_OK) return result;
|
|
return component_write_float(component, "out", a);
|
|
case SIM_HAL_COMPONENT_SUM2:
|
|
result = component_float_pin(component, "in0", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "in1", &b); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_param(component, "gain0", &c); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_param(component, "gain1", &value); if (result != SIM_HAL_OK) return result;
|
|
{ float offset; result = component_float_param(component, "offset", &offset); if (result != SIM_HAL_OK) return result; return component_write_float(component, "out", a * c + b * value + offset); }
|
|
case SIM_HAL_COMPONENT_MULT2:
|
|
result = component_float_pin(component, "in0", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "in1", &b); if (result != SIM_HAL_OK) return result;
|
|
return component_write_float(component, "out", a * b);
|
|
case SIM_HAL_COMPONENT_DIV2:
|
|
result = component_float_pin(component, "in0", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "in1", &b); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_param(component, "deadband", &c); if (result != SIM_HAL_OK) return result;
|
|
if (c < 1e-12f) c = 1e-12f; if (fabsf(b) < c) b = b < 0.0f ? -c : c;
|
|
return component_write_float(component, "out", a / b);
|
|
case SIM_HAL_COMPONENT_HYPOT:
|
|
result = component_float_pin(component, "in0", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "in1", &b); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "in2", &c); if (result != SIM_HAL_OK) return result;
|
|
return component_write_float(component, "out", sqrtf(a * a + b * b + c * c));
|
|
case SIM_HAL_COMPONENT_NEAR:
|
|
result = component_float_pin(component, "in1", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "in2", &b); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_param(component, "scale", &c); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_param(component, "difference", &value); if (result != SIM_HAL_OK) return result;
|
|
if (a < 0.0f) { a = -a; b = -b; }
|
|
return component_write_bit(component, "out", ((c > 1.0f && a / c <= b && b <= a * c) || fabsf(a - b) <= value));
|
|
case SIM_HAL_COMPONENT_COMP:
|
|
result = component_float_pin(component, "in0", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_pin(component, "in1", &b); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_param(component, "hyst", &c); if (result != SIM_HAL_OK) return result;
|
|
if (b - a < -0.5f * c) { result = component_write_bit(component, "out", 0U); if (result != SIM_HAL_OK) return result; return component_write_bit(component, "equal", 0U); }
|
|
if (b - a > 0.5f * c) { result = component_write_bit(component, "out", 1U); if (result != SIM_HAL_OK) return result; return component_write_bit(component, "equal", 0U); }
|
|
return component_write_bit(component, "equal", 1U);
|
|
case SIM_HAL_COMPONENT_INVERT:
|
|
result = component_float_pin(component, "in", &a); if (result != SIM_HAL_OK) return result;
|
|
result = component_float_param(component, "deadband", &c); if (result != SIM_HAL_OK) return result;
|
|
if (c < 1e-12f) c = 1e-12f; if (fabsf(a) < c) a = a < 0.0f ? -c : c;
|
|
return component_write_float(component, "out", 1.0f / a);
|
|
case SIM_HAL_COMPONENT_EDGE:
|
|
result = component_bit_pin(component, "in", &bit); if (result != SIM_HAL_OK) return result;
|
|
result = component_bit_param(component, "last-in", &other); if (result != SIM_HAL_OK) return result;
|
|
if (component->flags[0] == 0U) { component->flags[0] = 1U; component->memory[0] = bit; return component_write_bit(component, "out-invert", 1U); }
|
|
{ uint32_t both, in_edge; result = component_bit_param(component, "both", &both); if (result != SIM_HAL_OK) return result; result = component_bit_param(component, "in-edge", &in_edge); if (result != SIM_HAL_OK) return result; uint32_t rise = bit && !other, fall = !bit && other; uint32_t hit = both ? (rise || fall) : (in_edge ? fall : rise); result = component_write_bit(component, "out", hit); if (result != SIM_HAL_OK) return result; result = component_write_bit(component, "out-invert", !hit); if (result != SIM_HAL_OK) return result; result = component_write_bit_param(component, "last-in", bit); component->memory[0] = bit; return result; }
|
|
case SIM_HAL_COMPONENT_TOGGLE:
|
|
result = component_bit_pin(component, "in", &bit); if (result != SIM_HAL_OK) return result;
|
|
result = component_bit_pin(component, "out", &other); if (result != SIM_HAL_OK) return result;
|
|
{ sim_hal_value param = {0}; char name[SIM_HAL_NAME_CAPACITY]; component_pin_name(component, "debounce", name); result = sim_hal_get_param(name, ¶m); if (result != SIM_HAL_OK) return result; uint32_t debounce = param.value.u32 < 1U || param.value.u32 > 10000U ? 2U : param.value.u32; if (bit) { if (component->flags[0] < debounce) component->flags[0] += 1U; if (component->flags[0] >= debounce && component->flags[1] == 0U) { other = !other; component->flags[1] = 1U; } } else { component->flags[0] = 0U; component->flags[1] = 0U; } return component_write_bit(component, "out", other); }
|
|
case SIM_HAL_COMPONENT_ESTOP_LATCH:
|
|
result = component_bit_pin(component, "ok-in", &bit); if (result != SIM_HAL_OK) return result;
|
|
result = component_bit_pin(component, "fault-in", &other); if (result != SIM_HAL_OK) return result;
|
|
{ uint32_t reset; result = component_bit_pin(component, "reset", &reset); if (result != SIM_HAL_OK) return result; if (!bit || other) { component->flags[0] = 0U; } else if (reset && component->flags[1] == 0U) component->flags[0] = 1U; component->flags[1] = reset; result = component_write_bit(component, "ok-out", component->flags[0]); if (result != SIM_HAL_OK) return result; result = component_write_bit(component, "fault-out", !component->flags[0]); if (result != SIM_HAL_OK) return result; if (component->flags[0]) component->flags[2] ^= 1U; return component_write_bit(component, "watchdog", component->flags[2]); }
|
|
default: return SIM_HAL_ERR_REAL_EXCLUDED;
|
|
}
|
|
}
|
|
|
|
int32_t sim_hal_set_function_failure(const char *name, uint32_t fail) {
|
|
int index = find_function(name);
|
|
if (index < 0) return SIM_HAL_ERR_NOT_FOUND;
|
|
state.functions[index].fail = fail ? 1U : 0U;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
int32_t sim_hal_step(uint32_t ticks) {
|
|
hal_state before;
|
|
uint64_t target;
|
|
uint64_t tick;
|
|
uint32_t function_index;
|
|
if ((uint64_t)state.tick + (uint64_t)ticks > UINT32_MAX) return SIM_HAL_ERR_RANGE;
|
|
memcpy(&before, &state, sizeof(state));
|
|
target = (uint64_t)state.tick + (uint64_t)ticks;
|
|
for (tick = (uint64_t)state.tick + 1U; tick <= target; ++tick) {
|
|
for (function_index = 0; function_index < 256U; ++function_index) {
|
|
if (state.links[function_index].used) {
|
|
uint32_t source = state.links[function_index].source;
|
|
uint32_t target_pin = state.links[function_index].target;
|
|
state.pins[target_pin].value = state.pins[source].value;
|
|
}
|
|
}
|
|
for (function_index = 0; function_index < SIM_HAL_FUNCTION_CAPACITY; ++function_index) {
|
|
function_entry *function = &state.functions[function_index];
|
|
if (!function->used || tick % state.threads[function->thread].period != 0U) continue;
|
|
if (function->fail) { memcpy(&state, &before, sizeof(state)); return SIM_HAL_ERR_FUNCTION; }
|
|
if (function->component_kind != SIM_HAL_COMPONENT_NONE) {
|
|
int32_t result;
|
|
if (function->component_kind == SIM_HAL_COMPONENT_COREXY && function->component_index == UINT32_MAX) result = sim_hal_corexy_transform(function->name);
|
|
else if (function->component_index >= SIM_HAL_COMPONENT_CAPACITY || !state.components[function->component_index].used) result = SIM_HAL_ERR_NOT_FOUND;
|
|
else result = component_step(&state.components[function->component_index]);
|
|
if (result != SIM_HAL_OK) { memcpy(&state, &before, sizeof(state)); return SIM_HAL_ERR_FUNCTION; }
|
|
}
|
|
function->calls += 1U;
|
|
}
|
|
}
|
|
state.tick = (uint32_t)target;
|
|
return SIM_HAL_OK;
|
|
}
|
|
|
|
uint32_t sim_hal_tick(void) { return state.tick; }
|
|
uint32_t sim_hal_function_calls(const char *name) { int index = find_function(name); return index < 0 ? 0U : state.functions[index].calls; }
|
|
uint32_t sim_hal_pin_count(void) { uint32_t i, count = 0; for (i = 0; i < SIM_HAL_PIN_CAPACITY; ++i) count += state.pins[i].used; return count; }
|
|
uint32_t sim_hal_thread_count(void) { uint32_t i, count = 0; for (i = 0; i < SIM_HAL_THREAD_CAPACITY; ++i) count += state.threads[i].used; return count; }
|
|
uint32_t sim_hal_function_count(void) { uint32_t i, count = 0; for (i = 0; i < SIM_HAL_FUNCTION_CAPACITY; ++i) count += state.functions[i].used; return count; }
|
|
uint32_t sim_hal_component_count(void) { uint32_t i, count = 0; for (i = 0; i < SIM_HAL_COMPONENT_CAPACITY; ++i) count += state.components[i].used; return count; }
|
|
uint32_t sim_hal_param_count(void) { uint32_t i, count = 0; for (i = 0; i < SIM_HAL_PARAM_CAPACITY; ++i) count += state.params[i].used; return count; }
|