將硬件規定的通訊協議用Lua實現(涉及到不少Lua通訊的數據轉換)

1:此次處理的是大唐的gps通訊協議,先簡單介紹一下他規定的通訊規則:

信息結構:數組

傳輸說明:函數

  信息結構中的各個字節書寫時都是以十六進制標識,兩位數組成。傳輸時,SOIEOISOI=7EHEOI=0DH)各按一個字節傳輸,但其他各項每一個字節都是拆成兩個字節,每一個字節用兩個ASCII碼標識,即高4位用一個ASCII碼錶示,低4位用一個ASCII碼標識,傳輸時先發送高4位的ASCII碼,後發送低4位的ASCII碼。編碼

示例:CID2=4BH4ASCII碼是34HBASCII碼是42H,傳送時順序發送34H42H兩個字節。spa

所以,實際傳輸的字節數應是1以及下面各表中字節數乘以2code

2:要達到的目的: 

例如要處理一段這樣的數據:(須要計算的LCHkSUM和CHKSUM由46代替)                        orm

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

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

             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 CHKSUMstring

             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碼傳送,先高字節,後低字節。

示例:

收到或發送的字符序列爲:「~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);
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
相關文章
相關標籤/搜索