iosh.cc

来自「CNC 的开放码,EMC2 V2.2.8版」· CC 代码 · 共 1,639 行 · 第 1/3 页

CC
1,639
字号
/********************************************************************* Description: iosh.cc*   Extended-Tcl-based general IO programming shell with NML connectivity**   Derived from a work by Fred Proctor & Will Shackleford** Author:* License: GPL Version 2* System: Linux*    * Copyright (c) 2004 All rights reserved.** Last change:* $Revision: 1.23 $* $Author: cradek $* $Date: 2007/04/01 04:16:33 $********************************************************************//*! \todo   FIXME  add tool_in_spindle status*/#include <stdio.h>#include <string.h>#include <stdlib.h>#include <signal.h>#include "tcl.h"#include "tk.h"#include "rcs.hh"		// etime()#include "posemath.h"		// PM_POSE#include "emc.hh"		// EMC NML#include "emc_nml.hh"#include "emcglb.h"		// EMC_NMLFILE, TRAJ_MAX_VELOCITY, etc.#include "emccfg.h"		// DEFAULT_TRAJ_MAX_VELOCITY#include "inifile.hh"		// INIFILE#include "rcs_print.hh"#include "nml_oi.hh"            // nmlErrorFormat#include "timer.hh"             // esleep#include "motion.h"		// emc struct and commands#include "motion_debug.h"#include "motion_struct.h"#include "usrmotintf.h"		// usrmot interface/*  Using iosh:  iosh {<script>} {-- -ini <ini file>}  With filename, it opens NML buffers to the EMC IO, runs the script, closes  the buffers, and quits.  Without filename, it runs interactively.  With -- -ini <inifile>, uses inifile instead of emc.ini. Note that  the two dashes prevents Tcl from looking at the remaining args, which  would otherwise trigger a Tcl error that it doesn't understand what  -ini means.  EMC IO commands:  emc_io_connect  emc_io_disconnect  Open or close the NML buffers to the command in, status out, and error out.  Returns 0 if OK, or -1 if not.  emc_io_read_command  Peek the NML command buffer. Returns 0 if OK, -1 if not.  emc_io_get_command  Puts the command string, e.g., "emc_aux_estop_off", or "none". Returns 0.  emc_io_get_command_type  Puts the command NML number. Returns 0.  emc_io_get_serial_number  Puts the command serial number. Returns 0.  emc_io_write_status  Write the EMC_IO_STAT structure out to NML. Returns 0 if OK, -1 if error.  emc_io_write_error  Write the error string to the error NML buffer. Returns 0 if OK, -1 if error.  emc_io_load_tool_table  Loads the tool table specified in the ini file  IO status, sets associated field in the NML status structure  emc_io_status_heartbeat <number>  emc_io_status_echo_serial_number <number>  emc_io_status_status done | exec | error  emc_io_status_estop on | off  emc_io_status_mist on | off  emc_io_status_flood on | off  emc_io_status_lube on | off  emc_io_status_lube_level ok | low  emc_io_status_tool_prepped <number>  emc_io_status_tool_in_spindle <number>//FIXME: The following have been commented out, if there is need they will be made to work again,    or all the io will go through the motion controller, in which case all the NML needs to get rerouted  emc_io_status_spindle_speed <speed>  emc_io_status_spindle_enabled on | off  emc_io_status_spindle_direction <pos> <neg> 0  emc_io_status_spindle_increasing <pos> <neg> 0  emc_io_status_spindle_brake on | off  IO commands:  inb <address>  Reads and returns the byte at <address>. If address begins with 0x,  it's interpreted as a hex number, otherwise it's decimal.  outb <address> <value>  Writes the byte <value> to <address>. If address or value begins with 0x,  it's interpreted as a hex number, otherwise it's decimal. Returns nothing.  inw <address>  Reads and returns the short at <address>. If address begins with 0x,  it's interpreted as a hex number, otherwise it's decimal.  outw <address> <value>  Writes the short <value> to <address>. If address or value begins with 0x,  it's interpreted as a hex number, otherwise it's decimal. Returns nothing.  inl <address>  Reads and returns the long at <address>. If address begins with 0x,  it's interpreted as a hex number, otherwise it's decimal.  outl <address> <value>  Writes the long <value> to <address>. If address or value begins with 0x,  it's interpreted as a hex number, otherwise it's decimal. Returns nothing.  emc_mot_move <axis> <position> <velocity>      emc_mot_rawinput <axis>      emc_mot_shmem: need no args*/// the NML channels to the EMC taskstatic RCS_CMD_CHANNEL *emcioCommandBuffer = 0;// NML command channel data pointerstatic RCS_CMD_MSG *emcioCommand = 0;static RCS_STAT_CHANNEL *emcioStatusBuffer = 0;static EMC_IO_STAT emcioStatus;// the NML channel for errorsstatic NML *emcErrorBuffer = 0;// Shared memory to communicate with emcmotstatic emcmot_command_t emcmotCommand;extern emcmot_struct_t *emcmotshmem;static long shmem = 0;		// Shared memory flag// "defined but not used"...//static int motionId = 0;static int emcIoNmlGet(){    int retval = 0;    // try to connect to EMC IO cmd    if (emcioCommandBuffer == 0) {	emcioCommandBuffer =	    new RCS_CMD_CHANNEL(emcFormat, "toolCmd", "tool", EMC_NMLFILE);	if (!emcioCommandBuffer->valid()) {	    rcs_print_error("emcToolCmd buffer not available\n");	    delete emcioCommandBuffer;	    emcioCommandBuffer = 0;	    retval = -1;	} else {	    // get our command data structure	    emcioCommand = emcioCommandBuffer->get_address();	}    }    // try to connect to EMC IO status    if (emcioStatusBuffer == 0) {	emcioStatusBuffer =	    new RCS_STAT_CHANNEL(emcFormat, "toolSts", "tool",				 EMC_NMLFILE);	if (!emcioStatusBuffer->valid()) {	    rcs_print_error("toolSts buffer not available\n");	    delete emcioStatusBuffer;	    emcioStatusBuffer = 0;	    retval = -1;	} else {	    // initialize and write status	    emcioStatus.heartbeat = 0;	    emcioStatus.command_type = 0;	    emcioStatus.echo_serial_number = 0;	    emcioStatus.status = RCS_DONE;	    emcioStatusBuffer->write(&emcioStatus);	}    }    return retval;}static int emcErrorNmlGet(){    int retval = 0;    if (emcErrorBuffer == 0) {	emcErrorBuffer =	    new NML(nmlErrorFormat, "emcError", "tool", EMC_NMLFILE);	if (!emcErrorBuffer->valid()) {	    rcs_print_error("emcError buffer not available\n");	    delete emcErrorBuffer;	    emcErrorBuffer = 0;	    retval = -1;	}    }    return retval;}// EMC IO commandsstatic int emc_ini(ClientData clientdata,		   Tcl_Interp * interp, int objc, Tcl_Obj * CONST objv[]){    IniFile inifile;    const char *inistring;    const char *varstr, *secstr;    if (objc != 3) {	Tcl_SetResult(interp, "emc_ini: need 'var' and 'section'",		      TCL_VOLATILE);	return TCL_ERROR;    }    // open it    if (inifile.Open(EMC_INIFILE) == false) {	return -1;    }    varstr = Tcl_GetStringFromObj(objv[1], 0);    secstr = Tcl_GetStringFromObj(objv[2], 0);    if (NULL == (inistring = inifile.Find(varstr, secstr))) {	return TCL_OK;    }    Tcl_SetResult(interp, (char *) inistring, TCL_VOLATILE);    // close it    inifile.Close();    return TCL_OK;}static int emc_io_connect(ClientData clientdata,			  Tcl_Interp * interp, int objc,			  Tcl_Obj * CONST objv[]){    double end;    int good;#define RETRY_TIME 10.0		// seconds to wait for subsystems to come up#define RETRY_INTERVAL 1.0	// seconds between wait tries for a subsystem    if (objc != 1) {	Tcl_SetResult(interp, "emc_io_connect: need no args\n",		      TCL_VOLATILE);	return TCL_ERROR;    }    if (!(EMC_DEBUG & EMC_DEBUG_NML)) {	set_rcs_print_destination(RCS_PRINT_TO_NULL);	// inhibit diag	// messages    }    end = RETRY_TIME;    good = 0;    do {	if (0 == emcIoNmlGet()) {	    good = 1;	    break;	}	esleep(RETRY_INTERVAL);	end -= RETRY_INTERVAL;    } while (end > 0.0);    if (!(EMC_DEBUG & EMC_DEBUG_NML)) {	set_rcs_print_destination(RCS_PRINT_TO_STDOUT);	// restore diag	// messages    }    if (!good) {	Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));	return TCL_OK;    }    if (!(EMC_DEBUG & EMC_DEBUG_NML)) {	set_rcs_print_destination(RCS_PRINT_TO_NULL);	// inhibit diag	// messages    }    end = RETRY_TIME;    good = 0;    do {	if (0 == emcErrorNmlGet()) {	    good = 1;	    break;	}	esleep(RETRY_INTERVAL);	end -= RETRY_INTERVAL;    } while (end > 0.0);    if (!(EMC_DEBUG & EMC_DEBUG_NML)) {	set_rcs_print_destination(RCS_PRINT_TO_STDOUT);	// restore diag	// messages    }    if (!good) {	Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));	return TCL_OK;    }    Tcl_SetObjResult(interp, Tcl_NewIntObj(0));    return TCL_OK;}static int emc_io_disconnect(ClientData clientdata,			     Tcl_Interp * interp, int objc,			     Tcl_Obj * CONST objv[]){    if (objc != 1) {	Tcl_SetResult(interp, "emc_io_disconnect: need no args\n",		      TCL_VOLATILE);	return TCL_ERROR;    }    if (emcErrorBuffer != 0) {	delete emcErrorBuffer;	emcErrorBuffer = 0;    }    if (emcioStatusBuffer != 0) {	delete emcioStatusBuffer;	emcioStatusBuffer = 0;    }    if (emcioCommandBuffer != 0) {	delete emcioCommandBuffer;	emcioCommandBuffer = 0;    }    Tcl_SetObjResult(interp, Tcl_NewIntObj(0));    return TCL_OK;}/*  emc_io_read_command peeks the NML command buffer. The side effect is  that emcioCommand now latches the NML contents. Other functions, like  emc_io_get_command,serial_number, get the contents from emcioCommand.  Returns 0 if OK, -1 if error reading NML.*/static int emc_io_read_command(ClientData clientdata,			       Tcl_Interp * interp, int objc,			       Tcl_Obj * CONST objv[]){    if (objc != 1) {	Tcl_SetResult(interp, "emc_io_read_command: need no args\n",		      TCL_VOLATILE);	return TCL_ERROR;    }    // read NML buffer    if (0 == emcioCommandBuffer || 0 == emcioCommand) {	Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));	return TCL_OK;    }    // latch new command into emcioCommand    if (-1 == emcioCommandBuffer->peek()) {	Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));	return TCL_OK;    }    Tcl_SetObjResult(interp, Tcl_NewIntObj(0));    return TCL_OK;}/*  load the tool table from file filename into toolTable[] array.  Array is CANON_TOOL_MAX + 1 entries, since 0 is included.  If filename is "", use global established from ini file  */static int loadToolTable(const char *filename,			 CANON_TOOL_TABLE toolTable[]){    int t;    FILE *fp;    char buffer[CANON_TOOL_ENTRY_LEN];    const char *name;    // check filename    if (filename[0] == 0) {	name = TOOL_TABLE_FILE;    } else {	// point to name provided	name = filename;    }    // open tool table file    if (NULL == (fp = fopen(name, "r"))) {	// can't open file	return -1;    }    // clear out tool table    for (t = 0; t <= CANON_TOOL_MAX; t++) {	// unused tools are 0, 0.0, 0.0	toolTable[t].id = 0;	toolTable[t].xoffset = 0.0;	toolTable[t].zoffset = 0.0;	toolTable[t].diameter = 0.0;        toolTable[t].frontangle = 0.0;        toolTable[t].backangle = 0.0;        toolTable[t].orientation = 0;    }    /*       Override 0's with codes from tool file       File format is:       <header>       <pocket # 0..CANON_TOOL_MAX> <FMS id> <length> <diameter>       ...     */    // read and discard header    if (NULL == fgets(buffer, 256, fp)) {	// nothing in file at all	fclose(fp);	return -1;    }    while (!feof(fp)) {	int pocket;	int id;	double zoffset;        double xoffset;	double diameter;        double frontangle, backangle;        int orientation;	// just read pocket, ID, and length offset	if (NULL == fgets(buffer, CANON_TOOL_ENTRY_LEN, fp)) {	    break;	}        if (sscanf(buffer, "%d %d %lf %lf %lf %lf %lf %d",                    &pocket, &id, &zoffset, &xoffset, &diameter,                    &frontangle, &backangle, &orientation) == 8) {	    if (pocket < 0 || pocket > CANON_TOOL_MAX) {                printf("skipping tool: bad pocket number %d\n", pocket);		continue;	    } else {		/* lathe tool */		toolTable[pocket].id = id;                toolTable[pocket].xoffset = xoffset;		toolTable[pocket].zoffset = zoffset;		toolTable[pocket].diameter = diameter;                toolTable[pocket].frontangle = frontangle;                toolTable[pocket].backangle = backangle;                toolTable[pocket].orientation = orientation;	    }	} else if (sscanf(buffer, "%d %d %lf %lf",                    &pocket, &id, &zoffset, &diameter) == 4) {	    if (pocket < 0 || pocket > CANON_TOOL_MAX) {                printf("skipping tool: bad pocket number %d\n", pocket);		continue;	    } else {                /* mill tool */		toolTable[pocket].id = id;		toolTable[pocket].zoffset = zoffset;		toolTable[pocket].diameter = diameter;                toolTable[pocket].frontangle = toolTable[pocket].backangle = 0.0;                toolTable[pocket].xoffset = 0.0;                toolTable[pocket].orientation = 0;	    }	} else {            /* invalid line. skip it silently */	    continue;	}    }    // close the file    fclose(fp);    return 0;}/*  save the tool table to file filename from toolTable[] array.  Array is CANON_TOOL_MAX + 1 entries, since 0 is included.  If filename is "", use global established from ini file  *//* FIXME - commented out, seems it's not usedstatic int saveToolTable(const char *filename,			 CANON_TOOL_TABLE toolTable[]){    int pocket;    FILE *fp;    const char *name;    // check filename    if (filename[0] == 0) {	name = TOOL_TABLE_FILE;    } else {	// point to name provided	name = filename;    }    // open tool table file    if (NULL == (fp = fopen(name, "w"))) {	// can't open file	return -1;    }    // write header    fprintf(fp, "POC\tFMS\tLEN\t\tDIAM\n");    for (pocket = 1; pocket <= CANON_TOOL_MAX; pocket++) {	fprintf(fp, "%d\t%d\t%f\t%f\n",		pocket,		toolTable[pocket].id,		toolTable[pocket].length, toolTable[pocket].diameter);    }    // close the file    fclose(fp);    return 0;}FIXME - commented out, seems it's not used*//*  emc_io_get_command returns the string and any args associated with  the command, or "none" if nothing is there.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?