徐献圣 张震
摘要:针对基于OpenCPU的NB-IoT模块上作为兼任主处理器和数据传输功能时具有的内存压力,该文设计一种嵌入式脚本Lua脚本语言实现NB-IoT模块的内存优化方案。通过该方案,利用Lua脚本语言中自动内存管理和增量垃圾回收的特点弥补C语言的短板,从而优化内存空间,节省NB-IoT模块资源的消耗,降低功耗。
关键词:OpenCPU;嵌入式脚本;Lua;NB-IoT模块;内存;优化
中图分类号:TP393.409 文献标识码:A
文章编号:1009-3044(2021)25-0051-02
为了适应物联网的发展,满足更多的应用场景和市场需求,传感网中诞生了一批适合物与物之间远距离通信的无线通信技术,统稱为低功耗广域网,即LPWAN。NB-IoT是一种工作于授权频谱下的LPWAN,其具有广覆盖、低功耗、低成本、大连接等多个优点,深受国内物联网企业的青睐。在传统方案中,往往会将NB-IoT外接至MCU。这种方式主要由MCU接收传感器采集的数据,再通过UART方式将数据传至NB-IoT模组,最后上传至云平台[1-2]。肖磊[3]提出将OpenCPU应用到NB-IoT模组上,让NB-IoT模块本身成为处理器,这样用户能够在NB-IoT模块上同时实现数据采集和数据上云,降低了MCU成本,节省了MCU功耗,提高了系统的稳定性和数据上传的实时效率。但是,由于处理器功能的转移,是以牺牲NB-IoT模组的内部资源作为代价,影响自身的运行效率。
针对此类问题,本文提出一种基于Lua脚本语言实现内置中移M5311模组的LM-NB-M-01模块通信的解决方案,以TCP协议传输作为使用案例。此方案将外围设备数据获取和TCP通信任务都交由Lua虚拟机处理,根据获取的数据,决定是否调用启动关于TCP通信任务的Lua脚本,由此节省NB-IoT模组资源的消耗,提升运行效率。
1 Lua脚本语言简介
Lua[4-6]是一种遵循标准C写成的轻量级嵌入式脚本语言,其具有扩展性好、简单小巧、与平台无关的特点。Lua提供了易于使用的扩展接口和机制,尤其是当C/C++作为其宿主语言时,它们之间很容易完成交互,如同本身就是内置的功能一样,因此Lua非常方便移植到基于C语言的OpenCPU中使用,不会引起硬件增大消耗的额问题。基于Lua实现TCP协议传输的NB-IoT通信方案,主要依靠Lua的下列特点。
(1)Lua是动态类型语言,即其变量没有预定义的类型,值才有类型,并且函数也可以看成是一个值。Lua还提供了一种通用类型的表,用它可以实现数组,哈希表,集合。这些特点使得Lua除了支持面向过程编程和函数式编程,还支持面向对象编程,弥补了C语言在设计上的短板。
(2)Lua简单小巧,Lua5.3.4发行版所有标准库加起来只有640kb大小,编译后仅一百余K,能够有效节省系统内部资源。
(3)Lua具有自动内存管理和增量垃圾回收功能。设计者不需要担心如何管理资源,只需要分配内存,同时这个内存由Lua管理。当程序不需要某个对象时,Lua会自动删除这个失效的对象,节省系统内部资源。
(4)Lua提供的协同进程机制使得Lua脚本作为独立线程,与主程序和其他线程互不影响地同时工作,提升程序的运行效率。
2 设计方案介绍
本方案围绕基于中移M5311 NB-IoT模组的LM-NB-M-01模块与私有云平台实现TCP通信来进行设计,系统设计方案框架如图1所示,系统运行流程图如图2所示。
启动LM-NB-M-01模块,主程序建立OpenCPU任务,等待注册网络。网络在线后,外围传感器设备开始将感知到的数据通过外设接口传入至LM-NB-M-01模块中,接着主程序对数据进行处理,判断是否需要将数据传上云平台。例如数据在所设阈值范围内,不向云平台执行发送行为。这种情况在监测系统[7]尤为常见。当终端模块判断数据超过阈值时,需要发送报警信号给云平台,此时创建Lua虚拟机,将编写的TCP通信的C函数注册到Lua虚拟机中,然后读取Flash文件中独立于C程序的Lua脚本文件,完成TCP任务。之后关闭虚拟机,依靠Lua本身特点自动收集垃圾并清理内存,节省内存资源。
私有云服务器的设计,采用IOCP高并发架构设计,通过花生壳内网穿透软件,实现云服务器与私有内网服务器建立连接,同时把内网端口映射到云端。
3设计方案介绍
为了节省系统内部资源和提升程序的运行效率,本设计重点不在如何实现获取或处理传感器数据,而是着重于采用Lua与C语言混合编程的方案如何实现NB-IoT基于TCP协议的传输。具体步骤如下。
(1)将Lua移植到LM-NB-M-01模块的OpenCPU环境
将Lua5.3.4源码包中src目录内部除了lua.c与luac.c外的所有.c和.h加入到M5311-OPENCPU_SDK 3.3.0中。由于OpenCPU采用make-clean编译方式,因此可以使用Visual Studio Code IDE完成此项工作。但要编译成功,还需要注意将Lua源码中用到的clock()、remove(filename)以及rename(fromname, toname)函数删掉或修改,否则与原来OpenCPU的源码有冲突。
(2)建立Lua与C交互环境
C与Lua之间通过C API进行交互,其关键在于构建一个虚拟的栈,通过操作栈上的值来实现API调用和C与Lua之间数据交换。
①通过以下格式创建Lua虚拟机。
lua_State *L = NULL;
L = luaL_newstate(); //创建Lua状态机