物联网的Erlang

对微电子器件及其相互之间的相互作用的兴趣引起了工业和家庭需求,这导致了大量设计人员的开发,这些设计人员基于足够强大的SoC(片上系统)进行开发,相对于微控制器解决方案来说是微型的,但已经包含完整的操作系统。 实际上,针对此类设计器的应用程序开发与通常的服务器开发没有什么不同,只是仍应牢记资源限制。



随着生产力和功能的增长,使用高级解释语言(例如Lua,Python,JS)进行应用程序开发的做法正获得越来越多的动力。 有些语言以非常有限的形式逐渐渗透到微控制器的“年轻兄弟”中。

这有几个原因:

  • 快速原型制作-在充分尊重主要开发微控制器的C语言的前提下,很难做到简洁。 高级语言使您可以编写更少的代码,并简化对已编写内容的更改,这在原型阶段非常重要;
  • 自动内存管理和复杂计算机制的抽象-我认为它不需要注释,两个具有足够项目量的手动处理都变得很麻烦。
  • 简化调试和测试-解释代码更容易在现场测试之前在工作站上检查;
  • 与复杂性作斗争-通常,高生产率会带来一种自然务实的愿望,将更多的预处理和分析推到设备上,这并没有增加开发的简便性。

las,您必须支付所有便利设施的费用。 在这种情况下,为方便而付出的代价是最有价值的资源,性能和代码大小(在许多情况下,您必须携带相当多的运行时环境)。 因此,高级语言在SoC和SoM中的现场应用是一个模棱两可的事情,并且在某些地方是一个折衷方案。

我们使用Erlang语言进行开发,既将其用于预定目的(创建服务器应用程序和控制平面),又将其用于非常特殊的Web应用程序。 因此,使用这种语言的基础架构来创建IoT解决方案的想法早在出现Erlang运行时可以在其上正常工作的电路板之前就出现了。

使用Erlang的原因有很多,最重要的是:

  • Erlang对于解析和创建二进制序列非常方便。 模式匹配与位数据处理配合使用,可以非常快速,无言地实现二进制协议。
  • 缺乏全局变量和大多数数据的不变性-允许您编写并且同样重要的是,维护可靠的应用程序,在这些应用程序中很难意外更改某些错误;
  • 轻量级消息传递过程与嵌入式开发人员必须处理的过程非常相似。 从本质上讲,它们是一个初始化过程,并且是一个无限循环处理传入消息,更改内部状态的过程。 它与Arduino非常相似,只有许多进程可以并行运行,此外,在消息之间的间隔中,可以即时更改处理程序(热代码重载),这在需要修复小错误或调整行为时非常方便;
  • 我认为,隔离的环境和自动内存分配不需要解释;
  • 跨平台-ERTS运行时的字节代码可以在开发人员的计算机上编译,然后毫无问题地传输到目标设备;
  • 出色的自省工具-通过网络连接到正在运行的应用程序并发现它如此缓慢地减速的能力通常非常有用。

首先的工作板,我们尝试了二郎神,是杨桃2立陶宛开发商8devices ,聚集在热门芯片AR9331。 board,该电路板的第一个版本没有足够的闪存来适合运行时。 但是第二个版本已经完全可以容纳ERTS和小型应用程序。



安装是通过此类设备的经典方法进行的-组装包含Erlang的OpenWRT映像,然后将其刷新到设备的闪存中。 las,环境的首次发射使人们感到失望-一切都陷入困境。 我已经在InoThings 2018大会上解释了这样做的原因,但是可惜的是,后来发现,错误地命名了这种行为的来源,误导了我的同事。

