local mcSerial = {} local inst = mc.mcGetInstance() rs232 = require("luars232") port_name = "COM1" local out = io.stderr local read_len = 1 -- read one byte local timeout = 5 -- in miliseconds local ResponseTimer = 5 --Time to delay for drive response in milliseconds local max_flush = 4096 --Maximum number of characters to flush from the buffer while reading local max_length = 18 --Longest Serial Packet ---------------------------------- -- mcSerial.OpenPort() -- ---------------------------------- function mcSerial.OpenPort() --mc.mcCntlSetLastError(inst, "Starting Serial Port Open Function") --This function uses the RS232 library to open a serial port using the global variable port_name --Port settings are assigned immediately local ES = "" local RS = "" local RV = 0 --Open Serial port using the RS232 library and check for errors e, p = rs232.open(port_name) --mc.mcCntlSetLastError(inst, "Attepted to Open Port - Checking for Errors") if e ~= rs232.RS232_ERR_NOERROR then; ES = "F0101"..string.format("%02X",e)..":"; return ES; end --mc.mcCntlSetLastError(inst, "Port Open - No Errors, Applying Settings") -- set port settings assert(p:set_baud_rate(rs232.RS232_BAUD_38400) == rs232.RS232_ERR_NOERROR) assert(p:set_data_bits(rs232.RS232_DATA_8) == rs232.RS232_ERR_NOERROR) assert(p:set_parity(rs232.RS232_PARITY_NONE) == rs232.RS232_ERR_NOERROR) assert(p:set_stop_bits(rs232.RS232_STOP_1) == rs232.RS232_ERR_NOERROR) assert(p:set_flow_control(rs232.RS232_FLOW_OFF) == rs232.RS232_ERR_NOERROR) --mc.mcCntlSetLastError(inst, "Serial Port Open - Settings Applied") WriteRegister("SerialOpen", 1) return ES end ---------------------------------- -- mcSerial.ClosePort() -- ---------------------------------- function mcSerial.ClosePort() local ES = "" local RS = "" local RV = 0 p:close() WriteRegister("SerialOpen", 0) return ES end ---------------------------------- -- mcSerial.DebugWrite() -- ---------------------------------- function mcSerial.DebugWrite(string) local ES = "" local RS = "" local RV = 0 RV, len_written = p:write(string, timeout) --write the string over the serial port if (RV ~= rs232.RS232_ERR_NOERROR) then; ES = "F0601"..string.format("%02X",RV)..":" ; return ES; end return ES end ---------------------------------- -- mcSerial.FlushBuffer() -- ---------------------------------- function mcSerial.FlushBuffer() --Windows automatically fills a serial buffer with characters (up to 4096 I think) --This function reads the entire buffer to empty it out local ES = "" local RS = "" local RV = 0 local data_read local size --RV, data_read, size = p:read(max_flush, timeout) RV = p:flush() if RV ~= rs232.RS232_ERR_NOERROR then; ES = "F0201"..string.format("%02X",RV)..":"; return ES; end return ES end ---------------------------------- -- mcSerial.AppendChecksum(string) -- ---------------------------------- function mcSerial.AppendChecksum(str) --This function is for use with Ultra 3000 serial host commands --This function takes a string input then calculates two character checksum --The input string is concatenated with a leading colon, a trailing checksum, and a trailing carriage return local ES = "" local RS = "" local RV = 0 local ccSum = 0 local rString = "" --mc.mcCntlSetLastError(inst, "Entering Append Checksum, Input Data is :"..str) local len = string.len(str) --mc.mcCntlSetLastError(inst, "String Length is "..tostring(len)) if len == 0 then; ES = "F030101:"; rString = ""; return ES, rString; end if len > 70 then; ES = "F030102:"; rString = ""; return ES, rString; end for i=1,len,1 do ccSum = ccSum + str:byte(i) --mc.mcCntlSetLastError(inst, "Checksum Index "..tostring(i).." Current Sum = "..tostring(ccSum)) end local output = string.format("%X", bit32.band(256-ccSum)) --mc.mcCntlSetLastError(inst, "Calculated Checksum = "..output) local checksum = string.sub(output,-2,-1) --mc.mcCntlSetLastError(inst, "Truncated Checksum = "..checksum) rString = ':'..str..checksum.."\r" --mc.mcCntlSetLastError(inst, "String to be Returned is "..rString) return ES, rString end ---------------------------------- -- mcSerial.Hex2Num(string) -- ---------------------------------- function mcSerial.Hex2Num(str) --This function converts a hexidecimal number to decimal using twos complement --This function returns the decimal number (or nil) and an error code local ES = "" local RS = "" local RV = 0 local hexNum = nil local len = string.len(str) if len == 0 then; ES = "F040101:"; hexNum = nil; return ES, hexNum; end hexNum = tonumber(str,16) if len == 2 then if hexNum >= 128 then hexNum = hexNum - 256 end elseif len == 4 then if hexNum >= 32768 then hexNum = hexNum - 65536 end elseif len == 8 then if hexNum >= 2147484148 then hexNum = hexNum - 4294967296 end else; ES = "F040102:"; hexNum = nil; return ES, hexNum; end return ES, hexNum end ---------------------------------- -- mcSerial.WriteRead(string) -- ---------------------------------- function mcSerial.WriteRead(tString) --mc.mcCntlSetLastError(inst, "Starting Serial Routine Write/Read ") --This function is in charge of writing to the Ultra 3000 and handling reponses local ES = "" local RS = "" local RV = 0 local rString = "" --local sError = 0 local data = "" local len_written = 0 local data_read = "" local size local checkVerify = "" --mc.mcCntlSetLastError(inst, "Flushing Buffer") RS = mcSerial.FlushBuffer() if (RS ~= "") then; ES = "F050101:"..RS ; data = ""; return ES, data; end --mc.mcCntlSetLastError(inst, "Buffer Flush Complete, Writing String ="..tString) RV, len_written = p:write(tString, timeout) --write the string over the serial port if (RV ~= rs232.RS232_ERR_NOERROR) then; ES = "F0502"..string.format("%02X",RV)..":" ; data = ""; return ES, data; end --mc.mcCntlSetLastError(inst, "Write Complete, Starting Delay") wx.wxMilliSleep(2) --Sleep 2 milliseconds --mc.mcCntlSetLastError(inst, "Delay Complete, Looking for Drive Response") --read serial buffer until a colon is found for i = 0, max_flush, 1 do --Flush the buffer until a colon is found, routine resumes here after timer expiration RV, data_read, size = p:read(1, timeout) --RV, data_read, size = p:read(1) --mc.mcCntlSetLastError(inst, "Index = "..tostring(i).." Data = "..tostring(data_read)) if (RV ~= rs232.RS232_ERR_NOERROR) then; ES = "F0503"..string.format("%02X",RV)..":" ; data = ""; return ES, data; end if (data_read == "") then; ES = "F050401:"; data = ""; return ES, data; end if (i == max_flush) then; ES = "F050402:"; data = ""; return ES, data; end if data_read == ":" then break end end --mc.mcCntlSetLastError(inst, "Colon Found, Starting Data Read") --read serial buffer and concatenate a string until a is found for i = 0,max_length,1 do --Flush the buffer until a colon is found, routine resumes here after timer expiration RV, data_read, size = p:read(1, timeout) if (RV ~= rs232.RS232_ERR_NOERROR) then; ES = "F0505"..string.format("%02X",RV)..":" ; data = ""; return ES, data; end if (data_read == nil or i == max_length) then; ES = "F050601:"; data = ""; return ES, data; end rString = rString..data_read if data_read == "\r" then break end end --mc.mcCntlSetLastError(inst, "Data Read Complete, Validating Checksum") --validate checksum RS, checkVerify = mcSerial.AppendChecksum(string.sub(rString, 1,-4)) if (RS ~= "") then; ES = "F050701:"..RS ; return ES; end if (string.sub(rString, -3, -2) ~= string.sub(checkVerify,-3,-2)) then; ES = "F050801:"; data = ""; return ES, data; end --mc.mcCntlSetLastError(inst, "Checksum OK, Checking for Exceptions") --check if drive exception was received by checking if the received parameter code equals the transmitted parameter code + 0x800 if (string.sub(rString,3,5) == string.format("%x",tonumber("0x800")+tonumber(string.sub(tString,4,6),16))) then; ES = "F050901:"; data = ""; return ES, data; end --mc.mcCntlSetLastError(inst, "No Exceptions, Verifying Sender") --check if address, parameter, and function match what was sent, if so return data, else return error if (string.sub(rString,1,6) == string.sub(tString,2,7)) then data = string.sub(rString,7,-4) --mc.mcCntlSetLastError(inst, "Sender Verified, Returning Data") return ES, data else; ES = "F050A01:"; data = ""; return ES, data; end end return mcSerial