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
编译生成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网站->设备管理的使用。