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

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

信息结构:

传输说明:

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

示例:CID2=4BH,4的ASCII码是34H,B的ASCII码是42H,传送时顺序发送34H和42H两个字节。

因此,实际传输的字节数应是表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段的解释:

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

示例:

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

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

可以得出:LENGTH为1101 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的计算是除SOI、EOI和CHKSUM外,其他字符按ASCII码值累加求和,所得结果模65536余数取反加1。CHKSUM拆分4个ASCII码传送,先高字节,后低字节。

示例:

收到或发送的字符序列为:“~20014043E00200FD3B\R”(“~”为SOI,\R为EOI),则最后5个字符FD3B\R中的FD3B为CHKSUM,计算方法是:

‘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
时间: 2024-10-06 06:38:00

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

Lua初学者(三)--Lua 嵌入宿主语言(C++/C)

继续上节内容,在C中使用Lua,这个网上资源也比较多了,不过我这里也提下哈,毕竟自己过一遍还是很有好处的. 环境:Lua5.1,vs2013中文版 ----------------------------------------------------一.C++中配置 lua---------------------------------------- 1.下载lua源码么:http://www.lua.org/download.html 就OK了 2.打开VS2013,新建工程: 新建-->

Cocos2d-x lua游戏开发之安装Lua到mac系统

注意:mac ox ,lua version :5.15 下载lua官网的lua, 注意:最好是5.15以下,5.2的lua不支持table的getn()方法,这让我情何以堪.(获取table长度,相当与cout,size,length) 下载解压, cd 目录 make macosx sudo make install (是的,就是小写的install,虽然文件夹下的是INSTALL) ook,进入命令行,输入lua 看下,效果 Cocos2d-x lua游戏开发之安装Lua到mac系统,布布

lua学习笔记10:lua简单命令行

前面多次用了命令行,这次就好好学下命令行: 一 格式 lua [options][script][args] 二 具体命令 -e 直接将命令传个lua -l 加载一个文件 -i 进入交互模式 例如,终端输入: lua -e "print(math.sin(12))" lua学习笔记10:lua简单命令行,布布扣,bubuko.com

lua学习笔记11:lua中的小技巧

lua中的小技巧,即基础lua语言本身的特种,进行一个些简化的操作 一 巧用or x = x or v 等价于: if not x then x = v end 如果x为nil或false,就给他赋值为 二 三元运算符实现 a and b or c 类似C语言: a ? b : c and 的运算由优先级高于or lua学习笔记11:lua中的小技巧,布布扣,bubuko.com

LUA学习之路--初识LUA

LUA在葡萄牙语中是“月亮”的意思.1993年由巴西的Ponifical Catholic University开发.该语言是由一个来自计算机图形技术组织的团队开发,并作为自由软件发行.LUA开发小组的目标是开发一种小巧.高效并且能够很好的和C语言一起工作的编程语言.在脚本语言领域,LUA是最快.最高效的脚本语言之一. LUA和传统的脚本语言不同,它是一种易整合语言(glue language).一般的脚本语言用于控制执行重复的任务,而易整合语言可以让使用者把其他语言的功能整合在一起.这样就让脚

Lua学习 2) —— Android与Lua互调

2014-07-09 一.Android类调用lua并回调 Android调用Lua函数,同时把类作为参数传递过去,然后再Lua中回调类的函数 调用lua mLuaState = LuaStateFactory.newLuaState(); mLuaState.openLibs(); mLuaState.LdoString(KKLua.loadAssetsString(mContext, "lua/swallow.lua"));//将lua转换为字符串 mLuaState.getFie

Lua学习笔记--C调用Lua

Lua是一种嵌入式语言,可以很好的嵌入其他应用程序.lua为我们提供了一组灵活的C API,使C代码能够很好的与Lua进行交互.包括读写Lua全局变量,调用Lua函数,运行Lua代码,注册C函数反过来供Lua调用.简单的说,C能调用Lua,反过来Lua也能调用C.真的是灰常强大灵活的脚本!!现在,先来学习一下怎么用C调用Lua. 其实最简单的我们已经做过了,通过一个dofile,运行一个lua脚本文件. 一.栈 Lua与C的交互是通过一个虚拟栈进行的,这个栈对于Lua来说是严格的LIFO(后进先

用VC编译lua源码,生成lua语言的解释器和编译器

用VC编译lua源码,生成lua语言的解释器和编译器 1.去网址下载源码 http://www.lua.org/download.html 2.装一个VC++,我用的是VC6.0 3.接下来我们开始编译源码,我们需要编译: 一个静态库 一个动态库 一个lua语言解释器 一个lua编译器 建立一个工静态库工程 打开VC-->文件-->(点击)新建--(弹出框中选择)工程-->(win32 static library) 创一个空的工程 工程名为luaLib 把lua中所有的源码添加,去掉其

(转载)我所理解Cocos2d-x 3.6(Lua):Cocos如何绑定Lua自定义类

我所理解Cocos2d-x 3.6(Lua):Cocos如何绑定Lua自定义类 热血枫叶2015-06-19 16:27:182289 次阅读 Cocos2d-x 2.x 与 Cocos2d-x 3.x 差异(tolua++) Cocos2d-x在2.x版本里就是用toLua++和.pkg文件这么把自己注册进Lua环境里的,然而从Cocos2d-x 3.x开始,用bindings-generator脚本代替了toLua++. bindings-generator脚本的工作机制是: 1.不用编写.