Initial LinuxCNC WebAssembly workspace snapshot
This commit is contained in:
70
wasm-core/CMakeLists.txt
Normal file
70
wasm-core/CMakeLists.txt
Normal file
@@ -0,0 +1,70 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(linuxcnc_web_wasm_core LANGUAGES C CXX)
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_library(sim_core STATIC src/sim_api.c src/sim_protocol.c src/sim_event.c src/sim_hal.c src/sim_posemath.c)
|
||||
target_include_directories(sim_core PUBLIC include)
|
||||
target_compile_definitions(sim_core PRIVATE SIM_API_BUILD=1)
|
||||
|
||||
add_library(sim_posemath STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc/src/libnml/posemath/_posemath.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc/src/libnml/posemath/gomath.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc/src/libnml/posemath/sincos.c
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc/src/libnml/posemath/posemath.cc
|
||||
)
|
||||
target_include_directories(sim_posemath PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc/src/rtapi
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc/src/libnml/posemath
|
||||
)
|
||||
target_compile_definitions(sim_posemath PRIVATE ULAPI)
|
||||
target_link_libraries(sim_core PUBLIC sim_posemath)
|
||||
|
||||
if(NOT EMSCRIPTEN)
|
||||
add_executable(sim_api_test tests/sim_api_test.c)
|
||||
target_link_libraries(sim_api_test PRIVATE sim_core)
|
||||
target_include_directories(sim_api_test PRIVATE include)
|
||||
|
||||
enable_testing()
|
||||
add_test(NAME sim_api_test COMMAND sim_api_test)
|
||||
|
||||
add_executable(sim_protocol_test tests/sim_protocol_test.c)
|
||||
target_link_libraries(sim_protocol_test PRIVATE sim_core)
|
||||
target_include_directories(sim_protocol_test PRIVATE include)
|
||||
add_test(NAME sim_protocol_test COMMAND sim_protocol_test)
|
||||
|
||||
add_executable(sim_event_test tests/sim_event_test.c)
|
||||
target_link_libraries(sim_event_test PRIVATE sim_core)
|
||||
target_include_directories(sim_event_test PRIVATE include)
|
||||
add_test(NAME sim_event_test COMMAND sim_event_test)
|
||||
|
||||
add_executable(sim_hal_test tests/sim_hal_test.c)
|
||||
target_link_libraries(sim_hal_test PRIVATE sim_core)
|
||||
target_include_directories(sim_hal_test PRIVATE include)
|
||||
add_test(NAME sim_hal_test COMMAND sim_hal_test)
|
||||
|
||||
add_executable(sim_posemath_test tests/sim_posemath_test.c)
|
||||
target_link_libraries(sim_posemath_test PRIVATE sim_core)
|
||||
target_include_directories(sim_posemath_test PRIVATE include)
|
||||
add_test(NAME sim_posemath_test COMMAND sim_posemath_test)
|
||||
endif()
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
add_executable(sim_core_module src/sim_api.c src/sim_protocol.c src/sim_event.c src/sim_hal.c src/sim_posemath.c)
|
||||
target_include_directories(sim_core_module PRIVATE
|
||||
include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc/src/rtapi
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../linuxcnc/src/libnml/posemath
|
||||
)
|
||||
target_link_libraries(sim_core_module PRIVATE sim_posemath)
|
||||
set_target_properties(sim_core_module PROPERTIES
|
||||
OUTPUT_NAME "linuxcnc-sim-core"
|
||||
SUFFIX ".js"
|
||||
LINK_FLAGS "-sMODULARIZE=1 -sEXPORT_ES6=1 -sENVIRONMENT=web,worker -sEXPORTED_FUNCTIONS=['_malloc','_free','_sim_create','_sim_load_workspace','_sim_command','_sim_step','_sim_read_snapshot','_sim_read_event','_sim_export_state','_sim_import_state','_sim_destroy','_sim_protocol_reset','_sim_protocol_accept','_sim_protocol_pause','_sim_protocol_resume','_sim_protocol_state_value','_sim_protocol_last_seq','_sim_protocol_tick','_sim_protocol_set_tick','_sim_event_reset','_sim_event_append','_sim_event_count','_sim_event_cursor','_sim_event_read','_sim_event_export','_sim_event_import','_sim_hal_reset','_sim_hal_register_pin','_sim_hal_set_pin','_sim_hal_get_pin','_sim_hal_connect','_sim_hal_register_thread','_sim_hal_register_function','_sim_hal_set_function_failure','_sim_hal_step','_sim_hal_tick','_sim_hal_function_calls','_sim_hal_pin_count','_sim_hal_thread_count','_sim_hal_function_count','_sim_posemath_normalize','_sim_posemath_dot','_sim_posemath_line_point','_sim_posemath_is_finite'] -sEXPORTED_RUNTIME_METHODS=['ccall','cwrap']"
|
||||
)
|
||||
endif()
|
||||
34
wasm-core/include/sim_api.h
Normal file
34
wasm-core/include/sim_api.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef LINUXCNC_WEB_WASM_SIM_API_H
|
||||
#define LINUXCNC_WEB_WASM_SIM_API_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum sim_result {
|
||||
SIM_OK = 0,
|
||||
SIM_ERR_INVALID_ARGUMENT = -1,
|
||||
SIM_ERR_NOT_CREATED = -2,
|
||||
SIM_ERR_BUFFER_TOO_SMALL = -3,
|
||||
SIM_ERR_INVALID_STATE = -4,
|
||||
SIM_ERR_UNSUPPORTED = -5,
|
||||
};
|
||||
|
||||
/* Bootstrap ABI only. LinuxCNC behavior is added behind this stable boundary. */
|
||||
int32_t sim_create(const uint8_t *config, uint32_t config_len);
|
||||
int32_t sim_load_workspace(const char *root_path);
|
||||
int32_t sim_command(const uint8_t *command, uint32_t command_len);
|
||||
int32_t sim_step(uint32_t cycles);
|
||||
uint32_t sim_read_snapshot(uint8_t *out, uint32_t capacity);
|
||||
uint32_t sim_read_event(uint8_t *out, uint32_t capacity);
|
||||
int32_t sim_export_state(uint8_t *out, uint32_t capacity);
|
||||
int32_t sim_import_state(const uint8_t *data, uint32_t len);
|
||||
void sim_destroy(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
42
wasm-core/include/sim_event.h
Normal file
42
wasm-core/include/sim_event.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef LINUXCNC_WEB_WASM_SIM_EVENT_H
|
||||
#define LINUXCNC_WEB_WASM_SIM_EVENT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SIM_EVENT_KIND_CAPACITY 32U
|
||||
#define SIM_EVENT_CAPACITY 256U
|
||||
|
||||
enum sim_event_result {
|
||||
SIM_EVENT_OK = 0,
|
||||
SIM_EVENT_ERR_SEQUENCE = -200,
|
||||
SIM_EVENT_ERR_TICK = -201,
|
||||
SIM_EVENT_ERR_ARGUMENT = -202,
|
||||
SIM_EVENT_ERR_FULL = -203,
|
||||
SIM_EVENT_ERR_BUFFER = -204,
|
||||
};
|
||||
|
||||
typedef struct sim_event_record {
|
||||
uint32_t seq;
|
||||
uint32_t tick;
|
||||
uint64_t payload_hash;
|
||||
char kind[SIM_EVENT_KIND_CAPACITY];
|
||||
} sim_event_record;
|
||||
|
||||
void sim_event_reset(void);
|
||||
int32_t sim_event_append(uint32_t seq, uint32_t tick, const char *kind,
|
||||
const uint8_t *payload, uint32_t payload_len);
|
||||
uint32_t sim_event_count(void);
|
||||
uint32_t sim_event_cursor(void);
|
||||
uint32_t sim_event_read(uint32_t index, uint8_t *out, uint32_t capacity);
|
||||
uint32_t sim_event_export(uint8_t *out, uint32_t capacity);
|
||||
int32_t sim_event_import(const uint8_t *data, uint32_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
64
wasm-core/include/sim_hal.h
Normal file
64
wasm-core/include/sim_hal.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef LINUXCNC_WEB_WASM_SIM_HAL_H
|
||||
#define LINUXCNC_WEB_WASM_SIM_HAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SIM_HAL_NAME_CAPACITY 48U
|
||||
#define SIM_HAL_PIN_CAPACITY 64U
|
||||
#define SIM_HAL_THREAD_CAPACITY 16U
|
||||
#define SIM_HAL_FUNCTION_CAPACITY 64U
|
||||
|
||||
enum sim_hal_result {
|
||||
SIM_HAL_OK = 0,
|
||||
SIM_HAL_ERR_ARGUMENT = -300,
|
||||
SIM_HAL_ERR_FULL = -301,
|
||||
SIM_HAL_ERR_DUPLICATE = -302,
|
||||
SIM_HAL_ERR_NOT_FOUND = -303,
|
||||
SIM_HAL_ERR_TYPE = -304,
|
||||
SIM_HAL_ERR_RANGE = -305,
|
||||
SIM_HAL_ERR_CONNECTION = -306,
|
||||
SIM_HAL_ERR_FUNCTION = -307,
|
||||
SIM_HAL_ERR_REAL_EXCLUDED = -308,
|
||||
};
|
||||
|
||||
enum sim_hal_type {
|
||||
SIM_HAL_BIT = 1,
|
||||
SIM_HAL_S32 = 2,
|
||||
SIM_HAL_U32 = 3,
|
||||
SIM_HAL_FLOAT = 4,
|
||||
};
|
||||
|
||||
typedef struct sim_hal_value {
|
||||
uint32_t type;
|
||||
union {
|
||||
uint32_t bit;
|
||||
int32_t s32;
|
||||
uint32_t u32;
|
||||
float real;
|
||||
} value;
|
||||
} sim_hal_value;
|
||||
|
||||
void sim_hal_reset(void);
|
||||
int32_t sim_hal_register_pin(const char *name, uint32_t type);
|
||||
int32_t sim_hal_set_pin(const char *name, sim_hal_value value);
|
||||
int32_t sim_hal_get_pin(const char *name, sim_hal_value *out);
|
||||
int32_t sim_hal_connect(const char *source, const char *target);
|
||||
int32_t sim_hal_register_thread(const char *name, uint32_t period_ticks);
|
||||
int32_t sim_hal_register_function(const char *thread, const char *name);
|
||||
int32_t sim_hal_set_function_failure(const char *name, uint32_t fail);
|
||||
int32_t sim_hal_step(uint32_t ticks);
|
||||
uint32_t sim_hal_tick(void);
|
||||
uint32_t sim_hal_function_calls(const char *name);
|
||||
uint32_t sim_hal_pin_count(void);
|
||||
uint32_t sim_hal_thread_count(void);
|
||||
uint32_t sim_hal_function_count(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
32
wasm-core/include/sim_posemath.h
Normal file
32
wasm-core/include/sim_posemath.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef LINUXCNC_WEB_WASM_SIM_POSEMATH_H
|
||||
#define LINUXCNC_WEB_WASM_SIM_POSEMATH_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum sim_posemath_result {
|
||||
SIM_POSEMATH_OK = 0,
|
||||
SIM_POSEMATH_ERR_ARGUMENT = -400,
|
||||
SIM_POSEMATH_ERR_NONFINITE = -401,
|
||||
SIM_POSEMATH_ERR_DEGENERATE = -402,
|
||||
SIM_POSEMATH_ERR_RANGE = -403,
|
||||
};
|
||||
|
||||
typedef struct sim_posemath_cartesian {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} sim_posemath_cartesian;
|
||||
|
||||
int sim_posemath_normalize(const sim_posemath_cartesian *input, sim_posemath_cartesian *output);
|
||||
int sim_posemath_dot(const sim_posemath_cartesian *left, const sim_posemath_cartesian *right, double *output);
|
||||
int sim_posemath_line_point(const sim_posemath_cartesian *start, const sim_posemath_cartesian *end,
|
||||
double fraction, sim_posemath_cartesian *output);
|
||||
int sim_posemath_is_finite(const sim_posemath_cartesian *value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
46
wasm-core/include/sim_protocol.h
Normal file
46
wasm-core/include/sim_protocol.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef LINUXCNC_WEB_WASM_SIM_PROTOCOL_H
|
||||
#define LINUXCNC_WEB_WASM_SIM_PROTOCOL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum sim_protocol_result {
|
||||
SIM_PROTOCOL_OK = 0,
|
||||
SIM_PROTOCOL_ERR_SCHEMA = -100,
|
||||
SIM_PROTOCOL_ERR_SEQUENCE = -101,
|
||||
SIM_PROTOCOL_ERR_STATE = -102,
|
||||
SIM_PROTOCOL_ERR_OPERATION_ID = -103,
|
||||
SIM_PROTOCOL_ERR_KIND = -104,
|
||||
SIM_PROTOCOL_ERR_ARGUMENT = -105,
|
||||
SIM_PROTOCOL_ERR_TICK = -106,
|
||||
};
|
||||
|
||||
enum sim_protocol_state {
|
||||
SIM_PROTOCOL_NEW = 0,
|
||||
SIM_PROTOCOL_HELLO = 1,
|
||||
SIM_PROTOCOL_ATTACHED = 2,
|
||||
SIM_PROTOCOL_READY = 3,
|
||||
SIM_PROTOCOL_PAUSED = 4,
|
||||
SIM_PROTOCOL_DESTROYED = 5,
|
||||
};
|
||||
|
||||
/* The protocol validator is deliberately independent of JSON and malloc. */
|
||||
void sim_protocol_reset(void);
|
||||
int32_t sim_protocol_accept(uint32_t schema_version, uint32_t seq,
|
||||
const char *kind, const char *operation_id,
|
||||
uint32_t simulation_tick);
|
||||
int32_t sim_protocol_pause(void);
|
||||
int32_t sim_protocol_resume(void);
|
||||
int32_t sim_protocol_state_value(void);
|
||||
uint32_t sim_protocol_last_seq(void);
|
||||
uint32_t sim_protocol_tick(void);
|
||||
int32_t sim_protocol_set_tick(uint32_t simulation_tick);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
26
wasm-core/tests/sim_api_test.c
Normal file
26
wasm-core/tests/sim_api_test.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "sim_api.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
int main(void) {
|
||||
uint8_t snapshot[sizeof(uint64_t)] = {0};
|
||||
uint8_t state[32] = {0};
|
||||
assert(sim_step(1) == SIM_ERR_NOT_CREATED);
|
||||
assert(sim_create(NULL, 0) == SIM_OK);
|
||||
assert(sim_load_workspace("/workspace") == SIM_OK);
|
||||
assert(sim_step(7) == SIM_OK);
|
||||
assert(sim_read_snapshot(snapshot, sizeof(snapshot)) == sizeof(snapshot));
|
||||
uint64_t tick = 0;
|
||||
memcpy(&tick, snapshot, sizeof(tick));
|
||||
assert(tick == 7);
|
||||
assert(sim_export_state(state, sizeof(state)) > 0);
|
||||
assert(sim_step(3) == SIM_OK);
|
||||
assert(sim_import_state(state, sizeof(state)) == SIM_OK);
|
||||
assert(sim_read_snapshot(snapshot, sizeof(snapshot)) == sizeof(snapshot));
|
||||
memcpy(&tick, snapshot, sizeof(tick));
|
||||
assert(tick == 7);
|
||||
sim_destroy();
|
||||
return 0;
|
||||
}
|
||||
28
wasm-core/tests/sim_event_test.c
Normal file
28
wasm-core/tests/sim_event_test.c
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "sim_event.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void) {
|
||||
uint8_t record[sizeof(sim_event_record)] = {0};
|
||||
uint8_t exported[16384] = {0};
|
||||
const uint8_t payload[] = {'o', 'k'};
|
||||
|
||||
sim_event_reset();
|
||||
assert(sim_event_append(2, 0, "bad", payload, sizeof(payload)) == SIM_EVENT_ERR_SEQUENCE);
|
||||
assert(sim_event_append(1, 2, "STEP", payload, sizeof(payload)) == SIM_EVENT_OK);
|
||||
assert(sim_event_append(2, 1, "BAD_TICK", NULL, 0) == SIM_EVENT_ERR_TICK);
|
||||
assert(sim_event_read(0, NULL, 0) == sizeof(sim_event_record));
|
||||
assert(sim_event_read(0, record, sizeof(record)) == sizeof(record));
|
||||
assert(((sim_event_record *)record)->seq == 1);
|
||||
assert(sim_event_count() == 1);
|
||||
assert(sim_event_cursor() == 1);
|
||||
uint32_t export_size = sim_event_export(NULL, 0);
|
||||
assert(export_size > 0 && export_size < sizeof(exported));
|
||||
assert(sim_event_export(exported, sizeof(exported)) == export_size);
|
||||
sim_event_reset();
|
||||
assert(sim_event_import(exported, export_size) == SIM_EVENT_OK);
|
||||
assert(sim_event_count() == 1);
|
||||
assert(sim_event_import(exported, export_size - 1) == SIM_EVENT_ERR_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
29
wasm-core/tests/sim_hal_test.c
Normal file
29
wasm-core/tests/sim_hal_test.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "sim_hal.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
int main(void) {
|
||||
sim_hal_value bit = {SIM_HAL_BIT, {.bit = 1}};
|
||||
sim_hal_value wrong = {SIM_HAL_S32, {.s32 = 1}};
|
||||
sim_hal_value out = {0};
|
||||
|
||||
sim_hal_reset();
|
||||
assert(sim_hal_register_pin("source", SIM_HAL_BIT) == SIM_HAL_OK);
|
||||
assert(sim_hal_register_pin("target", SIM_HAL_BIT) == SIM_HAL_OK);
|
||||
assert(sim_hal_register_pin("source", SIM_HAL_BIT) == SIM_HAL_ERR_DUPLICATE);
|
||||
assert(sim_hal_set_pin("source", bit) == SIM_HAL_OK);
|
||||
assert(sim_hal_set_pin("source", wrong) == SIM_HAL_ERR_TYPE);
|
||||
assert(sim_hal_connect("source", "target") == SIM_HAL_OK);
|
||||
assert(sim_hal_get_pin("target", &out) == SIM_HAL_OK && out.value.bit == 1);
|
||||
assert(sim_hal_register_thread("servo", 2) == SIM_HAL_OK);
|
||||
assert(sim_hal_register_thread("servo", 2) == SIM_HAL_ERR_DUPLICATE);
|
||||
assert(sim_hal_register_function("servo", "update") == SIM_HAL_OK);
|
||||
assert(sim_hal_register_function("missing", "bad") == SIM_HAL_ERR_NOT_FOUND);
|
||||
assert(sim_hal_step(5) == SIM_HAL_OK);
|
||||
assert(sim_hal_tick() == 5 && sim_hal_function_calls("update") == 2);
|
||||
assert(sim_hal_set_function_failure("update", 1) == SIM_HAL_OK);
|
||||
assert(sim_hal_step(1) == SIM_HAL_ERR_FUNCTION);
|
||||
assert(sim_hal_tick() == 5);
|
||||
assert(sim_hal_register_thread("invalid", 0) == SIM_HAL_ERR_RANGE);
|
||||
return 0;
|
||||
}
|
||||
23
wasm-core/tests/sim_posemath_test.c
Normal file
23
wasm-core/tests/sim_posemath_test.c
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "sim_posemath.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
int main(void) {
|
||||
sim_posemath_cartesian input = {3.0, 4.0, 0.0};
|
||||
sim_posemath_cartesian output = {0};
|
||||
sim_posemath_cartesian end = {10.0, 10.0, 10.0};
|
||||
double dot = 0;
|
||||
|
||||
assert(sim_posemath_normalize(&input, &output) == SIM_POSEMATH_OK);
|
||||
assert(fabs(output.x - 0.6) < 1e-12 && fabs(output.y - 0.8) < 1e-12);
|
||||
assert(sim_posemath_dot(&input, &end, &dot) == SIM_POSEMATH_OK && dot == 70.0);
|
||||
assert(sim_posemath_line_point(&input, &end, 0.5, &output) == SIM_POSEMATH_OK);
|
||||
assert(output.x == 6.5 && output.y == 7.0 && output.z == 5.0);
|
||||
assert(sim_posemath_line_point(&input, &end, 1.1, &output) == SIM_POSEMATH_ERR_RANGE);
|
||||
input.x = NAN;
|
||||
assert(sim_posemath_normalize(&input, &output) == SIM_POSEMATH_ERR_ARGUMENT);
|
||||
input.x = 0.0; input.y = 0.0; input.z = 0.0;
|
||||
assert(sim_posemath_normalize(&input, &output) == SIM_POSEMATH_ERR_DEGENERATE);
|
||||
return 0;
|
||||
}
|
||||
25
wasm-core/tests/sim_protocol_test.c
Normal file
25
wasm-core/tests/sim_protocol_test.c
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "sim_protocol.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
int main(void) {
|
||||
sim_protocol_reset();
|
||||
assert(sim_protocol_state_value() == SIM_PROTOCOL_NEW);
|
||||
assert(sim_protocol_accept(1, 1, "HELLO", NULL, 0) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 3, "SESSION_ATTACH", NULL, 0) == SIM_PROTOCOL_ERR_SEQUENCE);
|
||||
assert(sim_protocol_accept(1, 2, "SESSION_ATTACH", NULL, 0) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_state_value() == SIM_PROTOCOL_READY);
|
||||
assert(sim_protocol_accept(1, 3, "MDI_EXECUTE", NULL, 0) == SIM_PROTOCOL_ERR_OPERATION_ID);
|
||||
assert(sim_protocol_accept(1, 3, "MDI_EXECUTE", "op-3", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 4, "PROGRAM_PAUSE", "op-4", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 5, "MDI_EXECUTE", "op-5", 2) == SIM_PROTOCOL_ERR_STATE);
|
||||
assert(sim_protocol_accept(1, 5, "PROGRAM_RESUME", "op-5", 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(2, 6, "PING", NULL, 2) == SIM_PROTOCOL_ERR_SCHEMA);
|
||||
assert(sim_protocol_accept(1, 6, "PING", NULL, 1) == SIM_PROTOCOL_ERR_TICK);
|
||||
assert(sim_protocol_accept(1, 6, "DESTROY", NULL, 2) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_accept(1, 7, "PING", NULL, 2) == SIM_PROTOCOL_ERR_STATE);
|
||||
assert(sim_protocol_accept(1, 8, "RESET", "reset-1", 0) == SIM_PROTOCOL_OK);
|
||||
assert(sim_protocol_state_value() == SIM_PROTOCOL_NEW);
|
||||
assert(sim_protocol_set_tick(4) == SIM_PROTOCOL_ERR_TICK);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user