import sys import traceback # A python interface for LinuxCNC tool database usage #Notes # 1) host (LinuxCNC) pushes commands to this program # 2) all writes to stdout go to host # (caller: use stderr for debug prints) #----------------------------------------------------------- DB_VERSION = 'v2.1' #----------------------------------------------------------- # functions for import by user # tooldb_callbacks # tooldb_tools # tooldb_loop #----------------------------------------------------------- def do_reply(msg): sys.stdout.write("%s\n"%msg) sys.stdout.flush() def saveline(line): global theline theline = line def currentline(): global theline return theline def nak_reply(msg): theline = currentline() if msg != "empty_line": sys.stderr.write(traceback.format_exc()+"\n") sys.stdout.write("NAK %s <%s>\n"%(msg,theline)) sys.stdout.flush() def tool_cmd(cmd,params): # debug usage: return info for tool # parms is toolno if not len(params): nak_reply("no toolno") return if len(params.split()) != 1: nak_reply("too many parms") return try: toolno = int(params) except Exception as e: nak_reply("non-integer toolno") return if toolno not in tools: nak_reply("toolno out-of-range") return do_reply(get_tool(toolno)) def get_cmd(cmd,params): for tno in tools: try: msg = get_tool(tno) except Exception as e: nak_reply( "get_cmd():Exception:%s"%str(e)) return try: do_reply(msg) except: if (tno==0): if debug: sys.stderr.write("no tool in spindle\n") pass do_reply("FINI (get_cmd)") def put_cmds(cmd,params): # note: checks are mainly for commandline debugging, # expect host to always provide a valid toolline uparams = params.upper() if len(uparams) == 0: raise Exception("cmd=%s: requires tool entry line"%cmd) try: toolno = int(uparams[0:uparams.index(" ")].strip("T")) toolline = uparams except Exception as e: sys.stderr.write("cmd=%s: %s:\n"%(cmd,e)) raise Exception("cmd=%s: failed to parse <%s>"%(cmd,params)) # require at least "Tvalue Pvalue" try: toolline.index("T");toolline.index(" P") except Exception as e: sys.stderr.write("cmd=%s: %s:\n"%(cmd,e)) raise Exception("cmd=%s: failed to parse <%s>"%(cmd,params)) try: if cmd == "p": put_tool( toolno,toolline) elif cmd == "l": load_spindle( toolno,toolline) elif cmd == "u": unload_spindle(toolno,toolline) except Exception as e: nak_reply( "cmd=%s: Exception:%s"%(cmd,str(e))) return do_reply("FINI (update recvd) %s"%params) def unknown_cmd(cmd,params): nak_reply("unknown cmd") return def do_cmd(line): global debug if debug: sys.stderr.write("!!line=<%s>\n"%line) linelist = line.strip().split() cmd = linelist[0] params = "" if len(linelist) > 1: # params is everything after first " ":0 params = line.strip()[line.index(" "):].strip() switcher = { "g": get_cmd, # get (all tools) "p": put_cmds, # put (update one tool offsets) "u": put_cmds, # unload spindle "l": put_cmds, # load spindle "t": tool_cmd, # debug usage } thecmd = switcher.get(cmd) or unknown_cmd thecmd(cmd,params) def startup_ack(): global debug debug = 0 do_reply("%s"%DB_VERSION); if (len(sys.argv)>1 and sys.argv[1] == 'debug'): debug = 1 #----------------------------------------------------------- # Begin functions that can be imported def tooldb_callbacks(tool_getter,tool_putter,spindle_loader,spindle_unloader): """Specify callback functions""" global get_tool, put_tool, load_spindle, unload_spindle get_tool = tool_getter put_tool = tool_putter load_spindle = spindle_loader unload_spindle = spindle_unloader def tooldb_tools(tool_list): """Specify list = available toolnumers""" global tools tools = tool_list def tooldb_loop(): """Loop forever: 1) send startup acknowledgment 2) read line from stdino 3) parse line execute command if valid nak command if invalid 4) repeat """ startup_ack() while True: try: line=sys.stdin.readline().strip() saveline(line) if (line == ""): nak_reply("empty_line") else: do_cmd(line) except BrokenPipeError: sys.stdout.close() except Exception as e: nak_reply("_exception=%s"%e)