• 将硬件规定的通信协议用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

     

  • 相关阅读:
    <![CDATA[文本内容]]>
    Java对于表达式中的自动类型提升
    oracle循环语句
    Recastnavigation 创建 off-mesh link 的潜规则
    CritterAI 翻译 Configuration Parameters
    ndk-build 修改输出so位置 (change ndk-build output so lib file path )
    C# List<> Find相关接口学习
    C++ sizeof(struct) 的注意
    Unity使用Resources读取Resources路径下的二进制文件(Binary Data)必须使用 .bytes扩展名
    C++ ifstream ofstream 注意事项
  • 原文地址:https://www.cnblogs.com/zzy-frisrtblog/p/5920034.html
Copyright © 2020-2023  润新知