按规划继续工作

结论:接入 vendored LinuxCNC tooldata_common.cc 负责刀具表解析与保存,WASM/SDK/OPFS/UI 仅做运行时边界搬运;native、WASM、OPFS 和浏览器 smoke 验证已通过。
This commit is contained in:
2026-06-08 08:31:10 +08:00
parent 5ea07606d7
commit a16f3605fa
24 changed files with 1302 additions and 53 deletions

View File

@@ -0,0 +1,423 @@
/*
** This file is part of a refactor of internal tool data management
** and incorporates work from removed files:
** src/emc/ini/initool.cc
** src/emc/rs274ngc/tool_parse.cc
**
** Copyright: 2021
** Author: Dewey Garrett <dgarrett@panix.com>
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdio.h>
#include <string.h>
#include <rtapi_string.h>
#include "tooldata.hh"
#define UNEXPECTED_MSG fprintf(stderr,"UNEXPECTED %s %d\n",__FILE__,__LINE__);
static bool is_random_toolchanger = 0;
static int nonrandom_idx = 0; // 'fakepocket' counter
static bool add_init_initialized = 0;
static tooldb_t db_mode = DB_NOTUSED;
void tooldata_init(bool random_toolchanger)
{
is_random_toolchanger = random_toolchanger;
} // tooldata_init
struct CANON_TOOL_TABLE tooldata_entry_init()
{
struct CANON_TOOL_TABLE tdata;
tdata.toolno = -1;
tdata.pocketno = -1;
tdata.diameter = 0;
tdata.frontangle = 0;
tdata.backangle = 0;
tdata.orientation = 0;
ZERO_EMC_POSE(tdata.offset);
tdata.comment[0] = 0;
return tdata;
} // tooldata_entry_init()
void tooldata_set_db(tooldb_t mode)
{
db_mode = mode;
return;
} //tooldata_set_db()
void tooldata_add_init(int nonrandom_start_idx)
{
// initialize file-static vars need for tooldata_add_line()
nonrandom_idx = nonrandom_start_idx;
add_init_initialized = 1;
return;
} // tooldata_add_init()
int tooldata_read_entry(const char *input_line)
{
char work_line[CANON_TOOL_ENTRY_LEN];
const char *token;
char *buff, *comment;
int toolno,orientation,valid=1;
EmcPose offset; //tlo
double diameter, frontangle, backangle;
int idx = 0;
int realpocket = 0;
if (!add_init_initialized) {
fprintf(stderr,"!!! PROBLEM no init %s\n",__FILE__);
return -1;
}
if (input_line[0] == ';') {return 0;} //ignore leading ';'
strncpy(work_line, input_line, sizeof(work_line)-1);
work_line[sizeof(work_line)-1] = 0;
CANON_TOOL_TABLE empty = tooldata_entry_init();
toolno = empty.toolno;
diameter = empty.diameter;
frontangle = empty.frontangle;
backangle = empty.backangle;
orientation = empty.orientation;
offset = empty.offset;
char* saveptr;
buff = strtok_r(work_line, ";", &saveptr);
if (strlen(buff) <=1) {
//fprintf(stderr,"skip blankline %s\n",__FILE__);
return 0;
}
comment = strtok_r(NULL, "\n", &saveptr);
token = strtok_r(buff, " ", &saveptr);
while (token != NULL) {
switch (toupper(token[0])) {
case 'T':
if (sscanf(&token[1], "%d", &toolno) != 1)
valid = 0;
break;
case 'P':
if (sscanf(&token[1], "%d", &idx) != 1) {
valid = 0;
break;
}
realpocket = idx; //random toolchanger
if (!is_random_toolchanger) {
if ( (nonrandom_idx <= 0)
|| (nonrandom_idx >= CANON_POCKETS_MAX) ) {
printf("Out-of-range nonrandom_idx=%d. Skipping tool=%d\n",
nonrandom_idx,toolno);
valid = 0;
break;
}
idx = nonrandom_idx; // nonrandom toolchanger
(nonrandom_idx)++;
}
if (idx < 0 || idx >= CANON_POCKETS_MAX) {
printf("max pocket number is %d. skipping tool %d\n",
CANON_POCKETS_MAX - 1, toolno);
valid = 0;
break;
}
break;
case 'D':
if (sscanf(&token[1], "%lf", &diameter) != 1)
valid = 0;
break;
case 'X':
if (sscanf(&token[1], "%lf", &offset.tran.x) != 1)
valid = 0;
break;
case 'Y':
if (sscanf(&token[1], "%lf", &offset.tran.y) != 1)
valid = 0;
break;
case 'Z':
if (sscanf(&token[1], "%lf", &offset.tran.z) != 1)
valid = 0;
break;
case 'A':
if (sscanf(&token[1], "%lf", &offset.a) != 1)
valid = 0;
break;
case 'B':
if (sscanf(&token[1], "%lf", &offset.b) != 1)
valid = 0;
break;
case 'C':
if (sscanf(&token[1], "%lf", &offset.c) != 1)
valid = 0;
break;
case 'U':
if (sscanf(&token[1], "%lf", &offset.u) != 1)
valid = 0;
break;
case 'V':
if (sscanf(&token[1], "%lf", &offset.v) != 1)
valid = 0;
break;
case 'W':
if (sscanf(&token[1], "%lf", &offset.w) != 1)
valid = 0;
break;
case 'I':
if (sscanf(&token[1], "%lf", &frontangle) != 1)
valid = 0;
break;
case 'J':
if (sscanf(&token[1], "%lf", &backangle) != 1)
valid = 0;
break;
case 'Q':
if (sscanf(&token[1], "%d", &orientation) != 1)
valid = 0;
break;
default:
if (strncmp(token, "\n", 1) != 0)
valid = 0;
break;
}
token = strtok_r(NULL, " ", &saveptr);
} // while token
if (valid) {
CANON_TOOL_TABLE tdata = tooldata_entry_init();
// verify no prior tool in pocket
if (tooldata_get(&tdata,idx) != IDX_OK) { UNEXPECTED_MSG; }
if (is_random_toolchanger && tdata.toolno != -1) {
fprintf(stderr,"WARNING: Attempt to assign multiple toolno.s to pocket %d\n",realpocket);
fprintf(stderr," %s %s()\n",__FILE__,__FUNCTION__);
fprintf(stderr," WAS: pocket=%3d toolno=%3d\n",tdata.pocketno,tdata.toolno);
fprintf(stderr," IS: pocket=%3d toolno=%3d\n",realpocket,toolno);
}
tdata.toolno = toolno;
tdata.pocketno = realpocket;
tdata.offset = offset;
tdata.diameter = diameter;
tdata.frontangle = frontangle;
tdata.backangle = backangle;
tdata.orientation = orientation;
if (comment) {
strncpy(tdata.comment,comment,CANON_TOOL_COMMENT_SIZE-1);
tdata.comment[CANON_TOOL_COMMENT_SIZE-1] = 0;
if (strlen(comment) > (CANON_TOOL_COMMENT_SIZE-1) ) {
fprintf(stderr,"%s():comment for toolno %d truncated to %d chars:\n <%s>\n"
,__FUNCTION__
,tdata.toolno
,CANON_TOOL_COMMENT_SIZE-1
,tdata.comment
);
}
}
if (tooldata_put(tdata,idx) == IDX_FAIL) {
UNEXPECTED_MSG;
}
} else {
return -1;
}
return idx;
} // tooldata_read_entry()
void tooldata_format_toolline (int idx,
bool ignore_zero_values,
CANON_TOOL_TABLE tdata,
char formatted_line[CANON_TOOL_ENTRY_LEN]
)
{
char tmp[CANON_TOOL_ENTRY_LEN-1] = {0};
int space = sizeof(tmp);
int len;
len = snprintf(tmp,sizeof(tmp),"T%-3d P%-3d"
,tdata.toolno
,is_random_toolchanger ? idx : tdata.pocketno);
strncat(formatted_line,tmp,space);
space -= len;
// format zero float values as %.0f for brevity
#define F_ITEM(item,letter) if (!ignore_zero_values || tdata.item) { \
char local_tmp[64] = {}; \
if (tdata.item) { \
len = snprintf(local_tmp,sizeof(local_tmp)," " letter "%+f", tdata.item); \
} else { \
len = snprintf(local_tmp,sizeof(local_tmp)," " letter "%.0f",tdata.item); \
} \
strncat(formatted_line,local_tmp,space); \
space -= len; \
}
#define I_ITEM(item,letter) if (!ignore_zero_values || tdata.item) { \
len = snprintf(tmp,sizeof(tmp)," " letter "%d",tdata.item); \
strncat(formatted_line,tmp,space); \
space -= len; \
}
F_ITEM(diameter, "D");
F_ITEM(offset.tran.x, "X");
F_ITEM(offset.tran.y, "Y");
F_ITEM(offset.tran.z, "Z");
F_ITEM(offset.a, "A");
F_ITEM(offset.b, "B");
F_ITEM(offset.c, "C");
F_ITEM(offset.u, "U");
F_ITEM(offset.v, "V");
F_ITEM(offset.w, "W");
F_ITEM(frontangle, "I");
F_ITEM(backangle, "J");
I_ITEM(orientation, "Q");
#undef F_ITEM
#undef I_ITEM
// Stop tracking len and space here for current tool table format
if (tdata.comment[0]) {
snprintf(tmp,space," ;%s\n",tdata.comment);
} else {
snprintf(tmp,space,"\n");
}
strncat(formatted_line,tmp,space);
return;
} // tooldata_format_toolline()
int tooldata_load(const char *filename)
{
FILE *fp;
char input_line[CANON_TOOL_ENTRY_LEN];
char orig_line[CANON_TOOL_ENTRY_LEN];
if (db_mode == DB_ACTIVE) { //expect data loaded from db
if (tooldata_db_getall()) {
fprintf(stderr,
"\ntooldata_load: Failed to load tooldata from database\n\n");
db_mode = DB_NOTUSED;
return -1;
}
return 0;
}
if(!filename) return -1;
// clear out tool table
// (Set vars to indicate no tool in pocket):
tooldata_reset();
// open tool table file
if (NULL == (fp = fopen(filename, "r"))) {
fprintf(stderr, "%s, %d: Failed to open tool table file '%s': %s\n",
__FILE__, __LINE__, filename, strerror(errno));
return -1;
}
// after initializing all available pockets,
// subsequent read from filename will update the last_index
// which becomes available by tooldata_last_index_get()
tooldata_last_index_set(0); // (only mmap uses)
const int nonrandom_start_idx = 1; // when reading file start at 0
tooldata_add_init(nonrandom_start_idx);
while (!feof(fp)) {
// for nonrandom machines, just read the tools into pockets 1..n
// no matter their tool numbers. NB leave the spindle pocket 0
// unchanged/empty.
if (NULL == fgets(input_line, CANON_TOOL_ENTRY_LEN, fp)) {
break;
}
strcpy(orig_line, input_line);
// parse and store one line from tool table file
int entry_idx = tooldata_read_entry(input_line);
if (entry_idx <0) {
printf("File: %s Unrecognized line skipped:\n %s",filename, orig_line);
continue;
}
if (!is_random_toolchanger) {
CANON_TOOL_TABLE spindletool;
if (tooldata_get(&spindletool,0) != IDX_OK) {
continue;
}
CANON_TOOL_TABLE edata; // just added
if (tooldata_get(&edata,entry_idx) != IDX_OK) {
UNEXPECTED_MSG;
}
if (!is_random_toolchanger && spindletool.toolno == edata.toolno) {
spindletool = edata;
tooldata_put(spindletool,0);
}
}
} // while
// close the file
fclose(fp);
return 0;
} // tooldata_load()
static void write_tool_line(FILE* fp,int idx)
{
CANON_TOOL_TABLE tdata;
if (tooldata_get(&tdata,idx) != IDX_OK) {return;}
if (db_mode == DB_ACTIVE && idx != 0 ) {
return;
}
if (tdata.toolno != -1) {
char theline[CANON_TOOL_ENTRY_LEN] = {0};
tooldata_format_toolline (idx,
1, // ignore_zero_values
tdata,theline);
fprintf(fp,"%s",theline);
}
return;
} // write_tool_line()
int tooldata_save(const char *filename)
{
int idx;
FILE *fp;
int start_idx;
if (db_mode == DB_ACTIVE) {
if (!is_random_toolchanger) {return 0;}
filename = DB_SPINDLE_SAVE; //one entry tbl (nonran only)
} else {
// filename == NULL happens without ini entry [EMCIO]TOOL_TABLE
// and a Task::emcToolSetOffset is performed.
if (!filename) {
fprintf(stderr, "%s: No filename. Are you missing INI-entry [EMCIO]TOOL_TABLE?\n",
__PRETTY_FUNCTION__);
return -1;
}
if (filename[0] == 0) {
UNEXPECTED_MSG;
}
}
// open tool table file
if (NULL == (fp = fopen(filename, "w"))) {
fprintf(stderr, "%s, %d: Failed to open tool table file '%s': %s\n",
__FILE__, __LINE__, filename, strerror(errno));
return -1;
}
if (db_mode == DB_ACTIVE) {
int spindle_idx = 0;
write_tool_line(fp,spindle_idx);
} else {
start_idx = is_random_toolchanger ? 0 : 1;
for (idx = start_idx; idx < CANON_POCKETS_MAX; idx++) {
write_tool_line(fp,idx);
}
}
fclose(fp);
return 0;
} //tooldata_save()