Index: sources/canbus/messageinterpreter.cpp =================================================================== diff -u -red85c796c2e3bd73aeda374d9a109750bd7732e3 -r56e378f7504701b9e9a9dccaf205aef2fd52c58e --- sources/canbus/messageinterpreter.cpp (.../messageinterpreter.cpp) (revision ed85c796c2e3bd73aeda374d9a109750bd7732e3) +++ sources/canbus/messageinterpreter.cpp (.../messageinterpreter.cpp) (revision 56e378f7504701b9e9a9dccaf205aef2fd52c58e) @@ -2,13 +2,14 @@ * * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. * \copyright - * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, - * IN PART OR IN WHOLE, - * WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * - * \file messageinterpreter.cpp - * \date 12/11/2019 - * \author Behrouz NematiPour + * \file messageinterpreter.cpp + * \author (last) Behrouz NematiPour + * \date (last) 20-Aug-2020 + * \author (original) Behrouz NematiPour + * \date (original) 13-Dec-2019 * */ #include "messageinterpreter.h" @@ -23,18 +24,8 @@ using namespace Can; -#define DEBUG_RECEIVE_SIGNAL(vID, vMODEL) // Debug() << #vID << #vMODEL; +#define DEBUG_RECEIVE_SIGNAL(vID, vMODEL) //qDebug() << vID << vMODEL; -// This define helps to prevent having multiple overloaded functions for each model -#define EMIT_RECEIVE_SIGNAL(vID, vMODEL) { \ - vMODEL mModel; \ - ok = prepareData(vMessage, vID, mModel, vData); \ - if ( ! ok ) return false; \ - emit didActionReceive(mModel.data()); \ - logReceived(mModel); \ - DEBUG_RECEIVE_SIGNAL(vID, vMODEL) \ -} - /*! * \brief MessageInterpreter::MessageInterpreter * \details Constructor @@ -44,6 +35,36 @@ MessageInterpreter::MessageInterpreter(QObject *parent) : QObject(parent) { } /*! + * \brief MessageInterpreter::notify + * \details Checks and prepares the model with the Message Data + * Regarding the type of message logs the message received. + * Notifies observers by emitting the didActionReceive( < Data > ) signal + * \param vMessage - The Denali message + * \param vID - The Message ID to be checked against + * \param vModel - The appropriate model for the Message Data + * \param vData - A QVariant list of the Message Data which will be used for debugging if needed. + * \return true on successful check and prepare. + */ +template +bool MessageInterpreter::notify(const Message &vMessage, QVariantList &vData, Gui::GuiActionType vIdCheck) +{ + bool ok = false; + TModel tModel; + if ( ! isValidMessage(vMessage, vIdCheck) ) return ok; + ok = tModel.fromByteArray(vMessage.data); + tModel.toVariantList(vData); + // coco begin validated : Tested manually. This code will never go false + // because the isValidMessage is catching errors. + // only is checking here for developer safety if logic has changed. + if ( ! ok ) return false; + // coco end + emit didActionReceive(tModel.data()); + logReceivedMessage(tModel); + DEBUG_RECEIVE_SIGNAL(vIdCheck, typeid(TModel).name()) + return ok; +} + +/*! * \brief MessageInterpreter::isType * \details Checks if this is the message intended to be * \param vMessage - The message @@ -60,8 +81,8 @@ /*! * \brief MessageInterpreter::isPayloadLenValid - * \details Checks if the Data length has been defined for this type od messsage - * if not logs Undefind Data Length error + * \details Checks if the Data length has been defined for this type of message + * if not logs Undefined Data Length error * if defined checks if the correct length of data is provided for this type of message. * if not logs Incorrect Data Length error * otherwise returns true @@ -83,24 +104,21 @@ return true; } -bool MessageInterpreter::isDataLenValid(const Gui::GuiActionType &vActionId, const QVariantList &vData) +/*! + * \brief MessageInterpreter::logInvalidLength + * \details Logs invalid data length for the message type vActionId + * \param vActionId - Message Type + */ +void MessageInterpreter::logInvalidLength(const Gui::GuiActionType &vActionId) { - if (vActionId == Gui::GuiActionType::ID_KeepAlive) - return true; // This message is an exception which is also used to generate fake data and it has a variable length. - - if (payloadLen[vActionId] == 0) - return true; // Message with zero length data are ok as been defined - - if (vData.length()) return true; - QString mActionIdHexString = Format::toHexString(vActionId); - LOG_DEBUG(QString("Data length for transmit Message with ID '%1'Can't be 0") + LOG_DEBUG(QString("Incorrect data length for transmit message with ID '%1'") .arg(mActionIdHexString)); - return false; } + /*! * \brief MessageInterpreter::validateMessage - * \details Validate the messgae by checking its type and data + * \details Validate the message by checking its type and data * \param vMessage - The message * \param vType - The type of the message to be checked against * \return true on valid massage @@ -125,36 +143,18 @@ QString mActionIdHexString = Format::toHexString(vMessage.actionId, false, eLenMessageIDDigits); QString logMessage = tr("Unhandled Message ID (HD)") + '\n' + QString("%1 # %2 %3") - .arg(int(vMessage.can_id), 3, 16, QChar('0')) - .arg(mActionIdHexString) - .arg(QString(vMessage.data.toHex('.'))); + .arg(int(vMessage.can_id), 3, 16, QChar('0')) + .arg(mActionIdHexString) + .arg(QString(vMessage.data.toHex('.'))); LOG_DEBUG(logMessage); } /*! - * \brief MessageInterpreter::prepareData - * \details Checks and Prepaires the model with the Message Data - * \param vMessage - The Denali message - * \param vID - The Message ID to be checked against - * \param vModel - The appropriate model for the Message Data - * \param vData - A QVariant list of the Message Data which will be used for debugging if needed. - * \return true on successful check and prepare. - */ -bool MessageInterpreter::prepareData(const Message &vMessage, Gui::GuiActionType vID, Model::MAbstract &vModel, QVariantList &vData) -{ - bool ok = false; - if ( ! isValidMessage(vMessage, vID) ) return ok; - ok = vModel.fromByteArray(vMessage.data); - vModel.toVariantList(vData); - return ok; -} - -/*! * \brief MessageInterpreter::logReceived - * \details Regarding the type of message logs the message recived. + * \details Regarding the type of message logs the message received. * \param vModel - the MAbstract model type */ -void MessageInterpreter::logReceived(const Model::MAbstract &vModel) +void MessageInterpreter::logReceivedMessage(const Model::MAbstract &vModel) { switch (vModel.typeText()) { case Model::MAbstract::Type_Enum::eDatum: @@ -184,63 +184,75 @@ QString mSenderID = "UI,"; vPayload.clear(); + int count = vData.length(); - if ( ! isDataLenValid(vActionId, vData)) return false; - switch (vActionId) { // notice we are in transmit mode - case Gui::GuiActionType::ID_PowerOff: { - quint8 state = vData[0].toUInt(); - vPayload += state; - LOG_EVENT(AdjustPowerOffRequestData(state).toString()); - } - break; + case Gui::GuiActionType::ID_Acknow: // len: 0, can have zero len + break; // No data, Just registered - case Gui::GuiActionType::ID_KeepAlive: - // Nothing needs to be done. - // KeepAlive has No data. - // Mentioned in the switch/case to be registered as a valid message. - // - // Note : added this line to be able to do the Fake Test - vPayload = Format::fromVariant(vData[0]); + + case Gui::GuiActionType::ID_KeepAlive: // len: 255, can have any len + if ( count ) { // this message has a variable length + vPayload = Format::fromVariant(vData[0]); + } LOG_EVENT(mSenderID + QString("CheckIn")); break; - case Gui::GuiActionType::ID_Acknow: - // Nothing needs to be done. - // Acknow has No data. - // Mentioned in the switch/case to be registered as a valid message. + case Gui::GuiActionType::ID_RawData: // len: 255, can have any len + if ( count ) { // this message has a variable length + vPayload = Format::fromVariant(vData[0]); + } + LOG_EVENT(mSenderID + QString("RawData")); break; - case Gui::GuiActionType::ID_RawData: - vPayload = Format::fromVariant(vData[0]); - LOG_EVENT(mSenderID + QString("RawData")); + case Gui::GuiActionType::ID_PowerOff: + if ( ! count ) { logInvalidLength(vActionId); return false; } + vPayload += Format::fromVariant(vData); + LOG_EVENT(AdjustPowerOffRequestData::toString(vData)); break; case Gui::GuiActionType::ID_AdjustBloodDialysateReq: + if ( ! count ) { logInvalidLength(vActionId); return false; } vPayload = Format::fromVariant(vData); LOG_EVENT(AdjustBloodDialysateRequestData::toString(vData)); break; case Gui::GuiActionType::ID_AdjustDurationReq: + if ( ! count ) { logInvalidLength(vActionId); return false; } vPayload = Format::fromVariant(vData); LOG_EVENT(AdjustDurationRequestData::toString(vData)); break; case Gui::GuiActionType::ID_AdjustUltrafiltrationStateReq: + if ( ! count ) { logInvalidLength(vActionId); return false; } vPayload = Format::fromVariant(vData); LOG_EVENT(AdjustUltrafiltrationStateRequestData::toString(vData)); break; case Gui::GuiActionType::ID_AdjustUltrafiltrationEditReq: + if ( ! count ) { logInvalidLength(vActionId); return false; } vPayload = Format::fromVariant(vData); LOG_EVENT(AdjustUltrafiltrationEditRequestData::toString(vData)); break; case Gui::GuiActionType::ID_AdjustUltrafiltrationConfirmReq: + if ( ! count ) { logInvalidLength(vActionId); return false; } vPayload = Format::fromVariant(vData); LOG_EVENT(AdjustUltrafiltrationConfirmRequestData::toString(vData)); break; + case Gui::GuiActionType::ID_AdjustSalineReq: + if ( ! count ) { logInvalidLength(vActionId); return false; } + vPayload = Format::fromVariant(vData); + LOG_EVENT(AdjustSalineRequestData::toString(vData)); + break; + + case Gui::GuiActionType::ID_AlarmSilenceReq: + if ( ! count ) { logInvalidLength(vActionId); return false; } + vPayload = Format::fromVariant(vData); + LOG_EVENT(AlarmSilenceRequestData::toString(vData)); + break; + default: QString mActionIdHexString = Format::toHexString(vActionId); LOG_DEBUG(mSenderID + tr("Unknown transmit Message with ID '%1'").arg(mActionIdHexString)); @@ -272,14 +284,14 @@ case eChlid_HD_Alarm: case eChlid_HD_Sync : ok = interpretMessage_HD(vMessage, vData); break; - // coco-begin-validated: Is a placeholder and There is no definition/implementation of DG communication with UI. + case eChlid_DG_HD : + case eChlid_DG_UI : - case eChlid_DG_Alarm: + // case eChlid_DG_Alarm: // commented out for now. Currently there is no message in this category. case eChlid_DG_Sync : ok = interpretMessage_DG(vMessage, vData); break; default: break; - // coco-end } return ok; } @@ -303,38 +315,44 @@ vData.clear(); switch (vMessage.actionId) { // notice we are in receive mode // ----- Debug - case Gui::GuiActionType::ID_CANBusFaultCount : ok = canbusFaultCountData (vMessage, vData); break; + case Gui::GuiActionType::ID_CANBusFaultCount : ok = canbusFaultCountData (vMessage, vData); break; // TODO : implement notify<>() // ----- Datum - case Gui::GuiActionType::ID_TreatmentTime : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_TreatmentTime , Model::MTreatmentTime ); break; - case Gui::GuiActionType::ID_BloodFlow : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_BloodFlow , Model::MBloodFlow ); break; - case Gui::GuiActionType::ID_DialysateInletFlow : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DialysateInletFlow , Model::MDialysateFlow ); break; - case Gui::GuiActionType::ID_DialysateOutletFlow : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DialysateOutletFlow , Model::MOutletFlow ); break; - case Gui::GuiActionType::ID_TreatmentRanges : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_TreatmentRanges , Model::MTreatmentRanges ); break; - case Gui::GuiActionType::ID_PressureOcclusion : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_PressureOcclusion , Model::MPressureOcclusion ); break; - case Gui::GuiActionType::ID_TreatmentStates : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_TreatmentStates , Model::MTreatmentStates ); break; + case Gui::GuiActionType::ID_TreatmentTime : ok = notify(vMessage, vData, Gui::GuiActionType::ID_TreatmentTime ); break; + case Gui::GuiActionType::ID_BloodFlow : ok = notify(vMessage, vData, Gui::GuiActionType::ID_BloodFlow ); break; + case Gui::GuiActionType::ID_DialysateInletFlow : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DialysateInletFlow ); break; + case Gui::GuiActionType::ID_DialysateOutletFlow : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DialysateOutletFlow ); break; + case Gui::GuiActionType::ID_TreatmentRanges : ok = notify(vMessage, vData, Gui::GuiActionType::ID_TreatmentRanges ); break; + case Gui::GuiActionType::ID_PressureOcclusion : ok = notify(vMessage, vData, Gui::GuiActionType::ID_PressureOcclusion ); break; + case Gui::GuiActionType::ID_TreatmentStates : ok = notify(vMessage, vData, Gui::GuiActionType::ID_TreatmentStates ); break; + case Gui::GuiActionType::ID_Saline : ok = notify(vMessage, vData, Gui::GuiActionType::ID_Saline ); break; // ----- Events - case Gui::GuiActionType::ID_HDOperationModeData : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_HDOperationModeData , Model::MHDOperationMode ); break; - case Gui::GuiActionType::ID_HDDebugText : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_HDDebugText , Model::MHDDebugText ); break; + case Gui::GuiActionType::ID_HDOperationModeData : ok = notify(vMessage, vData, Gui::GuiActionType::ID_HDOperationModeData ); break; + case Gui::GuiActionType::ID_HDDebugText : ok = notify(vMessage, vData, Gui::GuiActionType::ID_HDDebugText ); break; - case Gui::GuiActionType::ID_Acknow : ok = true; break; // Needs more investigation for EMIT_RECEIVE_SIGNAL consistency - case Gui::GuiActionType::ID_PowerOff : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_PowerOff , Model::MPowerOff ); break; - case Gui::GuiActionType::ID_ShuttingDown : ok = true; LOG_EVENT("HD,ShuttingDown"); break; // Needs more investigation for EMIT_RECEIVE_SIGNAL consistency - case Gui::GuiActionType::ID_AlarmStatus : ok = alarmStatus (vMessage, vData); break; - case Gui::GuiActionType::ID_AlarmTriggered : ok = alarmTriggered (vMessage, vData); break; - case Gui::GuiActionType::ID_AlarmCleared : ok = alarmCleared (vMessage, vData); break; + case Gui::GuiActionType::ID_Acknow : ok = true; break; // TODO : implement notify<>() + case Gui::GuiActionType::ID_PowerOff : ok = notify(vMessage, vData, Gui::GuiActionType::ID_PowerOff ); break; + case Gui::GuiActionType::ID_ShuttingDown : ok = true; LOG_EVENT("HD,ShuttingDown"); break; // TODO : implement notify<>() + case Gui::GuiActionType::ID_AlarmStatus : ok = alarmStatus (vMessage, vData); break; // TODO : implement notify<>() + case Gui::GuiActionType::ID_AlarmTriggered : ok = alarmTriggered (vMessage, vData); break; // TODO : implement notify<>() + case Gui::GuiActionType::ID_AlarmCleared : ok = alarmCleared (vMessage, vData); break; // TODO : implement notify<>() // Adjustment Response Messages - case Gui::GuiActionType::ID_AdjustDurationRsp : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_AdjustDurationRsp , Model::MAdjustDurationResponse ); break; - case Gui::GuiActionType::ID_AdjustBloodDialysateRsp : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_AdjustBloodDialysateRsp , Model::MAdjustBloodDialysateResponse ); break; - case Gui::GuiActionType::ID_AdjustUltrafiltrationStateReq : ok = adjustUltrafiltrationState (vMessage, vData); break; // Needs more investigation for EMIT_RECEIVE_SIGNAL consistency - case Gui::GuiActionType::ID_AdjustUltrafiltrationEditRsp : ok = adjustUltrafiltrationEdit (vMessage, vData); break; // Needs more investigation for EMIT_RECEIVE_SIGNAL consistency - case Gui::GuiActionType::ID_AdjustUltrafiltrationConfirmRsp : ok = adjustUltrafiltrationConfirm (vMessage, vData); break; // Needs more investigation for EMIT_RECEIVE_SIGNAL consistency + case Gui::GuiActionType::ID_AdjustDurationRsp : ok = notify(vMessage, vData, Gui::GuiActionType::ID_AdjustDurationRsp ); break; + case Gui::GuiActionType::ID_AdjustBloodDialysateRsp : ok = notify(vMessage, vData, Gui::GuiActionType::ID_AdjustBloodDialysateRsp); break; + case Gui::GuiActionType::ID_AdjustSalineRsp : ok = notify(vMessage, vData, Gui::GuiActionType::ID_AdjustSalineRsp ); break; - // unhandles messages: these will only be logged as received message + // ok = notify(vMessage, vData, Gui::GuiActionType::ID_AdjustUltrafiltrationStateReq); break; + // this message has been inherited from MAbstract and should use notify but since the response message is not standard can't use notify yet. + // when received gets payload len error and can't be interpreted. + case Gui::GuiActionType::ID_AdjustUltrafiltrationStateReq : ok = adjustUltrafiltrationState (vMessage, vData); break; // TODO : implement notify<>() + case Gui::GuiActionType::ID_AdjustUltrafiltrationEditRsp : ok = adjustUltrafiltrationEdit (vMessage, vData); break; // TODO : implement notify<>() + case Gui::GuiActionType::ID_AdjustUltrafiltrationConfirmRsp : ok = adjustUltrafiltrationConfirm (vMessage, vData); break; // TODO : implement notify<>() + + // unhandled messages: these will only be logged as received message // there has nothing been defined for these messages. - default : printUnhandled (vMessage ); break; + default : printUnhandled (vMessage ); break; } return ok; @@ -358,24 +376,23 @@ bool ok = false; vData.clear(); switch (vMessage.actionId) { // notice we are in receive mode - case Gui::GuiActionType::ID_DGCheckIn: + case Gui::GuiActionType::ID_DGCheckIn: // TODO : implement notify<>() ok = true; LOG_EVENT(QString("DG,CheckIn," + QVariant(vData).toStringList().join(','))); break; - case Gui::GuiActionType::ID_DGROPumpData : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DGROPumpData , Model::MDGROPump ); break; - case Gui::GuiActionType::ID_DGPressuresData : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DGPressuresData , Model::MDGPressures ); break; - case Gui::GuiActionType::ID_DGDrainPumpData : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DGDrainPumpData , Model::MDGDrainPump ); break; - case Gui::GuiActionType::ID_DGOperationModeData : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DGOperationModeData , Model::MDGOperationMode ); break; - case Gui::GuiActionType::ID_DGReservoirData : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DGReservoirData , Model::MDGReservoir ); break; - case Gui::GuiActionType::ID_DGValvesStatesData : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DGValvesStatesData , Model::MDGValvesStates ); break; - case Gui::GuiActionType::ID_DGHeatersData : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DGHeatersData , Model::MDGHeaters ); break; - case Gui::GuiActionType::ID_DGLoadCellReadingsData : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DGLoadCellReadingsData , Model::MDGLoadCellReadings ); break; - case Gui::GuiActionType::ID_DGTemperaturesData : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DGTemperaturesData , Model::MDGTemperatures ); break; + case Gui::GuiActionType::ID_DGROPumpData : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DGROPumpData ); break; + case Gui::GuiActionType::ID_DGPressuresData : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DGPressuresData ); break; + case Gui::GuiActionType::ID_DGDrainPumpData : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DGDrainPumpData ); break; + case Gui::GuiActionType::ID_DGOperationModeData : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DGOperationModeData ); break; + case Gui::GuiActionType::ID_DGReservoirData : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DGReservoirData ); break; + case Gui::GuiActionType::ID_DGValvesStatesData : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DGValvesStatesData ); break; + case Gui::GuiActionType::ID_DGHeatersData : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DGHeatersData ); break; + case Gui::GuiActionType::ID_DGLoadCellReadingsData : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DGLoadCellReadingsData); break; + case Gui::GuiActionType::ID_DGTemperaturesData : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DGTemperaturesData ); break; + case Gui::GuiActionType::ID_DGDebugText : ok = notify(vMessage, vData, Gui::GuiActionType::ID_DGDebugText ); break; - case Gui::GuiActionType::ID_DGDebugText : EMIT_RECEIVE_SIGNAL(Gui::GuiActionType::ID_DGDebugText , Model::MDGDebugText ); break; - - // unhandles messages: these will only be logged as received message + // unhandled messages: these will only be logged as received message // there has nothing been defined for these messages. default: printUnhandled (vMessage); @@ -441,14 +458,6 @@ emit didActionReceive(mData.data()); return ok; - - // --- an example of unit test --- // - // Types::Flags flag; - // int i = 0; - // QByteArray ba; - // ba += 0x83; ba += 0xf8; ba += 0x28; ba += 0xa1; - // Types::getBits(ba, i, flag, 32); - // qDebug() << '@' << flag << flag.toString() << ba; } /*! @@ -521,7 +530,7 @@ Model::MAdjustUltrafiltrationStateResponse mData; ok = mData.fromByteArray(vMessage.data); - LOG_EVENT("HD," + mData.toString()); + LOG_EVENT(mData.toString()); mData.toVariantList(vData); emit didActionReceive(mData.data());