将硬件规定的通信协议用Lua实现(涉及到很多Lua通信的数据转换)

1:这次处理的是大唐的gps通信协议,先简单介绍一下他规定的通信规则:

信息结构:

传输说明:

  信息结构中的各个字节书写时都是以十六进制标识,两位数组成。传输时,SOIEOISOI=7EHEOI=0DH)各按一个字节传输,但其余各项每个字节都是拆成两个字节,每个字节用两个ASCII码标识,即高4位用一个ASCII码表示,低4位用一个ASCII码标识,传输时先发送高4位的ASCII码,后发送低4位的ASCII码。

示例:CID2=4BH4ASCII码是34HBASCII码是42H,传送时顺序发送34H42H两个字节。

因此,实际传输的字节数应是1以及下面各表中字节数乘以2

2:要达到的目的: 

例如要处理一段这样的数据:(需要计算的LCHkSUM和CHKSUM由46代替)                        

info="7E 32 31 30 31 44 30 30 30 

            46 30 31 45 ( length段(1个LCHKSUM+3个LENTGTHID)

             30 30 30 36 33 32 36 31 42 37 30 31 44 34 42 42 42 39 30 31 45 41 30 30 30 30 30 30 30 30(数据段

             46 46 46 46 CHKSUM

             0D" 

  我们不知道LCHKSUM是多少,也不知道后面的CHKSUM是多少但是知道其他,总不能手动去算吧,于是写了如下程序用来自动计算这两个CHKSUM

3:关于LENGTH段的解释:

  LENGTH2个字节,由LENIDLCHKSUM组成,LENID表示INFO项的ASCII码字节数,当LENID=0时,INFO为空,即无该项。LENGTH拆分4ASCII码传送,先高字节,后低字节。校验码的计算:D11D10D9D8+D7D6D5D4+D3D2D1D0,求和后模16余数取反加1

示例:

INFO项的ASCII码字节数为18,即LENID=0000 0001 0010B

D11D10D9D8+D7D6D5D4+D3D2D1D0=0000B+0001B+0010B=0011B,模16余数为0011B0011B取反加1就是1101B,即LCHKSUM1101B

可以得出:LENGTH1101 0000 0001 0010B,即D012H

 

代码实现:(利用length段的后面234字节算出chksum得到第一个字节)

 

function LengthID(ch1, ch2, ch3)    local tmp = "";
    tmp = tmp .. string.char(0x30) .. string.char(ch1) .. string.char(ch2) .. string.char(ch3);
    print("tmp==>",tmp);
    local HI = Parse2btye(string.sub(tmp,1,2));
    local LO = Parse2btye(string.sub(tmp,3,4));
    print(LO)--两个十六进制数1e转化为十进制30
    print("lo==>",string.format("%x",LO));
    print("hi==>",string.format("%x",HI));
    local hh = bits.band(HI, 0x0F);
    local mid = bits.rshift(bits.band(LO, 0xF0),4);--z:加法时一定别带十六进制权(比如01e:并非10+0e,而是01+0e)
    local ll = bits.band(LO, 0x0F);
    print(string.format("%x",hh+mid+ll))
    local cs = bits.bnot(hh+mid+ll, 0xFF)+1;
    
    local rh = bits.bor(bits.lshift(cs, 4),hh);
    return Hex2Ascii(rh);--返回rh的高位和低位,高位就是我们需要的LCHKSUM
end

 

经过这个计算:上面给出例子中的info变成了:

info="7E 32 31 30 31 44 30 30 30 31 30 31 45 30 30 30 36 33 32 36 31 42 37 30 31 44 34 42 42 42 39 30 31 45 41 30 30 30 30 30 30 30 3046 46 46 460D" 

 

4:关于CHKSUM的解释:

  CHKSUM的计算是除SOIEOICHKSUM外,其他字符按ASCII码值累加求和,所得结果模65536余数取反加1CHKSUM拆分4ASCII码传送,先高字节,后低字节。

示例:

收到或发送的字符序列为:“~20014043E00200FD3BR”(“~”为SOIREOI),则最后5个字符FD3BR中的FD3BCHKSUM,计算方法是:

2+0+0+……+E+0+0+2+0+0

=32H+30H+30H+……+45H+30H+30H+32H+30H+30H

=02C5H

将由16进制字符组成的字符串转化为该十六进制相对应的ascii字符串

function CheckSum(strlen,buffer)--z:特别注意传输时一个数据字节直接使用了两个ascii码表示,一个ascii码占一个字节,用两位十六进制数表示
    
    --计算lengthchk并填充
    x,y=LengthID(buffer[11],buffer[12],buffer[13]);
    print("lengthchk:",string.format("%x",x))
    print("lengthchk:",string.format("%x",y))
    buffer[10]=x
    
    print("uncheck table:")
    for key,value in pairs(buffer) do
        io.write(string.format("%x",value)," ")
    end
    print()
    local sum = 0.0;
    
    for i = 2,strlen-5 do
        sum = sum + buffer[i];
    end
    print("checksum==>",string.format("%x",sum));
    --取得sum的高位和低位
    local hh = bits.rshift(bits.band(sum, 0xff00), 8);
    local ll = bits.band(sum, 0x00ff);
    --高位低位分别取反
    local nhh = bit32.band(bit32.bnot(hh),0x000000ff);
    local nll = bit32.band(bit32.bnot(ll),0x000000ff);
    --低位+1不进位的话就直接加,要进位的话就加高位
    if nll+1 <= 0xFF then
        chkh = nhh;
        chkl = nll+1;
    elseif nhh+1 <= 0xFF then
        chkh = nhh+1;
        chkl = 0;
    else
        chkh = 0;
        chkl = 0;
    end
    print("zzyh:",string.format("%x",chkh));
    h1,h2=Hex2Ascii(chkh)
    print(string.format("%x",h1))
    print(string.format("%x",h2))
    print("zzyl:",string.format("%x",chkl));
    l1,l2=Hex2Ascii(chkl);
    print(string.format("%x",l1))
    print(string.format("%x",l2))
    buffer[strlen-4]=h1
    buffer[strlen-3]=h2
    buffer[strlen-2]=l1
    buffer[strlen-1]=l2
    print("checked table:")
    for k,v in pairs(buffer) do
        io.write(string.format("%x",v)," ")
    end
    print()
end

经过这个计算:上面给出例子中的info变成了:

info="7E 32 31 30 31 44 30 30 30 31 30 31 45 30 30 30 36 33 32 36 31 42 37 30 31 44 34 42 42 42 39 30 31 45 41 30 30 30 30 30 30 30 30 46 37 34 37 0D"

完了!哈哈

5:上面的两个处理函数涉及到的自定义函数

 !(函数在这里没有分包,实际中是在不同的包中)

function utils.str2chr(str)--将由16进制字符组成的字符串转化为该十六进制相对应的ascii字符串
    local ret="";
    local tmp;
    print("undostring:",str);
    for w in string.gmatch(str,"%x+") do--循环的读取该串中的十六进制数据并且转化为字符,例如:0x32->2
        tmp=string.sub(w,0);
        ret=ret..string.char(tonumber(tmp,16));
    end
    print("done string:",ret);
    strlen=string.len(retStr);
    return strlen,retStr;
end;
function utils.str2table(str)--z:表格里面存的是每个字符对应的ascii数字编码
    local RetTable = {};
    if string.len(str) <= 0 then
        return nil;
    end;
    strlen,str = utils.str2chr(str);
    for i = 1, strlen do
        RetTable[i] = string.byte(string.sub(str, i, i + 1));--将ascii字符串每一个字符变为表的每一项,一个字符对应一个ascii数字编码
    end;
    return strlen,RetTable;    
end;
function Parse2btye(szStr)
    if string.byte(szStr,1) == 0x20 and string.byte(szStr,2) == 0x20 then
        return VALUE_INVALID;
    end
    local buf = '';
    
    buf = commutils.Hex2Dec(string.sub(szStr, 1));
    return string.byte(buf,1);
end
function Hex2Ascii(hex)--把两位十六进制表示的一个数据的高位和低位分别转为adcii码表示,高位对应一个adcii,低位对应一个ascii,该ascii又由一个两位十六进制数表示()
    local chartable = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    local low = bits.band(hex, 0x0f);
    local high = bits.rshift(bits.band(hex, 0xf0), 4);--z:与oxfo与运算并且右移四位去除低四位
    
    local lowAsc = string.byte(chartable[low+1]);
    local highAsc = string.byte(chartable[high+1]);
    --print(string.format("%x: %x", lowAsc, highAsc));
    return highAsc,lowAsc
end
local function Byte2Hex(szByte)
    if szByte >= string.byte('0') and szByte <= string.byte('9') then
        return szByte - string.byte('0');
    elseif  szByte >= string.byte('a') and szByte <= string.byte('f') then
        return szByte - string.byte('a')+10;
    elseif  szByte >= string.byte('A') and szByte <= string.byte('F') then
        return szByte - string.byte('A')+10;
    else
        print("ParseData error,szByte = ",string.format("%02x",string.byte(szByte)));
        return 0;
    end
end

local function Hex2Dec(szStr)--把两个十六进制数转化为一个long型数
    local tmp1,tmp2;
    --if string.byte(szStr,1)==nil or string.byte(szStr,2)==nil then
    --   return 0;
    --else
       print("tmp1udo==>",string.byte(szStr,1))
       tmp1 = Byte2Hex(string.byte(szStr,1));
       print("tmp1==>",tmp1)
       tmp2 = Byte2Hex(string.byte(szStr,2));
       print("tmp2udo==>",string.byte(szStr,2))
       print("tmp2==>",tmp2)
       print("dec==>",tmp1*16 + tmp2);
       return string.char(tmp1*16 + tmp2);
    --end
    --return string.char(tmp1*16 + tmp2);
end

 

原文地址:https://www.cnblogs.com/zzy-frisrtblog/p/5920034.html