function m4000(hVars) local inst = mc.mcGetInstance() -- File input/output names. Default directory is typically C:\Mach4Hobby local ifilename = wx.wxGetCwd() .. "\\pp-input.txt" local ofilename = wx.wxGetCwd() .. "\\pp-output.nc" --local ifilename = wx.wxGetCwd() .. "\\Profiles\\<>\\Macros\\pp-input.txt" --local ifilename = wx.wxGetCwd() .. "\\Profiles\\<>\\Macros\\pp-output.nc" -- Output selection: -- M4000 E0 -> Do not send to live gcode execution -- M4000 E1 -> Send to live gcode execution -- M4000 F0 -> Do not save output gcode -- M4000 F1 -> Save output gcode -- Tip: It is best to always specify both parameters, since MACH remembers the last used values, e.g. M4000 E0 F1, etc. local execute = false local save_output = true if hVars ~= nil then execute = (mc.mcCntlGetLocalVar(inst, hVars, mc.SV_E) ~= 0.0) save_output = (mc.mcCntlGetLocalVar(inst, hVars, mc.SV_F) ~= 0.0) end -- Remove comment from string, and trailing spaces local function remove_comment(s) local i = string.find(s, "%-%-") if(i ~= nil) then s = s.sub(s, 1, i - 1) s = s.gsub(s, "%s+$", "") end return s end -- Detect variable definition local function is_def(s) local i = string.find(s, ">>") return i == 1 end -- Detect multiline variable definitions, replace with newline if found local function is_multiline_def(s) local i = string.find(s, ";") if(i ~= nil) then return true, s.sub(s, 1, i - 1) .. "\n" else return false, s end end -- Extract defined variable and its value local function extract_var(s) local i1 = string.find(s, "%s") if(i1 == nil) then return s.sub(s, 3), "" end local var = s.sub(s, 3, i1 - 1) local i2 = string.find(s, "%S", i1) if(i2 ~= nil) then return var, s.sub(s, i2) else return var, "" end end -- Detect variable reference local function is_ref(s) local i1 = string.find(s, "<<") if(i1 ~= nil) then local i2 = string.find(s, "%W", i1 + 2) if(i2 ~= nil) then return true, s.sub(s, i1 + 2, i2 - 1) else return true, s.sub(s, i1 + 2) end else return false, "" end end -- Replace variable references local function replace_ref(s, var, val) return string.gsub(s, "<<" .. var, val) end -- Get next non-empty line from file, remove comments local function get_next_line(ifile) while(true) do local line = ifile:read("*line") if(line ~= nil) then line = remove_comment(line) if(string.len(line) > 0) then return line end else return nil end end end -- Open input/output files local ifile = io.open(ifilename, "r") if(ifile == nil) then mc.mcCntlSetLastError(inst, "Failed to open input file " .. ifilename) return end local ofile if(save_output) then ofile = io.open(ofilename, "w") if(ofile == nil) then mc.mcCntlSetLastError(inst, "Failed to open output file " .. ofilename) return end end local vars = {} while(true) do local ret local line = get_next_line(ifile) if(line == nil) then break end if(is_def(line)) then -- Process variable definition, possibly multiline ret, line = is_multiline_def(line) while(ret) do local line_cont = get_next_line(ifile) if(line_cont ~= nil) then line = line .. line_cont ret, line = is_multiline_def(line) else break end end var, val = extract_var(line) vars[var] = val else -- Process output line, replacing variable references ret, var = is_ref(line) while(ret) do val = vars[var] if(val == nil) then -- Unknown variable, output without changes mc.mcCntlSetLastError(inst, "Unknown varable [" .. var .. "]") break end line = replace_ref(line, var, val) ret, var = is_ref(line) end -- Save output/execute if(ofile ~= nil) then ofile:write(line .. "\n") end if(execute) then mc.mcCntlGcodeExecuteWait(inst, line) end end end io.close(ifile) if(ofile ~= nil) then io.close(ofile) end end if (mc.mcInEditor() == 1) then m4000() end