AI型驱动编写

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

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
  1. 构造函数 device_type_ ai_general_temp_humid表明驱动文件名
  2. InitSetting version_ 表示使用哪种解法的配置
  3. process 注意看对ai大于20000的特殊处理
    if(ai > 20000)
    {
    ai_index_ = ai - 20000;
    }
  4. RunCheckThreshold CheckThreshold要求对value规则进行告警判断
  5. get_providers 注册AI_GeneralTempHumidProvider

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

问题?