Masterctrl/Sources/Chalet/ChaletDevice.cpp

498 lines
16 KiB
C++

#include "ChaletDevice.h"
#include "GlobalDefine.h"
CChaletDevice::CChaletDevice(int Address, CAbstractNetworkCommIF *NetworkInterface):
CNetworkDevice(ID_CHALET_DEVICE,Address,NetworkInterface)
{
NetworkInterface->mDevicePtr = this;
mDeviceAddress = Address;
mDeviceID = ID_CHALET_DEVICE;
mChaletStatusTimer = new QTimer();
mChaletStatusTimer->setInterval(1000);
mChaletStatusTimer->setSingleShot(true);
connect(mChaletStatusTimer,SIGNAL(timeout()),this,SLOT(CommTimerExpired()));
// mJFUbidotsInterface = new CChaletJFUbidotsInterface("BBFF-tEq4lGAegEyP1H4EaYckNQ7ZHdZYzI");
mThingsBoardInterface.mChaletLoraDevice = this;
mChaletModbusRepo.AddHRDataMap(0x2000,50);
mChaletModbusServer = new CChaletModbusServer(&mChaletModbusRepo,512,1);
mDeviceWiFiParameters.fill(0xFF);
mDeviceFirmwareVersion.fill(0xFF);
ResetCommStats();
}
CChaletDevice::~CChaletDevice()
{
delete mChaletStatusTimer;
}
int CChaletDevice::Start()
{
ScheduleChaletStatusRequest();
mChaletStatusTimer->start(1000);
mThingsBoardInterface.RegisterThingsboardRPC();
return RET_OK;
}
int CChaletDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data)
{
Q_UNUSED(DeviceID)
Q_UNUSED(DeviceAddress)
Q_UNUSED(DataSize)
switch(MessageID)
{
case CHALET_ACK:
{
CmdResponseReceived(CHALET_ACK);
break;
}
case CHALET_GENERAL_STATUS_RESPONSE:
{
float temp;
qint16 temp2;
quint32 temp3;
// qDebug("Chalet Status RX");
char VoltageArray[4];
char TemperatureArray[4];
char TotalRequestsArray[4];
char SolarPanelCurrentArray[2];
char BatterySOCArray[2];
mChaletMainStatus.mInverterRelayStatus = ((Data[0] & LORA_CHALET_STATUS_POWER_RELAY_MASK) != 0);
mChaletMainStatus.mCurrentSensorStatus = ((Data[0] & LORA_CHALET_STATUS_CUR_SENSOR_MASK) != 0);
mChaletMainStatus.mWiFiModuleStatus = Data[1];
VoltageArray[0] = Data[2];
VoltageArray[1] = Data[3];
VoltageArray[2] = Data[4];
VoltageArray[3] = Data[5];
memcpy(&temp,VoltageArray,4);
mChaletMainStatus.mBatteryVoltage = temp;
SolarPanelCurrentArray[0] = Data[6];
SolarPanelCurrentArray[1] = Data[7];
memcpy(&temp2,SolarPanelCurrentArray,2);
mChaletMainStatus.mBatteryCurrent = temp2;
BatterySOCArray[0] = Data[8];
BatterySOCArray[1] = Data[9];
memcpy(&temp2,BatterySOCArray,2);
mChaletMainStatus.mBatterySOC = temp2;
TemperatureArray[0] = Data[10];
TemperatureArray[1] = Data[11];
TemperatureArray[2] = Data[12];
TemperatureArray[3] = Data[13];
memcpy(&temp,TemperatureArray,4);
mChaletMainStatus.mChaletTemperature = temp;
TotalRequestsArray[0] = Data[14];
TotalRequestsArray[1] = Data[15];
TotalRequestsArray[2] = Data[16];
TotalRequestsArray[3] = Data[17];
memcpy(&temp3,TotalRequestsArray,4);
mChaletMainStatus.mTotalNbChaletRxCmds = temp3;
mChaletMainStatus.mStatusToggleBit = !mChaletMainStatus.mStatusToggleBit;
mChaletMainStatus.mLastLoraStatus = QDateTime::currentDateTime();
CmdResponseReceived(CHALET_GENERAL_STATUS_REQUEST);
// qDebug("voltage: %f",mChaletMainStatus.mBatteryVoltage);
// qDebug("Current: %d",mChaletMainStatus.mBatteryCurrent);
// qDebug("SOC: %d",mChaletMainStatus.mBatterySOC);
// qDebug("Inverter: %d",mChaletMainStatus.mInverterRelayStatus);
// qDebug("Chalet Rx Nb Cmd: %d",mChaletMainStatus.mTotalNbChaletRxCmds);
mChaletDataLogger.LogChaletLORAData(&mChaletMainStatus);
// mJFUbidotsInterface->LogUbidotsChaletData(&mChaletMainStatus);
// mBlynkInterface.UpdateChaletCurrent(mChaletMainStatus.mBatteryCurrent);
// mBlynkInterface.UpdateChaletVoltage(mChaletMainStatus.mBatteryVoltage);
// mBlynkInterface.UpdateChaletWifiStatus((int)mChaletMainStatus.mInverterRelayStatus);
// mBlynkInterface.UpdateChaletInverterStatus((int)mChaletMainStatus.mInverterRelayStatus);
// mBlynkInterface.UpdateChaletStatusLed(((int)mChaletMainStatus.mStatusToggleBit)*255);
// mThingsBoardInterface.UpdateChaletVoltage(mChaletMainStatus.mBatteryVoltage);
//mThingsBoardInterface.UpdateChaletData(mChaletMainStatus.mInverterRelayStatus,mChaletMainStatus.mWiFiModuleStatus,mChaletMainStatus.mCurrentSensorStatus,mChaletMainStatus.mBatteryVoltage,mChaletMainStatus.mBatteryCurrent,mChaletMainStatus.mBatterySOC,mChaletMainStatus.mIsOnline);
mThingsBoardInterface.UpdateChaletData(&mChaletMainStatus);
// mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_ONLINE_STATE_REG,(quint16)mChaletMainStatus.mIsOnline);
// mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_WIFI_STATE_REG,(quint16)mChaletMainStatus.mWiFiModuleStatus);
// mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_CURRENT_SENSOR_STATE_REG,(quint16)mChaletMainStatus.mCurrentSensorStatus);
// mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_HARAKIRI_DONE_REG,(quint16)mChaletMainStatus.mHarakiriDone);
// mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_STATUS_TOGGLE_REG,(quint16)mChaletMainStatus.mStatusToggleBit);
// //mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_WATCHDOG_STATUS_REG,(quint16),mChaletMainStatus.m)
// mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_INVERTER_REG,(quint16)mChaletMainStatus.mInverterRelayStatus);
// quint16 TempInt16;
// memcpy(&TempInt16,&VoltageArray[0],2);
// mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_BATTERY_VOLTAGE_REG_1,TempInt16);
// memcpy(&TempInt16,&VoltageArray[2],2);
// mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_BATTERY_VOLTAGE_REG_2,TempInt16);
// mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_BATTERY_CURRENT_REG_1,mChaletMainStatus.mBatteryCurrent);
// mChaletModbusRepo.WriteSingleReg(CHALET_MODBUS_BATTERY_SOC_REG,mChaletMainStatus.mBatterySOC);
break;
}
case CHALET_AC_POWER_STATE_STATUS_RESPONSE:
{
mChaletMainStatus.mInverterRelayStatus = Data[0];
CmdResponseReceived(CHALET_AC_POWER_STATE_STATUS_REQUEST);
break;
}
case CHALET_AC_POWER_SET_STATE_RESPONSE:
{
// qDebug("Lora set Inverter Power response : 0x%d",(int)Data[0]);
mChaletMainStatus.mInverterRelayStatus = Data[0];
CmdResponseReceived(CHALET_AC_POWER_SET_STATE_REQUEST);
break;
}
case CHALET_BATTERY_VOLTAGE_RESPONSE:
{
CmdResponseReceived(CHALET_BATTERY_VOLTAGE_REQUEST);
break;
}
case CHALET_BATTERY_CURRENT_RESPONSE:
{
CmdResponseReceived(CHALET_BATTERY_CURRENT_REQUEST);
break;
}
case CHALET_WIFI_STATUS_RESPONSE:
{
CmdResponseReceived(CHALET_WIFI_STATUS_REQUEST);
emit DeviceWifiStatusReceived(Data);
break;
}
case CHALET_WIFI_SET_STATE_RESPONSE:
{
// qDebug("Lora set WiFi response : 0x%d",(int)Data[0]);
mChaletMainStatus.mWiFiModuleStatus = Data[0];
CmdResponseReceived(CHALET_WIFI_SET_STATE_REQUEST);
break;
}
case CHALET_DO_HARAKIRI_CONFIRMATION:
{
if(Data[0] == (char)1)
{
qDebug("ChaletDuino has commited suicide (HARAKIRI)");
mChaletMainStatus.mHarakiriDone = true;
}
else
{
qDebug("HARAKIRI magic word invalid.");
}
CmdResponseReceived(CHALET_DO_HARAKIRI_REQUEST);
break;
}
case CHALET_REBOOT_CPU_RESPONSE:
{
if(Data[0] == (char)1)
{
qDebug("ChaletDuino is rebooting");
}
else
{
qDebug("Reboot magic word invalid");
}
CmdResponseReceived(CHALET_DO_HARAKIRI_REQUEST);
break;
}
case CHALET_GET_STORED_WIFI_SETTINGS_RESPONSE:
{
CmdResponseReceived(CHALET_GET_STORED_WIFI_SETTINGS_REQUEST);
mDeviceWiFiParameters = Data.left(DataSize);
emit DeviceWifiStoredParamsReceived();
break;
}
case CHALET_SET_STORED_WIFI_SETTINGS_RESPONSE:
{
CmdResponseReceived(CHALET_SET_STORED_WIFI_SETTINGS_REQUEST);
emit DeviceWifiSetParamsResult(Data[0]);
break;
}
case CHALET_GET_FIRMWARE_VERSION_RESPONSE:
{
CmdResponseReceived(CHALET_GET_FIRMWARE_VERSION_REQUEST);
mDeviceFirmwareVersion = Data.left(15);
emit DeviceFirmwareVersionReceived();
break;
}
case CHALET_CLEAR_COMMS_STATISTICS_RESPONSE:
{
ResetCommStats();
CmdResponseReceived(CHALET_CLEAR_COMMS_STATISTICS_REQUEST);
break;
}
default:
{
return RET_ERROR;
break;
}
}
return RET_OK;
}
void CChaletDevice::CommTimerExpired()
{
if(mPendingNetworkMsgList.isEmpty())
{
qDebug("Empty command list in comm timer ");
ScheduleChaletStatusRequest();
mChaletStatusTimer->start(LORA_NORMAL_REQUEST_TIMEOUT);
return;
}
if(mPendingNetworkMsgList.first().PendingResponse == true)
{
//The current command is still waiting for a response. Check how many times we tried to send it
// qDebug("Cmd 0x%x timetout... retrying",mPendingNetworkMsgList.first().mMessageID);
if(mPendingNetworkMsgList.first().ResendCounter >= 2)
{
//After 2 retries, declare module offline, clear the send buffer and start sending status requests...
if(mChaletMainStatus.mIsOnline == true)
{
mChaletMainStatus.mIsOnline = false;
qDebug("Chalet LORA interface Offline. Switching to status requests...");
mPendingNetworkMsgList.clear();
ScheduleChaletStatusRequest();
mPendingNetworkMsgList.first().ResendCounter = 2;
}
}
mPendingNetworkMsgList[0].ResendCounter++;
mNbLostRequest++;
mChaletMainStatus.mMasterLostRequestCount = mNbLostRequest;
ComputeCommStats();
}
// qDebug("Sending chalet request 0x%x",mPendingNetworkMsgList.at(0).mMessageID);
mPendingNetworkMsgList[0].PendingResponse = true;
SendChaletCommand(mPendingNetworkMsgList.at(0).mMessageID,mPendingNetworkMsgList.at(0).mData.size(),mPendingNetworkMsgList.at(0).mData);
//Harakiri and Reboot commands should not stay in the queue...
if(mPendingNetworkMsgList.at(0).mMessageID == CHALET_DO_HARAKIRI_REQUEST ||
mPendingNetworkMsgList.at(0).mMessageID == CHALET_REBOOT_CPU_REQUEST)
{
mPendingNetworkMsgList.clear();
ScheduleChaletStatusRequest();
}
mChaletStatusTimer->start(LORA_RESPONSE_TIME_TIMEOUT); //we should get an answer within 5 seconds.
// SendChaletCommand(CHALET_GENERAL_STATUS_REQUEST,0,QByteArray());
}
int CChaletDevice::SendWiFiModuleSetState(bool State)
{
QByteArray Data;
Data.resize(1);
if(State)
{
Data[0] = 1;
}
else
{
Data[0] = 0;
}
return ScheduleChaletCommand(CHALET_WIFI_SET_STATE_REQUEST,1,Data);
}
int CChaletDevice::SendInverterPowerRelayState(bool State)
{
QByteArray Data;
Data.resize(1);
if(State)
{
Data[0] = 1;
}
else
{
Data[0] = 0;
}
return ScheduleChaletCommand(CHALET_AC_POWER_SET_STATE_REQUEST,Data);
}
int CChaletDevice::SendDOHarakiri()
{
QByteArray Data; //Magic word...
Data.clear();
Data.append(0xBA);
Data.append(0xAD);
Data.append(0xBE);
Data.append(0xEF);
return ScheduleChaletCommand(CHALET_DO_HARAKIRI_REQUEST,Data);
}
int CChaletDevice::SendRebootCmd()
{
QByteArray Data; //Magic word...
Data.clear();
Data.append(0xBA);
Data.append(0xAD);
Data.append(0xCA);
Data.append(0xFE);
return ScheduleChaletCommand(CHALET_REBOOT_CPU_REQUEST,Data);
}
int CChaletDevice::SendGetWifiParams()
{
return ScheduleChaletCommand(CHALET_GET_STORED_WIFI_SETTINGS_REQUEST,QByteArray());
}
int CChaletDevice::SendSetWifiParams(QByteArray Data)
{
return ScheduleChaletCommand(CHALET_SET_STORED_WIFI_SETTINGS_REQUEST,Data);
}
int CChaletDevice::SendGetFirmwareVersion()
{
return ScheduleChaletCommand(CHALET_GET_FIRMWARE_VERSION_REQUEST,QByteArray());
}
int CChaletDevice::SendClearCommStatsRequest()
{
return ScheduleChaletCommand(CHALET_CLEAR_COMMS_STATISTICS_REQUEST,QByteArray());
}
int CChaletDevice::SendGetWifiStatusRequest()
{
return ScheduleChaletCommand(CHALET_WIFI_STATUS_REQUEST,QByteArray());
}
int CChaletDevice::SendChaletCommand(int CmdID, int DataSize, QByteArray Data)
{
if(mNetworkInterfacePtr == 0)
{
return RET_ERROR;
}
mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_DEVICE,mDeviceAddress,CmdID,DataSize,&Data);
mTotalNbRequest++;
mChaletMainStatus.mTotalNbMasterTxCmds++;
ComputeCommStats();
return RET_OK;
}
int CChaletDevice::CmdResponseReceived(int CmdID)
{
Q_UNUSED(CmdID)
if(mChaletMainStatus.mIsOnline == false)
{
mChaletMainStatus.mIsOnline = true;
qDebug("Chalet is ONLINE!");
}
//qDebug("Chalet response received from cmd: 0x%x",CmdID);
if(mPendingNetworkMsgList.size() == 0)
{
qDebug("Cmd ack received but list is empty!!!");
}
else
{
CChaletNetworkMessage Msg = mPendingNetworkMsgList.takeFirst();
if(Msg.mMessageID != CmdID)
{
qDebug("Inconsistency between active cmd and ack received [received 0x%x] != [cur 0x%x]!!!", Msg.mMessageID,CmdID);
}
}
if(mPendingNetworkMsgList.size() == 0) //If no message is left pending... schedule status request
{
ScheduleChaletStatusRequest();
mChaletStatusTimer->start(LORA_NORMAL_REQUEST_TIMEOUT);//Next status request will be sent within this timeout
}
else
{
mChaletStatusTimer->start(500); //wait a little and send the next cmd.
}
return RET_OK;
}
int CChaletDevice::ScheduleChaletStatusRequest()
{
return ScheduleChaletCommand(CHALET_GENERAL_STATUS_REQUEST,0,QByteArray());
}
int CChaletDevice::ScheduleChaletCommand(int CmdID, int DataSize, QByteArray Data)
{
Q_UNUSED(DataSize)
// if(mChaletMainStatus.mIsOnline == false)
// {
// return RET_ERROR;
// }
// CChaletNetworkMessage Command(CmdID,Data);
// mPendingNetworkMsgList.append(Command);
ScheduleChaletCommand(CmdID,Data);
return RET_OK;
}
int CChaletDevice::ScheduleChaletCommand(int CmdID, QByteArray Data)
{
// if(mChaletMainStatus.mIsOnline == false)
// {
// return RET_ERROR;
// }
if(mChaletMainStatus.mIsOnline == true && CmdID != CHALET_GENERAL_STATUS_REQUEST) //When chalet is online, send command right away if we are not waiting for an answer.
{
//if we are in nominal conditions (waiting to send a status request). Cancel the status request and send the command right away.
if((mPendingNetworkMsgList.size() == 1) &&
(mPendingNetworkMsgList.at(0).mMessageID == CHALET_GENERAL_STATUS_REQUEST) &&
mPendingNetworkMsgList.at(0).PendingResponse == false)
{
mPendingNetworkMsgList.clear();
mChaletStatusTimer->start(10); //Allow some time to breathe
}
}
CChaletNetworkMessage Command(CmdID,Data);
mPendingNetworkMsgList.append(Command);
return RET_OK;
}
int CChaletDevice::ResetCommStats()
{
mLostRequestPercentage = 0.0;
mTotalNbRequest = 0;
mNbLostRequest = 0;
mChaletMainStatus.mTotalNbMasterTxCmds = 0;
mChaletMainStatus.mMasterLostRequestCount = 0;
return RET_OK;
}
int CChaletDevice::ComputeCommStats()
{
mLostRequestPercentage = ((float)mNbLostRequest/(float)mTotalNbRequest)*100;
mChaletMainStatus.mLostRequestPercentage = mLostRequestPercentage;
// qDebug("Percent lost request: %f%%",mLostRequestPercentage);
return RET_OK;
}