--Spindle Chiller RS232 control script local mcSerial = {} local inst = mc.mcGetInstance() package.path = package.path .. ";./Modules/?.lua;" package.cpath = package.cpath .. ";./Modules/?.dll;" --package.cpath = "C:/src/Mach4/Modules/?.dll;" rs232 = require("luars232") socket = require("socket") ------------------------------------------- -- Variables Declaration -- ------------------------------------------- --gRegs0/ChillerStatus --Chiller status 1=on / 0=Standby --gRegs0/WaterTemp --Actual water temp in Celsius port_name = "COM5" ChillerCom = 0 --Chiller port status 1=open / 0=closed SetTemp = 20 --Temp to set in Celsius ChillerFault = 0 local MaxTemp = 50 --Alarm water temp in Celsius Spindle_Overtemp = 0 --Chiller Water Overtemperature local out = io.stderr ------------------------------------------- -- Status Chiller Sync Cycle -- ------------------------------------------- function SyncChillerStatus() GetFaults() GetTemp() local hreg = mc.mcRegGetHandle(inst, string.format("gRegs0/%s", "WaterTemp")) local WTemp = mc.mcRegGetValue(hreg) if(WTemp >= MaxTemp) and (Spindle_Overtemp == 0) then mc.mcCntlSetLastError(inst, string.format("Cooling Water Overtemperature Alarm")) mc.mcCntlEStop(inst, 0); Spindle_Overtemp = 1 elseif (WTemp <= MaxTemp) and (Spindle_Overtemp == 1) then Spindle_Overtemp = 0 end end ------------------------------------------- -- Open Com Port -- ------------------------------------------- function OpenChillerCom() e, chiller = rs232.open(port_name) if e ~= rs232.RS232_ERR_NOERROR then -- handle error mc.mcCntlSetLastError(inst, string.format("can't open serial port '%s', error: '%s'\n", port_name, rs232.error_tostring(e))) return end -- set port settings assert(chiller:set_baud_rate(rs232.RS232_BAUD_9600) == rs232.RS232_ERR_NOERROR) assert(chiller:set_data_bits(rs232.RS232_DATA_8) == rs232.RS232_ERR_NOERROR) assert(chiller:set_parity(rs232.RS232_PARITY_NONE) == rs232.RS232_ERR_NOERROR) assert(chiller:set_stop_bits(rs232.RS232_STOP_1) == rs232.RS232_ERR_NOERROR) assert(chiller:set_flow_control(rs232.RS232_FLOW_OFF) == rs232.RS232_ERR_NOERROR) ChillerCom = 1 wx.wxMilliSleep(10) --Sleep 10 milliseconds ChillerSet() --mc.mcCntlSetLastError(inst, string.format("OK, port open with values '%s'\n", tostring(chiller))) end -------------------------------------------- -- Close Com Port -- ------------------------------------------- function CloseChillerCom() ChillerStandby() --Set Remote Stop assert(chiller:close() == rs232.RS232_ERR_NOERROR) ChillerCom = 0 end ------------------------------------------- -- Get chiller current water temperature -- ------------------------------------------- function GetTemp() --mcSerial.FlushBuffer() local reg = mc.mcRegGetHandle(inst, string.format("gRegs0/%s", "ChillerStatus")) --Write ChillerStatus register status local Status = mc.mcRegGetValue(reg) if Status == 1 then ChillerComSend("c9") --Ask temp remote running else ChillerComSend("89") --Ask temp remote Stopped end local read_len =1 -- read 2 bytes timeout = 500 -- in miliseconds local err, data_read, size = chiller:read(read_len, timeout) assert(e == rs232.RS232_ERR_NOERROR) local HSB = string.format("%02x",(string.byte(data_read))) local err, data_read, size = chiller:read(read_len, timeout) assert(e == rs232.RS232_ERR_NOERROR) local LSB = string.format("%02x",(string.byte(data_read))) Ftemp = (tonumber((LSB..HSB),16))*0.1 --hex to dec/*0.1 increments for degF FahrenheitToCelsius(Ftemp) local hreg = mc.mcRegGetHandle(inst, string.format("gRegs0/%s", "WaterTemp")) --Write WaterTemp register value mc.mcRegSetValue(hreg, CTemp) end ------------------------------------------- -- Set Temperature on chiller -- ------------------------------------------- function ChillerSet() CelsiusToFahrenheit(SetTemp) TempToChiller(Htemp) --if ChillerStatus == 0 --then ChillerComSend("a1") --Send Chiller set point 1 temperature remote Stopped --else --ChillerComSend("e1") --Send Chiller set point 1 temperature remote running --end ChillerComSend(SFtemp) end ------------------------------------------- -- Chiller Start Command -- ------------------------------------------- function ChillerStart() --ChillerSet() ChillerComSend("e0") --Set Remote Start local hreg = mc.mcRegGetHandle(inst, string.format("gRegs0/%s", "ChillerStatus")) --Write ChillerStatus register status mc.mcRegSetValue(hreg, 1) end ------------------------------------------- -- Write to Serial -- ------------------------------------------- function ChillerComSend(data) local timeout = 100 -- in miliseconds err, len_written = chiller:write((data:gsub("%w%w", function(s) return string.char(tonumber(s, 16)) end)), timeout) assert(e == rs232.RS232_ERR_NOERROR) end ------------------------------------------- -- Flush buffer -- --Windows automatically fills a serial buffer with characters (up to 4096 I think) --This function reads the entire buffer to empty it out ------------------------------------------- function mcSerial.FlushBuffer() local RV = 0 --RV, data_read, size = p:read(max_flush, timeout) RV = chiller:flush() end ------------------------------------------- -- Set chiller to Remote Stop{working} ------------------------------------------- function ChillerStandby() ChillerComSend("a0") --Set Remote Stop ChillerComSend("20") --Set local control local hreg = mc.mcRegGetHandle(inst, string.format("gRegs0/%s", "ChillerStatus")) --Write ChillerStatus register status mc.mcRegSetValue(hreg, 0) end ------------------------------------------- -- Get chiller current setpoint{release} ------------------------------------------- function GetSetpoint() mcSerial.FlushBuffer() local hreg = mc.mcRegGetHandle(inst, string.format("gRegs0/%s", "ChillerStatus")) --Write ChillerStatus register status local Status = mc.mcRegGetValueString(hreg) if Status == 0 then ChillerComSend("c1") --Ask Setpoint remote running else ChillerComSend("81") --Ask Setpoint remote Stopped end local read_len = 2 -- read 2 bytes timeout = 500 -- in miliseconds local err, data_read, size = chiller:read(read_len, timeout) assert(e == rs232.RS232_ERR_NOERROR) ChillerToTemp(data_read) local Setpoint = CTemp end ------------------------------------------- -- Get chiller fault code(0 = no faults) -- ------------------------------------------- function GetFaults() --mcSerial.FlushBuffer() local hreg = mc.mcRegGetHandle(inst, string.format("gRegs0/%s", "ChillerStatus")) --Write ChillerStatus register status local Status = mc.mcRegGetValueString(hreg) if Status == 0 then ChillerComSend("c8") --Ask faults remote running else ChillerComSend("88") --Ask faults remote Stopped end local read_len = 1 -- read 1 byte timeout = 500 -- in miliseconds local err, data_read, size = chiller:read(read_len, timeout) assert(e == rs232.RS232_ERR_NOERROR) local fault = (string.byte(data_read)) if fault ~= 0 and ChillerFault == 0 --0 = no faults/else check faults ChillerFaults() then mc.mcCntlSetLastError(inst, string.format("Chiller Fault No:'%s'\n", fault)) ChillerFaults{fault} mc.mcCntlEStop(inst, 0); elseif (fault == 0) then ChillerFault = 0 end end ------------------------------------------- -- Decode and show chiller fault code -- ------------------------------------------- function ChillerFaults(HexFault) for _,v in ipairs(HexFault) do if v == 1 then mc.mcCntlSetLastError(inst, string.format("Chiller Water Level Low")) elseif v == 2 then mc.mcCntlSetLastError(inst, string.format("Chiller Fan Fail")) elseif v == 8 then mc.mcCntlSetLastError(inst, string.format("Chiller Pump Fail")) elseif v == 10 then mc.mcCntlSetLastError(inst, string.format("Chiller RTD Open")) elseif v == 20 then mc.mcCntlSetLastError(inst, string.format("Chiller RTD Short")) elseif v == nil then mc.mcCntlSetLastError(inst, string.format("Chiller Communication Fault")) end end end ------------------------------------------- -- Convert Fahrenheit to Celsius -- ------------------------------------------- function FahrenheitToCelsius(temp) CTemp = (temp-32)*5/9 -- input >> temp -- Call >> FahrenheitToCelsius(temp) end ------------------------------------------- -- Convert Celsius to Fahrenheit -- ------------------------------------------- function CelsiusToFahrenheit(SetTemp) Htemp = (SetTemp*9/5)+32 -- input >> SetTemp -- Call >> CelsiusToFahrenheit(temp) end -------------------------------------------------------------------- -- Process data temp for send to chiller (F to 2 Bytes Hex) -- -------------------------------------------------------------------- function TempToChiller(Htemp) temp = string.format("%04x",(Htemp*10)) --farenheit*10 as 0xXXXX --Invert Bytes B1 = string.sub(temp,3,4) --Extract last 2 digits of temp B1 = B1:gsub("%xx", function(s) return string.char(tonumber(s, 16)) end) --convert to hex B2 = string.sub(temp,1,2) --Extract first 2 digits of temp B2 = B2:gsub("%xx", function(s) return string.char(tonumber(s, 16)) end) --convert to hex SFtemp = B1..B2 -- Call >> TempToChiller(68) -- Out >> SFtemp end