BlackBox:二进制协议处理器代码生成器。

 BlackBox 的基本思想 .

手动编写序列化和数据反序列化代码,尤其是不同编程语言的异构设备之间的编写是一个耗时的过程,通常会导致难以消除的错误。解决这个问题最有效的方法是创建一个  DSL  (通过它正式描述协议),然后创建一个程序,以所需的编程语言为基础,为各种目标平台生成基于此描述的源代码。以这种方式准备好的解决方案的例子有很多

Protocol Buffers 
Cap’n Proto 
FlatBuffers 
ZCM 
MAVLink 
Thrift

在研究了这些以及其他许多实施方法之后,我决定创建一个系统来实施和补充优点,消除已发现的缺点。

 

描述 BlackBox  交换协议的语言  是基于流行编程语言JAVA的结构。JAVA拥有大量方便的IDE。比如  Android Studio  。

一般来说,系统和组件的互连如下所示:

在层次结构的最高层 ,可以接收,处理和发送数据包的设备(  主机)被描述为JAVA  class 构造。

implements语句中,您正在请求您想要生成源代码的编程语言。

主机  可以包括由来描述一些交换接口 interface  声明

该接口组合了一组包(由class  构造描述  )。接口 extends  语句允许接口从其他接口继承多个数据包。

软件包描述类包含   描述软件包传输数据的字段。包描述类中的implements结构允许有选择地将包插入到implements语句后列出的接口中  。 包描述类的  extends语句允许包继承其他包的字段。包名称必须是唯一的。

的  黑盒子  允许以描述常量:
命名  具有独特的常数的组 的整数值  通过的领域中描述  enum构建体。 自动分配这些常量的唯一值(在 enum 内)
在需要控制常量整数值的情况下,它们以 enum static final 字段的形式描述,并通过所需的值进行初始化 enum 上注解   @BitFlags 
 允许指定这些常量是位标志。这会影响生成的常量值以及为其处理生成的代码。
与此同时,   BlackBox 为比特标志提供了一个更方便的替换:比特字段。
enum可以用作包字段的参考数据类型。该  enum  应在描述文件的根被声明,任何上下文之外。
如果需要的话,普通个体常数(包括非整数值)可以直接在包声明类中声明为static final字段。

注意!尽管JAVA中的源代码生成元素  被转换为带注释的基元,名为SlimEnum。为了方便使用它们,已经为IntelliJ IDE创建了插件SlimEnum。不要忘记从IntelliJ插件库安装它。

@A,@V,@X,@I 字段的注释  存储有关更改字段值模式的元信息。基于此注释信息代码生成器会引发Base 128 Varint算法     (例如,在协议缓冲区中使用),该算法允许有限且有限的负载压缩发送数据。这是通过排除发送端较旧的未填充位并在接收端恢复它们来实现的。     

该图显示了字节数与传输值的关系

 

节点之间发送的数据可以分为两种类型。

  1. 随机值,均匀分布在所有范围内。 几乎是一个噪音。

    这样的数据按原样传输,压缩或这种类型数据的任何编码都是计算资源的浪费。具有该类型值的字段没有任何注释或由 @I描述
  2. 数据在值的变化中具有某种模式/梯度。

这些字段用  @A,@V,@X注释   表示相对于最可能的值分布的三种变体。

只有在相对于最可能的价值val而言较大值的方向上才有可能出现罕见波动。
相对于最可能的价值val,在两个方向都可能出现罕见的波动。
只有在相对于最可能值val的较小值的方向上才可能出现波动。

最可能的值 –  val  作为参数传递给注释

使用数据分配注释的示例

语言构造

描述