我会简单地讲述。 在处理文件时,ERTS虚拟机使用off_t类型,该类型的大小是在自动配置程序集(如果它在目标平台上运行)或从交叉编译环境替换(如OpenWRT的情况)时计算的。 目前尚不清楚原因,但是在程序集配置文件中的MIPS处理器和派生设置中,其大小实际上是其两倍。 如果虚拟机代码未使用预处理器指令(例如,

#if SIZEOF_OFF_T == 4 

和代码中的常规检查(我怀疑最终的编译结果是相同的,但是没有足够的保险丝来检查):

 if (sizeof(off_t) == 4) { 

结果,在尝试从头开始读取〜/ .erlang.cookie文件 (一种用于在网络交互过程中进行标识的密码)时,在第一次迭代时收集的ERTS成功地接收到了高阶垃圾,并崩溃了。

可以从GitHub下载适用于OpenWRT的倒数第二个版本的ERTS 补丁和软件包。 除此之外,还没有发现问题,一切都按预期进行。

我们尝试使用Erlang的第二个硬件平台是MediatekSeeedStudioLinkIt Smart 7688设计 ,该设计器专门用于快速原型设计和学习基础知识。 该板卡只是放荡不羁的资源上的典范-MIPS内核的频率增长了1.5倍,内存更多(对于ERTS,这很重要,GC无法休眠)和更多的闪存,以及microSD卡的存在以及使用Atmel协处理器的可能性Duo版本的 Atmega 32U4用于外围设备。

通常,该平台非常适合继续举行宴会,并且存在无需焊接即可连接的其他插入式设备,可让您快速有条件地在膝盖上组装测试台。

该平台随附具有自己的Web界面的软件,以及用于开发的Python和NodeJS库。 装配体的生态系统没有改变-仍然是OpenWRT。 如果由于某种原因您发现所有这些多样性都是多余的,那么在上述存储库中,将包含包含最少一组必需组件的软件包。 组装后,会将闪存映像写入设备,并在重新引导后可以安全地使用REPL。

要在用于物联网的Erlang上构建应用程序,需要解决一个体系结构问题。

该语言的设计和开发着眼于用作控制平面的内容,即 控制层,而使用铁时应该通过FFI。 为此提供了三种类型的交互:

  1. 端口(端口)-用任何语言编写的独立工作进程,与之交互通过输入/输出流发生。 它们可以在跌倒的情况下重新启动,但是由于采用了交互方法,因此它们在通讯方面的生产率很小(但是,对我们而言这足够了);
  2. NIF函数-看起来像该语言的标准函数,但是它们的调用会在运行时空间内生成已编译代码的执行。 如果发生错误,他们可以将整个虚拟机拖到它们后面。
  3. C节点-当整个工作在单独的过程中完成,并且交互作用与网络上单独运行的运行时环境一样进行。 由于一个弱设备的框架内的开销成本非常大,因此我们将不考虑此选项。

难题是:我们只能将事物传输到FFI(即支持GPIO,I2C,SPI,PWM,UART等),并且我们可以直接与Erlang上的传感器和其他设备进行交互,或者相反,要将设备驱动程序完全转移到外部模块的代码,而让应用程序接收原始数据并对其进行处理,在这种情况下,使用已经编写的代码可能很有意义。

我们决定使用第一个选项。 这有几个原因:

  • 因为我们可以;
  • 正如我已经提到的,Erlang具有足够强大的工具来组合和反汇编二进制序列,而它的数学运算非常简单,因此您不必担心会受到溢出和其他用于处理结果的魔术的影响。 这不是稻草人的魔力,而是震惊地影响了新手。
  • 从直观上看,高级语言的驱动程序似乎更简单,更可靠(崩溃的进程将重新启动管理程序,这将导致受控设备的重新初始化)。

因此,很快就找到了ErlangALE库,该库包含已经通过内核接口实现的对GPIO,I2C和SPI的支持,而硬件平台的开发人员已经照顾好了它们。 用于UART的库已经过测试,并且我们添加了erlexec ,该应用程序允许您创建和管理OS进程。

所有这些应用程序都使用端口(单独启动的二进制进程)来与设备和OS配合使用,这需要对C和C ++语言的交叉编译支持,为此编写了相当详尽的Shell脚本 ,该脚本将构建环境配置为使用必需的编译器。

为了测试我们做出的决定,我们组装了一个来自LinkIt Smart 7866的简单设备,两个I2C设备(BMP280温度和压力传感器以及64像素的128 OLED显示屏)和一个通过UART发送数据的USB GPS模块。 GPIO已在板上的LED上进行了测试,它可以工作,并且在此复杂阶段不需要连接SPI显示器。



事实证明这是一个相当紧凑和简单的应用程序,可以在Github上查看源代码

我不会深入研究代码片段,而是尝试在概述中描述应用程序的工作方式。

所有设备的驱动程序都是以gen_server进程的形式制作的,这很方便,因为它允许您添加其他参数,有时还可以将设备的状态添加到该状态。 后者可以看出,在uart_gps从数据UART-而来异步明白- 解析器NMEA0183 ,结果从该累积应请求记录在过程的状态。

该应用程序的主要周期在gps_temp_display模块中进行了描述-该过程每秒读取一次GPS数据,并从BMP280请求温度和压力的状态,并将其显示在OLED显示屏上。 为了感兴趣,您可以看一下显示器传感器驱动程序BMP280-一切都非常简洁,每个模块150-170行。

通常,上述任务(编写驱动程序代码,将所有内容组合到一个应用程序,组装和测试中)大约花费了四个晚上,平均两个小时,即 严格来说,需要几个工作日。 在我个人看来,这是一个很好的指标,可以尝试在不需要严格实时限制的更复杂,更严格的嵌入式应用程序中使用Erlang。

当然,我们尝试将Erlang用于嵌入式系统绝不是唯一的尝试。 在这方面有几个有趣的项目:

Source: https://habr.com/ru/post/zh-CN417245/


All Articles