Initial LinuxCNC WebAssembly workspace snapshot
This commit is contained in:
79
wasm-core/src/sim_api.c
Normal file
79
wasm-core/src/sim_api.c
Normal file
@@ -0,0 +1,79 @@
|
||||
#include "sim_api.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t created;
|
||||
uint32_t loaded;
|
||||
uint64_t tick;
|
||||
uint32_t pending_event;
|
||||
} sim_state;
|
||||
|
||||
static sim_state state;
|
||||
|
||||
static int valid_buffer(const uint8_t *data, uint32_t len) {
|
||||
return len == 0 || data != NULL;
|
||||
}
|
||||
|
||||
int32_t sim_create(const uint8_t *config, uint32_t config_len) {
|
||||
if (!valid_buffer(config, config_len)) return SIM_ERR_INVALID_ARGUMENT;
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.created = 1;
|
||||
state.pending_event = 1;
|
||||
return SIM_OK;
|
||||
}
|
||||
|
||||
int32_t sim_load_workspace(const char *root_path) {
|
||||
if (!state.created) return SIM_ERR_NOT_CREATED;
|
||||
if (root_path == NULL || root_path[0] == '\0') return SIM_ERR_INVALID_ARGUMENT;
|
||||
state.loaded = 1;
|
||||
state.pending_event = 1;
|
||||
return SIM_OK;
|
||||
}
|
||||
|
||||
int32_t sim_command(const uint8_t *command, uint32_t command_len) {
|
||||
if (!state.created || !state.loaded) return SIM_ERR_INVALID_STATE;
|
||||
if (!valid_buffer(command, command_len) || command_len == 0) return SIM_ERR_INVALID_ARGUMENT;
|
||||
state.pending_event = 1;
|
||||
return SIM_OK;
|
||||
}
|
||||
|
||||
int32_t sim_step(uint32_t cycles) {
|
||||
if (!state.created || !state.loaded) return SIM_ERR_INVALID_STATE;
|
||||
state.tick += cycles;
|
||||
state.pending_event = 1;
|
||||
return SIM_OK;
|
||||
}
|
||||
|
||||
uint32_t sim_read_snapshot(uint8_t *out, uint32_t capacity) {
|
||||
const uint32_t size = (uint32_t)sizeof(state.tick);
|
||||
if (out == NULL || capacity < size) return size;
|
||||
memcpy(out, &state.tick, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t sim_read_event(uint8_t *out, uint32_t capacity) {
|
||||
const uint32_t size = 1;
|
||||
if (!state.pending_event) return 0;
|
||||
if (out == NULL || capacity < size) return size;
|
||||
out[0] = 1;
|
||||
state.pending_event = 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
int32_t sim_export_state(uint8_t *out, uint32_t capacity) {
|
||||
const uint32_t size = (uint32_t)sizeof(state);
|
||||
if (out == NULL || capacity < size) return SIM_ERR_BUFFER_TOO_SMALL;
|
||||
memcpy(out, &state, size);
|
||||
return (int32_t)size;
|
||||
}
|
||||
|
||||
int32_t sim_import_state(const uint8_t *data, uint32_t len) {
|
||||
if (data == NULL || len != sizeof(state)) return SIM_ERR_INVALID_ARGUMENT;
|
||||
memcpy(&state, data, sizeof(state));
|
||||
return SIM_OK;
|
||||
}
|
||||
|
||||
void sim_destroy(void) {
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
82
wasm-core/src/sim_event.c
Normal file
82
wasm-core/src/sim_event.c
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "sim_event.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct sim_event_state {
|
||||
uint32_t count;
|
||||
uint32_t last_seq;
|
||||
uint32_t last_tick;
|
||||
sim_event_record records[SIM_EVENT_CAPACITY];
|
||||
} sim_event_state;
|
||||
|
||||
static sim_event_state state;
|
||||
|
||||
static uint64_t hash_payload(const uint8_t *payload, uint32_t payload_len) {
|
||||
uint64_t hash = 1469598103934665603ULL;
|
||||
uint32_t index;
|
||||
if (payload == NULL && payload_len != 0U) return 0;
|
||||
for (index = 0; index < payload_len; ++index) {
|
||||
hash ^= payload[index];
|
||||
hash *= 1099511628211ULL;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
void sim_event_reset(void) {
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
||||
int32_t sim_event_append(uint32_t seq, uint32_t tick, const char *kind,
|
||||
const uint8_t *payload, uint32_t payload_len) {
|
||||
sim_event_record *record;
|
||||
size_t kind_len;
|
||||
if (seq == 0U || seq != state.last_seq + 1U) return SIM_EVENT_ERR_SEQUENCE;
|
||||
if (tick < state.last_tick) return SIM_EVENT_ERR_TICK;
|
||||
if (kind == NULL || kind[0] == '\0') return SIM_EVENT_ERR_ARGUMENT;
|
||||
kind_len = strlen(kind);
|
||||
if (kind_len >= SIM_EVENT_KIND_CAPACITY || (payload == NULL && payload_len != 0U)) return SIM_EVENT_ERR_ARGUMENT;
|
||||
if (state.count >= SIM_EVENT_CAPACITY) return SIM_EVENT_ERR_FULL;
|
||||
record = &state.records[state.count++];
|
||||
memset(record, 0, sizeof(*record));
|
||||
memcpy(record->kind, kind, kind_len);
|
||||
record->seq = seq;
|
||||
record->tick = tick;
|
||||
record->payload_hash = hash_payload(payload, payload_len);
|
||||
state.last_seq = seq;
|
||||
state.last_tick = tick;
|
||||
return SIM_EVENT_OK;
|
||||
}
|
||||
|
||||
uint32_t sim_event_count(void) {
|
||||
return state.count;
|
||||
}
|
||||
|
||||
uint32_t sim_event_cursor(void) {
|
||||
return state.last_seq;
|
||||
}
|
||||
|
||||
uint32_t sim_event_read(uint32_t index, uint8_t *out, uint32_t capacity) {
|
||||
const uint32_t size = (uint32_t)sizeof(sim_event_record);
|
||||
if (index >= state.count) return 0;
|
||||
if (out == NULL || capacity < size) return size;
|
||||
memcpy(out, &state.records[index], size);
|
||||
return size;
|
||||
}
|
||||
|
||||
uint32_t sim_event_export(uint8_t *out, uint32_t capacity) {
|
||||
const uint32_t size = (uint32_t)sizeof(state);
|
||||
if (out == NULL || capacity < size) return size;
|
||||
memcpy(out, &state, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
int32_t sim_event_import(const uint8_t *data, uint32_t len) {
|
||||
if (data == NULL || len != sizeof(state)) return SIM_EVENT_ERR_ARGUMENT;
|
||||
memcpy(&state, data, sizeof(state));
|
||||
if (state.count > SIM_EVENT_CAPACITY) {
|
||||
sim_event_reset();
|
||||
return SIM_EVENT_ERR_ARGUMENT;
|
||||
}
|
||||
return SIM_EVENT_OK;
|
||||
}
|
||||
166
wasm-core/src/sim_hal.c
Normal file
166
wasm-core/src/sim_hal.c
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "sim_hal.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];
|
||||
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;
|
||||
} function_entry;
|
||||
|
||||
typedef struct {
|
||||
uint32_t tick;
|
||||
pin_entry pins[SIM_HAL_PIN_CAPACITY];
|
||||
thread_entry threads[SIM_HAL_THREAD_CAPACITY];
|
||||
function_entry functions[SIM_HAL_FUNCTION_CAPACITY];
|
||||
} 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_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;
|
||||
}
|
||||
|
||||
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;
|
||||
state.pins[index].value = value;
|
||||
return SIM_HAL_OK;
|
||||
}
|
||||
|
||||
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_connect(const char *source, const char *target) {
|
||||
int source_index = find_pin(source);
|
||||
int target_index = find_pin(target);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
uint32_t target = state.tick + ticks;
|
||||
uint32_t tick;
|
||||
uint32_t function_index;
|
||||
for (tick = state.tick + 1U; tick <= target; ++tick) {
|
||||
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) return SIM_HAL_ERR_FUNCTION;
|
||||
function->calls += 1U;
|
||||
}
|
||||
}
|
||||
state.tick = 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; }
|
||||
62
wasm-core/src/sim_posemath.c
Normal file
62
wasm-core/src/sim_posemath.c
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "sim_posemath.h"
|
||||
|
||||
#include "posemath.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
static int finite_cart(const sim_posemath_cartesian *value) {
|
||||
return value != 0 && isfinite(value->x) && isfinite(value->y) && isfinite(value->z);
|
||||
}
|
||||
|
||||
static PmCartesian to_pm(const sim_posemath_cartesian *value) {
|
||||
PmCartesian result = {value->x, value->y, value->z};
|
||||
return result;
|
||||
}
|
||||
|
||||
static void from_pm(const PmCartesian *value, sim_posemath_cartesian *output) {
|
||||
output->x = value->x;
|
||||
output->y = value->y;
|
||||
output->z = value->z;
|
||||
}
|
||||
|
||||
int sim_posemath_is_finite(const sim_posemath_cartesian *value) {
|
||||
return finite_cart(value);
|
||||
}
|
||||
|
||||
int sim_posemath_normalize(const sim_posemath_cartesian *input, sim_posemath_cartesian *output) {
|
||||
PmCartesian source;
|
||||
PmCartesian result;
|
||||
double magnitude_squared = 0.0;
|
||||
if (!finite_cart(input) || output == 0) return SIM_POSEMATH_ERR_ARGUMENT;
|
||||
source = to_pm(input);
|
||||
if (pmCartMagSq(&source, &magnitude_squared) != 0 || !isfinite(magnitude_squared)) return SIM_POSEMATH_ERR_NONFINITE;
|
||||
if (magnitude_squared <= 1e-24) return SIM_POSEMATH_ERR_DEGENERATE;
|
||||
if (pmCartUnit(&source, &result) != 0) return SIM_POSEMATH_ERR_DEGENERATE;
|
||||
from_pm(&result, output);
|
||||
return SIM_POSEMATH_OK;
|
||||
}
|
||||
|
||||
int sim_posemath_dot(const sim_posemath_cartesian *left, const sim_posemath_cartesian *right, double *output) {
|
||||
PmCartesian lhs;
|
||||
PmCartesian rhs;
|
||||
if (!finite_cart(left) || !finite_cart(right) || output == 0) return SIM_POSEMATH_ERR_ARGUMENT;
|
||||
lhs = to_pm(left);
|
||||
rhs = to_pm(right);
|
||||
if (pmCartCartDot(&lhs, &rhs, output) != 0 || !isfinite(*output)) return SIM_POSEMATH_ERR_NONFINITE;
|
||||
return SIM_POSEMATH_OK;
|
||||
}
|
||||
|
||||
int sim_posemath_line_point(const sim_posemath_cartesian *start, const sim_posemath_cartesian *end,
|
||||
double fraction, sim_posemath_cartesian *output) {
|
||||
PmCartesian begin;
|
||||
PmCartesian finish;
|
||||
PmCartesian result;
|
||||
PmCartesian delta;
|
||||
if (!finite_cart(start) || !finite_cart(end) || output == 0) return SIM_POSEMATH_ERR_ARGUMENT;
|
||||
if (!isfinite(fraction) || fraction < 0.0 || fraction > 1.0) return SIM_POSEMATH_ERR_RANGE;
|
||||
begin = to_pm(start);
|
||||
finish = to_pm(end);
|
||||
if (pmCartCartSub(&finish, &begin, &delta) != 0 || pmCartScalMult(&delta, fraction, &delta) != 0 || pmCartCartAdd(&begin, &delta, &result) != 0) return SIM_POSEMATH_ERR_DEGENERATE;
|
||||
from_pm(&result, output);
|
||||
return SIM_POSEMATH_OK;
|
||||
}
|
||||
112
wasm-core/src/sim_protocol.c
Normal file
112
wasm-core/src/sim_protocol.c
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "sim_protocol.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t state;
|
||||
uint32_t last_seq;
|
||||
uint32_t tick;
|
||||
} protocol_state;
|
||||
|
||||
static protocol_state state;
|
||||
|
||||
static int has_text(const char *value) {
|
||||
return value != NULL && value[0] != '\0' && strlen(value) <= 128;
|
||||
}
|
||||
|
||||
static int is_kind(const char *kind, const char *expected) {
|
||||
return kind != NULL && strcmp(kind, expected) == 0;
|
||||
}
|
||||
|
||||
static int is_side_effect(const char *kind) {
|
||||
static const char *const commands[] = {
|
||||
"SESSION_CREATE", "LOAD_PROJECT", "START", "STOP", "RESET",
|
||||
"LOAD_WORKSPACE", "SIM_STEP", "COMMAND",
|
||||
"PROGRAM_LOAD", "PROGRAM_RUN", "PROGRAM_PAUSE", "PROGRAM_RESUME",
|
||||
"PROGRAM_ABORT", "PROGRAM_STEP", "PROGRAM_SEEK", "MDI_EXECUTE",
|
||||
"JOG_START", "JOG_STOP", "HOME", "SET_MODE", "SET_OVERRIDE",
|
||||
"SPINDLE_COMMAND", "COOLANT_COMMAND", "TOOL_PREPARE", "TOOL_CHANGE",
|
||||
"PROBE_CONFIG", "HAL_COMMAND", "HAL_SET", "PLC_START", "PLC_STOP",
|
||||
"PROJECT_SAVE", "IMPORT", "EXPORT", "CHECKPOINT", "RECOVER",
|
||||
"SUBSCRIBE", "UNSUBSCRIBE", "CANCEL", NULL,
|
||||
};
|
||||
size_t index;
|
||||
if (!has_text(kind)) return 0;
|
||||
for (index = 0; commands[index] != NULL; ++index) {
|
||||
if (is_kind(kind, commands[index])) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int state_accepts_kind(uint32_t current, const char *kind) {
|
||||
if (current == SIM_PROTOCOL_NEW) return is_kind(kind, "HELLO");
|
||||
if (current == SIM_PROTOCOL_HELLO) return is_kind(kind, "SESSION_ATTACH") || is_kind(kind, "CAPABILITIES");
|
||||
if (current == SIM_PROTOCOL_ATTACHED) return is_kind(kind, "SESSION_READY");
|
||||
if (current == SIM_PROTOCOL_READY) return 1;
|
||||
if (current == SIM_PROTOCOL_PAUSED) {
|
||||
return is_kind(kind, "PROGRAM_RESUME") || is_kind(kind, "RESUME") ||
|
||||
is_kind(kind, "PING") || is_kind(kind, "SNAPSHOT_REQUEST") ||
|
||||
is_kind(kind, "DESTROY");
|
||||
}
|
||||
return is_kind(kind, "RESET");
|
||||
}
|
||||
|
||||
void sim_protocol_reset(void) {
|
||||
memset(&state, 0, sizeof(state));
|
||||
}
|
||||
|
||||
int32_t sim_protocol_accept(uint32_t schema_version, uint32_t seq,
|
||||
const char *kind, const char *operation_id,
|
||||
uint32_t simulation_tick) {
|
||||
if (schema_version != 1U) return SIM_PROTOCOL_ERR_SCHEMA;
|
||||
if (!has_text(kind)) return SIM_PROTOCOL_ERR_KIND;
|
||||
if (state.state == SIM_PROTOCOL_DESTROYED && !is_kind(kind, "RESET")) return SIM_PROTOCOL_ERR_STATE;
|
||||
if (seq == 0U || seq != state.last_seq + 1U) return SIM_PROTOCOL_ERR_SEQUENCE;
|
||||
if (simulation_tick < state.tick) return SIM_PROTOCOL_ERR_TICK;
|
||||
if (!state_accepts_kind(state.state, kind)) return SIM_PROTOCOL_ERR_STATE;
|
||||
if (is_side_effect(kind) && !has_text(operation_id)) return SIM_PROTOCOL_ERR_OPERATION_ID;
|
||||
|
||||
state.last_seq = seq;
|
||||
state.tick = simulation_tick;
|
||||
if (is_kind(kind, "HELLO")) state.state = SIM_PROTOCOL_HELLO;
|
||||
/* SESSION_READY is the worker response; the next client command is valid immediately. */
|
||||
else if (is_kind(kind, "SESSION_ATTACH")) state.state = SIM_PROTOCOL_READY;
|
||||
else if (is_kind(kind, "SESSION_READY")) state.state = SIM_PROTOCOL_READY;
|
||||
else if (is_kind(kind, "PROGRAM_PAUSE")) state.state = SIM_PROTOCOL_PAUSED;
|
||||
else if (is_kind(kind, "PROGRAM_RESUME") || is_kind(kind, "RESUME")) state.state = SIM_PROTOCOL_READY;
|
||||
else if (is_kind(kind, "DESTROY")) state.state = SIM_PROTOCOL_DESTROYED;
|
||||
else if (is_kind(kind, "RESET")) sim_protocol_reset();
|
||||
return SIM_PROTOCOL_OK;
|
||||
}
|
||||
|
||||
int32_t sim_protocol_pause(void) {
|
||||
if (state.state != SIM_PROTOCOL_READY) return SIM_PROTOCOL_ERR_STATE;
|
||||
state.state = SIM_PROTOCOL_PAUSED;
|
||||
return SIM_PROTOCOL_OK;
|
||||
}
|
||||
|
||||
int32_t sim_protocol_resume(void) {
|
||||
if (state.state != SIM_PROTOCOL_PAUSED) return SIM_PROTOCOL_ERR_STATE;
|
||||
state.state = SIM_PROTOCOL_READY;
|
||||
return SIM_PROTOCOL_OK;
|
||||
}
|
||||
|
||||
int32_t sim_protocol_state_value(void) {
|
||||
return (int32_t)state.state;
|
||||
}
|
||||
|
||||
uint32_t sim_protocol_last_seq(void) {
|
||||
return state.last_seq;
|
||||
}
|
||||
|
||||
uint32_t sim_protocol_tick(void) {
|
||||
return state.tick;
|
||||
}
|
||||
|
||||
int32_t sim_protocol_set_tick(uint32_t simulation_tick) {
|
||||
if (simulation_tick < state.tick) return SIM_PROTOCOL_ERR_TICK;
|
||||
state.tick = simulation_tick;
|
||||
return SIM_PROTOCOL_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user