SP型驱动是使用最广泛的驱动,覆盖了所有的智能设备。
为FsuOS编写SP型驱动,首先要理解程序的工作方式是异步的,串口、网络本身发送和接收就是2个动作,我们在写SP型驱动时,发送后,不能期望直接得到返回值,必须等待底层接口回调传递过来回复的数据,整个过程类似select/poll和libevent,但是接受数据的动作被封装了,更容易使用了。
在驱动编写中,千万不要使用可能造成休眠的函数,比如read,sleep,因为驱动的接口实际是被FsuOS App的线程池异步调度的,一旦休眠卡住,调度线程资源就会耗尽,协议驱动就不能工作了。
SP型驱动的工作流程: RefreshStatus -> process -> process_payload(如果有) 即每轮调用都是从RefreshStatus开始,驱动下发命令,设置状态,在process里进行处理,根据状态进行数据的提取。
由于SP型驱动稍有些复杂,我们用3个例子来演示驱动的编写:
海虹协议,使用的是一种自定义协议,校验和采用Modbus16Crc
Haihong_interface.h
#ifndef HAIHONG_INTERFACE_H
#define HAIHONG_INTERFACE_H
#include "common_interface.h"
#pragma pack(push)
#pragma pack(1)
//0x30:
struct Haihong_30_t {
float Ua; //3,4
float Ub; //5,6
float Uc; //7,8
float Ia; //9,10
float Ib; //11,12
float Ic; //13,14
float activePowerRatio; //15,16,17,18,有功功率
float activePower; //19,20,21,22,有功电能
};
//电压,电流保留一位小数,功率保留一位小数,单位w;电能保留1位小数,单位Kwh
//0x31
struct Haihong_31_t {
float disactivePowerRatio; //3,4,5,6,无功功率
float disactivePower; //7,8,9,10,无功电能
float IA_needed; //11,12
float IB_needed; //13,14
float IC_needed; //15,16
float IA_MaxNeeded; //17,18
float IB_MaxNeeded; //19,20
float IC_MaxNeeded; //21,22
};
//所有数据保留一位有效数据
//0x32
struct Haihong_32_t {
float activePowerNeeded; //3,4,5,6
float maxActivePowerNeeded; //7,8,9,10
float fre; //11,12
float ratio; //13,14
unsigned char inputSwitchStatus; //0:合,1:分
unsigned char lightningProtection; //0:正常,1:告警
};
//有功需量保留两位小数,单位是KW,最大有功需量保留2为小数,单位是KW.频率保留两位小数,功率因数保留三位小数.
//0x33
struct Haihong_33_t {
unsigned char AOverVoltage; //3
unsigned char ADownVoltage; //4
unsigned char BOverVoltage; //5
unsigned char BDownVoltage; //6
unsigned char COverVoltage; //7
unsigned char CDownVoltage; //8
unsigned char IA_OverCurrent; //9
unsigned char IB_OverCurrent; //10
unsigned char IC_OverCurrent; //11
unsigned char lostPhase; //12
unsigned char overFre; //13
unsigned char downFre; //14
unsigned char OverPower; //15
};
struct HaiHong_Data_t {
unsigned int data_id;
Haihong_30_t Haihong_30;
Haihong_31_t Haihong_31;
Haihong_32_t Haihong_32;
Haihong_33_t Haihong_33;
Haihong_30_t Haihong_40;
Haihong_31_t Haihong_41;
Haihong_32_t Haihong_42;
Haihong_33_t Haihong_43;
tele_c_time update_time;
};
#pragma pack(pop)
#endif
Haihong.h
#ifndef HAIHONG_H
#define HAIHONG_H
#include "SMDSPDevice.hpp"
#include "Haihong_interface.h"
#include "UniDataDevice.h"
enum HaiHongStatus_et {
HAIHONG_IDLE = 0,
HAIHONG_30,
HAIHONG_31,
HAIHONG_32,
HAIHONG_33,
HAIHONG_40,
HAIHONG_41,
HAIHONG_42,
HAIHONG_43
};
/****** 编号14_海红通信列头柜--图片带协议 *********/
#define RT_HAIHONG 5061
class HaiHong: public UniDataDevice<HaiHong_Data_t, SMDSPDevice, RT_HAIHONG>
{
public:
HaiHong();
~HaiHong();
bool process(unsigned char *data, size_t len) override;
bool process_payload(unsigned char *data, size_t len);
bool RefreshStatus() override;
float Get_Value(uint32_t data_id, const std::string &var_name) const;
void RunCheckThreshold();
void SendCmd(int tCmd);
private:
unsigned char cmd[8];
};
PLUMA_INHERIT_PROVIDER(HaiHong, SMDSPDevice);
#endif
注意看 HaiHong这个类继承于 SMDSPDevice
Haihong.cpp
#include "Haihong.h"
#include "common_define.h"
#include "UniDataDevice.cpp"
#define DATA_LEN 0xFF /******* test data's len *********/
static const unsigned char ModbusCRCHi[] = {
0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,
0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41,
0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,
0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,
0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,
0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40,
0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0,
0x80, 0x41, 0x00, 0xc1, 0x81, 0x40, 0x00, 0xc1, 0x81, 0x40,
0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0, 0x80, 0x41, 0x00, 0xc1,
0x81, 0x40, 0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41,
0x00, 0xc1, 0x81, 0x40, 0x01, 0xc0, 0x80, 0x41, 0x01, 0xc0,
0x80, 0x41, 0x00, 0xc1, 0x81, 0x40
};
static const unsigned char ModbusCRCLo[] = {
0x00, 0xc0, 0xc1, 0x01, 0xc3, 0x03, 0x02, 0xc2, 0xc6, 0x06,
0x07, 0xc7, 0x05, 0xc5, 0xc4, 0x04, 0xcc, 0x0c, 0x0d, 0xcd,
0x0f, 0xcf, 0xce, 0x0e, 0x0a, 0xca, 0xcb, 0x0b, 0xc9, 0x09,
0x08, 0xc8, 0xd8, 0x18, 0x19, 0xd9, 0x1b, 0xdb, 0xda, 0x1a,
0x1e, 0xde, 0xdf, 0x1f, 0xdd, 0x1d, 0x1c, 0xdc, 0x14, 0xd4,
0xd5, 0x15, 0xd7, 0x17, 0x16, 0xd6, 0xd2, 0x12, 0x13, 0xd3,
0x11, 0xd1, 0xd0, 0x10, 0xf0, 0x30, 0x31, 0xf1, 0x33, 0xf3,
0xf2, 0x32, 0x36, 0xf6, 0xf7, 0x37, 0xf5, 0x35, 0x34, 0xf4,
0x3c, 0xfc, 0xfd, 0x3d, 0xff, 0x3f, 0x3e, 0xfe, 0xfa, 0x3a,
0x3b, 0xfb, 0x39, 0xf9, 0xf8, 0x38, 0x28, 0xe8, 0xe9, 0x29,
0xeb, 0x2b, 0x2a, 0xea, 0xee, 0x2e, 0x2f, 0xef, 0x2d, 0xed,
0xec, 0x2c, 0xe4, 0x24, 0x25, 0xe5, 0x27, 0xe7, 0xe6, 0x26,
0x22, 0xe2, 0xe3, 0x23, 0xe1, 0x21, 0x20, 0xe0, 0xa0, 0x60,
0x61, 0xa1, 0x63, 0xa3, 0xa2, 0x62, 0x66, 0xa6, 0xa7, 0x67,
0xa5, 0x65, 0x64, 0xa4, 0x6c, 0xac, 0xad, 0x6d, 0xaf, 0x6f,
0x6e, 0xae, 0xaa, 0x6a, 0x6b, 0xab, 0x69, 0xa9, 0xa8, 0x68,
0x78, 0xb8, 0xb9, 0x79, 0xbb, 0x7b, 0x7a, 0xba, 0xbe, 0x7e,
0x7f, 0xbf, 0x7d, 0xbd, 0xbc, 0x7c, 0xb4, 0x74, 0x75, 0xb5,
0x77, 0xb7, 0xb6, 0x76, 0x72, 0xb2, 0xb3, 0x73, 0xb1, 0x71,
0x70, 0xb0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9c, 0x5c,
0x5d, 0x9d, 0x5f, 0x9f, 0x9e, 0x5e, 0x5a, 0x9a, 0x9b, 0x5b,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4b, 0x8b,
0x8a, 0x4a, 0x4e, 0x8e, 0x8f, 0x4f, 0x8d, 0x4d, 0x4c, 0x8c,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};
static unsigned short ModbusCRC16( unsigned char buf[], int len)
{
unsigned char hi = 0xff;
unsigned char lo = 0xff;
unsigned char i;
unsigned short crc;
while(len--) {
i = hi ^ *buf++;
hi = lo ^ ModbusCRCHi [ i ];
lo = ModbusCRCLo [ i ];
}
crc = hi;
crc <<= 8;
crc += lo;
return crc;
}
HaiHong::HaiHong()
{
device_type_ = "haihong";
baud_rate_ = 9600;
addr_ = 1;
memset(cmd, 0x00, sizeof(cmd));
}
HaiHong::~HaiHong()
{
}
void HaiHong::SendCmd(int tCmd)
{
cmd[0] = addr_;
cmd[1] = tCmd;
cmd[2] = 0x30;
cmd[3] = 0x30;
cmd[4] = 0x30;
cmd[5] = 0x30;
unsigned short crc = ModbusCRC16(cmd, 6);
cmd[7] = ((unsigned char*)&crc)[0];
cmd[6] = ((unsigned char*)&crc)[1];
SendData(cmd, sizeof(cmd));
}
bool HaiHong::RefreshStatus()
{
SMDSPDevice::RefreshStatus();
state = HAIHONG_30;
SendCmd(0x30);
return true;
}
bool HaiHong::process_payload(unsigned char *data, size_t len)
{
if(HAIHONG_30 == state) {
if(data[1] == 0x30) {
cData.Haihong_30.Ua = data[3] << 8 | data[2];
cData.Haihong_30.Ub = data[5] << 8 | data[4];
cData.Haihong_30.Uc = data[7] << 8 | data[6];
cData.Haihong_30.Ia = data[9] << 8 | data[8];
cData.Haihong_30.Ib = data[11] << 8 | data[10];
cData.Haihong_30.Ic = data[13] << 8 | data[12];
cData.Haihong_30.activePowerRatio = ((float)(*(int*)(&data[14]))) / 10;
cData.Haihong_30.activePower = ((float)(*(int*)&data[18])) / 10;
state = HAIHONG_31;
SendCmd(0x31);
} else {
return false;
}
} else if(HAIHONG_31 == state) {
if(data[1] == 0x31) {
cData.Haihong_31.disactivePowerRatio = (float)(*(int *)&data[2]) / 10;
cData.Haihong_31.disactivePower = (float)(*(int *)&data[6]) / 10;
cData.Haihong_31.IA_needed = data[11] << 8 | data[10];
cData.Haihong_31.IB_needed = data[11] << 8 | data[10];
cData.Haihong_31.IC_needed = data[11] << 8 | data[10];
cData.Haihong_31.IA_MaxNeeded = data[13] << 8 | data[12];
cData.Haihong_31.IB_MaxNeeded = data[15] << 8 | data[14];
cData.Haihong_31.IC_MaxNeeded = data[17] << 8 | data[15];
state = HAIHONG_32;
SendCmd(0x32);
} else {
return false;
}
} else if(HAIHONG_32 == state) {
if(data[1] == 0x32) {
cData.Haihong_32.activePowerNeeded = (float)(*(int *)&data[2]) / 10;
cData.Haihong_32.maxActivePowerNeeded = (float)(*(int *)&data[6]) / 10;
cData.Haihong_32.fre = data[11] << 8 | data[10];
cData.Haihong_32.ratio = data[13] << 8 | data[12];
cData.Haihong_32.inputSwitchStatus = data[14] & 1 << 3;
cData.Haihong_32.lightningProtection = data[14] & 1;
state = HAIHONG_33;
SendCmd(0x33);
} else {
return false;
}
} else if(HAIHONG_33 == state) {
if(data[1] == 0x33) {
memcpy(&cData.Haihong_33, &data[2], sizeof(Haihong_33_t));
state = HAIHONG_40;
SendCmd(0x40);
} else {
return false;
}
} else if(HAIHONG_40 == state) {
if(data[1] == 0x40) {
cData.Haihong_40.Ua = data[3] << 8 | data[2];
cData.Haihong_40.Ub = data[5] << 8 | data[4];
cData.Haihong_40.Uc = data[7] << 8 | data[6];
cData.Haihong_40.Ia = data[9] << 8 | data[8];
cData.Haihong_40.Ib = data[11] << 8 | data[10];
cData.Haihong_40.Ic = data[13] << 8 | data[12];
cData.Haihong_40.activePowerRatio = ((float)(*(int*)(&data[14]))) / 10;
cData.Haihong_40.activePower = ((float)(*(int*)&data[18])) / 10;
state = HAIHONG_41;
SendCmd(0x41);
} else {
return false;
}
} else if(HAIHONG_41 == state) {
if(data[1] == 0x41) {
cData.Haihong_41.disactivePowerRatio = (float)(*(int *)&data[2]) / 10;
cData.Haihong_41.disactivePower = (float)(*(int *)&data[6]) / 10;
cData.Haihong_41.IA_needed = data[11] << 8 | data[10];
cData.Haihong_41.IB_needed = data[11] << 8 | data[10];
cData.Haihong_41.IC_needed = data[11] << 8 | data[10];
cData.Haihong_41.IA_MaxNeeded = data[13] << 8 | data[12];
cData.Haihong_41.IB_MaxNeeded = data[15] << 8 | data[14];
cData.Haihong_41.IC_MaxNeeded = data[17] << 8 | data[15];
state = HAIHONG_42;
SendCmd(0x42);
} else {
return false;
}
} else if(HAIHONG_42 == state) {
if(data[1] == 0x42) {
cData.Haihong_42.activePowerNeeded = (float)(*(int *)&data[2]) / 10;
cData.Haihong_42.maxActivePowerNeeded = (float)(*(int *)&data[6]) / 10;
cData.Haihong_42.fre = data[11] << 8 | data[10];
cData.Haihong_42.ratio = data[13] << 8 | data[12];
cData.Haihong_42.inputSwitchStatus = data[14] & 1 << 3;
cData.Haihong_42.lightningProtection = data[14] & 1;
state = HAIHONG_43;
SendCmd(0x43);
} else {
return false;
}
} else if(HAIHONG_43 == state) {
if(data[1] == 0x43) {
memcpy(&cData.Haihong_43, &data[2], sizeof(Haihong_33_t));
RoundDone();
}
return false;
}
return true;
}
bool HaiHong::process(unsigned char *data, size_t len)
{
if( (msg_index + len) > 4096) {
Reset();
return false;
}
bool ret = true;
if(msg_index == 0) {
for(size_t i = 0; i < len ; i++) {
if(data[i] == addr_) {
memcpy(msg_buf, data + i, len - i);
msg_index += len - i;
break;
}
}
} else {
memcpy(msg_buf + msg_index, data, len);
msg_index += len;
}
if(msg_index >= 26) {
unsigned short crc = ModbusCRC16(msg_buf, 24);
if(msg_buf[24] == ((uint8_t*)&crc)[0] && msg_buf[25] == ((uint8_t*)&crc)[1]) {
ret = process_payload(msg_buf, 26);
}
msg_index = 0;
}
return ret;
}
void HaiHong::RunCheckThreshold()
{
CheckThresholdBool(LEVEL_1,"Haihong_0", SIGID_16012, "防雷告警", "防雷告警", cData.Haihong_32.lightningProtection==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1", SIGID_16006, SIGNAME_16006, SIGNAME_16006, cData.Haihong_33.AOverVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_2", SIGID_16007, SIGNAME_16007, SIGNAME_16007, cData.Haihong_33.ADownVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_3", SIGID_16008, SIGNAME_16008, SIGNAME_16008, cData.Haihong_33.BOverVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_4", SIGID_16009, SIGNAME_16009, SIGNAME_16009, cData.Haihong_33.BDownVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_5", SIGID_16010, SIGNAME_16010, SIGNAME_16010, cData.Haihong_33.COverVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_6", SIGID_16011, SIGNAME_16011, SIGNAME_16011, cData.Haihong_33.CDownVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_7", SIGID_16012, "A项过流", "A项过流", cData.Haihong_33.IA_OverCurrent==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_8", SIGID_16012, "B项过流", "B项过流", cData.Haihong_33.IB_OverCurrent==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_9", SIGID_16012, "C项过流", "C项过流", cData.Haihong_33.IC_OverCurrent==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_10", SIGID_16012, "交流输入缺相", "交流输入缺相", cData.Haihong_33.lostPhase==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_11", SIGID_16004, SIGNAME_16004, SIGNAME_16004, cData.Haihong_33.overFre==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_12", SIGID_16005, SIGNAME_16005, SIGNAME_16005, cData.Haihong_33.downFre==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_13", SIGID_16012, "功率过高", "功率过高", cData.Haihong_33.OverPower==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_0", SIGID_16012, "防雷告警", "第二路防雷告警", cData.Haihong_42.lightningProtection==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_1", SIGID_16006, SIGNAME_16006, "第二路" SIGNAME_16006, cData.Haihong_43.AOverVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_2", SIGID_16007, SIGNAME_16007, "第二路" SIGNAME_16007, cData.Haihong_43.ADownVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_3", SIGID_16008, SIGNAME_16008, "第二路" SIGNAME_16008, cData.Haihong_43.BOverVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_4", SIGID_16009, SIGNAME_16009, "第二路" SIGNAME_16009, cData.Haihong_43.BDownVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_5", SIGID_16010, SIGNAME_16010, "第二路" SIGNAME_16010, cData.Haihong_43.COverVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_6", SIGID_16011, SIGNAME_16011, "第二路" SIGNAME_16011, cData.Haihong_43.CDownVoltage==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_7", SIGID_16012, "A项过流", "第二路A项过流", cData.Haihong_43.IA_OverCurrent==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_8", SIGID_16012, "B项过流", "第二路B项过流", cData.Haihong_43.IB_OverCurrent==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_9", SIGID_16012, "C项过流", "第二路C项过流", cData.Haihong_43.IC_OverCurrent==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_10", SIGID_16012, "交流输入缺相", "第二路交流输入缺相", cData.Haihong_43.lostPhase==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_11", SIGID_16004, SIGNAME_16004, "第二路" SIGNAME_16004, cData.Haihong_43.overFre==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_12", SIGID_16005, SIGNAME_16005, "第二路" SIGNAME_16005, cData.Haihong_43.downFre==1, signal_index_++);
CheckThresholdBool(LEVEL_1,"Haihong_1_13", SIGID_16012, "功率过高", "第二路功率过高", cData.Haihong_43.OverPower==1, signal_index_++);
}
float HaiHong::Get_Value(uint32_t data_id, const std::string & var_name) const
{
if(!bIsDataReady_)
throw std::out_of_range("数据未就绪");
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
boost::posix_time::time_duration diff = now - lastTime;
if( diff.total_seconds() > 60) {
throw std::out_of_range("数据已超时");
}
throw std::out_of_range("不支持变量");
}
#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<HaiHongProvider>());
return std::move(providerVec);
}
#endif
dtsd3366d_interface.h
#ifndef DTSD3366D_INTERFACE_H
#define DTSD3366D_INTERFACE_H
#include "common_interface.h"
#pragma pack(push)
#pragma pack(1)
struct DTSD3366D_REG_8_A_t
{
uint16_t Addr; //设备地址; 1~247;0为广播地址
uint16_t NC; //预留数据网页不用显示
uint16_t Ur; //Ur 电压变比; 1-5000;
uint16_t Ir; //Ir 电流变比; 1~5000 ;
};
struct DTSD3366D_REG_16E_199_t
{
uint32_t Ua;
uint32_t Ub;
uint32_t Uc; //三相相电电压 单位0.0001V 网页/10000
uint32_t Ia;
uint32_t Ib;
uint32_t Ic; //三相电流数据单位0.0001A 网页/10000
int32_t Psum; //瞬时总有功功率 单位KW 网页/10000
int32_t Pa;
int32_t Pb;
int32_t Pc;
int32_t Qsum; //瞬时总无功有功功率 单位KVAR网页/10000
int32_t Qa;
int32_t Qb;
int32_t Qc;
uint32_t Ssum; //瞬时总视在功率 单位KVA 网页/10000
uint32_t Sa;
uint32_t Sb;
uint32_t Sc;
int16_t PF; //功率因数 单位0.001 网页/1000
int16_t PFA; //A项功率因数 单位0.001 网页/1000
int16_t PFB; //B项功率因数单位0.001 网页/1000
int16_t PFC; //C项功率因数单位0.001 网页/1000
int16_t Acos; //A项相角 单位0.1° 网页/1000
int16_t Bcos; //B项相角单位0.1° 网页/1000
int16_t Ccos; //C项相角单位0.1° 网页/1000
int16_t F; //频率 0.01Hz 网页/100
};
struct DTSD3366D_REG_1000_1061_t
{
int32_t Eq; //组合有功电能 单位KWH
uint32_t EqPositive; //正向有功电能单位KWH
uint32_t EqReverse; //反向无功电能单位KWH
};
struct DTSD3366D_Data_t
{
unsigned int data_id;
DTSD3366D_REG_8_A_t DTSD3366D_REG_8_A;
DTSD3366D_REG_16E_199_t DTSD3366D_REG_16E_199;
DTSD3366D_REG_1000_1061_t DTSD3366D_REG_1000_1061;
tele_c_time update_time;
};
#pragma pack(pop)
#endif
dtsd3366d.h
#ifndef DTSD3366D_H
#define DTSD3366D_H
#include "SPModbus.h"
#include "dtsd3366d_interface.h"
#include "UniDataDevice.h"
enum DTSD3366D_Status {
DTSD3366D_IDLE,
DTSD3366D_REG_8_A,
DTSD3366D_REG_16E_199,
DTSD3366D_REG_1000,
DTSD3366D_REG_1030,
DTSD3366D_REG_1060
};
#define RT_DTSD3366D 5046
class DTSD3366D: public UniDataDevice<DTSD3366D_Data_t, SPModbus, RT_DTSD3366D>
{
public:
DTSD3366D();
~DTSD3366D();
bool process_payload(enum tab_type type, size_t len) override;
bool InitSetting(const Json::Value &settingRoot) override;
bool RefreshStatus() override;
float Get_Value(uint32_t data_id, const std::string &var_name) const override;
void RunCheckThreshold() ;
private:
short ct = 1;
bool hasA = true, hasB = true, hasC = true;
};
PLUMA_INHERIT_PROVIDER(DTSD3366D, SMDSPDevice);
#endif
注意
dtsd3366d.cpp
#include "dtsd3366d.h"
#include "UniDataDevice.cpp"
DTSD3366D::DTSD3366D()
{
device_type_ = "dtsd3366d";
baud_rate_ = 9600;
addr_ = 1;
//parity_ = EnumParity::EVEN;
}
DTSD3366D::~DTSD3366D()
{
}
bool DTSD3366D::InitSetting(const Json::Value &settingRoot)
{
cData.data_id = data_id_;
if(settingRoot["appSetting"] != Json::nullValue) {
if(settingRoot["appSetting"].type() == Json::objectValue) {
if(settingRoot["appSetting"]["ct"] != Json::nullValue) {
ct = atoi(settingRoot["appSetting"]["ct"].asString().c_str());
}
if(settingRoot["appSetting"]["has_a"] != Json::nullValue) {
hasA = atoi(settingRoot["appSetting"]["has_a"].asString().c_str());
}
if(settingRoot["appSetting"]["has_b"] != Json::nullValue) {
hasB = atoi(settingRoot["appSetting"]["has_b"].asString().c_str());
}
if(settingRoot["appSetting"]["has_c"] != Json::nullValue) {
hasC = atoi(settingRoot["appSetting"]["has_c"].asString().c_str());
}
}
}
return UniDataDevice<DTSD3366D_Data_t, SPModbus, RT_DTSD3366D>::InitSetting(settingRoot);;
}
bool DTSD3366D::RefreshStatus()
{
SMDSPDevice::RefreshStatus();
state = DTSD3366D_REG_8_A;
modbus_read_registers(0x07, 4);
return true;
}
static void copy_to_float(uint16_t* buf, uint8_t *pFloat)
{
memcpy(pFloat, buf+1, 2);
memcpy(pFloat+2, buf, 2);
}
bool DTSD3366D::process_payload(enum tab_type type, size_t len)
{
printf("DTSD3366D::process_payload len\n");
if(DTSD3366D_REG_8_A == state && type == TAB_REG) {
memcpy(&cData.DTSD3366D_REG_8_A, tab_reg, sizeof(DTSD3366D_REG_8_A_t));
state = DTSD3366D_REG_16E_199;
modbus_read_registers(0x16E, 44);
} else if(DTSD3366D_REG_16E_199 == state && type == TAB_REG) {
uint32_t *pDATA = (uint32_t*)&cData.DTSD3366D_REG_16E_199.Ua;
for(int i=0; i<18; i++) {
copy_to_float(tab_reg + 2*i, (uint8_t*)pDATA++);
}
memcpy(&cData.DTSD3366D_REG_16E_199.PF, &tab_reg[36], 16);
state = DTSD3366D_REG_1000;
modbus_read_registers(0x1000, 2);
} else if(DTSD3366D_REG_1000 == state && type == TAB_REG) {
cData.DTSD3366D_REG_1000_1061.Eq = tab_reg[0] << 16 | tab_reg[1];
state = DTSD3366D_REG_1030;
modbus_read_registers(0x1030, 2);
} else if(DTSD3366D_REG_1030 == state && type == TAB_REG) {
cData.DTSD3366D_REG_1000_1061.EqPositive = tab_reg[0] << 16 | tab_reg[1];
state = DTSD3366D_REG_1060;
modbus_read_registers(0x1060, 2);
} else if(DTSD3366D_REG_1060 == state && type == TAB_REG) {
cData.DTSD3366D_REG_1000_1061.EqReverse = tab_reg[0] << 16 | tab_reg[1];
//multiple ct ratio
cData.DTSD3366D_REG_16E_199.Ia *= ct;
cData.DTSD3366D_REG_16E_199.Ib *= ct;
cData.DTSD3366D_REG_16E_199.Ic *= ct;
cData.DTSD3366D_REG_16E_199.Psum *= ct;
cData.DTSD3366D_REG_16E_199.Pa *= ct;
cData.DTSD3366D_REG_16E_199.Pb *= ct;
cData.DTSD3366D_REG_16E_199.Pc *= ct;
cData.DTSD3366D_REG_16E_199.Qsum *= ct;
cData.DTSD3366D_REG_16E_199.Qa *= ct;
cData.DTSD3366D_REG_16E_199.Qb *= ct;
cData.DTSD3366D_REG_16E_199.Qc *= ct;
cData.DTSD3366D_REG_16E_199.Ssum *= ct;
cData.DTSD3366D_REG_16E_199.Sa *= ct;
cData.DTSD3366D_REG_16E_199.Sb *= ct;
cData.DTSD3366D_REG_16E_199.Sc *= ct;
cData.DTSD3366D_REG_1000_1061.Eq *= ct;
cData.DTSD3366D_REG_1000_1061.EqPositive *= ct;
cData.DTSD3366D_REG_1000_1061.EqReverse *= ct;
RoundDone();
return false;
}
return true;
}
void DTSD3366D::RunCheckThreshold()
{
CheckThresholdBool(1, "p41_44_0","321415001", "输入电源中断", "输入电源中断 UA:" + boost::lexical_cast<std::string>(((float)cData.DTSD3366D_REG_16E_199.Ua)/10000) + " UB:" + boost::lexical_cast<std::string>(((float)cData.DTSD3366D_REG_16E_199.Ub)/10000) + " UC:" + boost::lexical_cast<std::string>(((float)cData.DTSD3366D_REG_16E_199.Uc)/10000), (hasA && (((float)cData.DTSD3366D_REG_16E_199.Ua)/10000 < 120) ) ||
( hasB && (((float)cData.DTSD3366D_REG_16E_199.Ub)/10000 < 120 )) || ( hasC && (((float)cData.DTSD3366D_REG_16E_199.Uc)/10000 < 120 )), 1);
}
float DTSD3366D::Get_Value(uint32_t data_id, const std::string &var_name) const
{
if(!bIsDataReady_)
throw std::out_of_range("数据未就绪");
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
boost::posix_time::time_duration diff = now - lastTime;
if( diff.total_seconds() > 60) {
throw std::out_of_range("数据已超时");
}
if(var_name == "Ua") {
return ((float)cData.DTSD3366D_REG_16E_199.Ua)/10000;
} else if(var_name == "Ub") {
return ((float)cData.DTSD3366D_REG_16E_199.Ub)/10000;
} else if(var_name == "Uc") {
return ((float)cData.DTSD3366D_REG_16E_199.Uc)/10000;
} else if(var_name == "Ia") {
return ((float)cData.DTSD3366D_REG_16E_199.Ia)/10000;
} else if(var_name == "Ib") {
return ((float)cData.DTSD3366D_REG_16E_199.Ib)/10000;
} else if(var_name == "Ic") {
return ((float)cData.DTSD3366D_REG_16E_199.Ic)/10000;
}
throw std::out_of_range("不支持变量");
}
#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<DTSD3366DProvider>());
return std::move(providerVec);
}
#endif
注意
Gree_interface.h
#ifndef GREE_INTERFACE_H
#define GREE_INTERFACE_H
#include <stdint.h>
#pragma pack(push)
#pragma pack(1)
struct Gree_Data_t {
uint32_t data_id;
//4.5 获取空调机开关量,60-43
uint8_t state[9]; //1 空调机工作状态 2(13\14) 00H—开机; 01H—关机
//4.6 获取空调机告警量,60-44
uint8_t alarm[31];
//60_47
uint16_t setting_temp;//温度设定值
uint16_t temp;//环境温度
tele_c_time update_time;
};
#pragma pack(pop)
#endif
Gree.h
#ifndef GREE_H
#define GREE_H
#include "PMBusProtocol.h"
#include "Gree_interface.h"
#include "UniDataDevice.h"
/**
* @class HisenseS
* @author marship
* @date 04/08/23
* @file Hisense.h
* @brief 格力基站空调通信协议v3.1 (1).doc
*/
#define RT_GREE 5256
class Gree: public UniDataDevice<Gree_Data_t, PMBusProtocol, RT_GREE>
{
public:
Gree();
bool RefreshStatus() override;
bool process_payload() override;
float Get_Value ( uint32_t data_id, const std::string &var_name ) const override;
void RunCheckThreshold() override;
int DeviceIoControl(int ioControlCode, const void* inBuffer, int inBufferSize, void* outBuffer, int outBufferSize, int& bytesReturned) override;
protected:
enum HISENSE_RTN {
NORMAL = 0x00,
VER_MISMATCH = 0x01,
CHKSUM_ERR = 0x02,
LCHKSUM_ERR = 0x03,
CID2_INVALID = 0x04,
CMD_ERR = 0x05,
DATA_INVALID = 0x06,
OTHER_ERROR = 0x80
};
typedef enum {
DATAMATE_IDLE = 0,
RST_ALARM = 0x40,
GET_AI = 0x42,
GET_STATUS = 0x43,
GET_ALARM = 0x44,
REMOTE_CTL = 0x45,
GET_PARAMS = 0x47,
SET_PARAMS = 0x49,
GET_ADDR = 0x50
} HISENSE_CMD;
enum { STATE_IDLE, STATE_60_43, STATE_60_44, STATE_60_47};
private:
bool skipNext;
int cmd_result_ = -1;
uint8_t last_on_off_ = 255;//开机:00;关机01H
};
PLUMA_INHERIT_PROVIDER ( Gree, SMDSPDevice );
#endif
Gree.cpp
#include "Gree.h"
#include "common_define.h"
#include "UniDataDevice.cpp"
Gree::Gree()
{
device_type_ = "gree";
baud_rate_ = 4800;
addr_ = 1;
version_ = 0x21;
}
bool Gree::RefreshStatus()
{
SMDSPDevice::RefreshStatus();
state = STATE_60_43;
write_pmbus_cmd ( 0x60, 0x43 );
return true;
}
bool Gree::process_payload()
{
switch ( state ) {
case 300:
case 310:
case 320:
{
//SET TIME
cmd_result_ = 1;
return false;
}
case STATE_60_43: {
memcpy(cData.state, pPMBus->data, 9);
state = STATE_60_44;
write_pmbus_cmd ( 0x60, 0x44 );
break;
}
case STATE_60_44: {
memcpy(cData.alarm, pPMBus->data, 31);
state = STATE_60_47;
write_pmbus_cmd ( 0x60, 0x47);
break;
}
case STATE_60_47: {
uint16_t t;
memcpy(&t, pPMBus->data + 12, sizeof(uint16_t));
cData.setting_temp = ntohs(t);
memcpy(&t, pPMBus->data + 15, sizeof(uint16_t));
cData.temp = ntohs(t);
RoundDone();
return false;
}
}
return true;
}
void Gree::RunCheckThreshold()
{
}
int Gree::DeviceIoControl(int ioControlCode, const void* inBuffer, int inBufferSize, void* outBuffer, int outBufferSize, int& bytesReturned)
{
return 0;
}
float Gree::Get_Value ( uint32_t data_id, const std::string& var_name ) const
{
if ( !bIsDataReady_ )
throw std::out_of_range ( "数据未就绪" );
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
boost::posix_time::time_duration diff = now - lastTime;
if ( diff.total_seconds() > 60 ) {
throw std::out_of_range ( "数据已超时" );
}
throw std::out_of_range ( "不支持变量" );
}
#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<GreeProvider>() );
return std::move ( providerVec );
}
#endif