Use native LinuxCNC homing and consolidate web panel status
This commit is contained in:
168
wasm-core/src/sim_native_homing.c
Normal file
168
wasm-core/src/sim_native_homing.c
Normal file
@@ -0,0 +1,168 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "../include/sim_native_homing.h"
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#define API EMSCRIPTEN_KEEPALIVE
|
||||
#else
|
||||
#define API
|
||||
#endif
|
||||
|
||||
/* Only HAL allocation is adapted. The state machine below is the original
|
||||
* homemod source, including sequence, switch, index and final-move rules. */
|
||||
#define hal_malloc native_home_hal_malloc
|
||||
#define hal_pin_bit_newf native_home_hal_bit
|
||||
#define hal_pin_s32_newf native_home_hal_s32
|
||||
#include "../../linuxcnc/src/emc/motion/homing.c"
|
||||
#include "simple_tp.h"
|
||||
|
||||
static union { double align; unsigned char bytes[8192]; } pin_arena;
|
||||
static size_t pin_used;
|
||||
void *native_home_hal_malloc(long size) {
|
||||
size_t start = (pin_used + 7) & ~(size_t)7;
|
||||
if (size < 0 || start + (size_t)size > sizeof(pin_arena)) return NULL;
|
||||
pin_used = start + size;
|
||||
return pin_arena.bytes + start;
|
||||
}
|
||||
int native_home_hal_bit(hal_pin_dir_t dir, hal_bit_t **pin, int id, const char *fmt, ...) {
|
||||
(void)dir; (void)id; (void)fmt;
|
||||
*pin = native_home_hal_malloc(sizeof(**pin)); return *pin ? 0 : -1;
|
||||
}
|
||||
int native_home_hal_s32(hal_pin_dir_t dir, hal_s32_t **pin, int id, const char *fmt, ...) {
|
||||
(void)dir; (void)id; (void)fmt;
|
||||
*pin = native_home_hal_malloc(sizeof(**pin)); return *pin ? 0 : -1;
|
||||
}
|
||||
|
||||
struct native_home {
|
||||
emcmot_joint_t joint[EMCMOT_MAX_JOINTS];
|
||||
home_local_data local[EMCMOT_MAX_JOINTS];
|
||||
double period;
|
||||
int count, sequence, current, active, sync, mode;
|
||||
uint32_t tick, command_seq;
|
||||
};
|
||||
|
||||
/* homemod is a singleton in LinuxCNC. Swap its private data at the ABI
|
||||
* boundary to isolate multiple simulation sessions in one WASM module. */
|
||||
static void load(native_home *h) {
|
||||
joints = h->joint; all_joints = h->count; extra_joints = 0;
|
||||
servo_freq = 1 / h->period;
|
||||
memcpy(H, h->local, sizeof(H));
|
||||
sequence_state = h->sequence; current_sequence = h->current;
|
||||
homing_active = h->active; sync_now = h->sync;
|
||||
}
|
||||
static void save(native_home *h) {
|
||||
memcpy(h->local, H, sizeof(H));
|
||||
h->sequence = sequence_state; h->current = current_sequence;
|
||||
h->active = homing_active; h->sync = sync_now;
|
||||
}
|
||||
API uint32_t sim_native_home_size(void) { return sizeof(native_home); }
|
||||
API int sim_native_home_init(native_home *h, int count, double period) {
|
||||
if (!h || count < 1 || count > EMCMOT_MAX_JOINTS || !isfinite(period) || period <= 0) return -1;
|
||||
memset(h, 0, sizeof(*h)); memset(H, 0, sizeof(H));
|
||||
pin_used = 0; memset(&pin_arena, 0, sizeof(pin_arena));
|
||||
h->count = count; h->period = period; h->mode = 1; /* FREE */
|
||||
sequence_state = HOME_SEQUENCE_IDLE; current_sequence = 0; sync_now = 0;
|
||||
if (homing_init(0, period, count, 0, h->joint)) return -1;
|
||||
for (int j = 0; j < count; j++) {
|
||||
h->joint[j].flag |= EMCMOT_JOINT_ACTIVE_BIT | EMCMOT_JOINT_INPOS_BIT;
|
||||
}
|
||||
save(h); return 0;
|
||||
}
|
||||
/* p: offset, home, final velocity, search velocity, latch velocity, flags,
|
||||
* sequence, volatile, min limit, max limit, max velocity, max acceleration. */
|
||||
API int sim_native_home_config(native_home *h, int j, const double *p) {
|
||||
if (!h || !p || j < 0 || j >= h->count) return -1;
|
||||
for (int i = 0; i < 12; i++) if (!isfinite(p[i])) return -1;
|
||||
if (p[8] > p[9] || p[10] <= 0 || p[11] <= 0 || ((int)p[5] & HOME_UNLOCK_FIRST)) return -1;
|
||||
load(h);
|
||||
set_joint_homing_params(j, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7] != 0);
|
||||
joints[j].min_pos_limit = p[8]; joints[j].max_pos_limit = p[9];
|
||||
joints[j].vel_limit = p[10]; joints[j].acc_limit = p[11];
|
||||
joints[j].free_tp.max_acc = p[11]; save(h); return 0;
|
||||
}
|
||||
API int sim_native_home_sync(native_home *h, const double *position) {
|
||||
if (!h || !position || h->active || h->sequence != HOME_SEQUENCE_IDLE) return -1;
|
||||
for (int j = 0; j < h->count; j++) if (!isfinite(position[j])) return -1;
|
||||
for (int j = 0; j < h->count; j++) {
|
||||
emcmot_joint_t *p = &h->joint[j];
|
||||
p->pos_cmd = p->pos_fb = p->free_tp.curr_pos = position[j];
|
||||
p->motor_pos_fb = position[j] + p->motor_offset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
API int sim_native_home_mode(native_home *h, int mode) {
|
||||
if (!h || mode < 1 || mode > 3 || h->active || h->sequence != HOME_SEQUENCE_IDLE) return -1;
|
||||
load(h);
|
||||
if (mode != 1 && !get_allhomed()) return -2;
|
||||
h->mode = mode; return 0;
|
||||
}
|
||||
API int sim_native_home_start(native_home *h, int j, uint32_t seq) {
|
||||
if (!h || j < -1 || j >= h->count || h->active || h->sequence != HOME_SEQUENCE_IDLE) return -1;
|
||||
load(h); h->mode = 1; h->command_seq = seq;
|
||||
do_home_joint(j); save(h); return 0;
|
||||
}
|
||||
API int sim_native_home_step(native_home *h) {
|
||||
if (!h) return -1;
|
||||
load(h);
|
||||
/* control.c switches to TELEOP on the native all-homed edge. */
|
||||
if (do_homing()) h->mode = 3;
|
||||
/* control.c: homing runs before free-mode position generation. Ideal
|
||||
* feedback follows the commanded motor position in this simulation. */
|
||||
for (int j = 0; j < h->count; j++) {
|
||||
simple_tp_update(&joints[j].free_tp, h->period);
|
||||
joints[j].pos_cmd = joints[j].free_tp.curr_pos;
|
||||
joints[j].pos_fb = joints[j].pos_cmd;
|
||||
joints[j].motor_pos_fb = joints[j].pos_cmd + joints[j].motor_offset;
|
||||
if (joints[j].free_tp.active) joints[j].flag &= ~EMCMOT_JOINT_INPOS_BIT;
|
||||
else joints[j].flag |= EMCMOT_JOINT_INPOS_BIT;
|
||||
}
|
||||
h->tick++; save(h); return 0;
|
||||
}
|
||||
API int sim_native_home_cancel(native_home *h, int volatile_only) {
|
||||
if (!h) return -1;
|
||||
load(h);
|
||||
for (int j = 0; j < h->count; j++) {
|
||||
if (H[j].homing || H[j].home_state != HOME_IDLE || (homing_active && H[j].joint_in_sequence)) {
|
||||
H[j].home_state = HOME_ABORT;
|
||||
base_1joint_state_machine(j);
|
||||
}
|
||||
joints[j].free_tp.enable = 0;
|
||||
if (volatile_only) {
|
||||
joints[j].free_tp.curr_vel = 0;
|
||||
joints[j].free_tp.active = 0;
|
||||
joints[j].flag |= EMCMOT_JOINT_INPOS_BIT;
|
||||
}
|
||||
}
|
||||
sequence_state = HOME_SEQUENCE_IDLE; homing_active = 0;
|
||||
if (volatile_only) set_unhomed(-2, EMCMOT_MOTION_DISABLED);
|
||||
h->mode = 1; save(h); return 0;
|
||||
}
|
||||
API int sim_native_home_input(native_home *h, int j, int sw, int index, int neg, int pos) {
|
||||
if (!h || j < 0 || j >= h->count) return -1;
|
||||
h->local[j].home_sw = sw != 0; h->local[j].index_enable = index != 0;
|
||||
h->joint[j].on_neg_limit = neg != 0; h->joint[j].on_pos_limit = pos != 0; return 0;
|
||||
}
|
||||
API double sim_native_home_get(native_home *h, int j, int field) {
|
||||
if (!h) return -1;
|
||||
if (field == 0) {
|
||||
for (int i = 0; i < h->count; i++) if (h->joint[i].free_tp.active) return 1;
|
||||
return h->active || h->sequence != HOME_SEQUENCE_IDLE;
|
||||
}
|
||||
if (field == 1) return h->mode;
|
||||
if (field == 2) return h->tick;
|
||||
if (field == 3) return h->command_seq;
|
||||
if (j < 0 || j >= h->count) return -1;
|
||||
switch (field) {
|
||||
case 4: return h->local[j].homing;
|
||||
case 5: return h->local[j].homed;
|
||||
case 6: return h->local[j].home_state;
|
||||
case 7: return h->joint[j].pos_fb;
|
||||
case 8: return h->joint[j].motor_pos_fb;
|
||||
case 9: return h->joint[j].motor_offset;
|
||||
case 10: return h->local[j].home_sequence;
|
||||
case 11: return h->joint[j].free_tp.curr_vel;
|
||||
case 12: return h->local[j].index_enable;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
Reference in New Issue
Block a user