Socket型驱动编写

我们推荐使用代码生成工具进行驱动的编写,并在生成的代码上进行微调。

在最开始设计时,主要是针对摄像头和网络门禁这种使用私有协议的网络设备,需要让驱动可以和设备进行数据交互,于是创建了Socket型驱动这个分支。

但在后续的应用中,我们就发现Socket型驱动其实和串口驱动,在协议解析上类似,但是编写方法不同,造成维护不一致。

并且后续我们又加入了 “虚拟网络串口” 这个功能,虚拟网络串口 可以将一个IP:port模拟成FsuOS系统中的一个串口,然后串口驱动就可以正常的收发,只是开关串口实际没有效果。

当前Socket型驱动,主要用于那些需要调用第三方SDK的的驱动,比如使用TCP-Modbus的驱动。

注意: 要区分协议的工作模式,异步模式的协议,程序调度都是由SMDDevice或者SMDServer控制的,这种驱动,无论在设备上运行,还是在高性能高并发的服务端运行,很难出现性能问题。而同步模式工作的驱动,会使用调度器的RefreshDevice时间,会造成整体设备数据刷新变慢,甚至驱动程序有死锁的情况还会造成整体采集异常,但是同步模式程序易于理解,符合人思维习惯,我调用我拿到结果。由于DI,AI,SP驱动采用FSUOS标准接口本身就工作在异步模式,但是Socket驱动,主要依靠用户写代码调用其他库,需要用户格外注意。

用户虽然可以通过std::async将代码段异步化,但是实际运行情况,由于当前大多数二代FSU都是单核arm9 500MHz以下,开async后反而观测到性能降低,可见多线程对单核cpu会造成额外的负担,低配CPU比较尴尬,在配置较高的设备上没有感到影响,用户自己把握。

ModbusTcp协议支持
FsuOS SDK中集成了libmodbus开发库,用户可以直接使用modbus-tcp相关代码

#include <modbus/modbus.h>
#include <modbus/modbus-tcp.h>


class UnicomLL11: public UniDataDevice<UnicomLL11_Data_t,SMDSocketDevice, RT_UNICOMLL11>
类可以从SMDSocketDevice直接继承


在RefreshStatus里直接请求数据

pCtx = modbus_new_tcp(ip_.c_str(), port_);
int nRet = modbus_connect(pCtx);
if(-1 == modbus_read_registers(pCtx, 27-1, 12, regs))

BacNet协议支持 BacNet在楼宇自动化对接中比较常见,水泵,冷循环设备多提供此接口,FsuOS在2024-10-17号以后的版本提供此协议的支持。 使用方法:

#include "SMDBacNetDevice.hpp"

class BTBacnetLeng: public UniDataDevice<BTBacnetLeng_Data_t,SMDBacNetDevice, RT_BTBacnetLeng>
类需要从SMDBacNetDevice继承

逻辑参数:需要提供:ip, port:47808默认, device_id:对方设备ID
读取数据:
根据BACNET的规范,可以读,很多类型,一般设备导出的数据点表会注明类型
OBJECT_ANALOG_INPUT = 0,
    OBJECT_ANALOG_OUTPUT = 1,
    OBJECT_ANALOG_VALUE = 2,
    OBJECT_BINARY_INPUT = 3,
    OBJECT_BINARY_OUTPUT = 4,
    OBJECT_BINARY_VALUE = 5,

10005 是属性ID,即objectId, PROP_PRESENT_VALUE 是要读取属性的值

nt r =  Send_Read_Property_Request_Address((BACNET_OBJECT_TYPE)0, 10005, PROP_PRESENT_VALUE);
if(r){
    int len = Receive();
    if(len)
    {
        //这个appValue.type.Real是如果返回值是float型,就用这个读appValue就是从上面命令读取到的值
        cData.v0[i] = appValue.type.Real;
        std::cout<<"get 0 "<<v0addr[i]<<" value:"<<cData.v0[i]<<std::endl;
    }else{
        return false;
    }
}else{
    return false;
}