这是一个相当长的问题,所以请光临我。

我们正在为一块硬件实现一个模拟器 正在同时开发。这个想法是给第三方 一种软件解决方案,用于测试客户端软件并提供硬件 开发人员参考点来实现他们的固件。

为硬件编写协议的人使用了自定义 SUN XDR的版本名为INCA_XDR。它是一个序列化的工具 反序列化消息。它是用C语言编写的,我们希望避免任何问题 本机代码,所以我们手动解析协议数据。

协议本质上相当复杂并且是数据包 可以有许多不同的结构,但它总是具有相同的全局结构:

  

[HEAD] [INTRO] [DATA] [TAIL]

[HEAD] =
    byte sync 0x03
    byte length X       [MSB]       X = length of [HEADER] + [INTRO] + [DATA]
    byte length X       [LSB]       X = length of [HEADER] + [INTRO] + [DATA]
    byte check X        [MSB]       X = crc of [INTRO] [DATA]
    byte check X        [LSB]       X = crc of [INTRO] [DATA]
    byte headercheck X              X = XOR over [SYNC] [LENGTH] [CHECK]

[INTRO]
    byte version 0x03
    byte address X                  X = 0 for point-to-point, 1-254 for specific controller, 255 = broadcast
    byte sequence X                 X = sequence number
    byte group X        [MSB]       X = The category of the message
    byte group X        [LSB]       X = The category of the message
    byte type X         [MSB]       X = The id of the message
    byte type X         [LSB]       X = The id of the message

[DATA] =
    The actuall data for the specified message,
    this format really differs a lot.

    It always starts with a DRCode which is one byte.
    It more or less specifies the general structure of
    the data, but even within the same structure the data
    can mean many different things and have different lenghts.
    (I think this is an artifact of the INCA_XDR tool)

[TAIL] =
    byte 0x0D

正如您所看到的,有很多开销数据,但这是因为 协议需要使用RS232(点对多点)和TCP / IP(p2p)。

    name        size    value
    drcode      1       1   
    name        8               contains a name that can be used as a file name (only alphanumeric characters allowed)
    timestamp   14              yyyymmddhhmmss  contains timestamp of bitmap library
    size        4               size of bitmap library to be loaded
    options     1               currently no options

或者它可能有完全不同的结构:

    name        size    value
    drcode      1       2   
    lastblock   1       0 - 1   1 indicates last block. Firmware can be stored
    blocknumber 2               Indicates block of firmware
    blocksize   2       N       size of block to load
    blockdata   N               data of block of firmware

有时它只是一个DRCode而没有其他数据。

基于组和类型字段,模拟器 需要执行某些操作。首先我们来看看那些 基于两个字段,我们知道对数据的期望 并且必须正确地解析它。

然后需要再次生成响应数据 许多不同的数据结构。有些消息只是生成 ACK或NACK消息,而其他消息则生成带有数据的真实回复。

我们决定把事情分成几小块。

首先是IDataProcessor。

实现此接口的类负责 用于验证原始数据和生成Message类的实例。 他们不负责沟通,只需传递一个字节[]

原始数据验证意味着检查标头的校验和,crc和长度错误。

生成的消息将传递给实现IMessageProcessor的类。 即使原始数据被认为是无效的,因为IDataProcessor没有 响应消息或其他任何内容的概念,它只是验证原始数据。

要通知IMessageProcessor有关错误的信息,还添加了一些其他属性 到Message类:

bool nakError = false;
bool tailError = false;
bool crcError = false;
bool headerError = false;
bool lengthError = false;

它们与协议无关,仅存在于IMessageProcessor

IMessageProcessor是完成实际工作的地方。 因为我决定使用所有不同的消息组和类型 使用F#实现IMessageProcessor接口,因为模式匹配 似乎是避免大量嵌套if / else和caste语句的好方法。 (我之前没有使用过F#,甚至没有LINQ和SQL以外的函数式语言)

IMessageProcessor分析数据并决定它应该调用哪些方法 在IHardwareController上。拥有IHardwareController可能看起来多余, 但我们希望能够将其与不同的实现交换出来 并且不会被迫使用F#。当前的实现是一个WPF窗口, 但它可能是一个Cocoa#窗口,或者只是一个控制台。

IHardwareController还负责管理状态,因为 开发人员应该能够通过用户界面操作硬件参数和错误。

因此,一旦IMessageProcessor在IHardwareController上调用了正确的方法, 它必须生成响应MEssage。再次......这些响应消息中的数据 可以有许多不同的结构。

最终,IDataFactory用于将Message转换为原始协议数据 准备被送到任何一个负责沟通的班级。 (例如,可能需要额外封装数据)

这没什么“硬”的。关于编写这段代码,但所有不同 命令和数据结构需要很多很多

有帮助吗?

解决方案

我认为F#非常适合通过歧视的工会代表这个领域的信息;我想象的是。

type Message =
    | Message1 of string * DateTime * int * byte //name,timestamp,size,options
    | Message2 of bool * short * short * byte[]  //last,blocknum,blocksize,data
    ...

以及从/向字节数组解析/解析消息的方法。正如你所说,这项工作很简单,只是单调乏味。

我对消息的处理不太清楚,但总的来说,根据你的描述,听起来你已经掌握了它。

我有点担心你的'工具灵活性' - 你的约束是什么? (例如.Net,必须由熟悉X,Y,Z技术的程序员维护,必须满足某些性能标准,......)

其他提示

这是我的2美分(警告:我不知道F#):你有一个精确指定的输入文件, 即使有完整的语法。您希望将文件的内容映射到操作。因此,我建议你解析文件。 F#是一种函数式语言,它可能适合称为递归下降解析的解析技术。 书籍”专家F#“包含对递归下降解析的讨论。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top