#include "ChaletLoraDevice.h" #include "GlobalDefine.h" CChaletLoraDevice::CChaletLoraDevice(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())); } CChaletLoraDevice::~CChaletLoraDevice() { delete mChaletStatusTimer; } int CChaletLoraDevice::Start() { ScheduleChaletStatusRequest(); mChaletStatusTimer->start(1000); return RET_OK; } int CChaletLoraDevice::NewDeviceFrameReceived(int DeviceID, int DeviceAddress, int MessageID, int DataSize, QByteArray Data) { switch(MessageID) { case CHALET_ACK: { CmdResponseReceived(CHALET_ACK); break; } case CHALET_GENERAL_STATUS_RESPONSE: { float temp; qint16 temp2; qDebug("Chalet Status RX"); char VoltageArray[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; mChaletMainStatus.mStatusToggleBit = !mChaletMainStatus.mStatusToggleBit; CmdResponseReceived(CHALET_GENERAL_STATUS_REQUEST); qDebug("voltage: %f",mChaletMainStatus.mBatteryVoltage); qDebug("Current: %d",mChaletMainStatus.mBatteryCurrent); qDebug("SOC: %d",mChaletMainStatus.mBatterySOC); mChaletDataLogger.LogChaletLORAData(&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); 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: { mChaletMainStatus.mWiFiModuleStatus = Data[0]; CmdResponseReceived(CHALET_WIFI_STATUS_REQUEST); 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; } default: { return RET_ERROR; break; } } return RET_OK; } void CChaletLoraDevice::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++; } 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 CChaletLoraDevice::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 CChaletLoraDevice::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 CChaletLoraDevice::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 CChaletLoraDevice::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 CChaletLoraDevice::SendChaletCommand(int CmdID, int DataSize, QByteArray Data) { mNetworkInterfacePtr->SendNetworkMessage(ID_CHALET_DEVICE,mDeviceAddress,CmdID,DataSize,Data); return RET_OK; } int CChaletLoraDevice::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 CChaletLoraDevice::ScheduleChaletStatusRequest() { return ScheduleChaletCommand(CHALET_GENERAL_STATUS_REQUEST,0,QByteArray()); } int CChaletLoraDevice::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 CChaletLoraDevice::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; }