@I byte field 必填字段,发送前的字段数据不会被编码(压缩性较差),并且可以取值范围从  -128  到  127
@A byte field 必填字段,数据被压缩,字段可以取值范围从  0  到  255  。实际上,这 与  uint8_t 类型是类比的  
@I (-1000) byte field 必填字段(不要压缩),字段可以取值范围从  -1128  到  -873
@X_ short  field 的 可为空的(可选)  字段取值的范围在
从  -32 768  到  32 767。 将在发送时被压缩。
@A (1000)  short field 可空(可选)   字段取值在 – 65,535   到  0之间  将在发送时被压缩。
@V_ short field 可空字段取-65 535   到  0
之间的值 将在发送时被压缩。
@I(-11 / 75) short field 在指定范围内均匀分布值的必需字段。

 

带数组的字段说明

以下注释用于描述数组

@D 此注释类型表示具有预定义维度的数组,并预先分配所有数据空间。在已知数组最有可能完全填充数据的情况下使用。即使数据没有设置 – 分配空间,但没有资源浪费跟踪数据的完整性。
@D_ 此注释类型表示具有预定义参数的数组,但数据空间已设置在预定义范围内,仅在插入数据时分配。用于  稀疏  数组,当知道该数组最可能填充不足时。跟踪数据的完整性会产生额外的成本。

 

 

语言构造

描述

@D(1 | 2 | 3)  int  field1; 预定义维度为
1 x 2 x 3的强制多维数组
返回基元。
@D(1 | 2 | 3)  int []  field1; 具有预定义维度的多维数组
1 x 2
返回预定义 长度为  3的数组。
@D(1 | 2 | -3)  int []  field1; 具有预定义维度
1 x 2的多维数组
返回等长,可变(   1  到   3  )长度的数组
@D(1 | 2 | ~3)  int []  field1; 具有预定义维度的多维数组
1 x 2
返回不同  变量(   1  到   3  )长度的数组
@A @D1 | 2 | 3 ) byte field 具有预定义维度
1 x 2 x 3的
必需字段多维数组
返回值不均匀分布向上的基元。
@A_ @D1 | 2 | 3 ) byte field 可选字段是预定义维度为1 x 2 x 3的多维数组     创建数组时,会分配所有必需的空间。
向上返回值不等分布的基元。
@A(337) String field 返回一个字符串,每个 字符的最大长度为337个2字节
(注释  @V   表示一个字符串  1字节的字符串)
@V String [] field 返回字符串的内容 – 一个单字节字符数组。行的最大长度最多为127个字符。
@X_(3 / 45) @D( 12) byte [] field 可选字段返回一个预定义长度为   12  的数组。数组的值在给定的范围内,相对于范围的中间在两个方向上分布不均匀。
@D(-45) int [] field 可选字段。
返回从1  到  45的长度数组
@B) byte field 强制位字段。字段长度3位
@B_12 | 67 ) byte field 可选位域。以位为单位的字段长度将根据传输的允许值范围计算。
@D_(1 | -2 | -3)  int  field1; 具有预定第一维度而其他维度可变的多维阵列  。数据的位置在维度的最大值内,仅在添加到数组时被分配。
返回原语。

除了优化流量,  BlackBox 还 允许您考虑数据传输通道的拓扑结构和质量,并生成相应的源代码。主机之间的通信通道通过顶层  声明进行描述  。它包含:

  1. 交换协议的类型
  2. 设备通过给定通道交互的两个连接接口的列表。

  • 所述  SimpleProtocol协议类型意味着直接而没有任何变换发送的分组数据。此类型可用于通过传输协议传输具有内置错误保护(如   TCP / IP )   或本地,低噪声,高质量通道(如同步   SPI / I2C  总线)的数据,或用于从存储器到内存的简单转储数据该文件,以供以后恢复。
  • 对于不可靠的,具有高错误概率的噪声信道,如    无线电上的UART ,使用改进的AdvancedProtocol  协议的噪声保护版本   它使用  CRC16和Byte(0x55)填充进行错误后的快速恢复。

所有描述文件中的所有内容如下所示:

您可以下载  LedBlinkProject.java  并将其用作模板。