/*! * * Copyright (c) 2021-2024 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 CloudSyncController.h * \author (last) Behrouz NematiPour * \date (last) 22-Apr-2024 * \author (original) Behrouz NematiPour * \date (original) 14-Oct-2021 * */ #pragma once // Qt #include #include // Project #include "main.h" // Doxygen : do not remove #include "GuiController.h" // define #define _CloudSyncController CloudSyncController::I() // forward declarations class tst_initializations; // namespace /*! * \brief The CloudSyncController class * \details Singleton class which is the main gateway of CloudSync signal/slots. * \startuml * title CloudSync Buff communication protocol * participant HD * queue CAN * database FS * participant UI * database BUF * participant CS * participant DRT * participant DCS * * skinparam sequenceMessageAlign left * * === - Manufacturing - === * == CMDx1 - Registration == * UI -> BUF : log:\n[1001] Registration Request * BUF -> CS : notify * CS -> DRT : * DRT -> DCS : * DCS -> DRT : DONE * DCS -> CS : DONE * * == CMDx3 - Credentials - Save == * DCS -> CS : credentials * CS -> FS : write:\n - path_to_client_certificate_pem,\n - client_private_key_pem\n - client_public_key_pem * CS -> BUF : log:\n[2003] Credentials Store Request\n - path_to_client_certificate_pem\n - path_to_client_private_key_pem\n - path_to_client_public_key_pem * BUF -> UI : notify * UI -> FS : write:\nStore it in the encrypted partition * UI -> BUF : log:\n[1003] Credentials Store Response * * == CMDx4 - Credentials - Read == * CS -> DCS : start a Session * DCS -> CS : authentication request * CS -> BUF : log:\n[2004] Credentials Read Request * BUF -> UI : notify * UI -> FS : copy credentials on tmp * UI -> BUF : log:\n[1004] Credentials Read Response\n - path_to_credentials * BUF -> CS : notify * CS -> FS : read credentials * CS -> DCS : authentication response * * == CMDx5 - Factory Reset == * DCS -> CS : Registration Complete * CS -> BUF : log:\n[2005] Factory Reset Request * BUF -> UI : notify * UI -> FS : factory reset: clear the related information from the system. * UI -> BUF : log:\n[1002] Factory Reset Response * BUF -> CS : notify * * === - Normal Operation - === * * == CMDx7 - Send Treatment Report == * CS -> BUF : log:\n[2002] Device Info Request * BUF -> UI : notify * UI -> BUF : log:\n[1002] Device Info Response \n - HD Serial\n - DG Serial\n - SW Version * BUF -> CS : notify * * == CMDx6 - Device State == * CS -> BUF : log:\n[2006] Device State Request * HD -> CAN : msg:\n[0x37] Device State Broadcast * CAN -> UI : notify * UI -> BUF : log:\n[1006] Device State (Top History)\n - HD Op-Mode\n - HD Sub-Mode * BUF -> CS : notify * CS -> BUF : read:\n[1002] Device State * CS -> DCS : * * == CMDx7 - Send Tx Report == * * == CMDx8 - Tx Code Display == * * \enduml * * \startuml * title "Device Management flow" * * actor User * database System * * user -> qml : set vATTRIBUTE * qml -> VDevice : vATTRIBUTE##Request * VDevice -> DeviceController : didAttributeRequest \n(cosnt Device##vATTRIBUTE##RequestData &) * DeviceController -> Script : onAttributeRequest \n(const Device##vATTRIBUTE##RequestData &) * Script -> system : * system -> Script * * \enduml * */ class CloudSyncController : public QObject { Q_OBJECT // Singleton SINGLETON(CloudSyncController) // friends friend class ::tst_initializations; QThread *_thread = nullptr; bool _init = false; const int _interval = 1000; // 1s const QString _location = QString(Storage::SDCard_Base_Path_Name) + "cloudsync/"; const char* _out_File = "out.buf"; // The base file name : CloudSync puts its output to this file const char* _inp_File = "inp.buf"; // The base file name : UI Software puts the input data for the CloudSync in this file QString _date_out_File = ""; // The dated/actual filename : CloudSync puts its output to this file QString _date_inp_File = ""; // The dated/actual filename : UI Software puts the input data for the CloudSync in this file QDateTime _datetime ; qint64 _secSinceEpoch ; QString _dateFormatted ; QString _timeFormatted ; const char* _dateFormat = "yyyy_MM_dd" ; // date used in the file name const char* _timeFormat = "HH:mm:ss.zzz"; // timestamp in the file const char _dateSeparator = '_'; // used in filename const char _separator = ','; quint64 _seq = 0; bool _deviceInfoStop = true; const qint8 _deviceInfoSecs = 1; // in seconds is used for the DG serial response message, if DG is detached UI will timeout after a second and will send the message regardless. qint8 _deviceInfoWait = 0; QString _deviceInfoHD = ""; QString _deviceInfoDG = ""; QString _deviceInfoUI = ""; const quint8 _checkinIntervalSend = 60; // count down for check-in error if not responded back - regarding the _interval it will be 60s const quint8 _checkinIntervalTest = 5; // count down for check-in error if not responded back - regarding the _interval it will be 5s bool _checkinRcvd = false; // id check-in received will set to true. bool _postPass = false; bool _isWatching = false; enum Errors_Enum { // CS : 900 - 949 // UI : 950 - 999 eError_Unknown = 900, // Unknown error, initial error before error check // CS to UI Error start eError_Registration = 901, // CS_REQ_REGISTRATION_ERROR = 901 eError_DeviceState = 906, // CS_SEND_DEVICE_STATE_ERROR = 906 eError_TxReport = 907, // CS_SEND_TREATMENT_REPORT_ERROR = 907 eError_CheckIn = 908, // CS_REQ_CHECKIN_ERROR = 908 eError_Decommission = 909, // CS_REQ_DECOMMISSION_ERROR = 909 eError_UICRC = 910, // CS_BAD_CRC_ERROR = 910 eError_DeviceValidation = 920, // CS_DEVICE_VALIDATION_RESULT_ERROR = 920 eError_PatientAssociation = 921, // CS_SET_PATIENT_DEVICE_ASSOCIATION_ERROR = 921 eError_GetNewTokenCert = 922, // CS_GET_NEW_TOKEN_WITH_CERT_ERROR = 922 eError_VerifyToken = 923, // CS_VERIFY_TOKEN_ERROR = 923 eError_ValidateDevice = 924, // CS_VALIDATE_DEVICE_ERROR = 924 eError_PatientIdExists = 925, // CS_CHECK_IF_PATIENT_WITH_EMR_ID_EXISTS_ERROR = 925 eError_TemporaryPatient = 926, // CS_CREATE_TEMPORARY_PATIENT_ERROR = 926 eError_SaveCredentials = 927, // CS_SAVE_CREDENTIALS_ERROR = 927 eError_UnknownDeviceState = 928, // CS_UNKNOWN_DEVICE_STATE_ERROR = 928 eError_ConfigSave = 929, // CS_SAVE_CONFIG_ERROR = 929 eError_DeviceLog = 930, // CS_DEVICE_LOG_ERROR = 930 eError_Logging = 931, // CS_LOG_ERROR = 931 eError_FactoryReset = 932, // CS_FACTORY_RESET_ERROR = 932 eError_Retention = 933, // CS_LOG_RETENTION_ERROR = 933 // UI to CS Error start // eError_UI_Base = 950, // Base, not used eError_HeaderCount = 951, eError_Timestamp = 952, eError_Sequence = 953, eError_CSCRC = 954, eError_MessageID = 955, eError_InvalidID = 956, eError_ParamCount = 957, eError_ParamMismatch = 958, eError_ParamMissing = 959, eError_NoHistory = 960, eError_Duplicate = 961, eError_LogFolder = 962, eError_LogFileInp = 963, eError_CredentialPath = 964, // the UI vault folder for cloudsync credentials is not what is expected. eError_CredentialFile = 965, // the credential files sent to UI can't be find or read or doesn't exist.. eError_CredentialCount = 966, // No credential file sent to UI in the message. eError_CredentialEmpty = 967, // the UI folder doesn't have credential files. eError_TxCodeNoParam = 969, // the received Tx Code not provided eError_TxCodeEmpty = 970, // the received Tx Code is empty eError_OutFileExist = 971, // Out file does not exist. eError_OutFileEmpty = 972, // Out file has changed from CS2UI but the content is empty. eError_NotRegistered = 973, // avoid sending any message other than the device registration, when device is not registered. eError_LogNameNoParam = 974, // the received Log Name not provided eError_LogNameEmpty = 975, // the received Log Name is empty eError_LogRetentionNoParam = 976, // the received Log retention payload parameters not provided }; typedef QHash MessageList; MessageList _uiHistory ; // sent message history for later send upon request. enum Message_Enum { eMessage_Timestamp , eMessage_Sequence , eMessage_CRC , eMessage_MessageID , eMessage_ParamCount , eMessage_Count , }; typedef QStringList Params; struct Message { quint64 timestamp = 0; quint32 sequence = 0; quint8 crc = 0; qint32 id = 0; quint32 paramCount = 0; Params params { }; }; enum Entity_Start_Index { eUI = 1000, eCS = 2000, }; enum MessageID_Enum { eMessageID_Start = 0, // // [ #1( ID ) <-> #2( ID ) ] Description ( #1 Requests and #2 responses ) eMessageID_DeviceRegister = 1, // [ UI(1001) -> CS( ) ] Device Registration Request eMessageID_DeviceInfo = 2, // [ CS(2002) <-> UI(1002) ] Device information Request eMessageID_CredentialsSave = 3, // [ CS(2003) <-> UI(1003) ] Save Credentials Request/Response eMessageID_CheckIn = 4, // [ CS(2004) <-> UI(1004) ] CheckIn/HeartBeat Request/Response eMessageID_UIFactoryReset = 5, // [ CS(2005) <-> UI(1005) ] Factory Reset Request // Deployment eMessageID_DeviceState = 6, // [ CS(2006) <-> UI(1006) ] Device State Request // Tx Report eMessageID_TxReport = 7, // [ UI(1007) -> CS(2007) ] TxReport Notify // Tx Code eMessageID_TxCodeDisplay = 8, // [ CS(2008) -> UI( ) ] Display TxCode Request // Decommissioning eMessageID_CSDecommissioning= 9, // [ UI(1009) <-> CS(2009) ] Decommissioning Request // Log Upload eMessageID_SendLogUpload = 10, // [ UI(1010) <-> CS(2010) ] Log Upload Request/Response // CloudSync Log Retention eMessageID_SendLogRetention = 11, // [ UI(1011) <-> CS(2011) ] Log Retention Request/Response // Factory Reset eMessageID_CSFactoryReset = 99, // [ UI(1009) <-> CS(2009) ] Factory Reset Request // NOT IMPLEMENTED // // Subject to change so has been commented out for now // // eMessageID_PatientID = 202, // [No CS req defined] UI sends the patient ID // eMessageID_DeviceReport = 204, // [No CS req defined] UI sends the device report // eMessageID_HeartBeat = 900, // CS sends the periodic Hb and UI can set the interval eMessageID_Error = 999, // [ CS(2000) <-> UI(1000) ] Error Report eMessageID_Count }; QHash paramCount { // Received message length { eMessageID_CredentialsSave , 3 }, { eMessageID_TxCodeDisplay , 1 }, { eMessageID_Error , 2 }, { eMessageID_SendLogUpload , 1 }, { eMessageID_SendLogRetention , 2 }, }; enum DeviceInfo_Enum { eDeviceInfo_Ix = 0, // received message data index of each HD, DG. Data index 0 is always the info. eDeviceInfo_HD = 0, // stored index in the UI history. eDeviceInfo_DG = 1, // stored index in the UI history. eDeviceInfo_UI = 2, // stored index in the UI history. }; protected: void timerEvent(QTimerEvent *event) override; bool event(QEvent* vEvent) override; public slots: bool init(); bool init(QThread &vThread); void quit(); void doRegister (); private slots: void onWatchFileChange (const QString &vFile); void onActionReceive (GuiActionType vAction, const QVariantList &vData); void onPendingTxr (const QString &vFileName ); void onPendingLog (const QString &vFileName, const QString vChecksum ); void onRetentionLog (quint8 vMaxUsePercent); void onInitComplete (); void onPOSTCloudSync (bool vPass ); void onCryptSetupMount (bool vPass ); void onFactoryReset (bool vPass ); void onDecommissioning (bool vPass ); signals: void didInitComplete (); void didTxCodeReceive (const QString &vTxCode ); void didLogUpload (const QString &vFileName ); void didLogRetention (quint16 vLogsCount, quint32 vLogsSize); void didRegisterStart (bool vOK ); void didRegisterDone (bool vOK ); void didCloudSyncStatus (bool vReady ); void didCheckInReceive (); private: void initConnections(); void initThread(QThread &vThread); void quitThread(); quint8 generateCRC (quint64 vSecSinceEpoch, quint64 vSeq, const QStringList &vDataList); bool validateCRC () { return true; } // has not been implemented/decided yet void testWatchBuffDate (); bool interpret (const QString &vContent, Message &vMessage); bool addCSBuffWatch (); QStringList makeUIBuff (const qint32 vMessageID , const QStringList &vPrm = {}); bool isDuplicate (const qint32 vMessageID , const QStringList &vData); bool sendUIResponse (const QString &vContent ); bool sendUIBuff (const QStringList &vData ); bool saveUIHistory (const qint32 vAction , const QVariantList &vData); bool sendUIHistory (const qint32 vAction ); bool sendMessage (const Message &vMessage ); bool writeInpFile (const QString &vInpBuff ); QString toText (Errors_Enum vErrorID); QString toInfo (Errors_Enum vErrorID, const QVariantList &vInfoItems); void toLog (Errors_Enum vErrorID, const QVariantList &vInfoItems); void errorOut (Errors_Enum vErrorID, const QVariantList &vInfoItems); qint32 UI2CS (qint32 vID) { return vID + eUI ; } qint32 CS2UI (qint32 vID) { return abs(vID - eCS); } // error bool sendError (); // eMessageID_Error bool errorHandler ( const Message &vMessage ); // eMessageID_Error // device information bool saveDeviceInfo (GuiActionType vAction, const QVariantList &vData); // eMessageID_DeviceInfo bool saveDeviceInfoTimeOut (); // eMessageID_DeviceInfo bool sendDeviceInfo (); // eMessageID_DeviceInfo void testDeviceInfoWait (); void stopDeviceInfoWait (); void initDeviceInfoWait (); // device registration request bool sendDeviceRegister (); // eMessageID_DeviceRegister bool isRegistered (); void testReady(); // device state report bool saveDeviceState (const QVariantList &vData); bool sendDeviceState (); // eMessageID_DeviceState // Factory Reset bool csDecommissioning (); // eMessageID_CSDecommissioning bool csFactoryReset (); // eMessageID_CSFactoryReset bool uiFactoryReset (); // eMessageID_FactoryReset bool sendFactoryReset (); // eMessageID_FactoryReset // credentials bool sendCredentialsSave (const Message &vMessage ); // eMessageID_SaveCredentials bool sendCredentialsResponse(); // check-in bool sendCheckIn (); void testCheckIn (); bool takeCheckIn (); // pending Treatment log void sendPendingTxr ( const QString &vFileName ); // eMessageID_TxReport bool sendTxCodeDisplay ( const Message &vMessage ); // eMessageID_TxCodeDisplay // pending Treatment log void sendPendingLog (const QString &vFileName , const QString vChecksum); // eMessageID_SendLogUpload bool rcvdPendingLog (const Message &vMessage ); // eMessageID_SendLogUpload // CloudSync log retention void sendRetentionLog ( quint8 vMaxUsePercent ); // eMessageID_SendLogRetention bool rcvdRetentionLog (const Message &vMessage ); // eMessageID_SendLogRetention };