AI型驱动也是比较简单的一种设备驱动,只需要实现
bool process(short ai);
即可满足最低要求。
调用过程:FsuOS App会定时采集AI接口的状态,每次采集完成后,就会自动调用所有AI型驱动的process函数。
AI型驱动有个问题就是最早的FsuOS前身所适配的FSU只有8个AI,并且采用的是0-5V的方式,因此ai的值是个0-10000的值,代表0-5V的百分比。
现在AI的值复杂多变,不但有540V的整组电压,还有扩展板将AI索引扩展到几十,B接口也在用202这种较大的索引,造成short值无法准确表示这些新数据。因此FsuOS App在调用process的时候,如果ai的索引大于8,就会传递20000+index的值,此时驱动发现ai值大于20000,那么就是个索引值,需要调用ReadAi来获取实际值。
注意:驱动实例化的设备并不知道自己在哪个端口上
if(index <= MAX_AI_NUMBER) {
newValue = aiObj.second->process(ai[index-1]);
}else{
newValue = aiObj.second->process(20000 + index);
}
下文以通用AI型温湿度驱动为例: AI_GeneralTempHumid_interface.h
#ifndef AI_GENERALTEMPHUMID_INTERFACE_H
#define AI_GENERALTEMPHUMID_INTERFACE_H
#include "common_interface.h"
#pragma pack(push)
#pragma pack(1)
struct AI_GeneralTempHumid_Data_t {
unsigned int data_id;
float temperature;
float humid;
tele_c_time update_time;
};
#pragma pack(pop)
#endif
数据有temperature和humid 2个
AI_GeneralTempHumid.h
#ifndef AI_GENERALTEMPHUMID_H
#define AI_GENERALTEMPHUMID_H
#include "SMDAIDevice.hpp"
#include "AI_GeneralTempHumid_interface.h"
#include "UniDataDevice.h"
#define RT_AI_GENERALTEMPHUMID 5185
class AI_GeneralTempHumid: public UniDataDevice<AI_GeneralTempHumid_Data_t, SMDAIDevice, RT_AI_GENERALTEMPHUMID>
{
public:
AI_GeneralTempHumid();
~AI_GeneralTempHumid();
bool InitSetting(const Json::Value& settingRoot);
float process(short ai) override;
void RunCheckThreshold() override;
private:
int ai_index_ = 1;
int version_ = 1;//1: temp humid 2:humid temp
};
PLUMA_INHERIT_PROVIDER(AI_GeneralTempHumid, SMDAIDevice);
#endif
ai_index_ 可以通过逻辑参数强制设置本设备所在端口 version_ 是AI0:温度 AI1:湿度 还是 AI0:湿度 AI1:温度
#include “AI_GeneralTempHumid.cpp”
#include "AI_GeneralTempHumid.h"
#include "UniDataDevice.cpp"
AI_GeneralTempHumid::AI_GeneralTempHumid()
{
device_type_ = "ai_general_temp_humid";
}
AI_GeneralTempHumid::~AI_GeneralTempHumid()
{
}
bool AI_GeneralTempHumid::InitSetting(const Json::Value& settingRoot)
{
SMDVDevice::InitSetting(settingRoot);
if(settingRoot["appSetting"] != Json::nullValue && settingRoot["appSetting"].type() == Json::objectValue) {
if(settingRoot["appSetting"]["version"] != Json::nullValue) {
version_ = atoi(settingRoot["appSetting"]["version"].asString().c_str());
}
if(settingRoot["appSetting"]["ai_index"] != Json::nullValue) {
ai_index_ = atoi(settingRoot["appSetting"]["ai_index"].asString().c_str());
}
}
cData.data_id = data_id_;
return UniDataDevice<AI_GeneralTempHumid_Data_t, SMDAIDevice, RT_AI_GENERALTEMPHUMID>::InitSetting(settingRoot);
}
float AI_GeneralTempHumid::process(short ai)
{
if(ai > 20000)
{
ai_index_ = ai - 20000;
}
if(version_ == 1)
{
cData.temperature = ReadAi(ai_index_);
cData.humid = ReadAi(ai_index_ + 1);
cData.humid *= a;
cData.humid += b;
}else if(version_ == 2)
{
cData.temperature = ReadAi(ai_index_ + 1);
cData.humid = ReadAi(ai_index_);
cData.humid *= a;
cData.humid += b;
}else if(version_ == 3)
{
//正常的0-5电压
if(ai > 20000)
{
float temp_ai = ReadAi(ai_index_);
cData.temperature = ((float)temp_ai * 120) / 5 - 40;
}else{
cData.temperature = ((float)ai * 120) / 10000 - 40;
}
if(cData.temperature > 80) {
cData.temperature = 80;
} else if(cData.temperature < -40) {
cData.temperature = -40;
}
//需要读
float humid_ai = ReadAi(ai_index_ + 1);
cData.humid = humid_ai * 100 / 5;
cData.humid *= a;
cData.humid += b;
}else if(version_ == 4)
{
//正常的0-5电压
if(ai > 20000)
{
float humid_ai = ReadAi(ai_index_ + 1);
cData.humid = humid_ai * 100 / 5;
}else{
cData.humid = ((float)ai) / 100;
}
cData.humid *= a;
cData.humid += b;
float temp_ai = ReadAi(ai_index_ + 1);
cData.temperature = ((float)temp_ai * 120) / 5 - 40;
if(cData.temperature > 80) {
cData.temperature = 80;
} else if(cData.temperature < -40) {
cData.temperature = -40;
}
}else if(version_ == 5)
{
//正常的0-5电压
cData.temperature = ((float)ai * 100) / 10000 - 20;
if(cData.temperature > 80) {
cData.temperature = 80;
} else if(cData.temperature < -20) {
cData.temperature = -20;
}
//需要读
float humid_ai = ReadAi(ai_index_ + 1);
cData.humid = humid_ai * 100 / 5;
cData.humid *= a;
cData.humid += b;
}else if(version_ == 6)
{
//正常的0-5电压
cData.humid = ((float)ai) / 100;
cData.humid *= a;
cData.humid += b;
float temp_ai = ReadAi(ai_index_ + 1);
cData.temperature = ((float)temp_ai * 100) / 5 - 20;
if(cData.temperature > 80) {
cData.temperature = 80;
} else if(cData.temperature < -20) {
cData.temperature = -20;
}
}
lastTime = boost::posix_time::second_clock::local_time();
cData.update_time = get_ttime(boost::posix_time::second_clock::local_time());
RoundDone();
return false;
}
void AI_GeneralTempHumid::RunCheckThreshold()
{
std::ostringstream ss;
ss << "911143000" << std::setw(3) << std::setfill('0') << signal_index_;
CheckAOReport(ss.str(), cData.temperature);
//"温度传感器"
CheckThreshold("value", "温度", cData.temperature, 1);
CheckThreshold("humid", "湿度", cData.humid, 1);
}
#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<AI_GeneralTempHumidProvider>());
return std::move(providerVec);
}
#endif
编译生成ai_general_temp_humid.so就可以使用了。
application/helpers/device/ai_general_temp_humid.php
<?php
function Get_ai_general_temp_humid_RtData($memData, &$dataArray, $extraPara = false)
{
if(strlen($memData) != 19) {
$dataArray['无数据'] = true;
$dataArray['更新时间'] = '无';
$dataArray['错误'] = '数据长度不一致';
} else {
$dataArray['无数据'] = false;
$v = unpack('f*', substr($memData, 4, 4*2));
$dataArray["温度"] = number_format($v[1], 2)."℃";
$dataArray["湿度"] = number_format($v[2], 2)."%";
$v = unpack('v',substr($memData, 4 + 4*2, 2));
$year = $v[1];
$v = unpack('C*',substr($memData,4 + 4*2 + 2,5));
$dataArray['更新时间'] = date('Y-m-d H:i:s',strtotime($year.'-'.$v[1].'-'.$v[2].' '.$v[3].':'.$v[4].':'.$v[5]));
}
}
application/views/portal/DevicePage/ai_general_temp_humid.php
<h4>系统模拟量</h4>
<?php $signalList = [
'温度','湿度'
];
$this->load->view("portal/DevicePage/signal_ctrl", array("signalList"=>$signalList, "cols"=>1));
?>
AI型温湿度驱动的编写就完成了。 编译so文件需要使用工程文件,我们推荐用cmake编译,可下载代码研究。
使用方法,请参考FsuOS网站->设备管理的使用。