DI型驱动编写

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

DI型设备驱动是最简单的一种设备驱动,只需要实现
bool process(char di, bool first_time);
即可满足最低要求。

调用过程:FsuOS App会定时采集DI接口的状态,每次采集完成后,就会自动调用所有DI型驱动的process函数。

注意:驱动实例化的设备并不知道自己在哪个端口上

下文以烟感驱动为例: smoke2_interface.h

#ifndef SMOKE2_INTERFACE_H
#define SMOKE2_INTERFACE_H
#include "common_interface.h"

#pragma pack(push)
#pragma pack(1)

struct Smoke2_Data_t {
	unsigned int data_id;
	uint8_t value;
	tele_c_time update_time;
};

#pragma pack(pop)
#endif

只有一个value值,表示当前是告警还是正常,一般0是告警

smoke2.h

#ifndef SMOKE2_H
#define SMOKE2_H
#include "SMDDIDevice.hpp"
#include "DI_interface.h"
#include "UniDataDevice.h"

#define RT_SMOKE2 5175
class Smoke2:public UniDataDevice<DI_Data_t, SMDDIDevice, RT_SMOKE2>
{
public:
	Smoke2();

	bool InitSetting(const Json::Value&  settingRoot);
	bool process(char di, bool first_time) override;
	void RunCheckThreshold() override;
private:
	int count;
	int signal_index_ = 1;
    uint8_t mode_ = '0';
};


PLUMA_INHERIT_PROVIDER(Smoke2, SMDDIDevice);

#endif // SMOKESENSOR_H

smoke2.cpp

#include "Smoke2.h"
#include "UniDataDevice.cpp"
Smoke2::Smoke2(): count {0}
{
	device_type_ = "smoke2";
}

bool Smoke2::InitSetting(const Json::Value&  settingRoot)
{
	if(settingRoot["appSetting"] != Json::nullValue && settingRoot["appSetting"].type() == Json::objectValue) {
		if(settingRoot["appSetting"]["signal_index"] != Json::nullValue) {
			signal_index_ = atof(settingRoot["appSetting"]["signal_index"].asString().c_str());
		}
        if(settingRoot["appSetting"]["mode"] != Json::nullValue) {
			if(atoi(settingRoot["appSetting"]["mode"].asString().c_str()) == 0){
                mode_ = '0';
            }else{
                mode_ = '1';
            }
		}
	}
	return UniDataDevice<DI_Data_t, SMDDIDevice, RT_SMOKE2>::InitSetting(settingRoot);

}

bool Smoke2::process(char di, bool first_time)
{
	bCompareSave = false;
	if(di == mode_) {
		if(value) {
			if(++count > hit_count) {
				value = false;
				bCompareSave = true;
			}
		}
	} else { //(di == '1')
		count = 0;
		//只要告警一次,就不能自动恢复,必须板子重新签入才行
		if(!value && first_time) {
			value = true;
			bCompareSave = true;
		}
	}

	if(bIsDataReady_)
		bIsDataReady_ = true;

	cData.value = value;
	RoundDone();
	return value;
}

void Smoke2::RunCheckThreshold()
{
        //"烟感传感器"
	CheckThreshold("value", "烟感", value ? 1.0 : 0.0, signal_index_);
}
#ifdef USE_SEPERATE_DRIVER

extern "C"
std::vector<std::shared_ptr<Provider>> get_providers()
{
	std::vector<std::shared_ptr<Provider>> providerVec;
	providerVec.push_back(std::make_shared<Smoke2Provider>());
	return std::move(providerVec);
}

#endif
  1. 构造函数 device_type_ smoke2表明驱动文件名
  2. InitSetting mode_ 表示是0告警还是1告警
  3. process di是当前值,first_time表明是否第一次进入
  4. RunCheckThreshold CheckThreshold要求对value规则进行告警判断
  5. get_providers 注册Smoke2Provider

编译生成smoke2.so就可以使用了。

application/helpers/device/smoke2.php

<?php
function Get_smoke2_RtData($memData, &$dataArray, $extraPara = false)
{
    if(strlen($memData) != 12) {
        $dataArray['无数据'] = true;
        $dataArray['更新时间'] = '无';
        $dataArray['错误'] = '数据长度不一致';
    } else {
        $dataArray['无数据'] = false;

        $v = unpack('C', substr($memData, 4, 1));
        $dataArray["AlertArray"] = array();
        $dataArray["烟感状态"] = $v[1] ? "正常" : "告警";
        $dataArray["AlertArray"]["烟感状态"] = $v[1] == 0;
        $v = unpack('v', substr($memData, 4 + 1 , 2));
        $year = $v[1];
        $v = unpack('C*', substr($memData,  4 + 1 + 2, 5));
        $dataArray["更新时间"] = date('Y-m-d H:i:s', strtotime($year . '-' . $v[1] . '-' . $v[2] . ' ' . $v[3] . ':' . $v[4] . ':' . $v[5]));
    }
}

函数名必须是get_{xxxx}_RtData,内部代码就是对Smoke2_Data_t进行解析。

application/views/portal/DevicePage/smoke2.php

<h4>系统模拟量</h4>
<?php $signalList = [
    '烟感状态',
  ];
$this->load->view("portal/DevicePage/signal_ctrl", array("signalList"=>$signalList, "cols"=>1));
?>

烟感驱动的编写就完成了。 编译so文件需要使用工程文件,我们推荐用cmake编译,可下载代码研究。

使用方法,请参考FsuOS网站->设备管理的使用。

问题?