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

将硬件规定的通信协议用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的高位和低位,高位就是我们需要的LCHKSUMend

 

经过这个计算:上面给出例子中的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码传送,先高字节,后低字节。

示例:

收到或发送的字符序列为:“~20014043E00200FD3B\R”(“~”为SOI\REOI),则最后5个字符FD3B\R中的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);endfunction 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,lowAscend

 

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;    endendlocal 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

 

 

 

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