Use native LinuxCNC homing and consolidate web panel status

This commit is contained in:
2026-09-09 12:28:02 +08:00
parent eb5c58cdb3
commit 0be2ee8ce1
35 changed files with 881 additions and 350 deletions

View 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;
}