require("bit") dyutils = {} -- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss -- licensed under the terms of the LGPL2 -- character table string local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -- translate string of hex to data function dyutils.hex_str_to_bin(hex_str) local t_str='' for i=1, string.len(hex_str),2 do t_str=t_str .. string.char(tonumber(string.sub(hex_str, i, i+1),16)) end return t_str, string.len(t_str) end -- translate data to hex str function dyutils.bin_str_to_hex(bin_str) local t_str = '' local charcode local hexstr for i = 1, string.len(bin_str) do local charcode = tonumber(string.byte(bin_str, i, i)) local hexstr = string.format("%02X", charcode) t_str = t_str .. hexstr end return t_str, string.len(t_str) end -- 字符串分割 function dyutils.split(input, delimiter) local arr = {} string.gsub(input, '[^' .. delimiter ..']+', function(w) table.insert(arr, w) end) return arr end -- 查看某值是否为表tbl中的key值 function table.kIn(tbl, key) if tbl == nil then return false end for k, v in pairs(tbl) do if k == key then return true end end return false end -- 查看某值是否为表tbl中的value值 function table.vIn(tbl, value) if tbl == nil then return false end for k, v in pairs(tbl) do if v == value then return true end end return false end -- encoding function dyutils.enc(data) return ((data:gsub('.', function(x) local r,b='',x:byte() for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end return r; end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x) if (#x < 6) then return '' end local c=0 for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end return b:sub(c+1,c+1) end)..({ '', '==', '=' })[#data%3+1]) end -- decoding function dyutils.dec(data) data = string.gsub(data, '[^'..b..'=]', '') return (data:gsub('.', function(x) if (x == '=') then return '' end local r,f='',(b:find(x)-1) for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end return r; end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x) if (#x ~= 8) then return '' end local c=0 for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(7-i) or 0) end return string.char(c) end)) end function dyutils.CRC16(modbusdata, length) local i=0; local j=0; local crc=0xFFFF; local k=1; local k=1; local l=1; for k=1, length do crc = bit.bxor(crc, string.byte(string.sub(modbusdata,k,k))) for l=1, 8 do if bit.band(crc, 1) == 1 then crc = bit.rshift(crc, 1) crc = bit.bxor(crc, 0xa001) else crc = bit.rshift(crc, 1) end end end return bit.band(bit.lshift(crc,8),0xFFFF)+bit.rshift(crc,8) end function dyutils.CRC16_ZERO(modbusdata, length) local i=0; local j=0; local crc=0x0000; local k=1; local k=1; local l=1; for k=1, length do crc = bit.bxor(crc, string.byte(string.sub(modbusdata,k,k))) for l=1, 8 do if bit.band(crc, 1) == 1 then crc = bit.rshift(crc, 1) crc = bit.bxor(crc, 0xa001) else crc = bit.rshift(crc, 1) end end end crc = bit.band(bit.lshift(crc,8),0xFFFF)+bit.rshift(crc,8) crc = tonumber(string.format("%u", crc)) return crc end function dyutils.CalculateiU16XorCrc(arr_buff, len) local lastValue = 0 local shiftBitNum = 8 local fractionalData = bit.band(len, 0x1) local crc = 0 local int_len = math.modf(len/2) local k = 1 local i = 1 for k=0, int_len-1 do local sub = string.sub(arr_buff,k*2 + 1, k*2 + 2) _, t = bunpack(sub, "S") crc = bit.bxor(crc, t) end if (fractionalData ~= 0) then lastValue = bit.bor(lastValue, bit.lshift(string.byte(string.sub(arr_buff,len-fractionalData+i,len-fractionalData+i)), shiftBitNum)) crc = bit.bxor(crc, lastValue) end crc = tonumber(string.format("%u", crc)) return crc; end function dyutils.CalculateXorCrc(arr_buff, len) local lastValue = 0 local shiftBitNum = {24, 16, 8} local fractionalData = bit.band(len, 0x3) local crc = 0 local int_len = math.modf(len/4) local k = 1 local i = 1 for k=0, int_len-1 do local sub = string.sub(arr_buff,k*4 + 1, k*4 + 4) _, t = bunpack(sub, "I") crc = bit.bxor(crc, t) end if (fractionalData ~= 0) then for i=1, fractionalData do lastValue = bit.bor(lastValue, bit.lshift(string.byte(string.sub(arr_buff,len-fractionalData+i,len-fractionalData+i)), shiftBitNum[i])) end crc = bit.bxor(crc, lastValue) end crc = tonumber(string.format("%u", crc)) return crc; end function dyutils.packIEEE754(number) if number == 0 then return string.char(0x00, 0x00, 0x00, 0x00) elseif number ~= number then return string.char(0xFF, 0xFF, 0xFF, 0xFF) else local sign = 0x00 if number < 0 then sign = 0x80 number = -number end local mantissa, exponent = math.frexp(number) exponent = exponent + 0x7F if exponent <= 0 then mantissa = math.ldexp(mantissa, exponent - 1) exponent = 0 elseif exponent > 0 then if exponent >= 0xFF then return string.char(sign + 0x7F, 0x80, 0x00, 0x00) elseif exponent == 1 then exponent = 0 else mantissa = mantissa * 2 - 1 exponent = exponent - 1 end end mantissa = math.floor(math.ldexp(mantissa, 23) + 0.5) return string.char( sign + math.floor(exponent / 2), (exponent % 2) * 0x80 + math.floor(mantissa / 0x10000), math.floor(mantissa / 0x100) % 0x100, mantissa % 0x100) end end function dyutils.unpackIEEE754(packed) local b1, b2, b3, b4 = string.byte(packed, 1, 4) local exponent = (b1 % 0x80) * 0x02 + math.floor(b2 / 0x80) local mantissa = math.ldexp(((b2 % 0x80) * 0x100 + b3) * 0x100 + b4, -23) if exponent == 0xFF then if mantissa > 0 then return 0 / 0 else mantissa = math.huge exponent = 0x7F end elseif exponent > 0 then mantissa = mantissa + 1 else exponent = exponent + 1 end if b1 >= 0x80 then mantissa = -mantissa end local tmp=math.ldexp(mantissa, exponent - 0x7F) return tmp-tmp%0.000001 end --Define some commonly used constants here so we don't have to do this at runtime --ln(2), used for change of base down the line local log2 = math.log(2) --Used to convert the fraction into a (very large) integer local pow2to52 = math.pow(2,52) --Used for bit-shifting local f08 = math.pow(2, 8) local f16 = math.pow(2,16) local f24 = math.pow(2,24) local f32 = math.pow(2,32) local f40 = math.pow(2,40) local f48 = math.pow(2,48) function dyutils.encodeDouble(number) --IEEE double-precision floating point number --Specification: https://en.wikipedia.org/wiki/Double-precision_floating-point_format --Separate out the sign, exponent and fraction local sign = number < 0 and 1 or 0 local exponent = math.ceil(math.log(math.abs(number))/log2) - 1 local fraction = math.abs(number)/math.pow(2,exponent) - 1 --Make sure the exponent stays in range - allowed values are -1023 through 1024 if (exponent < -1023) then --We allow this case for subnormal numbers and just clamp the exponent and re-calculate the fraction --without the offset of 1 exponent = -1023 fraction = math.abs(number)/math.pow(2,exponent) elseif (exponent > 1024) then --If the exponent ever goes above this value, something went horribly wrong and we should probably stop error("Exponent out of range: " .. exponent) end --Handle special cases if (number == 0) then --Zero exponent = -1023 fraction = 0 elseif (math.abs(number) == math.huge) then --Infinity exponent = 1024 fraction = 0 elseif (number ~= number) then --NaN exponent = 1024 fraction = (pow2to52-1)/pow2to52 end --Prepare the values for encoding local expOut = exponent + 1023 --The exponent is an 11 bit offset-binary local fractionOut = fraction * pow2to52 --The fraction is 52 bit, so multiplying it by 2^52 will give us an integer --Combine the values into 8 bytes and return the result return string.char( 128*sign + math.floor(expOut/16), --Byte 0: Sign and then shift exponent down by 4 bit (expOut%16)*16 + math.floor(fractionOut/f48), --Byte 1: Shift fraction up by 4 to give most significant bits, and fraction down by 48 math.floor(fractionOut/f40)%256, --Byte 2: Shift fraction down 40 bit math.floor(fractionOut/f32)%256, --Byte 3: Shift fraction down 32 bit math.floor(fractionOut/f24)%256, --Byte 4: Shift fraction down 24 bit math.floor(fractionOut/f16)%256, --Byte 5: Shift fraction down 16 bit math.floor(fractionOut/f08)%256, --Byte 6: Shift fraction down 8 bit math.floor(fractionOut % 256) --Byte 7: Last 8 bits of the fraction ) end function dyutils.decodeDouble(str) --Get bytes from the string local byte0 = string.byte(string.sub(str,1,1)) local byte1 = string.byte(string.sub(str,2,2)) local byte2 = string.byte(string.sub(str,3,3)) local byte3 = string.byte(string.sub(str,4,4)) local byte4 = string.byte(string.sub(str,5,5)) local byte5 = string.byte(string.sub(str,6,6)) local byte6 = string.byte(string.sub(str,7,7)) local byte7 = string.byte(string.sub(str,8,8)) --Separate out the values local sign = byte0 >= 128 and 1 or 0 local exponent = (byte0%128)*16 + math.floor(byte1/16) local fraction = (byte1%16)*f48 + byte2*f40 + byte3*f32 + byte4*f24 + byte5*f16 + byte6*f08 + byte7 --Handle special cases if (exponent == 2047) then --Infinities if (fraction == 0) then return math.pow(-1,sign) * math.huge end --NaN if (fraction == pow2to52-1) then return 0/0 end end --Combine the values and return the result if (exponent == 0) then --Handle subnormal numbers return math.pow(-1,sign) * math.pow(2,exponent-1023) * (fraction/pow2to52) else --Handle normal numbers return math.pow(-1,sign) * math.pow(2,exponent-1023) * (fraction/pow2to52 + 1) end end return dyutils