问候所有人,
我正在尝试为具有通用通信媒体层的嵌入式设备实现中间件(驱动程序)。不知道什么是最好的方法,所以我正在寻求更有经验的stackoverflow用户的建议:)。基本上我们有全国各地的设备与我们的服务器(或现场使用的pda /笔记本电脑)通信。通常的通信形式是通过TCP / IP,但也可以使用usb,RF加密狗,IR等。计划是让对象与这些设备中的每一个相对应,一方面处理专有协议,另一方面请求/响应。内部系统在另一方面。
问题是如何在媒体和处理对象之间创建通用的东西。我使用boost.asio玩TCP调度程序,但尝试创建通用似乎是一场噩梦:)。有人试图这样做吗?如何做到最好的方法是什么?
示例:设备连接到我们的Linux服务器。创建新的中间件实例(在服务器上),该实例将其自身通告给其中一个正在运行的服务(细节并不重要)。该服务负责确保设备的时间同步。因此,它询问中间件设备的时间是什么,驱动程序将其转换为设备语言(协议)并发送消息,设备响应和驱动程序再次将其转换为服务。对于这样一个简单的请求来说,这似乎有点过分,但想象一下,驱动程序必须翻译更复杂的请求,同时有多个版本的设备使用不同的协议等,但会使用相同的时间同步服务。目标是通过中间件抽象设备,以便能够使用相同的服务与它们进行通信。
另一个例子:我们发现与设备的远程通信已关闭。所以我们派人带PDA,他用USB线连接到设备。启动具有与timesync服务相同功能的应用程序。再次创建中间件实例(在PDA上)以转换应用程序和设备之间的通信,这次仅使用USB /串行媒体而不是前面示例中的TCP / IP。 我希望现在更有意义:))
干杯, 汤姆
答案 0 :(得分:1)
问题是如何在媒体和处理对象之间创建通用的东西。我使用boost.asio玩TCP调度程序,但尝试创建通用似乎是一场噩梦:)。有人试图这样做吗?如何做到最好的方法是什么?
我没有使用过Boost,但我通常处理这种问题的方法是创建一个服务器与之交互的Device基类,然后为每个设备类型创建子类,并使子类处理设备奇怪。这样,Device类就成了协议的定义。此外,Device类需要是可移植的,但子类不是。
如果你必须得到比这更好的,你可以使用Factory模式来创建实际的子类对象。
就实际通信而言,我会看看我是否可以为每个设备运行一个进程。如果每个进程必须有多个设备,那么在Linux上我只需使用select()
及其朋友来管理各种设备实例之间的I / O.我不知道如何在Windows上这样做;它的select
仅适用于套接字,不适用于串口或其他类似文件的内容。
其他可能有用的东西包括dbus和MPI(消息传递接口)库,尽管它们不是解决您问题的完整解决方案(dbus不进行计算机间通信,IIRC)。 / p>
这有帮助吗?
编辑:需要格式化回复汤姆的回复......
您的设备类是否包含通信特定部分?因为那是我想要避免的事情。
子类包含通信特定部分。这就是在这里使用子类的重点;泛型的东西放在基类中,具体内容在子类中。
我正在考虑这样的事情:假设有一个特定于所用媒体的调度程序,它为每个连接创建Connection对象(特定于媒体),Device obj。也会被创建,但只是一个通用的,Connection会将传入的数据传递给Device,而Device会将响应传递回Connection。
我认为这可能有点复杂,而且您期望通用设备处理特定的连接,这很难维持很快。
我建议的是一个Device子类,专门用于处理这种类型的Connection,它从调度程序获取Connection并拥有它直到连接关闭。然后,您的经理可以与通用设备通信,连接可能会弄乱具体细节。
一个例子:假设你有一个温度传感器USB thingamajig。你有一些调度员捕获“插入USB信号”信号。当它看到USB插件插入时:
USBTemperatureThingConnection
。USBTemperatureDevice
,它是Device的子类,将USBTemperatureThingConnection
作为构造函数参数提供给USBTemperatureDevice
。USBTemperatureDevice::USBTemperatureDevice(USBTemperatureThingConnection* conn)
进行设置本地需要的任何内容以完成Connection的设置,然后向设备管理器发送一条消息,说明它已自行设置。一段时间后,设备管理器想要在所有设备上设置时间。因此,它遍历其设备列表并在每个设备上调用泛型(甚至是抽象的)Device::SetTime(const struct timespec_t&)
方法。
当它到达您的温度设备时,它会调用USBTemperatureDevice::SetTime(const struct timespec_t&)
,因为USBTemperatureDevice
覆盖了Device
中的那个(这是抽象的,即virtual void SetTime(const struct timespec_t&) = 0;
或不是op,即virtual void SetTime(const struct timespec_t&) {}
,因此您不必为无法设置时间的设备覆盖它。 USBTemperatureDevice::SetTime(const struct timespec_t&)
使用USBTemperatureThingConnection
执行所需的USB温度传感器特定事项,以便设置时间。
一段时间后,设备可能会发回“时间设置结果”消息,说明它是否有效。它出现在USBTemperatureThingConnection
上,它会唤醒你的线程,你需要处理它。因此,您的USBTemperatureDevice::DealWithMessageFromSensor()
方法(仅存在于USBTemperatureDevice
中)潜入消息内容,并确定时间设置是否有效。然后它接受该结果,将其转换为enum Device::ResultCode
中定义的值并调用Device::TimeSetComplete(ResultCode result)
,它记录结果,设置一个标志(bool Device::timeComplete
)表示结果是,然后点击Semaphore
或Condition
唤醒设备管理器并让它检查所有Device
,以防它等待所有设备完成设置时间后再继续。
我不知道这个模式叫什么。如果按下,我会说“子类化”或“面向对象的设计”,如果我感到脾气暴躁。 “中间件”是Device
类,DeviceManager及其所有下属。然后,应用程序只与设备管理器对话,或者最多与特定设备的通用Device
接口进行通信。
顺便说一下。计划了工厂模式,每个对象将在单独的线程中运行:)
很高兴听到。
答案 1 :(得分:0)
我假设您通过TCP / IP表示远程节点,并通过USB等连接到同一物理盒的本地设备。我认为你在解释中遗漏的部分是向服务器进程宣布新本地设备的部分(即监听套接字的模拟)再次,假设Linux uevent
的某些内容,我会开始具有以下结构:
高级协议非常简单 - 在收到或“新设备”事件时,查询“设备类”了解给定设备的时间,然后更新在设备上的时间。 “设备类”是实现从查询/更新接口到设备特定命令(远程节点的网络交换)的转换的驱动程序/转换器/网桥。它还包含其设备列表。
这应该很容易映射到类图。还有其他我错过的东西吗?