Index: denali.pro =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- denali.pro (.../denali.pro) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ denali.pro (.../denali.pro) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -1,6 +1,19 @@ QT += widgets qml quick serialbus CONFIG += c++17 warn_on + +#CONFIG += disable_crc +#CONFIG += disable_keepalive + +disable_crc { + message( *** IMPORTANT : DISABLED CRC CHECK *** ) + DEFINES += DISABLE_CRC +} +disable_keepalive { + message( *** IMPORTANT : DISABLED KEEP ALIVE *** ) + DEFINES += DISABLE_KEEP_ALIVE +} + # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Refer to the documentation for the @@ -16,7 +29,8 @@ sources \ sources/storage \ sources/gui \ - sources/canbus + sources/canbus \ + sources/utility HEADERS += \ sources/applicationcontroller.h \ @@ -36,7 +50,9 @@ sources/maintimer.h \ sources/storage/filehandler.h \ sources/storage/logger.h \ - sources/storage/settings.h + sources/storage/settings.h \ + sources/utility/crc.h \ + sources/utility/types.h SOURCES += \ main.cpp \ @@ -55,7 +71,8 @@ sources/maintimer.cpp \ sources/storage/filehandler.cpp \ sources/storage/logger.cpp \ - sources/storage/settings.cpp + sources/storage/settings.cpp \ + sources/utility/crc.cpp RESOURCES += \ denali.qrc Index: main.cpp =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- main.cpp (.../main.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ main.cpp (.../main.cpp) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -75,12 +75,14 @@ //! - Initializing CanBus Interface _CanInterface->init(); + _CanInterface->enableConsoleOut(false); //! - Initializing CanBus Message Handler _MessageHandler->init(); //! - Initializing CanBus Message Dispatcher _MessageDispatcher->init(); + _MessageDispatcher->enableConsoleOut(false); //! - Initializing Application Controller _ApplicationController->init(); Index: sources/canbus/caninterface.cpp =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/canbus/caninterface.cpp (.../caninterface.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/canbus/caninterface.cpp (.../caninterface.cpp) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -29,7 +29,7 @@ * \brief Caninterface Constructor * \param parent object */ -CanInterface::CanInterface(QObject *parent) : QObject(parent) {} +CanInterface::CanInterface(QObject *parent) : QObject(parent) { } /*! * \brief CanInterface Initialization @@ -126,13 +126,22 @@ return false; return _canDevice->writeFrame(vFrame);} -void CanInterface::consoleOut(const QCanBusFrame &vFrame, const QString &vView) +void CanInterface::consoleOut(const QCanBusFrame &vFrame) { + if ( ! _enableConsoleOut ) return; + const QString time = QString::fromLatin1("%1.%2 ") .arg(vFrame.timeStamp().seconds(), 10, 10, QLatin1Char(' ')) .arg(vFrame.timeStamp().microSeconds() / 100, 4, 10, QLatin1Char('0')); const QString flags = frameFlags(vFrame); - qDebug() << time + flags + vView; + QString view; + if (vFrame.frameType() == QCanBusFrame::ErrorFrame) { + view = _canDevice->interpretErrorFrame(vFrame); + } + else { + view = vFrame.payload().toHex('.').replace(QByteArray("a5"),QByteArray("\033[1;33mA5\033[0m")); + } + fprintf(stderr, "%s %s %i %s\n", time.toLatin1().constData(), flags.toLatin1().constData(), vFrame.frameId(), view.toLatin1().constData()); } /*! @@ -217,18 +226,7 @@ while (_canDevice->framesAvailable()) { const QCanBusFrame frame = _canDevice->readFrame(); - - if (_consoleOutEnabled) { - QString view; - if (frame.frameType() == QCanBusFrame::ErrorFrame) { - view = _canDevice->interpretErrorFrame(frame); - } - else { - view = frame.toString(); - } - consoleOut(frame, view); - } - + consoleOut(frame); emit didFrameReceive(frame); } } Index: sources/canbus/caninterface.h =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/canbus/caninterface.h (.../caninterface.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/canbus/caninterface.h (.../caninterface.h) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -52,21 +52,21 @@ QCanBusDevice *_canDevice = nullptr; qint64 _numberFramesWritten = 0; QString _canStatus = ""; - bool _consoleOutEnabled = false; + bool _enableConsoleOut = false; // Singleton SINGLETON_DECL(CanInterface) public: bool init(); void quit(); QString status() const; - void consoleOutEnabled(bool vEnabled) { _consoleOutEnabled = vEnabled; } + void enableConsoleOut(bool vEnabled) { _enableConsoleOut = vEnabled; } private: void initConnections(); - void status (const QString &vDescription, QString vError = ""); + void status (const QString &vDescription, QString vError = ""); bool transmit (const QCanBusFrame &vFrame); - void consoleOut (const QCanBusFrame &vFrame, const QString &vView); + void consoleOut (const QCanBusFrame &vFrame); static QString frameFlags(const QCanBusFrame &frame); @@ -80,7 +80,7 @@ void onFrameTransmit (const QCanBusFrame &vFrame); void onFrameReceive (); void onFrameError (QCanBusDevice::CanBusError vError); - void onFrameWrittern (qint64 vFramesCount); + void onFrameWrittern (qint64 vFramesCount); }; } Index: sources/canbus/messagebuilder.cpp =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/canbus/messagebuilder.cpp (.../messagebuilder.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/canbus/messagebuilder.cpp (.../messagebuilder.cpp) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -17,6 +17,8 @@ #include // Project +#include "crc.h" + // namespace using namespace Can; @@ -62,8 +64,7 @@ void MessageBuilder::addData(QByteArray &vPayload, GuiActionType vAction, const QByteArray &vData) { - quint16 i = static_cast(vAction); - quint8 len = payloadLen[i]; + quint8 len = payloadLen[vAction]; // if len has been set to max(255) // it means it has no limit and can be as long as 255 bytes if (len == eLenMaxData) { @@ -79,63 +80,73 @@ void MessageBuilder::addCRC(QByteArray &vPayload) { - vPayload += calcCRC(vPayload); + // sync byte should not be passed for crc calculation + vPayload += calcCRC(vPayload.mid(1)); } void MessageBuilder::addPadding(QByteArray &vPayload) { vPayload = vPayload.leftJustified(eLenCanFrame, '\0'); } +// TODO : This section better to be in the MessageModel quint8 MessageBuilder::calcCRC(const QByteArray &vData) { - // TODO : calcCRC has not been used yet - Q_UNUSED(vData) -#ifdef QT_DEBUG - return ePayload_Sync; -#else - return '\0'; -#endif + quint8 crc = crc8(vData); + return crc; } // CRC is always next byte after Data +// TODO : This section better to be in the MessageModel bool MessageBuilder::checkCRC(const QByteArray &vData) { -#ifdef QT_DEBUG - //qDebug() << "qChecksum(\"0\",1) : " << qChecksum("\0",1); - // TODO : If a Message ID has not data does it still have CRC ? - if ( ! vData.length()) return false; +#ifndef DISABLE_CRC + int len = vData.length(); + if ( ! len ) return false; quint8 crc = vData.back(); - bool ok = calcCRC(vData) == crc; + quint8 got = calcCRC(vData.mid(0, len - 1)); + bool ok = got == crc; + // it's very good but I'm not sure if it's correct. + //bool ok = calcCRC(vData) == 0; + if ( ! ok ) { + qDebug() << "ch crc :" << hex << got << crc << vData.toHex('.'); + } return ok; #else - Q_UNUSED(vData) return true; #endif - - } -bool MessageBuilder::buildMessage(const QByteArray &vPayload, Message &vMessage) +bool MessageBuilder::buildMessage(const QByteArray &vPayload, Message &vMessage, Can_Id vCan_Id) { QByteArray mPayload = vPayload; - if (vMessage.data.isEmpty()) { // message is empty so expected a header + if (vMessage.data.isEmpty()) { // message is empty so expected a header if (hasSyncByte(mPayload)) { // Got header - vMessage.actionId = getActionId(mPayload); - vMessage.length = getLength (mPayload); - vMessage.data = getData (mPayload, vMessage.length); + consoleOut(vPayload, true, vCan_Id); + vMessage.can_id = vCan_Id; + vMessage.head = getHeader (mPayload); // keep header before taking it out of the payload. doesn't affect payload + vMessage.actionId = getActionId (mPayload); + vMessage.length = getLength (mPayload); + vMessage.data = getData (mPayload, vMessage.length); vMessage.initialized = true; } else { // Expected Header but got pure data - qDebug() << "ERROR :" << "Expected Header, got frame without Sync byte"; + printPayload(vPayload, false ,vCan_Id); + qDebug() << "ERROR :" << tr("Expected Header, got frame without Sync byte"); return false; } } else { + consoleOut(vPayload, false ,vCan_Id); vMessage.data += vPayload.mid(0, vMessage.length - vMessage.data.length()); } + // TODO : This section better to be in the MessageModel + // and when Message model identifies the message is complete + // will SIGNAL builder to check for crc. if (vMessage.isComplete()) { - if ( ! checkCRC(vMessage.data) ) { // CRC is always next byte after Data - qDebug() << "ERROR :" << "CRC error"; + consoleOut("", false, Can_Id::eChlid_NONE); + QByteArray crcData = vMessage.head + vMessage.data; + if ( ! checkCRC(crcData) ) { // CRC is always next byte after Data + qDebug() << "ERROR :" << tr("CRC error"); return false; } } @@ -153,6 +164,15 @@ return false; } +QByteArray MessageBuilder::getHeader(const QByteArray &vPayload) +{ + QByteArray headInfo; + for (int i = 0; i < eLenHeaderInfo; i++) { + headInfo += vPayload[i]; + } + return headInfo; +} + GuiActionType MessageBuilder::getActionId(QByteArray &vPayload) { quint16 mActionId; @@ -184,3 +204,42 @@ return mData; } +void MessageBuilder::printPayload(const QByteArray &vPayload, bool vIsHeader, Can_Id vCan_Id, bool vUseColor) +{ + if (vCan_Id == Can_Id::eChlid_NONE) { + qDebug() << " "; + return; + } + QByteArray view; + if (vUseColor) { + QList byteList; + byteList = vPayload.toHex('.').split('.'); + for (int i = 0; i < byteList.length(); i++) { + if (vIsHeader) { + if(i == 0) { + byteList[i] = QByteArray("\033[32m") + byteList[i].constData(); + } + if (i == 1 || i == 2) { + byteList[i] = QByteArray("\033[33m") + byteList[i].constData(); + } + if (i > 2) { + byteList[i] = QByteArray("\033[36m") + byteList[i].constData() + QByteArray("\033[0m"); + } + } else { + byteList[i] = QByteArray("\033[36m") + byteList[i].constData() + QByteArray("\033[0m"); + } + } + view = GuiActions::toHexString(vCan_Id, false, 3).toLatin1() + " " + byteList.join('.'); + fprintf(stderr, "%s\n", view.constData()); + } else { + view = GuiActions::toHexString(vCan_Id, false, 3).toLatin1() + " " + vPayload.toHex('.'); + fprintf(stderr, "%s\n", view.constData()); + } +} + +void MessageBuilder::consoleOut(const QByteArray &vPayload, bool vIsHeader, Can_Id vCan_Id, bool vUseColor) +{ + if ( ! _enableConsoleOut) return; + printPayload(vPayload, vIsHeader, vCan_Id, vUseColor); + +} Index: sources/canbus/messagebuilder.h =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/canbus/messagebuilder.h (.../messagebuilder.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/canbus/messagebuilder.h (.../messagebuilder.h) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -50,27 +50,36 @@ { Q_OBJECT - void addSyncByte ( QByteArray &vPayload); - void addActionId ( QByteArray &vPayload, GuiActionType vAction); - void addData ( QByteArray &vPayload, GuiActionType vAction, const QByteArray &vData); - void addCRC ( QByteArray &vPayload); - void addPadding ( QByteArray &vPayload); + bool _enableConsoleOut = false; - quint8 calcCRC (const QByteArray &vData); - bool checkCRC (const QByteArray &vData); + void addSyncByte ( QByteArray &vPayload); + void addActionId ( QByteArray &vPayload, GuiActionType vAction); + void addData ( QByteArray &vPayload, GuiActionType vAction, const QByteArray &vData); + void addCRC ( QByteArray &vPayload); + void addPadding ( QByteArray &vPayload); - bool hasSyncByte ( QByteArray &vPayload); - GuiActionType getActionId ( QByteArray &vPayload); - int getLength ( QByteArray &vPayload); - QByteArray getData ( QByteArray &vPayload, int vLen); + quint8 calcCRC (const QByteArray &vData); + bool checkCRC (const QByteArray &vData); + bool hasSyncByte ( QByteArray &vPayload); + QByteArray getHeader (const QByteArray &vPayload); + GuiActionType getActionId ( QByteArray &vPayload); + int getLength ( QByteArray &vPayload); + QByteArray getData ( QByteArray &vPayload, int vLen); + + void printPayload(const QByteArray &vPayload, bool vIsHeader, Can_Id vCan_Id, bool vUseColor = true); + void consoleOut (const QByteArray &vPayload, bool vIsHeader, Can_Id vCan_Id, bool vUseColor = true); + public: explicit MessageBuilder(QObject *parent = nullptr); // build message to be sent frame by frame FrameList buildFrames ( GuiActionType vAction , const QByteArray &vData); // build message from received frames - bool buildMessage (const QByteArray &vPayload, Message &vMessage); + bool buildMessage (const QByteArray &vPayload, Message &vMessage, Can_Id vCan_Id); + + void enableConsoleOut( bool vEnabled) { _enableConsoleOut = vEnabled; } + signals: public slots: Index: sources/canbus/messagedispatcher.cpp =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/canbus/messagedispatcher.cpp (.../messagedispatcher.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/canbus/messagedispatcher.cpp (.../messagedispatcher.cpp) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -61,7 +61,7 @@ void MessageDispatcher::keepAlive() { -#ifndef QT_DEBUG +#ifndef DISABLE_KEEP_ALIVE QVariantList mData; mData += static_cast(GuiActionData::NoData); actionTransmit(GuiActionType::KeepAlive, mData); @@ -75,29 +75,13 @@ _messageList[vCanId].append(Message()); } - // build the message - if (! _builder.buildMessage(vPayload, _messageList[vCanId].last())) { - // Test - for (const auto &key : _messageList.keys()) { - for (const auto &item : _messageList[key]) { - qDebug() << "item :" << key << item.actionId << item.data; - } - } - qDebug() << ""; + if (! _builder.buildMessage(vPayload, _messageList[vCanId].last(), vCanId)) { _messageList[vCanId].removeLast(); return; } Message mMessage = _messageList[vCanId].last(); - // Test - for (const auto &key : _messageList.keys()) { - for (const auto &item : _messageList[key]) { - qDebug() << "item :" << key << item.actionId << item.data; - } - } - qDebug() << ""; - // TODO : must be moved to a MessageModel class if (mMessage.isComplete()) { GuiActionType mActionId; @@ -117,7 +101,7 @@ void MessageDispatcher::actionTransmit(GuiActionType vActionId, const QVariantList &vData) { QByteArray mData; - if (! _interpreter.interpretAction(vActionId, vData, mData)) { + if (! _interpreter.interpretMessage(vActionId, vData, mData)) { qDebug() << "Error :" << "Incorrect Message"; return; } Index: sources/canbus/messagedispatcher.h =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/canbus/messagedispatcher.h (.../messagedispatcher.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/canbus/messagedispatcher.h (.../messagedispatcher.h) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -88,6 +88,7 @@ SINGLETON_DECL(MessageDispatcher) public: void init(); + void enableConsoleOut(bool vEnable) { _builder.enableConsoleOut(vEnable); } private: void initConnections(); Index: sources/canbus/messageglobals.h =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/canbus/messageglobals.h (.../messageglobals.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/canbus/messageglobals.h (.../messageglobals.h) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -26,12 +26,11 @@ * \brief Payload Length * \details List of each action acceptable data length in the whole message packet. */ -const QHash payloadLen { -// {/*GuiActionType::PowerOff*/ 0x0100, 1}, -// {/*GuiActionType::Check_In*/ 0x0700, 0} - {static_cast(GuiActionType::PowerOff ), 1}, - {static_cast(GuiActionType::KeepAlive), 0}, - {static_cast(GuiActionType::String ), 255}, +const QHash payloadLen { + {GuiActionType::PowerOff , 1}, + {GuiActionType::KeepAlive , 0}, + {GuiActionType::BloodFlow , 24}, + {GuiActionType::String , 255}, }; /*! @@ -48,21 +47,22 @@ * \details Global information for each message frame. */ enum Frame_Data : quint8 { - eLenCanFrame = 8, - eLenMaxHeaderData = 3, - eLenMaxData = 255, + eLenCanFrame = 8, ///< The length of each can frame. Should be padded by 0x00 if is less. + eLenHeaderInfo = 3, ///< The Header length witch is included in CRC after Sync byte + eLenMaxHeaderData = 3, ///< Maximum data byte can be in one frame as header data portion + eLenMaxData = 255, ///< Maximum data length in a Can Message since data length value kept in one byte - eLenSyncByte = 1, - eLenActionId = 2, - eLenLength = 1, - + eLenSyncByte = 1, ///< The length of Sync byte at the beginning of each header frame + eLenActionId = 2, ///< The length of Message ID bytes (2) at the beginning of each header frame after sync + eLenLength = 1, ///< The length of data length value byte at the beginning of each header frame after Message ID }; /*! * \brief The Can_Id enum * \details The Valid Can Bus Message Id of each frame */ enum Can_Id : quint16 { + eChlid_NONE = 0x000, // Broadcasts //// Alarm eChlid_HD_Alarm = 0x001, ///< HD alarm broadcast @@ -90,9 +90,11 @@ * \brief The Message struct * \details The message structure after it's been glued together. */ -struct Message { // TODO : Should be converted to MessageModel +struct Message { // TODO : Should be converted to MessageModel class // no time left for now !!! + Can_Id can_id; GuiActionType actionId = GuiActionType::Unknown; int length = 0; + QByteArray head; QByteArray data; bool initialized = false; bool isEmpty () { return !initialized || !data.length(); } Index: sources/canbus/messageinterpreter.cpp =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/canbus/messageinterpreter.cpp (.../messageinterpreter.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/canbus/messageinterpreter.cpp (.../messageinterpreter.cpp) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -13,6 +13,10 @@ */ #include "messageinterpreter.h" +// Qt + +// Project + using namespace Can; MessageInterpreter::MessageInterpreter(QObject *parent) : QObject(parent) { } @@ -32,7 +36,7 @@ return ok; } -bool MessageInterpreter::interpretAction(const GuiActionType &vActionId, const QVariantList &vData, QByteArray &vPayload) +bool MessageInterpreter::interpretMessage(const GuiActionType &vActionId, const QVariantList &vData, QByteArray &vPayload) { bool ok = true; vPayload.clear(); @@ -44,17 +48,25 @@ if (l >= ix + 1) { quint8 tmp = vData[ix].toUInt(); vPayload += tmp; + } else { + QString mActionIdHexString = GuiActions::toHexString(vActionId); + qDebug() << "ERROR :" << tr("Incorrect data for Message ID (UI) '%1'").arg(mActionIdHexString); + ok = false; } break; case GuiActionType::KeepAlive: + // Nothing needs to be done. + // KeepAlive has No data. + // Mentioned in the switch/case to be registered as a valid message. break; case GuiActionType::String: vPayload = fromVariant(vData[0]); break; default: - qDebug() << "ERROR :" << "Unknown Message ID"; + QString mActionIdHexString = GuiActions::toHexString(vActionId); + qDebug() << "ERROR :" << tr("Unknown Message ID (UI) '%1'").arg(mActionIdHexString); ok = false; break; } @@ -74,32 +86,49 @@ bool MessageInterpreter::interpretMessage_HD(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData) { - bool ok = true; - int l = vMessage.data.length(); - quint8 ix = 0; - quint16 id = static_cast(vActionId); - vActionId = vMessage.actionId; + bool ok = true; + vActionId = vMessage.actionId; vData.clear(); switch (vActionId) { // notice we are in receive mode - case GuiActionType::PowerOff: - ix = static_cast(GuiActionIndx::PowerOff_ShowHide); - if (l >= ix + 1) { - quint8 tmp = vMessage.data[ix]; - vData += tmp; - } else { - qDebug() << "ERROR :" << tr("Incorrect data for MessageId %1").arg(id); - ok = false; + case GuiActionType::PowerOff: { + quint8 mShowHide; + ok = getPowerOffData(vMessage, mShowHide); + if (ok) { + vData += mShowHide; } break; - case GuiActionType::BloodFlow: - ok = false; + } + + case GuiActionType::BloodFlow: { + types::I32 i32 ; + types::F32 f32_1; + types::F32 f32_2; + types::F32 f32_3; + types::F32 f32_4; + types::F32 f32_5; + ok = getBloodFlowData(vMessage, i32, f32_1, f32_2, f32_3, f32_4, f32_5); + if (ok) { + vData += i32 .value; + vData += f32_1.value; + vData += f32_2.value; + vData += f32_3.value; + vData += f32_4.value; + vData += f32_5.value; + } break; - default: - qDebug() << "ERROR :" << "Unknown Message ID"; + } + + case GuiActionType::Alarm: + break; + + default: { + QString mActionIdHexString = GuiActions::toHexString(vMessage.actionId); + qDebug() << "ERROR :" << tr("Unknown Message ID (HD) '%1'").arg(mActionIdHexString); ok = false; break; } + } return ok; } @@ -108,6 +137,87 @@ Q_UNUSED(vMessage ); Q_UNUSED(vActionId); Q_UNUSED(vData ); - // No data have been interpreted from GD yet + // No data have been interpreted from DG yet return false; } + +bool MessageInterpreter::getBloodFlowData(const Message &vMessage, types::I32 &vI32, types::F32 &vF32_1, types::F32 &vF32_2, types::F32 &vF32_3, types::F32 &vF32_4, types::F32 &vF32_5) +{ + if ( vMessage.actionId != GuiActionType::BloodFlow ) { + return false; + } + if ( vMessage.data.length() < payloadLen[GuiActionType::BloodFlow] ) { + QString mActionIdHexString = GuiActions::toHexString(vMessage.actionId); + qDebug() << "ERROR :" << tr("Incorrect data for Message ID (HD) '%1'").arg(mActionIdHexString); + return false; + } + int i = 0; + int p = 0; + int j = 0; + + p += 4; + j = 0; + while (i < p) { + vI32.bytes[j] = vMessage.data[i]; + j++; + i++; + } + + p += 4; + j = 0; + while (i < p) { + vF32_1.bytes[j] = vMessage.data[i]; + j++; + i++; + } + + p += 4; + j = 0; + while (i < p) { + vF32_2.bytes[j] = vMessage.data[i]; + j++; + i++; + } + + p += 4; + j = 0; + while (i < p) { + vF32_3.bytes[j] = vMessage.data[i]; + j++; + i++; + } + + p += 4; + j = 0; + while (i < p) { + vF32_4.bytes[j] = vMessage.data[i]; + j++; + i++; + } + + p += 4; + j = 0; + while (i < p) { + vF32_5.bytes[j] = vMessage.data[i]; + j++; + i++; + } + + return true; +} + +bool MessageInterpreter::getPowerOffData(const Message &vMessage, quint8 &vShowHide) +{ + bool ok = true; + int l = vMessage.data.length(); + quint8 ix = static_cast(GuiActionIndx::PowerOff_ShowHide); + if (l >= ix + 1) { + quint8 tmp = vMessage.data[ix]; + vShowHide = tmp; + } else { + QString mActionIdHexString = GuiActions::toHexString(vMessage.actionId); + qDebug() << "ERROR :" << tr("Incorrect data for Message ID (HD) '%1'").arg(mActionIdHexString); + ok = false; + } + return ok; +} Index: sources/canbus/messageinterpreter.h =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/canbus/messageinterpreter.h (.../messageinterpreter.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/canbus/messageinterpreter.h (.../messageinterpreter.h) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -19,6 +19,7 @@ // Project #include "guiglobals.h" #include "messageglobals.h" +#include "types.h" using namespace Gui; namespace Can { @@ -31,12 +32,18 @@ bool interpretMessage_HD(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData); bool interpretMessage_DG(const Message &vMessage, GuiActionType &vActionId, QVariantList &vData); + + bool getBloodFlowData (const Message &vMessage, + types::I32 &vI32 , + types::F32 &vF32_1, types::F32 &vF32_2, types::F32 &vF32_3, types::F32 &vF32_4, types::F32 &vF32_5 ); + bool getPowerOffData (const Message &vMessage, quint8 &vShowHide); + public: explicit MessageInterpreter(QObject *parent = nullptr); // interpret the data into GUI understandable Actions/Data bool interpretMessage(const Can_Id vCan_Id, const Message &vMessage, GuiActionType &vActionId, QVariantList &vData); - bool interpretAction (const GuiActionType &vActionId, const QVariantList &vData, QByteArray &vPayload); + bool interpretMessage(const GuiActionType &vActionId, const QVariantList &vData, QByteArray &vPayload); signals: Index: sources/gui/guiglobals.cpp =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/gui/guiglobals.cpp (.../guiglobals.cpp) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/gui/guiglobals.cpp (.../guiglobals.cpp) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -65,4 +65,13 @@ }); _viewer->setSource(QStringLiteral("qrc:/main.qml")); } + + QString GuiActions::toHexString(quint16 vValue, bool vWith0x, quint8 vLen) { + if ( vWith0x ) { + return "0x" + QString("%1").arg(vValue,0,16).rightJustified(vLen, '0'); + } else { + return QString("%1").arg(vValue,0,16).rightJustified(vLen, '0'); + } + } + } Index: sources/gui/guiglobals.h =================================================================== diff -u -r1732e83d2a0308b9c706f37d6d7724a364bbff2a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/gui/guiglobals.h (.../guiglobals.h) (revision 1732e83d2a0308b9c706f37d6d7724a364bbff2a) +++ sources/gui/guiglobals.h (.../guiglobals.h) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -27,14 +27,17 @@ Q_GADGET explicit GuiActions(); public: - enum class GuiActionsType_Enum /*: quint16 QML doesn't support*/ { + enum /*class*/ GuiActionsType_Enum /*: quint16 QML doesn't support*/ { Unknown = 0x0000, PowerOff = 0x0100, KeepAlive = 0x0700, BloodFlow = 0x0500, + Alarm = 0x0200, ///< ? + String = 0xFFFF, }; + static QString toHexString(quint16 vValue, bool vWith0x = true, quint8 vLen = 4); enum class GuiActionsIndx_Enum { PowerOff_ShowHide = 0, Index: sources/gui/qml/components/TouchRect.qml =================================================================== diff -u -r174d5078531f9dfbe9cdc45274b852984bb72647 -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/gui/qml/components/TouchRect.qml (.../TouchRect.qml) (revision 174d5078531f9dfbe9cdc45274b852984bb72647) +++ sources/gui/qml/components/TouchRect.qml (.../TouchRect.qml) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -28,6 +28,8 @@ property alias text : _text property alias button : _mouseArea + property bool animate : false + width : Variables.touchRectWidth height : Variables.touchRectHeight radius : Variables.touchRectRadius @@ -43,5 +45,16 @@ } MouseArea { id: _mouseArea anchors.fill: parent + onPressed: { + if ( animate ) { + _clickAnimation.running = true + } + } } + + SequentialAnimation { id: _clickAnimation + running: false + PropertyAnimation { target: _root; property: "color"; to: _root.border.color; duration: 50; } + PropertyAnimation { target: _root; property: "color"; to: _root.color ; duration: 50; } + } } Index: sources/gui/qml/pages/SettingsHome.qml =================================================================== diff -u -r2085b749d1d0aafe823e840f5aa0bc88a340798a -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/gui/qml/pages/SettingsHome.qml (.../SettingsHome.qml) (revision 2085b749d1d0aafe823e840f5aa0bc88a340798a) +++ sources/gui/qml/pages/SettingsHome.qml (.../SettingsHome.qml) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -31,6 +31,7 @@ TouchRect { id : _poweroff width: 150 height: Variables.logoHeight + animate: true anchors { top : parent.top right : parent.right Index: sources/gui/qml/pages/TreatmentStart.qml =================================================================== diff -u -r174d5078531f9dfbe9cdc45274b852984bb72647 -r460df093c4475816fc25d6b4c3ebfc50424ccca3 --- sources/gui/qml/pages/TreatmentStart.qml (.../TreatmentStart.qml) (revision 174d5078531f9dfbe9cdc45274b852984bb72647) +++ sources/gui/qml/pages/TreatmentStart.qml (.../TreatmentStart.qml) (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -17,6 +17,8 @@ import QtQuick.Controls 2.12 // Project +import Gui.Actions 0.1; + // Qml imports import "qrc:/globals" import "qrc:/components" @@ -39,4 +41,75 @@ text: qsTr("Start Treatment Placeholder") } } + + Column { + spacing: 20 + topPadding: 100 + leftPadding: 10 + Text { + id: _U32 + text: qsTr("") + width: 250 + horizontalAlignment: Text.AlignRight + color: Colors.textMain + font.pixelSize: Fonts.fontPixelTitle + } + Text { + id: _F32_1 + text: qsTr("") + width: 250 + horizontalAlignment: Text.AlignRight + color: Colors.textMain + font.pixelSize: Fonts.fontPixelTitle + } + Text { + id: _F32_2 + text: qsTr("") + width: 250 + horizontalAlignment: Text.AlignRight + color: Colors.textMain + font.pixelSize: Fonts.fontPixelTitle + } + Text { + id: _F32_3 + text: qsTr("") + width: 250 + horizontalAlignment: Text.AlignRight + color: Colors.textMain + font.pixelSize: Fonts.fontPixelTitle + } + Text { + id: _F32_4 + text: qsTr("") + width: 250 + horizontalAlignment: Text.AlignRight + color: Colors.textMain + font.pixelSize: Fonts.fontPixelTitle + } + Text { + id: _F32_5 + text: qsTr("") + width: 250 + horizontalAlignment: Text.AlignRight + color: Colors.textMain + font.pixelSize: Fonts.fontPixelTitle + } + } + Connections { + target: _GuiView + onDidActionReceive: { + if ( ! visible ) return; + switch(vAction) { + case GuiActions.BloodFlow: + //console.debug(vData) + _U32 .text = vData[0]; + _F32_1.text = vData[1].toFixed(2); + _F32_2.text = vData[2].toFixed(2); + _F32_3.text = vData[3].toFixed(2); + _F32_4.text = vData[4].toFixed(2); + _F32_5.text = vData[5].toFixed(2); + break; + } + } + } } Index: sources/utility/crc.cpp =================================================================== diff -u --- sources/utility/crc.cpp (revision 0) +++ sources/utility/crc.cpp (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -0,0 +1,59 @@ +/*! + * + * Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. + * \copyright \n + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, \n + * IN PART OR IN WHOLE, \n + * WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. \n + * + * \file crc.cpp + * \date 2019/12/14 + * \author Behrouz NematiPour + * + */ + +#include "crc.h" + +/*! The CRC table + * This code has been borrowed from Firmware repository + * This should be exactly the same replica of that copy. + * PLEASE DO UPDATE ON ANY MODIFICATION IN FIRMWARE OF SOFTWARE + */ +const unsigned char crc8_table[] = { + 0, 49, 98, 83, 196, 245, 166, 151, 185, 136, 219, 234, 125, 76, 31, 46, + 67, 114, 33, 16, 135, 182, 229, 212, 250, 203, 152, 169, 62, 15, 92, 109, + 134, 183, 228, 213, 66, 115, 32, 17, 63, 14, 93, 108, 251, 202, 153, 168, + 197, 244, 167, 150, 1, 48, 99, 82, 124, 77, 30, 47, 184, 137, 218, 235, + 61, 12, 95, 110, 249, 200, 155, 170, 132, 181, 230, 215, 64, 113, 34, 19, + 126, 79, 28, 45, 186, 139, 216, 233, 199, 246, 165, 148, 3, 50, 97, 80, + 187, 138, 217, 232, 127, 78, 29, 44, 2, 51, 96, 81, 198, 247, 164, 149, + 248, 201, 154, 171, 60, 13, 94, 111, 65, 112, 35, 18, 133, 180, 231, 214, + 122, 75, 24, 41, 190, 143, 220, 237, 195, 242, 161, 144, 7, 54, 101, 84, + 57, 8, 91, 106, 253, 204, 159, 174, 128, 177, 226, 211, 68, 117, 38, 23, + 252, 205, 158, 175, 56, 9, 90, 107, 69, 116, 39, 22, 129, 176, 227, 210, + 191, 142, 221, 236, 123, 74, 25, 40, 6, 55, 100, 85, 194, 243, 160, 145, + 71, 118, 37, 20, 131, 178, 225, 208, 254, 207, 156, 173, 58, 11, 88, 105, + 4, 53, 102, 87, 192, 241, 162, 147, 189, 140, 223, 238, 121, 72, 27, 42, + 193, 240, 163, 146, 5, 52, 103, 86, 120, 73, 26, 43, 188, 141, 222, 239, + 130, 179, 224, 209, 70, 119, 36, 21, 59, 10, 89, 104, 255, 206, 157, 172 +}; + +/*! + * \brief crc8 + * \param vData the data which to be used for crc8 generation + * \return a byte contains the generated crc8. + * \note this algorithm borrowed from Firmware repository + * some changed has been made to be able to work with Qt libraries. + */ +quint8 crc8(const QByteArray &vData) +{ + quint8 crc = 0; + int len = vData.length(); + int i = 0; + while ( len-- > 0 ) + { + crc = crc8_table[ (static_cast(vData[i])) ^ crc ]; + i++; + } + return crc; +} Index: sources/utility/crc.h =================================================================== diff -u --- sources/utility/crc.h (revision 0) +++ sources/utility/crc.h (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -0,0 +1,18 @@ +/*! + * + * Copyright (c) 2019-2019 Diality Inc. - All Rights Reserved. + * \copyright \n + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, \n + * IN PART OR IN WHOLE, \n + * WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. \n + * + * \file crc.h + * \date 2019/12/14 + * \author Behrouz NematiPour + * + */ +#pragma once + +#include + +quint8 crc8(const QByteArray &vData); Index: sources/utility/types.h =================================================================== diff -u --- sources/utility/types.h (revision 0) +++ sources/utility/types.h (revision 460df093c4475816fc25d6b4c3ebfc50424ccca3) @@ -0,0 +1,28 @@ +/*! + * + * 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. + * + * file types.h + * date 12/13/2019 + * author Behrouz NematiPour + * + */ +#pragma once + +namespace types { + +union F32{ + float value = 0; + quint8 bytes[sizeof(float)]; +}; + +union I32 { + qint32 value = 0; + quint8 bytes[sizeof(qint32)]; +}; + +}