===== Modbus RTU in custom protocol version =====
An example of custom protocol for Modbus RTU.
*Type: Serial Port
*Address validation: ^(C[0-9]+)$|^(DI[0-9]+)$|^(HR[0-9]+)$|^(IR[0-9]+)$
*Validation error message: Invalid register address. Valid ModBus addresses are Cxxx, DIxxx, IRxxx, HRxxx.
Code:
-- MODBUS RTU Demo Driver
function createDevices ()
-- read FC write FC
addDevice({name = "C", shift = 0, base = 10, xtraFields = {1, 5}})
addDevice({name = "DI", shift = 0, base = 10, xtraFields = {2, 0}})
addDevice({name = "HR", shift = 0, base = 10, xtraFields = {3, 6}})
addDevice({name = "HRI", shift = 0, base = 10, xtraFields = {3, 6, 1, 0}}) -- uint 0 inverse
addDevice({name = "HRIF", shift = 0, base = 10, xtraFields = {3, 6, 1, 5}}) -- float inverse (maybe 7 ? https://docs.webhmi.com.ua/access_via_api?s[]=float)
addDevice({name = "HRF", shift = 0, base = 10, xtraFields = {3, 6, 0, 5}}) -- float 5
addDevice({name = "IR", shift = 0, base = 10, xtraFields = {4, 0}})
end
local errorCount = 0
SLAVE_ADDR = 1
FUNC_CODE = 2
REG_ADDR_HI = 3
REG_ADDR_LO = 4
DATA_LEN_HI = 5;
DATA_LEN_LO = 6
CRC_POS_LO = 7 -- CRC LITTLE-ENDIAN (lowest comes first!)
CRC_POS_HI = 8
CRC_BIG_ENDIAN = false
if CRC_BIG_ENDIAN then
CRC_POS_HI = 7
CRC_POS_LO = 8 -- CRC BIG-ENDIAN (biggest comes first)
end
-- template
local request = {SLAVE_ADDR, FUNC_CODE,
REG_ADDR_HI, REG_ADDR_LO,
DATA_LEN_HI, DATA_LEN_LO,
CRC_POS_LO, CRC_POS_HI
}
EXCEPTIONS = { "Illegal Function", "Illegal Data Address",
"Illegal Data Value", "Slave Device Failure",
"Acknowledge", "Slave Device Busy",
"Negative Acknowledge", "Memory Parity Error",
"Gateway Path Unavailable", "Gateway Target Device Failed to Respond"
}
-- dataType – The type of data that the user specified for the register. 0 = Bit, 1 = Byte, 2 = Word, 3 = Double Word, 4 = UnixTime
DATATYPE = {DW = 3}
DATALEN = {DW = 4, WORD=2, BYTE=1,BIT=1}
FORMAT = {UINT = 0, FLOAT_32=5}
table.unpack = unpack
function readRegister (reg, device, unitId)
--------------------------------------------- FORMING REQUEST ----------------------------------------------
request[SLAVE_ADDR] = unitId
request[FUNC_CODE] = device.xtraFields[1]
request[REG_ADDR_HI] = GetHiByte(reg.internalAddr)
request[REG_ADDR_LO] = GetLoByte(reg.internalAddr)
count = reg.dataType == DATATYPE.DW and 2 or 1
request[DATA_LEN_HI] = GetHiByte(count)
request[DATA_LEN_LO] = GetLoByte(count)
local crc = GetCRC(request, 2)
local crcLo, crcHi -- will be used below too
crcLo = GetLoByte(crc) ; request[CRC_POS_LO] = crcLo
crcHi = GetHiByte(crc) ; request[CRC_POS_HI] = crcHi
---------------------------------------------- SENDING REQUEST ----------------------------------------------
if not (sendBytes(request)) then
DEBUG("Can't send bytes")
return false
end
---------------------------------------------- RECEIVING REPLY ----------------------------------------------
local respHead, respData, respCRC = {}, {}, {}
-- read Header with length
respHead = readBytes(3)
if (respHead == false) then
DEBUG("Can't read response")
return false
end
if (respHead[SLAVE_ADDR] ~= request[SLAVE_ADDR]) then
ERROR("Wrong slaveID in response!")
return false
end
if (respHead[FUNC_CODE] ~= request[FUNC_CODE]) then
if (respHead[FUNC_CODE] >= 0x81) then
ERROR("EXCEPTION: "..EXCEPTIONS[bit.band(respHead[FUNC_CODE], 0x0F)])
readBytes(2) -- read till the end
else
ERROR("Wrong Func Code in response. In response = 0d" .. tostring( respHead[FUNC_CODE]) .. ', but expected = 0d' .. tostring(request[FUNC_CODE]))
end
return false;
end
local resp_Lentgh = respHead[3];
respData = readBytes(resp_Lentgh)
if (respData == false) then
DEBUG("Can't read response");
return false;
end
local tmpResponseTab = {}
for i,v in ipairs(respHead) do
table.insert(tmpResponseTab, v)
end
for i,v in ipairs(respData) do
table.insert(tmpResponseTab, v)
end
-- check CRC in reply
crc = GetCRC(tmpResponseTab, 0)
crcLo = GetLoByte(crc)
crcHi = GetHiByte(crc)
respCRC = readBytes(2)
if (respCRC == false) then
DEBUG("Can't read response");
return false;
end
if (respCRC[1] ~= crcLo) or (respCRC[2] ~= crcHi) then
DEBUG("Wrong CRC in reply! "..string.format("%X", crcLo).." "..string.format("%X", crcHi));
return false;
end
if (device.name == "DI") or (device.name == "C") then
if (resp_Lentgh ~= count) then
ERROR("Wrong length in response");
return false;
end
else
if (resp_Lentgh ~= count*2) then
ERROR("Wrong length in response");
return false;
end
end
---------------------------------------------- RETURN DATA ----------------------------------------------
local inversion = device.xtraFields[3]
return GetHexFromTable(respData, not((inversion or 0) == 1))
end -- readRegister
function GetHexFromTable(inputTab, _invert)
if #inputTab > 2 then
local invert = _invert or false
if invert then
invertedInputTab = {}
half1, half2 = SplitInHalf(inputTab)
for i, v in pairs(half2) do table.insert(invertedInputTab, v) end
for i, v in pairs(half1) do table.insert(invertedInputTab, v) end
inputTab = invertedInputTab;
end
local toReturn = {}
for i,v in pairs(inputTab) do toReturn[i]=tonumber(string.format("%X",v),16) end
return toReturn
else
-- get hex and concat it to number via string operatoin
-- TRACE("entered GetHexFromTable with table - "..table.concat(inputTab))
local numberAs_String = ""
local tmpStr = ""
for i,v in pairs(inputTab) do
tmpStr = string.format("%X",v)
if (#tmpStr == 1) then
tmpStr = "0"..tmpStr
end
numberAs_String = numberAs_String..tmpStr
end
-- TRACE("GetHexFromTable: decimal number is "..table.concat(inputTab).." hexadecimal = ".. numberAs_String)
return tonumber(numberAs_String, 16)
end
end
function writeRegister (reg, device, unitId, newValue)
local inversion = not(device.xtraFields[3] == 1 or false)
reg.value_format = device.xtraFields[4]
if reg.dataType == DATATYPE.DW and reg.value_format == FORMAT.FLOAT_32 then
DEBUG("Going to write this value ".. (decodeIEEE754FloatToLua(newValue) or 'nil') .. ', \nuint(dec): ' .. '0d'..newValue .. ', binary: ' .. '0b'..table.concat(toBits(newValue,32)) .. ', uint(hex): ' .. string.format("0x%x", newValue)) -- TRACE("newValue = 0d" .. newValue .. ' hex = 0x' .. string.format("%X", newValue))
else
DEBUG("Going to write this value "..newValue)
end
if device.name == "IR" or device.name == "DI" then
ERROR("Can't write these type of registers (" .. device.name .. ")")
return true
end
local wrRequest = {};
wrRequest[SLAVE_ADDR] = unitId;
wrRequest[FUNC_CODE] = device.xtraFields[2]
wrRequest[REG_ADDR_HI] = GetHiByte(reg.internalAddr)
wrRequest[REG_ADDR_LO] = GetLoByte(reg.internalAddr)
local dataTable = GetDataAsTable(newValue, reg.dataType)
if reg.dataType == DATATYPE.DW and inversion then
dataTableTmp = {}
dataTableTmp[1]=dataTable[3]; dataTableTmp[2]=dataTable[4]
dataTableTmp[3]=dataTable[1]; dataTableTmp[4]=dataTable[2]
dataTable=dataTableTmp
end
-- local coilsTmp = 0
if (device.name == "C") then
local coilsTmp = dataTable[2] * 0xFF
dataTable[2] = dataTable[1]
dataTable[1] = coilsTmp
end
wrRequest[DATA_LEN_HI] = dataTable[1]
wrRequest[DATA_LEN_LO] = dataTable[2]
local crc, crcLo, crcHi = 0,0,0
crc = GetCRC(wrRequest, 0)
crcLo = GetLoByte(crc)
crcHi = GetHiByte(crc)
wrRequest[CRC_POS_LO] = crcLo
wrRequest[CRC_POS_HI] = crcHi
local res = sendBytes(wrRequest);
if (res == false) then
DEBUG("Can't send request");
return false;
end
-- read response
res = readBytes(8)
if (res == false) then
DEBUG("Can't receive reply")
return false
end
if (table.concat(res) ~= table.concat(wrRequest)) then
DEBUG("Response does not match!")
return false
end
if (#dataTable == DATALEN.DW) then
-- TRACE("DWORD CASE!!!")
-- repeat steps for 2nd Word
wrRequest[REG_ADDR_HI] = GetHiByte(reg.internalAddr + 1)
wrRequest[REG_ADDR_LO] = GetLoByte(reg.internalAddr + 1)
wrRequest[DATA_LEN_HI] = dataTable[3]
wrRequest[DATA_LEN_LO] = dataTable[4]
crc = GetCRC(wrRequest, 2); crcLo = GetLoByte(crc); crcHi = GetHiByte(crc) -- offset = 2 for omit crc from previous word
wrRequest[CRC_POS_LO] = crcLo
wrRequest[CRC_POS_HI] = crcHi
res = sendBytes(wrRequest);
if (res == false) then
DEBUG("Can't send request");
return false;
end
end
return true
end
-- Calculating CRC16 for MODBUS RTU
function GetCRC(req, offset)
local crc = 0xffff
local mask = 0
-- iterate bytes
for i=1,#req-offset do
crc = bit.bxor(crc,req[i])
-- iterate bits in byte
for j=1,8 do
mask = bit.band(crc,0x0001)
if mask == 0x0001 then
crc = bit.rshift(crc,1)
crc = bit.bxor(crc,0xA001)
else
crc = bit.rshift(crc,1)
end
end
end
return crc
end
function GetHiByte(c)
assert(c < 65536, "This is not a two bytes!")
-- DEBUG("Going to get high byte from "..c .. ' 0x'.. string.format("%04X", c))
return bit.rshift(c,8)
end
function GetLoByte(c)
assert(c < 65536, "This is not a two bytes!")
-- DEBUG("Going to get low byte from "..c .. ' 0x'.. string.format("%04X", c))
return bit.band(c,0xFF)
end
function SplitInHalf(full)
local h1, h2 = {}, {}
local half = math.ceil(#full/2)
for i = 1, half do
table.insert(h1, full[i])
end
for i = half+1, #full do
table.insert(h2, full[i])
end
return h1,h2
end
function GetDataAsTable(value, datatype)
local highWord, lowWord, tmpTable = 0, 0, {}
if (datatype ~= DATATYPE.DW) then
DEBUG("GetDataAsTable - going to process value "..value)
tmpTable[1] = GetHiByte(value) ; DEBUG('tmpTable[1] = ' .. tmpTable[1])
tmpTable[2] = GetLoByte(value) ; DEBUG('tmpTable[2] = ' .. tmpTable[2])
else
highWord = bit.rshift(value, 16)
lowWord = bit.band (value, 0xFFFF)
tmpTable[1] = GetHiByte(highWord)
tmpTable[2] = GetLoByte(highWord)
tmpTable[3] = GetHiByte(lowWord)
tmpTable[4] = GetLoByte(lowWord)
DEBUG("GetDataAsTable DW = - " .. table.concat(tmpTable))
end
return tmpTable
end
function toBits(num,bits)
-- returns a table of bits, most significant first.
bits = bits or math.max(1, select(2, math.frexp(num)))
local t = {} -- will contain the bits
for b = bits, 1, -1 do
t[b] = math.fmod(num, 2)
num = math.floor((num - t[b]) / 2)
end
return t
end
function Bin2Hex(s)
assert (type(s) == "string", "binary as string expected")
-- s -> binary string
local bin2hex = {
["0000"] = "0", ["0001"] = "1", ["0010"] = "2", ["0011"] = "3",
["0100"] = "4", ["0101"] = "5", ["0110"] = "6", ["0111"] = "7",
["1000"] = "8", ["1001"] = "9", ["1010"] = "A", ["1011"] = "B",
["1100"] = "C", ["1101"] = "D", ["1110"] = "E", ["1111"] = "F"
}
tabBytes={}
local l = 0
local h, b = "", ""
local rem
l = string.len(s)
rem = l % 4
l = l-1
-- need to prepend zeros to eliminate mod 4
if (rem > 0) then
s = string.rep("0", 4 - rem)..s
end
for i = 1, l, 4 do
b = string.sub(s, i, i+3)
table.insert(tabBytes,bin2hex[b])
if not b then ERROR("bin2hex b is nil") end
TRACE("bin2hex b = " .. tostring(b))
h = h..bin2hex[b]
end
return h, tabBytes
end
function hex2dec(hexstr)
return tonumber(hexstr,16)
end
function decodeIEEE754FloatToLua(input)
sign = input < 0 and -1 or 1
input = math.abs(input)
bitsTable = toBits(input,32)
exponentTable={table.unpack(bitsTable, 2,9)}
mantissaTable={table.unpack(bitsTable,10)}
mantissaStr, manstissaTabBytes = Bin2Hex(table.concat(mantissaTable))
mantissaNum = hex2dec(table.concat(manstissaTabBytes))
exponentStr, exponentBytesTable = Bin2Hex(table.concat(exponentTable))
exponentNum = hex2dec(table.concat(exponentBytesTable))
exponent = exponentNum - 127 -- 0 - 127 = -127 --> denormalized mode
mantissa=mantissaNum/8388608
if exponent == -127 then -- denormalized mode
exponent = -126
mantissa = mantissa
else
mantissa = mantissa + 1
end
float_number=math.ldexp(mantissa,exponent) * sign
return float_number
end
==== Version 2 ====
-- MODBUS RTU Driver
function createDevices ()
-- read FC write FC
addDevice({name = "C", shift = 0, base = 10, xtraFields = {1, 5}})
addDevice({name = "DI", shift = 0, base = 10, xtraFields = {2, 0}})
addDevice({name = "HR", shift = 0, base = 10, xtraFields = {3, 6}})
addDevice({name = "IR", shift = 0, base = 10, xtraFields = {4, 0}})
addDevice({name = "MHR",shift = 0, base = 10, xtraFields = {3, 16}})
end
local errorCount = 0
-- template
local request = {1, 2, -- slaveId FC
3, 4, -- addr high lo
5, 6, -- count hi lo
0, 0 -- crc high lo
}
local requestM = {1, 2, -- Адрес устройства, Функциональный код
3, 4, -- Адрес первого регистра Hi, Lo
5, 6, -- Количество регистров Hi, Lo
7, -- Количество байт далее
8, 9, -- Значение1 Hi, Lo
10, 11, -- Значение2 Hi, Lo
-------------------------------
0, 0 -- Контрольная сумма CRC Hi, Lo
}
EXCEPTIONS = {"Illegal Function", "Illegal Data Address",
"Illegal Data Value", "Slave Device Failure",
"Acknowledge", "Slave Device Busy",
"Negative Acknowledge", "Memory Parity Error",
"Gateway Path Unavailable", "Gateway Target Device Failed to Respond"
}
function readRegister (reg, device, unitId)
--- FORMING REQUEST -----------
-- slave address
request[1] = unitId;
-- function code
request[2] = device.xtraFields[1]
-- address of register
request[3] = GetHiByte(reg.internalAddr)
request[4] = GetLoByte(reg.internalAddr)
-- count of registers
local count = 1
if (reg.dataType == 3) then -- double word
count = 2
end
request[5] = GetHiByte(count)
request[6] = GetLoByte(count)
-- CRC
local crc = GetCRC(request, 2)
local crcLo,crcHi = 0,0 -- will be used below too
crcLo = GetLoByte(crc) ; request[7] = crcLo
crcHi = GetHiByte(crc) ; request[8] = crcHi
-- SENDING REQUEST
if not (sendBytes(request)) then
DEBUG("Can't send bytes")
return false
end
-- RECEIVING REPLY ---
local respHead, respData, respCRC = {}, {}, {}
-- read Header with length
respHead = readBytes(3)
if (respHead == false) then
DEBUG("Can't read response")
return false
end
if (respHead[1] ~= request[1]) then
ERROR("Wrong slaveID in response!")
return false
end
if (respHead[2] ~= request[2]) then
if (respHead[2] >= 0x81) then
ERROR("EXCEPTION: "..EXCEPTIONS[bit.band(respHead[2], 0x0F)])
readBytes(2) -- read till the end
else
ERROR("Wrong Func Code in response")
end
return false;
end
local resp_Lentgh = respHead[3];
respData = readBytes(resp_Lentgh)
if (respData == false) then
DEBUG("Can't read response");
return false;
end
-- check CRC in reply
local tmpResponseTab = {}
for i,v in ipairs(respHead) do
table.insert(tmpResponseTab, v)
end
for i,v in ipairs(respData) do
table.insert(tmpResponseTab, v)
end
crc = GetCRC(tmpResponseTab, 0)
crcLo = GetLoByte(crc)
crcHi = GetHiByte(crc)
respCRC = readBytes(2)
if (respCRC == false) then
DEBUG("Can't read response");
return false;
end
if (respCRC[1] ~= crcLo) or (respCRC[2] ~= crcHi) then
DEBUG("Wrong CRC in reply! "..string.format("%X", crcLo).." "..string.format("%X", crcHi));
return false;
end
if (device.name == "DI") or (device.name == "C") then
if (resp_Lentgh ~= count) then
ERROR("Wrong length in response");
return false;
end
else
if (resp_Lentgh ~= count*2) then
ERROR("Wrong length in response");
return false;
end
end
-- RETURN DATA --
--return GetHexFromTable(respData)
return respData
end -- readRegister
function writeRegister (reg, device, unitId, newValue)
-- for read-only don't write
DEBUG("Going to write this value "..newValue)
if device.name == "IR" or device.name == "DI" then
ERROR("Can't write these type of registers (" .. device.name .. ")")
return true
end
if device.name == "MHR" then
ERROR("Can't write these type of registers (" .. device.name .. ")")
-------------------------------------- My Write MHR --------------------------------------
local wrRequest = {};
local n_byte =1;
-- Адрес устройства
wrRequest[n_byte] = unitId;
-- Функциональный код
n_byte = n_byte +1;
wrRequest[n_byte] = device.xtraFields[2]
-- Адрес первого регистра Hi, Lo
n_byte = n_byte +1;
wrRequest[n_byte] = GetHiByte(reg.internalAddr)
n_byte = n_byte +1;
wrRequest[n_byte] = GetLoByte(reg.internalAddr)
-- копируем в dataTable байты которые нужно записать
local dataTable = GetDataAsTable(newValue, reg.dataType)
local kol = #dataTable; -- количество байт которые нужно записать
-- Количество регистров Hi, Lo
n_byte = n_byte +1;
wrRequest[n_byte] = 0;
n_byte = n_byte +1;
wrRequest[n_byte] = kol/2;
-- Количество байт далее
n_byte = n_byte +1;
wrRequest[n_byte] = kol;
-- Значение 1,2,3... Hi, Lo
for i = 1, kol do
n_byte = n_byte +1;
wrRequest[n_byte] = dataTable[i]
end
-- CRC
local crc, crcLo, crcHi = 0,0,0
crc = GetCRC(wrRequest, 0)
crcLo = GetLoByte(crc)
crcHi = GetHiByte(crc)
n_byte = n_byte +1;
wrRequest[n_byte] = crcLo
n_byte = n_byte +1;
wrRequest[n_byte] = crcHi
DEBUG("Going to send this packet "..table.concat(wrRequest))
local res = sendBytes(wrRequest);
if (res == false) then
DEBUG("Can't send request");
return false;
end
-- читаем ответ
res = readBytes(8)
if (res == false) then
DEBUG("Can't receive reply")
return false
end
-- проверяем записалось или нет по количеству записанных регистров
if ( res[6] ~= (kol/2)) then
DEBUG("Response does not match!")
return false
end
-------------------------------------- My Write MHR --------------------------------------
return true
else
local wrRequest = {};
-- slave address
wrRequest[1] = unitId;
-- function code
wrRequest[2] = device.xtraFields[2]
-- address of register
wrRequest[3] = GetHiByte(reg.internalAddr)
wrRequest[4] = GetLoByte(reg.internalAddr)
local dataTable = GetDataAsTable(newValue, reg.dataType)
local coilsTmp = 0
if (device.name == "C") then
coilsTmp = dataTable[2] * 0xFF
dataTable[2] = dataTable[1]
dataTable[1] = coilsTmp
end
DEBUG("#dataTable now "..#dataTable)
wrRequest[5] = dataTable[1]
wrRequest[6] = dataTable[2]
-- CRC
local crc, crcLo, crcHi = 0,0,0
crc = GetCRC(wrRequest, 0)
crcLo = GetLoByte(crc)
crcHi = GetHiByte(crc)
wrRequest[7] = crcLo
wrRequest[8] = crcHi
DEBUG("Going to send this packet "..table.concat(wrRequest))
local res = sendBytes(wrRequest);
if (res == false) then
DEBUG("Can't send request");
return false;
end
-- читаем ответ
res = readBytes(8)
if (res == false) then
DEBUG("Can't receive reply")
return false
end
if (table.concat(res) ~= table.concat(wrRequest)) then
DEBUG("Response does not match!")
return false
end
if (#dataTable == 4) then
-- если пишем DWORD
-- repeat steps for 2nd Word
wrRequest[3] = GetHiByte(reg.internalAddr + 1)
wrRequest[4] = GetLoByte(reg.internalAddr + 1)
wrRequest[5] = dataTable[3]
wrRequest[6] = dataTable[4]
wrRequest[7] = nil -- удаляем ячейку со старым CRC
wrRequest[8] = nil -- удаляем ячейку со старым CRC
-- CRC
crc = GetCRC(wrRequest, 0)
crcLo = GetLoByte(crc)
crcHi = GetHiByte(crc)
wrRequest[7] = crcLo
wrRequest[8] = crcHi
DEBUG("Going to send this packet "..table.concat(wrRequest))
res = sendBytes(wrRequest);
if (res == false) then
DEBUG("Can't send request");
return false;
end
-- читаем ответ
res = readBytes(8)
if (res == false) then
DEBUG("Can't receive reply")
return false
end
end
return true
end
end
-- Calculating CRC for RTU
function GetCRC(req, offset)
local crc = 0xffff
local mask = 0
-- iterate bytes
for i=1,#req-offset do
crc = bit.bxor(crc,req[i])
-- iterate bits in byte
for j=1,8 do
mask = bit.band(crc,0x0001)
if mask == 0x0001 then
crc = bit.rshift(crc,1)
crc = bit.bxor(crc,0xA001)
else
crc = bit.rshift(crc,1)
end
end
end
return crc
end
function GetHiByte(c)
DEBUG("Going to get high byte from "..c)
return bit.rshift(c,8)
end
function GetLoByte(input_val)
DEBUG("Going to get low byte from "..input_val)
return bit.band(input_val,0xFF)
end
function GetHexFromTable(inputTab)
-- get hex and concat it to number via string operatoin
DEBUG("entered GetHexFromTable with table - "..table.concat(inputTab))
local numberAs_String = ""
local tmpStr = ""
for i,v in pairs(inputTab) do
tmpStr = string.format("%X",v)
if (#tmpStr == 1) then
tmpStr = "0"..tmpStr
end
numberAs_String = numberAs_String..tmpStr
end
DEBUG("number is "..numberAs_String.." decimal = "..numberAs_String)
return tonumber(numberAs_String, 16)
end
function GetDataAsTable(value, datatype)
local highWord, lowWord, tmpTable = 0, 0, {}
if (datatype ~= 3) then
DEBUG("getdataastable - going to process value "..value)
tmpTable[1] = GetHiByte(value) ; DEBUG(tmpTable[1])
tmpTable[2] = GetLoByte(value) ; DEBUG(tmpTable[2])
else
highWord = bit.rshift(value,16)
lowWord = bit.band(value,0xFFFF)
tmpTable[1] = GetHiByte(highWord)
tmpTable[2] = GetLoByte(highWord)
tmpTable[3] = GetHiByte(lowWord)
tmpTable[4] = GetLoByte(lowWord)
end
return tmpTable
end