Index: denali.pro =================================================================== diff -u -r90e68000c37bc14b0dfd5f18caf425c24cc0b5f4 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- denali.pro (.../denali.pro) (revision 90e68000c37bc14b0dfd5f18caf425c24cc0b5f4) +++ denali.pro (.../denali.pro) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -5,6 +5,9 @@ QMAKE_CXXFLAGS += -Wall -Werror -Wextra -Wimplicit-fallthrough=3 # -save-temps # see .ii # -Wpedantic -Wconversion -Wshadow # these can't always be used, since it gives errors in Qt library. +TRANSLATIONS += denali.ts + + #CONFIG += disable_crc disable_crc { message( *** IMPORTANT : DISABLED CRC CHECK *** ) Index: denali.ts =================================================================== diff -u --- denali.ts (revision 0) +++ denali.ts (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -0,0 +1,5435 @@ + + + + + AlarmListDialog + + + Alarm list + + + + + ApplicationController + + + %1 Initialized + + + + + ApplicationPost + + + The POST log file could not be read. + + + + + BPHREntry + + + Blood Pressure + + + + + mmHg + + + + + Heart Rate + + + + + BPM + + + + + BackButton + + + BACK + + + + + Bluetooth::BluetoothInterface + + + %1 Initialized + + + + + BCUFF Battery: %1 + + + + + Can::CanInterface + + + Connected + + + + + %1 Initialized + + + + + Device Creation + + + + + Connection + + + + + Disconnected + + + + + %1 '%2[%3]', %4 + + + + + Can::FrameInterface + + + %1 Initialized + + + + + Can::MessageAcknowModel + + + %1 Initialized + + + + + Can::MessageDispatcher + + + %1 Initialized + + + + + Out of Sync : %1 , %2 + + + + + Ack Req, Sq:%1, ID:%2 + + + + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UI AckReq : %1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + + + + ,%1,Ack Bak, Sq:%2 + + + + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HD AckBak : %1 %2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + + + + ,%1,Ack Req, Sq:%2, ID:%3 + + + + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ HD AckReq : %1 %2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + + + + Ack Bak, Sq:%1, Dst:%2 + + + + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ UI AckBak : %1 %2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + + + + Can::MessageInterpreter + + + Unhandled Message ID (HD) + + + + + Unknown transmit Message with ID '%1' + + + + + CheckListView + + + Complete! + + + + + CloudSyncController + + + %1 Initialized + + + + + CS Unknown Error + + + + + CS The device registration failed + + + + + CS Invalid Device State + + + + + CS The treatment report delivery failed + + + + + CS The device check-in failed + + + + + CS The device decommissioning failed + + + + + CS Invalid UI Message CRC + + + + + CS DRT device registration failed + + + + + CS Patient association failed + + + + + CS New token certification failed + + + + + CS Token verification failed + + + + + CS Cloud device validation failed + + + + + CS Patient ID does not exists + + + + + CS Temporary patient ID creation failed + + + + + CS Save credentials failed + + + + + CS Unknown device state + + + + + CS Config file save failed + + + + + + CS Log upload failed + + + + + CS The device factory reset failed + + + + + CS The log retention failed + + + + + CS Out buffer file does not exist + + + + + CS Out buffer empty + + + + + CS Incorrect header + + + + + CS Incorrect timestamp + + + + + CS Incorrect sequence + + + + + CS Incorrect CRC + + + + + CS Incorrect ID + + + + + CS Incorrect parameter count + + + + + CS Invalid ID + + + + + CS Mismatch parameter count + + + + + CS Missing parameter + + + + + CS No history available + + + + + CS Duplicate data + + + + + CS The log folder cannot be created. + + + + + CS Error writing to the input file. + + + + + CS The credentials file does not exist. + + + + + CS The credentials folder is incorrect. + + + + + CS No credential file name provided. + + + + + CS The credentials folder is empty. + + + + + CS No Treatment Code provided. + + + + + CS The provided Treatment Code is empty. + + + + + CS No Log Name provided. + + + + + CS The provided Log Name is empty. + + + + + CS Not Sent, Device not registered. + + + + + CS No Log Retention summary provided. + + + + + ConfirmButton + + + CONFIRM + + + + + ConfirmDialog + + + Are you sure? + + + + + CANCEL + + + + + CONFIRM + + + + + ID + + + + + ConfirmTreatmentTable + + + New Treatment + + + + + PRESCRIPTION + + + + + OPERATING PARAMETERS + + + + + Blood Flow Rate + + + + + Dialysate Flow Rate + + + + + Duration + + + + + Heparin Dispensing Rate + + + + + Heparin Bolus Volume + + + + + Heparin Stop Time + + + + + Saline Bolus Volume + + + + + Heparin Type + + + + + Acid Concentrate + + + + + Bicarbonate Concentrate + + + + + Dialyzer Type + + + + + Dialysate Temperature + + + + + Blood Pressure Measure Interval + + + + + Device::DeviceController + + + %1 - Device or resource busy (%2) + + + + + %1 - %2 (%3 , %4) + + + + + Encrypted Partition %1 started. + + + + + Factory Reset started. + + + + + Decommissioning started. + + + + + USB unmount started. + + + + + USB mount started + + + + + Device::DeviceError + + + The device script abnormal exit. + + + + + The device script file is not found. + + + + + The device script file is not executable. + + + + + The request is already in progress. + + + + + The requested value is out of range. + + + + + The requested value is incorrect. + + + + + The response value is incorrect. + + + + + The watch file cannot be created. + + + + + The watch file is not found. + + + + + The watch file cannot be added. + + + + + The Bluetooth cuff pair clear error. + + + + + The Bluetooth cuff pair query error. + + + + + No paired Bluetooth cuff found. + + + + + The Bluetooth cuff pair invalid address. + + + + + The Encrypted Partition error. + + + + + DiagnosticsDialog + + + ROP + + + + + DRP + + + + + Prssr + + + + + Rsrvr + + + + + Heatrs + + + + + CANerr: %1 + + + + + LoadCl + + + + + Tmprtr + + + + + Conduct + + + + + Air Status + + + + + DG Mode + + + + + BP + + + + + DPi + + + + + UF/DPo + + + + + Prsr Oc + + + + + Syringe + + + + + HD Mode + + + + + Vlv + + + + + BLD + + + + + Alarms + + + + + PreTx States + + + + + DisinfectStack + + + Disinfection + + + + + Water Flush + + + + + Heat Disinfect with Active Cool + + + + + Chemical Disinfect + + + + + Chemical Flush + + + + + RO Permeate Sample + + + + + Heat Disinfect + + + + + EndTreatmentAdditional + + + Saline Bolus + + + + + EndTreatmentEndStack + + + Treatment Complete + + + + + START RINSEBACK + + + + + Treatment Complete Paused + + + + + EndTreatmentRecirculateStack + + + BACK TO RECIRCULATE + + + + + END TREATMENT + + + + + RESUME TREATMENT + + + + + Recirculate Disconnect + + + + + Recirculate + + + + + Recirculate Stopped + + + + + Recirculate Reconnect + + + + + EndTreatmentRinseback + + + Rinseback + + + + + End + + + + + Decelerate + + + + + Resume + + + + + Pause + + + + + Accelerate + + + + + EndTreatmentRinsebackComplete + + + Rinseback Complete + + + + + END TREATMENT + + + + + RECIRCULATE + + + + + SALINE BOLUS + + + + + (50mL) + + + + + EndTreatmentRinsebackInit + + + Rinseback Setup + + + + + END TREATMENT + + + + + START RINSEBACK + + + + + EndTreatmentRinsebackReconnect + + + Rinseback Reconnect + + + + + END TREATMENT + + + + + ExportButton + + + Export + + + + + Gui::GuiController + + + %1 Initialized + + + + + MainHome + + + CREATE TREATMENT + + + + + MainStack + + + SERVICE MODE + + + + + MainTimer + + + %1 Initialized + + + + + ManagerStack + + + Treatment Management + + + + + NotificationBar + + + ID + + + + + NotificationDialog + + + Notification + + + + + RESUME + + + + + RINSEBACK + + + + + END TREATMENT + + + + + OK + + + + + ID + + + + + PostTreatmentBase + + + Disconnection + + + + + Review + + + + + Disposables + + + + + Disinfection + + + + + PostTreatmentReview + + + NEXT + + + + + Code: + + + + + PostTreatmentStack + + + Patient Disconnection + + + + + Treatment Review + + + + + Disposables Removal + + + + + PowerItem + + + Cannot shutdown during 'Treatment' + + + + + System is shutting down + + + + + PreTreatmentBase + + + Create + + + + + Sample + + + + + Consumables + + + + + Disposables + + + + + Prime + + + + + BP/HR + + + + + Ultrafiltration + + + + + Connection + + + + + Start + + + + + PreTreatmentConfirm + + + Code: + + + + + PreTreatmentConnectionStack + + + CONFIRM + + + + + BP/HR + + + + + CONNECTION + + + + + Press CONNECTION to pair a Bluetooth Pressure Measurement Cuff. + + + + + Press START on Blood Pressure Measurement Cuff to display reading or enter vitals manually + + + + + Bluetooth Cuff + + + + + Ultrafiltration Setup + + + + + Patient Connection + + + + + CONTINUE + + + + + Start Treatment + + + + + START + + + + + PreTreatmentConsumablesStack + + + Consumables Installation + + + + + Consumables Self Test + + + + + Self Test Complete! + + + + + BiCarb Pump Check + + + + + Acid Pump Check + + + + + PreTreatmentCreate + + + RESET + + + + + PREPOPULATE + + + + + PRESCRIPTION + + + + + Blood Flow Rate + + + + + Dialysate Flow Rate + + + + + Duration + + + + + Heparin Dispensing Rate + + + + + + + + + + OFF + + + + + + + ON + + + + + Heparin Bolus Volume + + + + + Heparin Stop Time + + + + + Saline Bolus + + + + + OPERATING PARAMETERS + + + + + Heparin Type + + + + + Acid Concentrate + + + + + Bicarbonate Concentrate + + + + + Dialyzer Type + + + + + Dialysate Temperature + + + + + Blood Pressure Measurement Interval + + + + + PreTreatmentCreateStack + + + Patient ID + + + + + + CONTINUE + + + + + SKIP + + + + + Create a Custom Treatment + + + + + Confirm Treatment + + + + + PreTreatmentDisposablesStack + + + System Self Test + + + + + Cartridge Installation + + + + + + + NEXT + + + + + Cartridge Connection + + + + + Heparin Syringe + + + + + Saline Bag + + + + + CONFIRM + + + + + PreTreatmentPrimeStack + + + Begin Prime + + + + + Self Test Complete! + + + + + Occlusion Sensor Check + + + + + Cartridge Install Checks + + + + + Pressure Leak Check + + + + + Priming Heparin Line + + + + + Syringe Pump Occlusion Check + + + + + CONTINUE + + + + + Priming + + + + + Priming Complete! + + + + + Start Prime + + + + + Blood Circuit Priming + + + + + Dialysate Circuit Priming + + + + + Wet Self Tests + + + + + PreTreatmentUltrafiltration + + + Ultrafiltration Volume + + + + + PreTreatmentWaterSampleStack + + + Flushing Carbon Filters for Water Sample + + + + + NEXT + + + + + Water Sample + + + + + WATER SAMPLE + + + + + Water Sample Result + + + + + FAIL + + + + + PASS + + + + + Water Sample Result Failed + + + + + OK + + + + + PressureRangeSlider + + + LOW + + + + + HIGH + + + + + QObject + + + Application terminated by SIGINT + + + + + Application terminated by SIGTERM + + + + + Unknown device error %2 [%1] + + + + + Device error [%1] + + + + + Removed previously paired device(s). + + + + + The Encrypt Partition Command Complete. + + + + + Paired BCuff Query %1 %2 + + + + + The Factory Reset Command Complete. + + + + + The Decommissioning Command Complete. + + + + + The USB (un)mount Command Complete. + + + + + Indication for when no alarms is a possible situation. + + + + + HD stuck button POST failure. +Stop or Off button detected to be pressed for at least 1 second during test shortly after power up. + + + + + HD FPGA POST failure. + + + + + DG FPGA POST failure. + + + + + HD Watchdog POST failure. + + + + + DG Watchdog POST failure. + + + + + HD UI communication POST failure. +UI failed to communicate within a reasonable time after power up. + + + + + HD RTC battery low. + + + + + HD accelerometer failed POST. + + + + + DG accelerometer failed POST. + + + + + HD blood leak sensor setting embedded mode failure. + + + + + HD dialysate temperature below target temperature or below safety temp. + + + + + HD firmware image integrity POST test failed. + + + + + DG firmware image integrity POST test failed. + + + + + DG invalid usage record CRC. + + + + + HD dialysate temperature above high safety. + + + + + HD alarm audio failed POST. + + + + + HD UI POST failed. + + + + + HD didn't get ACK on message to DG that required acknowledgment. + + + + + HD dialysate temperature above target temperature. + + + + + DG conductivity sensors invalid calibration record. + + + + + DG drain line volume invalid calibration record. + + + + + DG reservoirs invalid calibration record. + + + + + DG acid concentrate calibration record. + + + + + DG bicarb concentrate calibration record. + + + + + DG accelerometer invalid calibration record. + + + + + HD accelerometer invalid calibration record. + + + + + HD blood leak sensor zero and self test sequence failed. + + + + + DG two wire sensors FPGA fault. + + + + + HD heparin force sensor invalid calibration record. + + + + + HD Software fault. +Software found itself in an unexpected state. + + + + + HD blood pump failed motor controller current check. +Too high when pump should be off or out of range when pump should be running. + + + + + HD blood pump failed motor off check. +Measured speed while commanded off. + + + + + HD blood pump failed motor direction check. +Measured vs commanded. + + + + + HD blood pump failed rotor speed check. +Mismatch with rotor and motor speeds. + + + + + HD dialysis inlet pump failed motor controller current check. +Too high when pump should be off or out of range when pump should be running. + + + + + HD dialysis inlet pump failed motor off check. +Measured speed while commanded off. + + + + + HD dialysis inlet pump failed motor direction check. +Measured vs commanded. + + + + + HD dialysis inlet pump failed rotor speed check. +Mismatch with rotor and motor speeds. + + + + + HD dialysis outlet pump failed motor controller current check. +Too high when pump should be off or out of range when pump should be running. + + + + + HD dialysis outlet pump failed motor off check. +Measured speed while commanded off. + + + + + HD dialysis outlet pump failed motor direction check. +Measured vs commanded. + + + + + HD dialysis outlet pump failed rotor speed check. +Mismatch with rotor and motor speeds. + + + + + DG main primary heater FPGA fault. + + + + + HD UI communication timeout. + + + + + HD too many bad communications CRC. + + + + + HD didn't get ACK on message to UI that required acknowledgment. + + + + + DG maximum RO Pump PWM exceeded. + + + + + HD ultrafiltration volume accuracy error during treatment. + + + + + HD FPGA communication down for too long. + + + + + DG FPGA not accepting commanded valve states. + + + + + HD blood pump failed motor speed check. +Measured vs commanded. + + + + + HD dialysate inlet pump failed motor speed check. +Measured vs commanded. + + + + + HD dialysate outlet pump failed motor speed check. +Measured vs commanded. + + + + + HD critical data integrity check failed. + + + + + DG critical data integrity check failed. + + + + + HD accelerometer error (no readings or FPGA reports error). + + + + + DG accelerometer error (no readings or FPGA reports error). + + + + + HD valve homing failed. + + + + + HD valve transition time out. + + + + + HD valve not functional. + + + + + HD valve current out of range. + + + + + HD valve position out of target. + + + + + HD syringe pump prime timeout. + + + + + DG barometric pressure sensor out of range. + + + + + HD DG requests DG command with invalid parameter fault. + + + + + HD blood leak sensor set point set failure. + + + + + HD blood pump occlusion self-test failure alarm. + + + + + HD active reservoir recirculation out of range. + + + + + HD blood leak sensor invalid calibration record. + + + + + HD arterial pressure self-test failure alarm. + + + + + HD venous pressure self-test failure alarm. + + + + + HD No load cell data message receive at least once every 2 seconds. + + + + + HD No dialysate temperature data message receive at least once every 2 seconds. + + + + + DG inlet UV reactor is on with no flow. + + + + + HD syringe pump self-test failure alarm. + + + + + HD monitored voltage is out of range. + + + + + DG monitored voltage is out of range. + + + + + HD syringe pump direction (from encoder) error. + + + + + HD syringe pump direction (from controller) error. + + + + + HD syringe pump fault reported by FPGA. + + + + + HD syringe pump over travel error. + + + + + HD syringe pump DAC write failure. + + + + + HD syringe pump is running while the BP is off. + + + + + DG set RTC year is invalid. + + + + + HD pump track latch opened alarm. + + + + + HD set RTC year is invalid. + + + + + DG heating invalid calibration record. + + + + + DG concentrate pumps hall sensor out of range. + + + + + DG outlet UV reactor on with no flow. + + + + + + DG load cells A1/B1 FPGA fault. + + + + + HD No dialysate flow data receive in the last 3 seconds. + + + + + DG temperature sensors invalid calibration record. + + + + + DG outlet primary conductivity out of range. + + + + + DG pressure out of range. + + + + + DG watchdog expired. + + + + + DG inlet water temperature in high range. + + + + + DG fill conductivity out of range. + + + + + HD battery communication fault. + + + + + HD syringe pump stall alarm. + + + + + DG conductivity sensors invalid temperature compensation calibration record. + + + + + UI POST HD communication failure. + + + + + DG heat disinfect temperature gradient out of range. + + + + + HD invalid calibration CRC. + + + + + HD air trap level sensors reporting illegal combination of air/fluid. + + + + + DG invalid calibration CRC. + + + + + DG dialysate flow sensor invalid calibration record. + + + + + HD reports DG restarted fault. + + + + + HD syringe pump ADC FPGA fault. + + + + + HD syringe pump volume check error. + + + + + HD syringe pump speed check error. + + + + + HD syringe pump not stopped in off state error. + + + + + DG Drain pump current out of range. + + + + + HD venous air bubble detector self-test failure. + + + + + DG temperature sensor out of range. + + + + + HD UI SD card failure. + + + + + DG CAN message not acked. + + + + + DG RTC config error. + + + + + DG RTC battery low error. + + + + + HD pre-treatment mode wet self-test prime check failure. + + + + + DG main primary heater voltage out of range. + + + + + DG small primary heater voltage out of range. + + + + + DG trimmer heater voltage out of range. + + + + + HD end of treatment alarm (high priority). + + + + + HD blood sitting too long after treatment stopped by user alarm (>5 min). + + + + + HD blood leak detected alarm. + + + + + HD venous pressure too low during treatment. + + + + + HD venous air bubble detected alarm. + + + + + HD blood leak recovering please wait. + + + + + HD venous pressure too high during treatment. + + + + + HD arterial pressure too low during treatment. + + + + + HD arterial pressure too high during treatment. + + + + + DG fluid leak detected alarm. + + + + + HD fluid leak detected alarm. + + + + + HD experienced large acceleration. + + + + + DG experienced large acceleration. + + + + + HD tilt exceeds maximum. + + + + + DG tilt exceeds maximum. + + + + + HD AC power lost alarm. + + + + + HD DG communication timeout. + + + + + HD air trap fill timeout during treatment. + + + + + HD blood pump occlusion detected. + + + + + DG dialysate temperature sensors out of range. + + + + + DG cleaning mode inlet water conductivity out of high range. + + + + + DG concentrate conductivity after adding acid out of range alarm. + + + + + DG RTC or timer accuracy failure. + + + + + DG wait for the DG to produce dialysate. + + + + + DG Cleaning mode inlet water temperature too high. + + + + + HD watchdog expired. + + + + + DG inlet water conductivity in high range. + + + + + DG inlet water conductivity in low range. + + + + + DG inlet water pressure in low range. + + + + + HD prime completed high priority alarm. + + + + + DG cleaning mode inlet water conductivity out of low range. + + + + + HD No reservoirs data message receive at least once every 2 seconds. + + + + + HD No DG operation mode message receive at least once every 2 seconds. + + + + + DG chemical disinfect prime acid line timeout. + + + + + DG inlet water temperature is in the low range. + + + + + DG chemical disinfect flush remove acid and close the concentrate cap. + + + + + HD blood pump rotor speed too high. + + + + + DG comm too many bad CRCs. + + + + + DG FPGA clock speed check failure. + + + + + HD sees primary load cell for reservoir 1 change too much too fast. + + + + + HD sees primary load cell for reservoir 2 change too much too fast. + + + + + HD in treatment rinseback operation timeout. + + + + + + + Test alarm, clear top only. + + + + + HD cartridge door opened alarm. + + + + + DG Dialysate flow rate out of maximum range. + + + + + HD syringe empty alarm. + + + + + HD syringe pump occlusion alarm. + + + + + HD syringe pump not enough Heparin alarm. + + + + + HD RTC configuration error. + + + + + HD RTC or timer accuracy failure. + + + + + HD pump direction status error. + + + + + DG software fault. +Software found itself in an unexpected state. + + + + + HD communication timeout. + + + + + DG FPGA communication down for too long. + + + + + DG RO flow out of maximum range. + + + + + DG load cells weight out of range for tare. + + + + + DG load cells invalid calibration. + + + + + DG invalid load cell value. + + + + + DG inlet UV reactor not healthy. + + + + + DG fan RPM out of range. + + + + + DG concentrate pump fault. + + + + + DG concentrate pump CP1 speed control error. + + + + + DG concentrate pump CP2 speed control error. + + + + + DG drain pump RPM out of range. + + + + + DG drain pump off fault. + + + + + DG flow rate out of upper range. + + + + + DG flow rate out of lower range. + + + + + HD blood pump partial occlusion detected. + + + + + DG RO pump duty cycle out of range. + + + + + DG RO pump pressure out of range. + + + + + DG CPi/CPo sensors FPGA fault. + + + + + DG CD1/CD2 sensors FPGA fault. + + + + + DG RO flow too low while primary heater is on. + + + + + DG Dialysate flow too low while trimmer heater is on. + + + + + DG thermistors/sensors temperature out of range. + + + + + HD pre-treatment mode wet self-test lc vs FMD failure. + + + + + HD pre-treatment mode dry pressure normal self-test failure. + + + + + DG fill conductivities acid/bicarb invalid calibration record. + + + + + DG RO rejection ratio out of range. + + + + + DG conductivity sensor fault. + + + + + DG dialysate fill runs out of time. + + + + + DG flow meter check failure alarm. + + + + + HD venous pressure occlusion alarm. + + + + + DG drain circulation line timeout. + + + + + HD battery pack detected an error. + + + + + HD blood sitting too long warning (>4 min). + + + + + HD end of treatment alarm (user not acting to end treatment). + + + + + HD prime completed medium priority alarm. + + + + + + + + + + Available for use. + + + + + HD end treatment sub-mode timeout alarm. + + + + + HD syringe detected alarm. + + + + + HD syringe pump syringe removed alarm. + + + + + DG THd sensors FPGA fault. + + + + + HD Saline bag is empty. + + + + + HD occlusion sensor FPGA fault. + + + + + HD arterial sensor FPGA fault. + + + + + HD treatment stopped by user action. + + + + + HD end of treatment warning. + + + + + HD prime completed low priority alarm. + + + + + HD time out on prime saline purge air state. + + + + + HD prime dialysate dialyzer time out alarm. + + + + + HD prime dialysate bypass time out alarm. + + + + + HD pre-treatment mode dry pressure self-test failure. + + + + + HD pre-treatment mode wet self-test LC vs LC failure. + + + + + DG barometric sensor coefficients bad CRC. + + + + + DG inlet water pressure in high range. + + + + + HD in treatment stopped sub-mode after rinseback completed (no escalation). + + + + + HD needs new cartridge to be installed. + + + + + HD no cartridge loaded or installed improperly alarm. + + + + + HD fail to remove cartridge alarm. + + + + + DG bicarb conductivity out of range during bicarb pump check alarm. + + + + + DG reservoir drain time out. + + + + + DG reservoir fill time out. + + + + + DG reservoir leak time out. + + + + + DG cleaning mode temperature sensors difference out of range. + + + + + DG heat disinfect target temperature time out (could not reach to temperature). + + + + + DG cleaning mode conductivity sensors out of range. + + + + + + Alarm Id available. + + + + + DG chemical disinfect could not reach to target temperature out of range. + + + + + DG chemical disinfect target conductivity out of range. + + + + + DG chemical disinfect insert acid and remove the concentrate cap. + + + + + HD invalid system record. + + + + + HD invalid service record. + + + + + DG invalid system record. + + + + + DG invalid service record. + + + + + HD and UI software builds are not compatible. + + + + + HD processor is in Disinfect Chemical Flush mode. + + + + + HD invalid institutional record. + + + + + HD UI POST OS version compatibility failure. + + + + + HD temperatures out of range. + + + + + HD UI POST Application Integrity (Sha256Sum) failure. + + + + + HD UI POST CANBus failure. + + + + + HD UI POST Touch failure. + + + + + HD UI POST SD-Card failure. + + + + + HD UI POST RTC failure. + + + + + HD UI POST WiFi failure. + + + + + HD UI POST Bluetooth failure. + + + + + HD UI POST Ethernet failure. + + + + + HD UI POST Sound failure. + + + + + HD POST Safety Shutdown failure. + + + + + DG POST Safety Shutdown failure. + + + + + HD Fan RPM out of range. + + + + + DG inactive reservoir weight out of range. + + + + + HD arterial pressure sensor is reading out of range. + + + + + HD venous pressure sensor is reading out of range. + + + + + HD BP occlusion sensor is reading out of range. + + + + + HD active reservoir weight out of range. + + + + + DG dialysate drain time out. + + + + + DG drain pump direction invalid. + + + + + Acid concentration bottle low volume alarm. + + + + + Bicarbonate concentration bottle low volume alarm. + + + + + DG load cells weight out of range. + + + + + DG load cells primary/back up drift out of range. + + + + + HD processor is in RO permeate sample mode. + + + + + DG concentrate cap not in proper position. + + + + + HD processor clock speed checks against FPGA clock failure. + + + + + HD load cells primary/back up drift out of range. + + + + + DG dialysate cap not closed. + + + + + HD venous pressure sensor FPGA fault. + + + + + HD processor is in Disinfect Flush mode. + + + + + HD processor is in Disinfect Heat mode. + + + + + HD processor is in Disinfect Chemical mode. + + + + + HD processor is in Disinfect active cool mode. + + + + + HD UI POST CloudSync failure. + + + + + DG TDi sensors FPGA fault. + + + + + DG TRo sensors FPGA fault. + + + + + DG baro sensor FPGA fault. + + + + + DG invalid serial number. + + + + + HD invalid serial number. + + + + + DG RO permeate sample remove the dialysate cap. + + + + + DG processor RAM error. + + + + + DG drain pump direction FPGA fault. + + + + + HD invalid usage record. + + + + + HD processor RAM error. + + + + + DG turn off inlet water valves. + + + + + HD AC power lost second alarm. + + + + + DG CPi conductivity sensor invalid character received. + + + + + DG CPo conductivity sensor invalid character received. + + + + + DG CD1 conductivity sensor invalid character received. + + + + + DG CD2 conductivity sensor invalid character received. + + + + + HD Dialysate In flow rate to too low. + + + + + DG cleaning mode inlet water temperature too low. + + + + + DG cleaning mode inlet water pressure too high. + + + + + DG cleaning mode inlet water pressure too low. + + + + + + Alarm available. + + + + + Alarm available for use. + + + + + DG chemical disinfect flush flush sample. + + + + + DG chemical disinfect flush sample timeout. + + + + + DG outlet UV reactor not healthy. + + + + + HD UI POST Year check failure. + + + + + HD UI POST Configuration check failure. + + + + + Total number of alarms. + + + + + ALARM_ID_UNDEFINED [%1] + + + + + SDCProgressItem + + + SD + + + + + SettingsBluetoothCuff + + + Devices + + + + + SCAN + + + + + SettingsDGCleaning + + + Last Basic Flush Complete + + + + + Last Chemical Disinfect Start + + + + + Last Chemical Disinfect Complete + + + + + Last Chemical Disinfect Flush Complete + + + + + Last Heat Disinfect Complete + + + + + Proceed to Cleaning Mode + + + + + SettingsDGScheduling + + + Water Flush + + + + + + Cycle (Days) + + + + + Heat Disinfection + + + + + SettingsDateTime + + + Time (HH:MM) + + + + + : + + + + + Date (MM/DD/YYYY) + + + + + + / + + + + + SettingsDecommission + + + Do you want to perform the %1? + + + + + Please wait ... + + + + + SettingsDeviceRegistration + + + UI Version + + + + + HD Serial + + + + + DG Serial + + + + + Wireless + + + + + Ethernet + + + + + Registration complete + + + + + Cloud Service is running + + + + + Registering the device + + + + + START + + + + + No Network Connection + + + + + No device Serial + + + + + SettingsExportLogs + + + SD-Card + + + + + USB Drive + + + + + Application + + + + + Service + + + + + Treatment + + + + + log export to USB in progress ... + + + + + log export to USB is complete + + + + + SettingsFactoryReset + + + Do you want to perform the %1? + + + + + Please wait ... + + + + + SettingsHome + + + Clear Alarm Condition + + + + + SettingsInformation + + + Versions + + + + + OS Version + + + + + UI Version + + + + + HD Version + + + + + HD FPGA Version + + + + + HD Serial Number + + + + + DG Version + + + + + DG FPGA Version + + + + + DG Serial Number + + + + + Service + + + + + HD Last Service Date + + + + + HD Next Service Date + + + + + DG Last Service Date + + + + + DG Next Service Date + + + + + Treatment + + + + + Total Hours + + + + + Hours Since Last Service + + + + + Last Start + + + + + Last Reset + + + + + SettingsLocalization + + + Language + + + + + SettingsManufacturingSetup + + + Do you want to perform the %1? + + + + + Please wait ... + + + + + SettingsROInput + + + Pure Water Mode + + + + + ON + + + + + OFF + + + + + SettingsRootSSHAccess + + + Enable SSH Login + + + + + Enable Root Login + + + + + SettingsServicePassword + + + Set Service Password + + + + + Service Password + + + + + Incorrect password + + + + + Mismatch Passwords + + + + + Invalid Password + + + + + SettingsStack + + + Information + + + + + Volume And Brightness + + + + + Wi-Fi + + + + + Bluetooth Cuff + + + + + DG Cleaning + + + + + DG Scheduling + + + + + + Service + + + + + Date and Time + + + + + Export Logs + + + + + Language + + + + + Water Input Mode + + + + + Calibration + + + + + Device Configuration + + + + + Device Registration + + + + + + Software Update + + + + + Enable Root SSH + + + + + Factory Reset + + + + + Decommissioning + + + + + Institutional Configurations + + + + + Manufacturing Setup + + + + + Device Settings + + + + + COMPLETE + + + + + SHUTDOWN + + + + + + Application POST Failed, please shutdown and retry + + + + + SettingsVolumeBrightness + + + Brightness + + + + + Alarm Volume + + + + + System Volume + + + + + % + + + + + SettingsWiFi + + + IP Address + + + + + Gateway + + + + + Subnet Mask + + + + + DNS + + + + + SSID + + + + + SCAN + + + + + Not Supported + + + + + Connected + + + + + Do you want to disconnect from `%1`? + + + + + Join + + + + + Password + + + + + Disconnect + + + + + Storage::Logger + + + %1 Initialized + + + + + Application %1 Started + + + + + The '%1' folder selected for the treatment reports + + + + + Initializing log clean up + + + + + Remove Logs Ended: %1 + + + + + Storage::TreatmentLog + + + + NONE + + + + + + + + OFF + + + + + mL/min + + + + + hour + + + + + min + + + + + mEq/L + + + + + C + + + + + L + + + + + mL + + + + + IU/mL + + + + + mL/hr + + + + + mmHg + + + + + Patient ID + + + + + + + Blood Flow Rate + + + + + Dialysate Flow Rate + + + + + Treatment Duration + + + + + Actual Treatment Duration + + + + + Acid ConcentrateType + + + + + Bicarbonate Concentrate Type + + + + + Potassium Concentration + + + + + Calcium Concentration + + + + + Bicarbonate Concentration + + + + + Sodium Concentration + + + + + Dialysate Temperature + + + + + Dialyzer Type + + + + + Heparin Type + + + + + Heparin Concentration + + + + + Heparin Bolus Volume + + + + + Heparin Dispense Rate + + + + + Heparin Stop + + + + + Heparin Delivered Volume + + + + + Treatment Start DateTime + + + + + Treatment End DateTime + + + + + Water Sample Test Result + + + + + Dialysate Volume Used + + + + + Prescribed UF Volume + + + + + Target UF Volume + + + + + Actual UF Volume + + + + + Prescribed UF Rate + + + + + Target UF Rate + + + + + Actual UF Rate + + + + + Saline Bolus Volume + + + + + TimeEntry + + + Time + + + + + : + + + + + TreatmentAdjustmentDuration + + + TREATMENT DURATION + + + + + TreatmentAdjustmentFlow + + + FLOWS + + + + + Blood Flow Rate + + + + + Dialysate Flow Rate + + + + + TreatmentAdjustmentPressuresLimits + + + PRESSURES + + + + + Arterial Window + + + + + Venous Window + + + + + Venous Asymmetric + + + + + TreatmentAdjustmentUltrafiltrationConfirm + + + ULTRAFILTRATION VOLUME + + + + + To confirm new UF Volume (%1), +select a treatment adjustment: + + + + + CONFIRM + + + + + %1 UF Rate + + + + + The rate %3 by %1 %2, +the treatment duration remains the same. + + + + + + UF Rate : %1 %2 + + + + + %1 Treatment Duration + + + + + The rate remains, the treatment +duration %2 by %1 minutes. + + + + + TreatmentAdjustmentUltrafiltrationEdit + + + ULTRAFILTRATION VOLUME + + + + + NEXT + + + + + TreatmentAdjustmentUltrafiltrationPaused + + + ULTRAFILTRATION VOLUME + + + + + EDIT ULTRAFILTRATION VOLUME + + + + + RESUME ULTRAFILTRATION + + + + + TreatmentAdjustmentUltrafiltrationStart + + + ULTRAFILTRATION VOLUME + + + + + PAUSE ULTRAFILTRATION + + + + + Note: Ultrafiltration needs to be paused to edit the volume. + + + + + TreatmentBloodPrime + + + Blood Priming + + + + + TreatmentFlowBase + + + TreatmentFlowBase + + + + + TreatmentFlows + + + FLOWS + + + + + Blood + + + + + Dialysate + + + + + TreatmentFluid + + + FLUID MANAGEMENT + + + + + Volume Delivered + + + + + (%1 %2) + + + + + Cumulative Delivered + + + + + TreatmentHeparin + + + HEPARIN DELIVERY + + + + + + OFF + + + + + PAUSE HEPARIN + + + + + RESUME DELIVERY + + + + + Maximum Cumulative Heparin Volume Delivered + + + + + Bolus Active + + + + + Syringe Empty + + + + + + + + + + Delivery Stopped + + + + + Delivery Paused + + + + + Dispensing Active + + + + + HEPARIN + + + + + TreatmentHome + + + Interval: + + + + + min + + + + + OFF + + + + + Last Read: + + + + + TreatmentPressures + + + PRESSURE + + + + + (mmHg) + + + + + Arterial + + + + + Venous + + + + + TreatmentSaline + + + START BOLUS + + + + + STOP BOLUS + + + + + Maximum cumulative saline bolus volume delivered + + + + + SALINE BOLUS + + + + + TreatmentStack + + + Ultrafiltration Paused + + + + + Treatment + + + + + Trending + + + + + Settings + + + + + VITALS + + + + + TreatmentTime + + + Time Remaining + + + + + Treatment Paused + + + + + TreatmentUltrafiltration + + + ULTRAFILTRATION VOLUME + + + + + (%1 %2) + + + + + TreatmentVitals + + + VITALS + + + + + USBProgressItem + + + USB + + + + + UltrafiltrationButton + + + Invalid + + + + + Increase + + + + + Decrease + + + + + Due to out of range adjustment, this option +is disabled. + + + + + UserConfirmation + + + Current + + + + + New + + + + + Confirm + + + + + VAlarmStatus + + + Suppressing HD communication timeout. + + + + + Alarm + + + + + VDevice + + + + Not enough secure information provided + + + + + Variables + + + CREATE + + + + + CONFIRM + + + + + PRIME + + + + + BEGIN + + + + + min + + + + + mL/min + + + + + mL/hr + + + + + mmHg + + + + + BPM + + + + + (L) + + + + + mL + + + + + °C + + + + + mEq/L + + + + + IU/mL + + + + + View::VAdjustmentAlarmVolume + + + The alarm volume change request has been rejected [%1] + + + + + View::VAdjustmentInstitutionalRecord + + + Enabled + + + + + Disabled + + + + + Blood Flow Rate + + + + + Dialysate Flow Rate + + + + + Treatment Duration + + + + + Heparin Stop + + + + + Saline Bolus Volume + + + + + Dialysate Temperature + + + + + Arterial Pressure Limit + + + + + Venous Pressure Limit + + + + + Venous Asym Pressure Limit + + + + + Prescribed UF Volume + + + + + Heparin Dispense Rate + + + + + Heparin Bolus Volume + + + + + Chemical Disinfect + + + + + + mL/min + + + + + + min + + + + + + mL + + + + + C + + + + + + + mmHg + + + + + L + + + + + mL/hr + + + + + View::VAlarmActiveList + + + No Active Alarm List +%1 + + + + + View::VBluetooth + + + Bluetooth reconnected. + + + + + Bluetooth paired and connected. + + + + + Bluetooth paired and disconnected. + + + + + BluetoothInterface Closed + + + + + The Bluetooth Adapter Is Ready %1 + + + + + The Bluetooth Adapter Connected + + + + + The Bluetooth Adapter Disconnected + + + + + No Valid Bluetooth Adapter + + + + + The Bluetooth Adapter POST Failed + + + + + The Bluetooth Adapter Is Off + + + + + The Bluetooth Adapter IO Error + + + + + The Bluetooth Adapter Unknown Error + + + + + No Valid device found + + + + + Scanning ... + + + + + Scanning Rejected + + + + + Device Discovering ... + + + + + Blood Pressure Device Found + + + + + Scanning Stopped + + + + + Scanning Finished + + + + + Device Initializing ... + + + + + Device Initialization Error + + + + + Device Connecting ... + + + + + Device Waiting For Measurement ... + + + + + Device Connection Error + + + + + Device Connected + + + + + Device Clean Up + + + + + Device In Power Saving Mode + + + + + Service Scanning ... + + + + + Service Error: %1 + + + + + Service Invalid + + + + + Service Discovered + + + + + Service Detail Discovering ... + + + + + Service Detail Error + + + + + Service Detail Done + + + + + Service Clean Up + + + + + Service Characteristic Changed + + + + + Service Characteristic Read + + + + + Service Characteristic Write + + + + + Service Descriptor Read + + + + + Service Descriptor Write + + + + + View::VConfirm + + + Shutdown + + + + + Are you sure you want to Shutdown? + + + + + SHUTDOWN + + + + + + CANCEL + + + + + Confirm + + + + + Are you sure? + + + + + CONFIRM + + + + + View::VDateTime + + + SetDateTime %1 + + + + + Not Set + + + + + Succeed + + + + + Failed + + + + + Good Morning + + + + + Good Afternoon + + + + + Good Evening + + + + + View::VDuetRoWaterDG + + + The RO Water Mode change request has been rejected [%1] + + + + + View::VNetworkModel + + + Scanning... + + + + + Scan Finished + + + + + Connecting to %1... + + + + + Disconnecting from %1... + + + + + Connected to %1. + + + + + Disconnected from %1. + + + + + No Ethernet + + + + + No WiFi + + + + + WiFi Disconnect + + + + + Successfully set the IP address. + + + + + Successfully set the gateway. + + + + + Successfully set the subnet mask. + + + + + Successfully set the DNS. + + + + + View::VTreatmentCreate + + + + + + OFF + + + + + + + + NONE + + + + + View::VTreatmentVitals + + + Vital received,%1,%2,%3 + + + + + Vital Confirmed,%1,%2,%3 + + + + + Vital Skipped + + + + + WifiInterface + + + %1 Initialized + + + + + %1.Obtaining IP Address.%1 + + + + + Failed to disconnect from %1 + + + + + Failed to set static IP Address + + + + + Failed to set gateway. + + + + + Failed to set subnet mask. + + + + + Failed to set DNS. + + + + + main + + + Treatment + + + + + Manager + + + + + Settings + + + + + Show the Can Frame Output + + + + + Show the Message Output + + + + + Show the Logs Output + + + + + Enable send low priority, empty message on the CANBus just to keep UI board CAN driver awake + + + + + Test fake message interval(ms) + + + + + interval + + + + + Test fake message data +will use default sequenced long fake message if set to 00(default) +will used only if correct integer value assigned for interval option + + + + + data + + + + + Test fake message sequence at the beginning of the frame + + + + + Disable unhandled messages report as an error in the log + + + + + Disable the Dialin messages logged as unhandled + + + + + Disables HD communication timeout + + + + + Disables alarm no minimize + + + + + disable-sd-card-fail-log-stop + + + + + disable-cloudsync-fail-stop + + + + + Disables Check-In Log + + + + + Disables Acknowledgment Log + + + + + Enables Dry-Demo Mode + + + + + Sets the Active CANBus [Shall start with 'can' or 'vcan] + + + + + CANBus + + + + + Enables the manufacturing mode to configure the system for the first time. + + + + + In case the application is not in Manufacturing Setup but needs to use root home folder for configurations. + + + + + Enables the update mode to update only necessary files during the update and keep the rest. + + + + + Use the log long file name format +<date>_<time>_<serial>_<mode> + + + + + Use the log cloud upload + + + + + Use the log compression + + + + + tst_acknow + + + Connected + + + + + Disconnected + + + + + tst_canbus + + + Connection + + + + + Connected + + + + + Disconnected + + + + + tst_models + + + ALARM_ID_UNDEFINED [-1] + + + + + ALARM_ID_UNDEFINED [599] + + + + + tst_views + + + REQUEST_REJECT_REASON_INVALID_TREATMENT_STATE + + + + + REQUEST_REJECT_REASON_UF_NOT_IN_PROGESS + + + + + REQUEST_REJECT_REASON_UF_NOT_PAUSED + + + + Index: sources/ApplicationController.cpp =================================================================== diff -u -ra522e6aa7a36ac696a9a956200e89d838f319e25 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/ApplicationController.cpp (.../ApplicationController.cpp) (revision a522e6aa7a36ac696a9a956200e89d838f319e25) +++ sources/ApplicationController.cpp (.../ApplicationController.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -49,7 +49,7 @@ _init = true; initConnections(); - LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); + LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); return true; } Index: sources/MainTimer.cpp =================================================================== diff -u -r2ef03b2ce51b4dc507f66e9671953a8e0824bde9 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/MainTimer.cpp (.../MainTimer.cpp) (revision 2ef03b2ce51b4dc507f66e9671953a8e0824bde9) +++ sources/MainTimer.cpp (.../MainTimer.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -44,7 +44,7 @@ } initConnections(); - LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); + LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); return true; } Index: sources/bluetooth/BluetoothInterface.cpp =================================================================== diff -u -r2ef03b2ce51b4dc507f66e9671953a8e0824bde9 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/bluetooth/BluetoothInterface.cpp (.../BluetoothInterface.cpp) (revision 2ef03b2ce51b4dc507f66e9671953a8e0824bde9) +++ sources/bluetooth/BluetoothInterface.cpp (.../BluetoothInterface.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -53,7 +53,7 @@ // runs in BluetoothInterface thread // REMINDER:initConnections(); has been removed from here to the ondoStart, // since the _local, _agent objects are created there. - LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); + LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); // TODO: the same logic has to work for all the controllers // needs more testing. Index: sources/canbus/CanInterface.cpp =================================================================== diff -u -r2ef03b2ce51b4dc507f66e9671953a8e0824bde9 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/canbus/CanInterface.cpp (.../CanInterface.cpp) (revision 2ef03b2ce51b4dc507f66e9671953a8e0824bde9) +++ sources/canbus/CanInterface.cpp (.../CanInterface.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -54,9 +54,9 @@ initConnections(); - status(tr("Connected")); + status(QString("Connected")); QString logMessage = QString("UI,%1,%2") - .arg(tr("%1 Initialized").arg(metaObject()->className())) + .arg(QString("%1 Initialized").arg(metaObject()->className())) .arg(status()); LOG_DEBUG(logMessage); @@ -246,7 +246,7 @@ else { mError = vError; } - _canStatus = tr("%1 '%2[%3]', %4") + _canStatus = QString("%1 '%2[%3]', %4") .arg(vDescription) .arg(_canType) .arg(_canInterface) Index: sources/canbus/FrameInterface.cpp =================================================================== diff -u -r2ef03b2ce51b4dc507f66e9671953a8e0824bde9 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/canbus/FrameInterface.cpp (.../FrameInterface.cpp) (revision 2ef03b2ce51b4dc507f66e9671953a8e0824bde9) +++ sources/canbus/FrameInterface.cpp (.../FrameInterface.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -47,7 +47,7 @@ startTimer(1, Qt::PreciseTimer); - LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); + LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); return true; } Index: sources/canbus/MessageAcknowModel.cpp =================================================================== diff -u -r2ef03b2ce51b4dc507f66e9671953a8e0824bde9 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/canbus/MessageAcknowModel.cpp (.../MessageAcknowModel.cpp) (revision 2ef03b2ce51b4dc507f66e9671953a8e0824bde9) +++ sources/canbus/MessageAcknowModel.cpp (.../MessageAcknowModel.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -44,7 +44,7 @@ // runs in MessageAcknowModel thread initConnections(); - LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); + LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); return true; } Index: sources/canbus/MessageDispatcher.cpp =================================================================== diff -u -r5687815256ae070a9a207107088e3f72dd464da0 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/canbus/MessageDispatcher.cpp (.../MessageDispatcher.cpp) (revision 5687815256ae070a9a207107088e3f72dd464da0) +++ sources/canbus/MessageDispatcher.cpp (.../MessageDispatcher.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -48,7 +48,7 @@ // runs in the thread initConnections(); - LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); + LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); return true; } Index: sources/cloudsync/CloudSyncController.cpp =================================================================== diff -u -r5687815256ae070a9a207107088e3f72dd464da0 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/cloudsync/CloudSyncController.cpp (.../CloudSyncController.cpp) (revision 5687815256ae070a9a207107088e3f72dd464da0) +++ sources/cloudsync/CloudSyncController.cpp (.../CloudSyncController.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -12,1354 +12,1354 @@ * \date (original) 14-Oct-2021 * */ -#include "CloudSyncController.h" - -// Qt -#include - -// Project -#include "ApplicationController.h" -#include "DeviceController.h" -#include "FileHandler.h" -#include "TreatmentLog.h" -#include "crc.h" - -SINGLETON_DISABLE(CloudSyncController) - -/*! - * \brief CloudSyncController::CloudSyncController - * \details Constructor - * \param parent - QObject parent owner object. - * Qt handles the children destruction by their parent objects life-cycle. - */ -CloudSyncController::CloudSyncController(QObject *parent) : QObject(parent) { - testWatchBuffDate(); - startTimer(_interval); -} - -/*! - * \brief CloudSyncController initializer - */ -bool CloudSyncController::init() -{ - if ( _init ) return false; - _init = true; - - initConnections(); - LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); - - return true; -} - -/*! - * \brief CloudSyncController::init - * \details Initialized the Class by calling the init() method first - * And initializes the thread vThread by calling initThread - * on success init(). - * \param vThread - the thread - * \return returns the return value of the init() method - */ -bool CloudSyncController::init(QThread &vThread) -{ - if ( ! init() ) return false; - initThread(vThread); - return true; -} - -/*! - * \brief CloudSyncController::quit - * \details quits the class - * Calls quitThread - */ -void CloudSyncController::quit() -{ - // disabled coco begin validated: CloudSync termination is not correctly done in coco!!! - // it has been tested and works perfectly fine in normal run. - quitThread(); // validated -} -// disabled coco end - -/*! - * \brief CloudSyncController::doRegister - * \details Send the register device command. - */ -void CloudSyncController::doRegister() -{ - sendDeviceRegister(); -} - -/*! - * \brief CloudSyncController::initConnections - * \details Initializes the required signal/slot connection between this class and other objects - * to be able to communicate. - */ -void CloudSyncController::initConnections() -{ - if ( ! gDisableCloudSyncFailStop ) { - SINGLETON_DISABLE_CONNECT(didPOSTCloudSync) - } - - connect(&_ApplicationController , SIGNAL(didPOSTCloudSync(bool)), - this , SLOT( onPOSTCloudSync(bool))); - connect(&_ApplicationController , SIGNAL(didActionReceive (GuiActionType , const QVariantList &)), - this , SLOT( onActionReceive (GuiActionType , const QVariantList &))); - - connect(&_DeviceController , SIGNAL(didCryptSetupMount(bool)), - this , SLOT( onCryptSetupMount(bool))); - connect(&_DeviceController , SIGNAL(didPendingLog (const QString &, const QString &)), - this , SLOT( onPendingLog (const QString &, const QString &))); - connect(&_Logger , SIGNAL(didRetentionLogCS (quint8)), - this , SLOT( onRetentionLog (quint8))); - - connect(&_DeviceController , SIGNAL(didWatchFileChange (const QString &)), - this , SLOT( onWatchFileChange (const QString &))); - connect(&_DeviceController , SIGNAL(didFactoryReset (bool)), - this , SLOT( onFactoryReset (bool))); - connect(&_DeviceController , SIGNAL(didDecommissioning (bool)), - this , SLOT( onDecommissioning (bool))); - connect(&_TreatmentLog , SIGNAL(didPendingTxr (const QString &)), - this , SLOT( onPendingTxr (const QString &))); - connect(this , SIGNAL(didInitComplete ()), - this , SLOT( onInitComplete ()),Qt::QueuedConnection); // it has to be queued connection, don't remove it. -} - -/*! - * \brief CloudSyncController::initThread - * \details Moves this object into the thread vThread. - * And checks that this method is called from main thread. - * Also connects quitThread to CloudSync aboutToQuit. - * \param vThread - the thread - */ -void CloudSyncController::initThread(QThread &vThread) -{ - // runs in main thread - Q_ASSERT_X(QThread::currentThread() == qApp->thread(), __func__, "The Class initialization must be done in Main Thread" ); - _thread = &vThread; - _thread->setObjectName(QString("%1_Thread").arg(metaObject()->className())); - connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(quit())); - _thread->start(); - moveToThread(_thread); -} - -/*! - * \brief CloudSyncController::quitThread - * \details Moves this object to main thread to be handled by QCloudSync - * And to be destroyed there. - */ -void CloudSyncController::quitThread() -{ - // disabled coco begin validated: CloudSync termination is not correctly done in coco!!! - // it has been tested and works perfectly fine in normal run. - - if ( ! _thread ) return; - - // runs in thread - moveToThread(qApp->thread()); // validated -} -// disabled coco end - -/*! - * \brief CloudSyncController::timerEvent - * \details The timer event handler which currently is triggered on each second to check for the date change, - * Which caused the watched file change and needs to updated the watched list. - * The check-in (watch dog) also needs to be here. - */ -void CloudSyncController::timerEvent(QTimerEvent *) -{ - TIME_CALL(sendCheckIn(), _checkinIntervalSend); // call every x times/second - will be called on first call. - TIME_CALL(testCheckIn(), _checkinIntervalTest); // call every x times/second - will be called on first call. - testWatchBuffDate(); - testDeviceInfoWait(); -} - -/*! - * \brief CloudSyncController::event - * \details The override method of QObject event to handle the ThreadChange. - * \param vEvent - the QObject event - * \return true if the event e was recognized and processed - */ -bool CloudSyncController::event(QEvent *vEvent) { - if (vEvent->type() == QEvent::ThreadChange) { - emit didInitComplete(); - } - // Make sure the rest of events are handled - return QObject::event(vEvent); -} - -/*! - * \brief CloudSyncController::onInitComplete - * \details The slot to be called when the CloudSync initialization is complete - * Does nothing for now - */ -void CloudSyncController::onInitComplete() { - /* Development testability: - For testing if -C (gDisableCloudSyncFailStop) is used call the testReady - which is called - - when the encrypted partition is mounted - - a request for credential save received - testReady will set ok = true if -C (gDisableCloudSyncFailStop) is used. - */ - if ( gDisableCloudSyncFailStop ) testReady(); -} - -/*! - * \brief CloudSyncController::onPOSTCloudSync - * \details This the handler for the ApplicationController::didPOSTCloudSync(bool) - * \param vPass - will be true if the POST test of CloudSync passed and it is running. - */ -void CloudSyncController::onPOSTCloudSync(bool vPass) -{ - _postPass = vPass; -} - -/*! - * \brief CloudSyncController::onCryptSetupMount - * \details This the handler for the DeviceController::onCryptSetupMount() - */ -void CloudSyncController::onCryptSetupMount(bool vPass) -{ - if ( vPass ) { - testReady(); - } -} - -/*! - * \brief CloudSyncController::onFactoryReset - * \details this slot will be called when the DeviceController is done with the Factory Reset - * to let the UI request CS to do the Factory Reset and clean up all the Logs. - * \param vPass - Device controller factory reset was successful. - */ -void CloudSyncController::onFactoryReset(bool vPass) -{ - if ( vPass ) { - csFactoryReset(); - } -} - -/*! - * \brief CloudSyncController::onDecommissioning - * \details this slot will be called when the DeviceController is done with the Decommissioning - * to let the UI request CS to do the Decommissioning and clean up all the Tokens. - * \param vPass - Device controller Decommissioning was successful. - */ -void CloudSyncController::onDecommissioning(bool vPass) -{ - if ( vPass ) { - csDecommissioning(); - } -} - -/*! - * \brief CloudSyncController::onWatchFileChange - * \details This slot will be called when the Device Controller identifies any changes in the watched files. - * \param vFile - watched file - * \note The DeviceController will emit the signal on any watched file update, it's up to the CloudSyncController to filter the result. - */ -void CloudSyncController::onWatchFileChange(const QString &vFile) -{ - // TODO: It may improve the performance of the code to make it more specific. - // Meaning, Device controller has only one file watcher and it will call all the slots of all the classes watching for a file change. - // then ignore what is not important, but it may effect, the call queue and the threading performance. - // Later investigation. - if ( vFile != _date_out_File ) return; // ignore unwanted file updates. - QString content; - Storage::FileHandler::read(vFile, content); - sendUIResponse(content); -} - -/*! - * \brief CloudSyncController::addCSBuffWatch - * \details Adds a watcher on the CloudSync Application output file. - * \sa _out_File - */ -bool CloudSyncController::addCSBuffWatch() -{ - bool ok = true; - QVariantList args {}; - Errors_Enum error = eError_Unknown; - QString dateFormatted; - - // -------------------------------------------------- check the folder - // this makeFolder function call investigated for permissions - // during setup the folder if does not exists will be created (root) - // the lockdown.sh script will set the permissions for it. - // on power cycle to normal operation the folder with the correct exists. - // *** NOTE: the makeFolder returns true if the folder already exists. *** - ok = Storage::FileHandler::makeFolder(_location); - if ( ! ok ) { error = eError_LogFolder; args = {{ _location }}; ok = false; goto lErr; } - - // -------------------------------------------------- Check the out file - // check the date time for the file to watch - dateFormatted = _datetime.toString(_dateFormat); - if (_dateFormatted != dateFormatted ) { - _dateFormatted = dateFormatted; - _isWatching = false; // first time the date changes and CSctrl needs a new watch this flag need to be reset until the watch is added. - } - _date_out_File = _location + _dateFormatted + _dateSeparator + _out_File; - // watching/wait for the cloud sync output file buffer. - // if the file does not exists, send a check-in to the CS and wait for the response. - // by CS sending the response it will create the out file and next time this function with start watching the file. - // since this class has a one second timer set, next call is next second - // TODO: during this less that 1s UI will not see messages from CS, since the file was not there to watch. - // send device state to make the CloudSync send back a message to create the out buff with its user to own the file - ok = QFileInfo(_date_out_File).exists(); - if ( ! ok ) { - _isWatching = false; - sendCheckIn(); - } - if ( ! ok ) { error = eError_OutFileExist; args = {{ _location }}; ok = false; goto lErr; } - - // -------------------------------------------------- return if already watching - if ( _isWatching ) { goto lOut; } - - // -------------------------------------------------- add the watch - _DeviceController.doAddWatch(_date_out_File, false); - _isWatching = true; // when the watch is added then the flag sets until next time the date changes. - // since the buff files will be deleted on each power cycle, when the out buf is created it means the CloudSync is running. - // we emit the ApplicationController to check the post.log for the CloudSync status check. - goto lOut; - -lErr: - toLog(error, args); - -lOut: - return ok; -} - -/*! - * \brief CloudSyncController::interpret - * \details Checks the received buffer to make sure it has all the required parameters - * \param vIndex - * \return true if the buffer is correct. - */ -bool CloudSyncController::interpret(const QString &vContent, Message &vMessage) -{ - bool ok = true; - QVariantList args {}; - Errors_Enum error = eError_Unknown; - - QStringList lines; - QString buffer; - - int index = -1; - quint32 count = 0; - - Message message; - QStringList items; - quint32 id; - - if ( vContent.trimmed().isEmpty() ) { error = eError_OutFileEmpty ; ok = false; goto lErr; } - - lines = vContent.split('\n',Qt::SkipEmptyParts); - buffer = lines.last(); - // DEBUG: LOG_DEBUG(QString("CS [%1]").arg(buffer)); - - items = buffer.split(_separator); - count = items.count(); - - // check the required message length - if ( count < eMessage_Count ) { error = eError_HeaderCount ; ok = false; goto lErr; } - index = eMessage_Timestamp ; message.timestamp = items[index].toUInt(&ok); if (!ok) { error = eError_Timestamp ; ok = false; goto lErr; } - index = eMessage_Sequence ; message.sequence = items[index].toUInt(&ok); if (!ok) { error = eError_Sequence ; ok = false; goto lErr; } - index = eMessage_CRC ; message.crc = items[index].toUInt(&ok); if (!ok) { error = eError_CSCRC ; ok = false; goto lErr; } - index = eMessage_MessageID ; message.id = items[index].toInt (&ok); if (!ok) { error = eError_MessageID ; ok = false; goto lErr; } - index = eMessage_ParamCount; message.paramCount = items[index].toUInt(&ok); if (!ok) { error = eError_ParamCount ; ok = false; goto lErr; } - - // check the parameters count - if ( count - eMessage_Count != message.paramCount ) { error = eError_ParamMismatch ; ok = false; goto lErr; } - - // check missing parameters - id = CS2UI(message.id); - if ( ! paramCount.contains(id)) paramCount[id] = 0; - if ( message.paramCount < paramCount[id] ) { error = eError_ParamMissing ; ok = false; goto lErr; } - - // convert the message id and check its validity - id = message.id; // keep the original recevied message id after we are done using the id for loggging. - message.id = CS2UI(static_cast(message.id)); - if ( eMessageID_Start > message.id || message.id > eMessageID_Count ) { error = eError_InvalidID ; ok = false; goto lErr; } - - // getting the parameters - for ( quint32 i = eMessage_Count; i < eMessage_Count + message.paramCount; i++ ) { - message.params.append( items[i] ); - } - - vMessage = message; - LOG_APPED_CS(QString("%1,%2").arg(id).arg(message.params.join(','))); - - return true; - -lErr: - // building the error info for each error - switch (error) { - case eError_Unknown : args = { }; break; - case eError_OutFileExist : args = { }; break; - case eError_OutFileEmpty : args = { }; break; - case eError_HeaderCount : args = { count , eMessage_Count }; break; - case eError_Timestamp : args = { items[index].trimmed() }; break; - case eError_Sequence : args = { items[index].trimmed() }; break; - case eError_CSCRC : args = { items[index].trimmed() }; break; - case eError_MessageID : args = { items[index].trimmed() }; break; - case eError_InvalidID : args = { items[index].trimmed() }; break; - case eError_ParamCount : args = { items[index].trimmed() }; break; - case eError_ParamMismatch : args = { count - eMessage_Count , message.paramCount }; break; - case eError_ParamMissing : args = { paramCount[message.id] , message.paramCount }; break; - // Interpreter function only handles the message parsing errors. So default can be used. - default : break; - } - toLog(error, args); - return false; -} - -/*! - * \brief CloudSyncController::toText - * \details returns the error message of the error id. - * \param vErrorID - Error id - * \param vMessage - error message - * \return the error message or empty string if the error is 0 (no error), or Unknown Error if not found - */ -QString CloudSyncController::toText(CloudSyncController::Errors_Enum vErrorID) -{ - QString text = tr( "CS Unknown Error" ) ; - if ( vErrorID == 0 ) return text; - switch (vErrorID) { - case eError_Unknown : /* "CS Unknown Error" */ ; break; - // CS Errors - case eError_Registration : text = tr( "CS The device registration failed" ) ; break; - case eError_DeviceState : text = tr( "CS Invalid Device State" ) ; break; - case eError_TxReport : text = tr( "CS The treatment report delivery failed" ) ; break; - case eError_CheckIn : text = tr( "CS The device check-in failed" ) ; break; - case eError_Decommission : text = tr( "CS The device decommissioning failed" ) ; break; - case eError_UICRC : text = tr( "CS Invalid UI Message CRC" ) ; break; - case eError_DeviceValidation : text = tr( "CS DRT device registration failed" ) ; break; - case eError_PatientAssociation : text = tr( "CS Patient association failed" ) ; break; - case eError_GetNewTokenCert : text = tr( "CS New token certification failed" ) ; break; - case eError_VerifyToken : text = tr( "CS Token verification failed" ) ; break; - case eError_ValidateDevice : text = tr( "CS Cloud device validation failed" ) ; break; - case eError_PatientIdExists : text = tr( "CS Patient ID does not exists" ) ; break; - case eError_TemporaryPatient : text = tr( "CS Temporary patient ID creation failed" ) ; break; - case eError_SaveCredentials : text = tr( "CS Save credentials failed" ) ; break; - case eError_UnknownDeviceState : text = tr( "CS Unknown device state" ) ; break; - case eError_ConfigSave : text = tr( "CS Config file save failed" ) ; break; - case eError_DeviceLog : text = tr( "CS Log upload failed" ) ; break; - case eError_Logging : text = tr( "CS Log upload failed" ) ; break; - case eError_FactoryReset : text = tr( "CS The device factory reset failed" ) ; break; - case eError_Retention : text = tr( "CS The log retention failed" ) ; break; - // UI Errors - case eError_OutFileExist : text = tr( "CS Out buffer file does not exist" ) ; break; - case eError_OutFileEmpty : text = tr( "CS Out buffer empty" ) ; break; - case eError_HeaderCount : text = tr( "CS Incorrect header" ) ; break; - case eError_Timestamp : text = tr( "CS Incorrect timestamp" ) ; break; - case eError_Sequence : text = tr( "CS Incorrect sequence" ) ; break; - case eError_CSCRC : text = tr( "CS Incorrect CRC" ) ; break; - case eError_MessageID : text = tr( "CS Incorrect ID" ) ; break; - case eError_ParamCount : text = tr( "CS Incorrect parameter count" ) ; break; - case eError_InvalidID : text = tr( "CS Invalid ID" ) ; break; - case eError_ParamMismatch : text = tr( "CS Mismatch parameter count" ) ; break; - case eError_ParamMissing : text = tr( "CS Missing parameter" ) ; break; - case eError_NoHistory : text = tr( "CS No history available" ) ; break; - case eError_Duplicate : text = tr( "CS Duplicate data" ) ; break; - case eError_LogFolder : text = tr( "CS The log folder cannot be created." ) ; break; - case eError_LogFileInp : text = tr( "CS Error writing to the input file." ) ; break; - case eError_CredentialFile : text = tr( "CS The credentials file does not exist." ) ; break; - case eError_CredentialPath : text = tr( "CS The credentials folder is incorrect." ) ; break; - case eError_CredentialCount : text = tr( "CS No credential file name provided." ) ; break; - case eError_CredentialEmpty : text = tr( "CS The credentials folder is empty." ) ; break; - case eError_TxCodeNoParam : text = tr( "CS No Treatment Code provided." ) ; break; - case eError_TxCodeEmpty : text = tr( "CS The provided Treatment Code is empty." ) ; break; - case eError_LogNameNoParam : text = tr( "CS No Log Name provided." ) ; break; - case eError_LogNameEmpty : text = tr( "CS The provided Log Name is empty." ) ; break; - case eError_NotRegistered : text = tr( "CS Not Sent, Device not registered." ) ; break; - case eError_LogRetentionNoParam : text = tr( "CS No Log Retention summary provided." ) ; break; - - } - return text; -} - -/*! - * \brief CloudSyncController::toInfo - * \details Provides extra information, related to each error, to be concatenated later to the error description. - * \param vErrorID - the error id - * \param vInfoItems - the information items to be used in creating the info. - * \return the extra info for the error as string - */ -QString CloudSyncController::toInfo(CloudSyncController::Errors_Enum vErrorID, const QVariantList &vInfoItems) -{ - // IMPORTANT: Please be careful here used QVariantList::value to act as a loose list. - // It means it is designed to not throw out of bound error and just use "~" as a missing info argument. - auto item = [=](uint i) { return vInfoItems.value(i,"~").toString(); }; - - QString info = QString( "[%1]" ).arg( vErrorID ) ; - switch (vErrorID) { - case eError_Unknown : ; break; - // CS Errors - case eError_Registration : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_DeviceState : ; break; - case eError_TxReport : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_CheckIn : ; break; - case eError_Decommission : ; break; - case eError_UICRC : /* info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) */ ; break; - case eError_DeviceValidation : ; break; - case eError_PatientAssociation : ; break; - case eError_GetNewTokenCert : ; break; - case eError_VerifyToken : ; break; - case eError_ValidateDevice : ; break; - case eError_PatientIdExists : ; break; - case eError_TemporaryPatient : ; break; - case eError_SaveCredentials : ; break; - case eError_UnknownDeviceState : ; break; - case eError_ConfigSave : ; break; - case eError_DeviceLog : ; break; - case eError_Logging : ; break; - case eError_FactoryReset : ; break; - case eError_Retention : ; break; - // UI Errors - case eError_OutFileExist : ; break; - case eError_OutFileEmpty : ; break; - case eError_HeaderCount : info = QString( "[%1:%2/%3]" ).arg( vErrorID ).arg( item(0) ).arg( item(1) ) ; break; - case eError_Timestamp : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_Sequence : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_CSCRC : /* info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) */ ; break; - case eError_MessageID : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_InvalidID : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_ParamCount : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_ParamMismatch : info = QString( "[%1:%2/%3]" ).arg( vErrorID ).arg( item(0) ).arg( item(1) ) ; break; - case eError_ParamMissing : info = QString( "[%1:%2/%3]" ).arg( vErrorID ).arg( item(0) ).arg( item(1) ) ; break; - case eError_NoHistory : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_Duplicate : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_LogFolder : ; break; - case eError_LogFileInp : ; break; - case eError_CredentialFile : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_CredentialPath : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_CredentialCount : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_CredentialEmpty : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_TxCodeNoParam : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_TxCodeEmpty : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_LogNameNoParam : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_LogNameEmpty : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_NotRegistered : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - case eError_LogRetentionNoParam : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; - } - return info; -} - -/*! - * \brief CloudSyncController::errorOut - * \details the function to send out the error message to the cloudsync inp buffer. - * \param vErrorID - the error id from CloudSyncController::Errors_Enum in range of 950 to 999 - * \param vInfoItems - - */ -void CloudSyncController::errorOut(CloudSyncController::Errors_Enum vErrorID, const QVariantList &vInfoItems) { - QString msg = QString::number(UI2CS(eMessageID_Error)); - QString len = QString::number(1 + vInfoItems.count()); - QString prm = QString::number(vErrorID); - QStringList buf = { msg, len, prm }; - for (const auto &item: vInfoItems) { - buf += item.toString(); - } - sendUIBuff(buf); -} - -/*! - * \brief CloudSyncController::toLog - * \details logs the error in debug mode (service log) - * \param vErrorID - error id - * \param vInfoItems - extra information - */ -void CloudSyncController::toLog(CloudSyncController::Errors_Enum vErrorID, const QVariantList &vInfoItems) -{ - errorOut(vErrorID, vInfoItems); - LOG_DEBUG(toText(vErrorID) + " " + toInfo(vErrorID, vInfoItems)); -} - -/*! - * \brief CloudSyncController::sendUIResponse - * \details the function to be called after reading the CloudSync out file to interpret the content of the file. - * \param vContent - the content to be interpreted. - * \return true if the content has a meaning for the interpreter, false otherwise. - */ -bool CloudSyncController::sendUIResponse(const QString &vContent) -{ - // IMPORTANT: - // please note the following in development testing it has been found out that. - // Do not use gedit. - // if the out.buf is edited by the "gedit" application the watch will be broken. - // The "nano" application works fine. - // A simple python3 code to open file and write to file works as well and that's sufficient for UI<=>CS communication. - // TODO: messages have to have a sequence. - // if the seq is duplicate it will be ignored. - // seq, id, payload - // DEBUG: qDebug() << vContent; - - bool ok = true; - Message message; - if ( ! interpret(vContent, message) ) return false; // The error handling internal to interpret method. - ok = sendMessage(message); - - return ok; -} - -/*! - * \brief CloudSyncController::testWatchBuffDate - * \details Checks the date and updated the watched file in case the date changed. - */ -void CloudSyncController::testWatchBuffDate() -{ - // prepare date values for addCSBufWatch - _datetime = QDateTime::currentDateTime().toUTC(); - _secSinceEpoch = _datetime.toSecsSinceEpoch(); - _timeFormatted = _datetime.toString(_timeFormat); - - addCSBuffWatch(); // bool out is not used here and error handling is internal to the addCSBuffWatch -} - -/*! - * \brief CloudSyncController::makeUIBuff - * \details make formatted UI buffer to send out. - * \param vMessage - The message id with destination added. 2k, 1K - * \return the formatted buffer - */ -QStringList CloudSyncController::makeUIBuff(const qint32 vMessageID, const QStringList &vPrm) -{ - int count = vPrm.count(); - QStringList prm = count ? vPrm : _uiHistory[ vMessageID ]; - QString msg = QString::number(vMessageID); - QString len = QString::number(prm.count()); - - QStringList dataList; - dataList += msg; - dataList += len; - dataList += prm; - - return dataList; -} - -/*! - * \brief CloudSyncController::isDuplicate - * \param vMessage - current action/messageID received. - * \param vData - current data to compare with the history - * \return true if duplicate - */ -bool CloudSyncController::isDuplicate(const qint32 vMessageID, const QStringList &vData) -{ - return _uiHistory.contains(vMessageID) && _uiHistory[vMessageID] == vData; -} - -/*! - * \brief CloudSyncController::writeInpFile - * \details Writes to the CS Input buffer - * \param vBuffer - the string out buffer. - * \return true if successful - */ -bool CloudSyncController::writeInpFile(const QString &vInpBuff) -{ - bool ok = true; - QVariantList args ; - Errors_Enum error = eError_Unknown; - - _date_inp_File = _location + // The location - _dateFormatted + _dateSeparator + _inp_File; // The file name - - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // writing the message into the buffer. - LOG_APPED_UI( vInpBuff ); - if(!QFile::exists(_date_inp_File)){ - Storage::FileHandler::makeFolder(_location); - } - if ( ! Storage::FileHandler::write(_date_inp_File, vInpBuff + "\n") ) { error = eError_LogFileInp; args = { _date_inp_File }; ok = false; goto lErr; } - return ok; - -lErr: - // don't send the error back to the CS - // it calls this same function if the error is in this function - // and creates a loop - LOG_DEBUG(toText(error) + " " + toInfo(error, args)); - return ok; -} - -/*! - * \brief CloudSyncController::sendUIBuff - * \details Sends the UI Buffer to the UI input file. - * \param vData - the data to be sent out. - * \return true on successful writing to the file buffer. - * \sa _inp_File - */ -bool CloudSyncController::sendUIBuff(const QStringList &vDataList) -{ - bool ok = true; - QString inpBuff = "%1,%2,%3,%4"; - - inpBuff = inpBuff - .arg( _secSinceEpoch ) - .arg( Types::safeIncrement(_seq)) - .arg( generateCRC(_secSinceEpoch, _seq, vDataList)) - .arg( vDataList.join(_separator)); - - ok = writeInpFile(inpBuff); - return ok; -} - -/*! - * \brief CloudSyncController::saveUIHistory - * \details stores the action data in history, if vData is provided. - * \param vAction - the request id, which in current design is same as the Message comes to the UI. - * \param vData - The message data - * \return true if a message history is available, false otherwise. - */ -bool CloudSyncController::saveUIHistory(const qint32 vAction, const QVariantList &vData) -{ - bool ok = true; - QVariantList args ; - Errors_Enum error = eError_Unknown; - - qint32 messageID = UI2CS(static_cast(vAction)); - QStringList data; - - if ( vData.isEmpty() ) { error = eError_NoHistory; args = { messageID }; ok = false; goto lErr; } - - data = Format::fromVariantList(vData); - - if ( isDuplicate(messageID, data) ) { error = eError_Duplicate; args = { messageID }; ok = false; return ok; } // TODO: goto lErr; } don't log it just ignore and return false. - - // store the last message data - _uiHistory[messageID] = data; - - return ok; - -lErr: - toLog(error, args); - return ok; -} - -/*! - * \brief CloudSyncController::sendUIHistory - * \details sends the saved history of the message as a response to the cloud sync upon request. - * \param vAction - the request id, which in current design is same as the Message comes to the UI. - * \return true if a message history is available, false otherwise. - */ -bool CloudSyncController::sendUIHistory(const qint32 vAction) -{ - bool ok = true; - QVariantList args ; - Errors_Enum error = eError_Unknown; - - // only sends messages if device has been registered - qint32 messageID = UI2CS(static_cast(vAction)); - if ( ! isRegistered() && vAction != eMessageID_DeviceRegister ) { error = eError_NotRegistered ; args = { messageID }; ok = false; goto lErr; } - if ( ! _uiHistory.contains( messageID ) ) { error = eError_NoHistory ; args = { messageID }; ok = false; goto lErr; } - - sendUIBuff(makeUIBuff(messageID)); - - return ok; - -lErr: - toLog(error, args); - return ok; -} - -/*! - * \brief CloudSyncController::onActionReceive - * \details The slot which will be called when a CANBus message is received, and will be sent to CloudSync if related. - * \param vAction - The message action - * \param vData - The message data - */ -void CloudSyncController::onActionReceive(GuiActionType vAction, const QVariantList &vData) -{ - // TODO: This section is the translation/mapping section - // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - // preparing the message - // Same parameters will be sent for these messages for now, so data is not changed. - - switch (vAction) { - case GuiActionType::ID_HDOperationModeData : { - // ---------------------------------------------------------------------------------------- - // DEBUG : disable the HD HW message on the device on CloudSync integration testing. - // currently it is always on fault and resets CloudSync inp log - QVariantList varData = vData; - QStringList strData = Format::fromVariantList(vData); - if ( strData.length() == 2 ) { - if ( strData[0] == "0" ) { - if ( strData[1] == "1") { varData = {0,0}; } // use Fault, wait4Tx instead of 0,0 to send fault. to able to simulate and bypass HD. - else { return; } - } - } - // ---------------------------------------------------------------------------------------- - - if (saveDeviceState(varData)) // if not empty, nor duplicate, and saved - sendDeviceState(); - } - break; - - case GuiActionType::ID_AdjustSerialHDRsp : - case GuiActionType::ID_AdjustSerialDGRsp : - // this message is not complete in one step and saves only the received info and waits for the other if complete will send. - saveDeviceInfo(vAction, vData); - break; - - default: - break; - } -} - -void CloudSyncController::sendPendingTxr(const QString &vFileName) -{ - bool ok = true; Q_UNUSED(ok) - QVariantList args ; - Errors_Enum error = eError_Unknown; - qint32 messageID = UI2CS(static_cast( eMessageID_TxReport )); - // DEBUG ok = false; // using the ok bool which is true as the debug flag to bypass the registration on debug testing. - if ( ok && ! isRegistered() ) { error = eError_NotRegistered ; args = { vFileName }; ok = false; goto lErr; } - sendUIBuff(makeUIBuff( messageID , { vFileName } )); - - return; -lErr: - toLog(error, args); -} - -void CloudSyncController::onPendingTxr(const QString &vFileName) -{ - sendPendingTxr(vFileName); -} - -/*! - * \brief CloudSyncController::onPendingLog - * \details The signal handler to call the function to send the CloudSync a message to upload the pending file. - * \param vFileName - The pending file name - * \param vChecksum - The sha256sum of the file content - */ -void CloudSyncController::onPendingLog(const QString &vFileName, const QString vChecksum) -{ - sendPendingLog(vFileName, vChecksum); -} - -/*! - * \brief CloudSyncController::sendPendingLog - * \details The function to send CloudSync a message to uplaod the pending log file. - * \param vFileName - The pending file name - * \param vChecksum - The sha256sum of the file content - */ -void CloudSyncController::sendPendingLog(const QString &vFileName, const QString vChecksum) -{ - bool ok = true; Q_UNUSED(ok) - QVariantList args ; - Errors_Enum error = eError_Unknown; - qint32 messageID = UI2CS(static_cast( eMessageID_SendLogUpload )); - // DEBUG ok = false; // using the ok bool which is true as the debug flag to bypass the registration on debug testing. - if ( ok && ! isRegistered() ) { error = eError_NotRegistered ; args = { vFileName }; ok = false; goto lErr; } - sendUIBuff(makeUIBuff( messageID , { vFileName, vChecksum } )); - - return; -lErr: - toLog(error, args); -} - -/*! - * \brief CloudSyncController::rcvdPendingLog - * \details reads the received Log Name from CloudSync app and notifies with a signal. - * \param vMessage : message containing the uploaded Log name. - * \return true on successful extracting the Log Name. - */ -bool CloudSyncController::rcvdPendingLog(const Message &vMessage) -{ - bool ok = true; - QString mLogName; - // although it has been checked in the interpreter, we won't risk the crash and check the list empty. - if ( vMessage.params.isEmpty() ) { toLog(eError_LogNameNoParam , {}); ok = false; goto lOut; } - mLogName = vMessage.params[0].trimmed(); - if ( mLogName.isEmpty() ) { toLog(eError_LogNameEmpty , {}); ok = false; goto lOut; } - //DEBUG qDebug() << " ---------- " << mLogName; - emit didLogUpload( mLogName ); - - lOut: - return ok; -} - -/// -------------------------------------------------- Retention Log -/*! - * \brief CloudSyncController::onRetentionLog - * \details The slot tha handles the received even to request for the log retention - * \param vMaxUsePercent - the maximum size of the SD-Card (log storage device) cloudsync can get for the logs - */ -void CloudSyncController::onRetentionLog(quint8 vMaxUsePercent) -{ - sendRetentionLog(vMaxUsePercent); -} - -void CloudSyncController::sendRetentionLog(quint8 vMaxUsePercent) -{ - bool ok = true; Q_UNUSED(ok) - QVariantList args ; - Errors_Enum error = eError_Unknown; - qint32 messageID = UI2CS(static_cast( eMessageID_SendLogRetention )); - // DEBUG ok = false; // using the ok bool which is true as the debug flag to bypass the registration on debug testing. - if ( ok && ! isRegistered() ) { error = eError_NotRegistered ; args = { eMessageID_SendLogRetention, vMaxUsePercent }; ok = false; goto lErr; } - sendUIBuff(makeUIBuff( messageID , { QString::number(vMaxUsePercent) } )); - - return; -lErr: - toLog(error, args); -} - -bool CloudSyncController::rcvdRetentionLog(const Message &vMessage) -{ - bool ok = true; - QString tmp; - quint16 mLogsCount; // number of deleted logs - quint32 mLogsSize ; // total current logs size - // although it has been checked in the interpreter, we won't risk the crash and check the list empty. - if ( vMessage.params.isEmpty() ) { toLog(eError_LogRetentionNoParam , {eMessageID_SendLogRetention }); ok = false; goto lOut; } - if ( vMessage.params.count () < paramCount[eMessageID_SendLogRetention]) { toLog(eError_ParamCount , {eMessageID_SendLogRetention }); ok = false; goto lOut; } - - tmp = vMessage.params[0]; - mLogsCount = tmp.toUInt(&ok); - if ( ! ok ) { toLog(eError_ParamMismatch , {eMessageID_SendLogRetention, 0}); ok = false; goto lOut; } - - tmp = vMessage.params[1]; - mLogsSize = tmp.toUInt(&ok); - if ( ! ok ) { toLog(eError_ParamMismatch , {eMessageID_SendLogRetention, 1}); ok = false; goto lOut; } - - //DEBUG qDebug() << " ---------- " << mLogsCount << mLogsSize; - emit didLogRetention( mLogsCount, mLogsSize ); - - LOG_APPED_CS(QString("Log retention deleted %1 files of total %2 MB.").arg(mLogsCount).arg(mLogsSize)); - - lOut: - return ok; -} -/// -------------------------------------------------- - -/*! - * \brief CloudSyncController::sendMessage - * \details Makes and Sends the appropriate message for the vAction. - * Some messages are sent out upon request form the last received on the history and will not be asked from FW. - * \return true if there is a history for that message and no error happened. - */ -bool CloudSyncController::sendMessage(const Message &vMessage) { - bool ok = false; - // we are using the file system for the UI<=>CS communication, - // and the file events are multiple during the write to the file. - // if a write to the _out.buf trigeres the message to be sent more than once, - // ignore the same message, with the same sequence number. - static quint32 sequence ; - if ( sequence == vMessage.sequence ) return ok; - sequence = vMessage.sequence ; - - //DEBUG qDebug() << Q_FUNC_INFO << vMessage.id; - // this function is used in sendUIResponse, therefore the message IDs which are responses should be implemented here. - switch (vMessage.id) { - case eMessageID_DeviceRegister : /* No Request/Response */ break; - case eMessageID_CheckIn : ok = takeCheckIn ( ); break; - case eMessageID_DeviceInfo : ok = sendDeviceInfo ( ); break; - case eMessageID_CredentialsSave : ok = sendCredentialsSave( vMessage ); break; - case eMessageID_UIFactoryReset : ok = sendFactoryReset ( ); break; - case eMessageID_DeviceState : ok = sendDeviceState ( ); break; - - case eMessageID_TxCodeDisplay : ok = sendTxCodeDisplay ( vMessage ); break; - case eMessageID_SendLogUpload : ok = rcvdPendingLog ( vMessage ); break; - case eMessageID_SendLogRetention : ok = rcvdRetentionLog ( vMessage ); break; - - case eMessageID_TxReport : /* No Req/Rsp, it is event based */ break; // This message doesn't have the response since there is no request. UI will send when the data ready by HD. - - case eMessageID_Error : ok = errorHandler ( vMessage ); break; - - } - return ok; -} - -/*! - * \brief CloudSyncController::saveDeviceState - * \details Saves the device state in the history for later request - * \param vData - the device information - * \return - */ -bool CloudSyncController::saveDeviceState(const QVariantList &vData) -{ - bool ok = false; - ok = saveUIHistory(eMessageID_DeviceState, vData); - return ok; -} - -/*! - * \brief CloudSyncController::sendDeviceState - * \return Sends the last received device state from history to CloudSync - */ -bool CloudSyncController::sendDeviceState() -{ - bool ok = false; - ok = sendUIHistory(eMessageID_DeviceState); - return ok; -} - -/*! - * \brief CloudSyncController::csFactoryReset - * \details This function is requesting CloudSync to remove all the logs - * in the logs folder (/media/sd-card/cloudsync/log/) - * during Factory Reset - * It is a request from UI to CS since UI Linux user (denali) should not have access - * to remove the CloudSync logs. - */ -bool CloudSyncController::csFactoryReset() -{ - - bool ok = true; - return ok; // NOT IMPLEMENTED - - QVariantList args ; - Errors_Enum error = eError_Unknown; - qint32 messageID = UI2CS(static_cast( eMessageID_CSFactoryReset )); - - if ( ! isRegistered() ) { error = eError_NotRegistered ; args = {}; ok = false; goto lErr; } - sendUIBuff(makeUIBuff( messageID , { } )); - - return ok; -lErr: - toLog(error, args); - return ok; -} - -/*! - * \brief CloudSyncController::Decommissioning - * \details This function is requesting CloudSync to remove all the credentials and configurations - * in the settings partition (/var/configurations/CloudSync) - * during decommissioning - * which then it means the device needs to be re-registered to able to communicate with cloud. - * It is a request from UI to CS since UI Linux user (denali) should not have access - * to remove the CloudSync credentials. - */ -bool CloudSyncController::csDecommissioning() -{ - bool ok = true; - QVariantList args ; - Errors_Enum error = eError_Unknown; - qint32 messageID = UI2CS(static_cast( eMessageID_CSDecommissioning )); - - if ( ! isRegistered() ) { error = eError_NotRegistered ; args = {}; ok = false; goto lErr; } - sendUIBuff(makeUIBuff( messageID , { } )); - - return ok; -lErr: - toLog(error, args); - return ok; -} - -/*! - * \brief CloudSyncController::factoryReset - * \details does the reset factory - * \return true on successful reset - */ -bool CloudSyncController::uiFactoryReset() -{ - // reset factory has not been implemented yet. - bool ok = true; - // TODO: call the UI Software Reset Factory here when it has implemented. - LOG_DEBUG("CloudSync Reset factory request has not been implemented yet."); - return ok; -} - -/*! - * \brief CloudSyncController::sendFactoryReset - * \details sends the factory reset response to CloudSync - * \return true on successful send. - */ -bool CloudSyncController::sendFactoryReset() -{ - enum { eSucceed, eFailed }; - bool ok = false; - ok = uiFactoryReset(); - // if ( ! ok ) { } /* Not defined */ - qint32 messageID = UI2CS(eMessageID_UIFactoryReset); - // TODO : Store registration success in here - ok = sendUIBuff({ QString("%1").arg( messageID ) ,"1", QString("%1").arg( ok ? eSucceed : eFailed ) }); - return ok; -} - -/*! - * \brief CloudSyncController::sendCredentialsSave - * \details validates the credentials files which their sent location. - * \param vMessage - the message received from CloudSync - * \return true on successfully validate the files. - */ -bool CloudSyncController::sendCredentialsSave( const Message &vMessage) -{ - bool ok = true; - QString destination = QString(Storage::CloudSync_Base_Path_Name) + Storage::CloudSync_Credentials_Folder_Name; - - // file existence has been separated from copy remove to avoid partial copy. - if ( ! vMessage.params.count() ) { toLog(eError_CredentialCount , { }); ok = false; goto lOut; } - for ( auto fileName : vMessage.params ) { - QFileInfo fileinfo(fileName); - if ( ! fileinfo.exists() ) { toLog(eError_CredentialFile , {fileName }); ok = false; goto lOut; } - if ( fileinfo.absolutePath() != destination ) { toLog(eError_CredentialPath , {fileName }); ok = false; goto lOut; } - } - // no need to call for isRegistered() function, we are testing for the count, location, and existence. - -lOut: - if ( ok ) sendCredentialsResponse(); - emit didRegisterDone(ok); - testReady(); - return ok; -} - -/*! - * \brief CloudSyncController::sendCredentialsResponse - * \return send the confirmation of the credential save on the device from UI to CS to let CS know when to delete them. - */ -bool CloudSyncController::sendCredentialsResponse() -{ - enum { eSucceed, eFailed }; - bool ok = false; - qint32 messageID = UI2CS(eMessageID_CredentialsSave); - ok = sendUIBuff({ QString("%1").arg( messageID ) ,"1", QString("%1").arg( ok ? eSucceed : eFailed ) }); - return ok; -} - -/*! - * \brief CloudSyncController::sendCheckIn - * \details Send a check-in message and expects the same check-in message from CS - * \return - */ -bool CloudSyncController::sendCheckIn() -{ - _checkinRcvd = false; - qint32 messageID = UI2CS(eMessageID_CheckIn); - return sendUIBuff( { QString("%1").arg( messageID ) ,"0" } ); -} - -/*! - * \brief CloudSyncController::testCheckIn - * \details - * \return - */ -void CloudSyncController::testCheckIn() -{ - if ( ! _checkinRcvd ) { - LOG_APPED_UI(QString("CloudSync check-in failed")); - } -} - -/*! - * \brief CloudSyncController::takeCheckIn - * \details if the check-in received this method will be called - * \return true - - */ -bool CloudSyncController::takeCheckIn() -{ - _checkinRcvd = true; - emit didCheckInReceive(); - return true; -} - -/*! - * \brief CloudSyncController::sendTxCodeDisplay - * \details reads the received Tx Code from CloudSync app and notifies with a signal. - * \param vMessage : message containing the Tx Code. - * \return true on successful extracting the Tc Code. - */ -bool CloudSyncController::sendTxCodeDisplay(const CloudSyncController::Message &vMessage) -{ - bool ok = true; - QString mTxCode; - - // although it has been checked in the interpreter, we won't risk the crash and check the list empty. - if ( vMessage.params.isEmpty() ) { toLog(eError_TxCodeNoParam , {}); ok = false; goto lOut; } - - mTxCode = vMessage.params[0].trimmed(); - if ( mTxCode.isEmpty() ) { toLog(eError_TxCodeEmpty , {}); ok = false; goto lOut; } - - //DEBUG qDebug() << " ---------- " << mTxCode; - emit didTxCodeReceive ( mTxCode ); - -lOut: - return ok; -} - -/*! - * \brief CloudSyncController::errorHandler - * \details nothing for now. - * \param vMessage - the received message - * \return always true for now. - */ -bool CloudSyncController::errorHandler(const Message &vMessage) -{ - qDebug() << "ERR: " << vMessage.params; - return true; -} - -/*! - * \brief CloudSyncController::sendDeviceRegister - * \details sends the device registration request - * \return true on successful send. - */ -bool CloudSyncController::sendDeviceRegister() -{ - bool ok = false; - ok = sendUIHistory(eMessageID_DeviceRegister); - return ok; -} - -/*! - * \brief CloudSyncController::isRegistered - * \details checks if the device is registered by looking for existing credentials. - * \return true if device has been registered. - */ -bool CloudSyncController::isRegistered() -{ -#ifdef BUILD_FOR_DESKTOP - return true; -#else - QString source = QString(Storage::CloudSync_Base_Path_Name) + Storage::CloudSync_Credentials_Folder_Name; - QFileInfoList fileInfos = QDir(source).entryInfoList(QDir::NoDotAndDotDot|QDir::Files); - return !fileInfos.isEmpty(); -#endif -} - -/*! - * \brief CloudSyncController::testReady - * \details Checks if the CloudSync POST was passed and the device registration is complete. - */ -void CloudSyncController::testReady() -{ - bool ok = _postPass && isRegistered(); -#ifdef BUILD_FOR_DESKTOP - ok = true; -#endif - emit didCloudSyncStatus( ok - || gDisableCloudSyncFailStop // Development testability - ); -} - -/*! - * \brief CloudSyncController::saveDeviceInfo - * \details keeps the received device information and set a flag to wait for the next message. - * \param vAction - the action enum which identifies information source of HD or DG. - * \param vData - the device information - * \param vTimedOut - if true the missing device information will be filled by zero and will be sent anyway. - * \return - */ -bool CloudSyncController::saveDeviceInfo(GuiActionType vAction, const QVariantList &vData) -{ - bool ok = false; - - // the messages are coming from different sources and the order of receiving could not be guessed. - // so for each of these two we check and fill the designated variable - // if both values received - initDeviceInfoWait(); - - if ( vAction == GuiActionType::ID_AdjustSerialHDRsp ) { - if ( vData.count() ) { - _deviceInfoHD = vData[eDeviceInfo_Ix].toString(); - } else { - _deviceInfoHD = ""; - } - } - if ( vAction == GuiActionType::ID_AdjustSerialDGRsp ) { - if ( vData.count() ) { - _deviceInfoDG = vData[eDeviceInfo_Ix].toString(); - } else { - _deviceInfoDG = ""; - } - } - - if ( !_deviceInfoHD.isEmpty() && !_deviceInfoDG.isEmpty() ) { - saveDeviceInfoTimeOut(); - ok = true; - } - return ok; -} - -/*! - * \brief CloudSyncController::saveDeviceInfoTimeOut - * \details send the Device information regardless of the information filled or not. - * \return true on successful save and send. - */ -bool CloudSyncController::saveDeviceInfoTimeOut() -{ - bool ok = false; - if ( _deviceInfoUI.isEmpty() ) { _deviceInfoUI = qApp->applicationVersion(); } - saveUIHistory(eMessageID_DeviceInfo , { _deviceInfoHD, _deviceInfoDG, _deviceInfoUI } ); - saveUIHistory(eMessageID_DeviceRegister , { _deviceInfoHD, _deviceInfoDG, _deviceInfoUI } ); // the device registration request format is the same as Device info with different message id. - - sendDeviceInfo (); // this one may need to be removed and only will be sent on the request - - stopDeviceInfoWait(); - - return ok; -} - -/*! - * \brief CloudSyncController::sendDeviceInfo - * \details sends the devices information if both the HD and DG information are ready otherwise will fill the missing with 0 if the vTimeout is set to true. - * \return - */ -bool CloudSyncController::sendDeviceInfo() -{ - bool ok = false; - ok = sendUIHistory(eMessageID_DeviceInfo); - return ok; -} - -/*! - * \brief CloudSyncController::testDeviceInfoWait - * \details tests the wait conditions if there is a wait, decrements until times out and sends the device info. - */ -void CloudSyncController::testDeviceInfoWait() -{ - if (_deviceInfoStop ) return; - // DEBUG: qDebug() << _deviceInfoWait; - if (_deviceInfoWait ){ - _deviceInfoWait -- ; - } - else { - saveDeviceInfoTimeOut(); - } -} - -/*! - * \brief CloudSyncController::stopDeviceInfoWait - * \details stops waiting for the device info. - */ -void CloudSyncController::stopDeviceInfoWait() { - _deviceInfoStop = true; - // NOTE: if it is accepted to use the last received info just comment these 3 cleanup lines. - // so the last message will update the history only and it will be sent out. - _deviceInfoHD = ""; - _deviceInfoDG = ""; - _deviceInfoUI = ""; -} - -/*! - * \brief CloudSyncController::initDeviceInfoWait - * \details if currently not in wait, then set the wait to the secs of wait. - */ -void CloudSyncController::initDeviceInfoWait() { - if ( _deviceInfoStop ) { // if timer is stopped - _deviceInfoWait = _deviceInfoSecs; // enable the timer. - _deviceInfoStop = false; - } -} - -/*! - * \brief CloudSyncController::generateCRC - * \details The crc algorithm is to get - * all the message sections including, epoch, seq, and the parameters, - * without any separator - * concatenate them together like a one long string - * and run the crc on them - * \example 1674193951,4,,1001,3,HD1234567890123,DG1234567890123,DEN-14517-UI-BN-S88.01192111.1 - * str: 1674193951410013HD1234567890123DG1234567890123DEN-14517-UI-BN-S88.01192111.1 - * out: 145 - * \note the parameters values will keep untouched, meaning, if a parameter has space it will not be removed. - * \param vSecSinceEpoch - * \param vSeq - the message sequence - * \param vData - the message payload in list of strings - * \return - quint8 crc code - */ -quint8 CloudSyncController::generateCRC(quint64 vSecSinceEpoch, quint64 vSeq, const QStringList &vDataList) -{ - quint8 crc = 0; - QByteArray buf; - buf += QByteArray::number(vSecSinceEpoch); - buf += QByteArray::number(vSeq); - buf += vDataList.join("").toLatin1(); - crc = crc8(buf); - return crc; -} +#include "CloudSyncController.h" + +// Qt +#include + +// Project +#include "ApplicationController.h" +#include "DeviceController.h" +#include "FileHandler.h" +#include "TreatmentLog.h" +#include "crc.h" + +SINGLETON_DISABLE(CloudSyncController) + +/*! + * \brief CloudSyncController::CloudSyncController + * \details Constructor + * \param parent - QObject parent owner object. + * Qt handles the children destruction by their parent objects life-cycle. + */ +CloudSyncController::CloudSyncController(QObject *parent) : QObject(parent) { + testWatchBuffDate(); + startTimer(_interval); +} + +/*! + * \brief CloudSyncController initializer + */ +bool CloudSyncController::init() +{ + if ( _init ) return false; + _init = true; + + initConnections(); + LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); + + return true; +} + +/*! + * \brief CloudSyncController::init + * \details Initialized the Class by calling the init() method first + * And initializes the thread vThread by calling initThread + * on success init(). + * \param vThread - the thread + * \return returns the return value of the init() method + */ +bool CloudSyncController::init(QThread &vThread) +{ + if ( ! init() ) return false; + initThread(vThread); + return true; +} + +/*! + * \brief CloudSyncController::quit + * \details quits the class + * Calls quitThread + */ +void CloudSyncController::quit() +{ + // disabled coco begin validated: CloudSync termination is not correctly done in coco!!! + // it has been tested and works perfectly fine in normal run. + quitThread(); // validated +} +// disabled coco end + +/*! + * \brief CloudSyncController::doRegister + * \details Send the register device command. + */ +void CloudSyncController::doRegister() +{ + sendDeviceRegister(); +} + +/*! + * \brief CloudSyncController::initConnections + * \details Initializes the required signal/slot connection between this class and other objects + * to be able to communicate. + */ +void CloudSyncController::initConnections() +{ + if ( ! gDisableCloudSyncFailStop ) { + SINGLETON_DISABLE_CONNECT(didPOSTCloudSync) + } + + connect(&_ApplicationController , SIGNAL(didPOSTCloudSync(bool)), + this , SLOT( onPOSTCloudSync(bool))); + connect(&_ApplicationController , SIGNAL(didActionReceive (GuiActionType , const QVariantList &)), + this , SLOT( onActionReceive (GuiActionType , const QVariantList &))); + + connect(&_DeviceController , SIGNAL(didCryptSetupMount(bool)), + this , SLOT( onCryptSetupMount(bool))); + connect(&_DeviceController , SIGNAL(didPendingLog (const QString &, const QString &)), + this , SLOT( onPendingLog (const QString &, const QString &))); + connect(&_Logger , SIGNAL(didRetentionLogCS (quint8)), + this , SLOT( onRetentionLog (quint8))); + + connect(&_DeviceController , SIGNAL(didWatchFileChange (const QString &)), + this , SLOT( onWatchFileChange (const QString &))); + connect(&_DeviceController , SIGNAL(didFactoryReset (bool)), + this , SLOT( onFactoryReset (bool))); + connect(&_DeviceController , SIGNAL(didDecommissioning (bool)), + this , SLOT( onDecommissioning (bool))); + connect(&_TreatmentLog , SIGNAL(didPendingTxr (const QString &)), + this , SLOT( onPendingTxr (const QString &))); + connect(this , SIGNAL(didInitComplete ()), + this , SLOT( onInitComplete ()),Qt::QueuedConnection); // it has to be queued connection, don't remove it. +} + +/*! + * \brief CloudSyncController::initThread + * \details Moves this object into the thread vThread. + * And checks that this method is called from main thread. + * Also connects quitThread to CloudSync aboutToQuit. + * \param vThread - the thread + */ +void CloudSyncController::initThread(QThread &vThread) +{ + // runs in main thread + Q_ASSERT_X(QThread::currentThread() == qApp->thread(), __func__, "The Class initialization must be done in Main Thread" ); + _thread = &vThread; + _thread->setObjectName(QString("%1_Thread").arg(metaObject()->className())); + connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(quit())); + _thread->start(); + moveToThread(_thread); +} + +/*! + * \brief CloudSyncController::quitThread + * \details Moves this object to main thread to be handled by QCloudSync + * And to be destroyed there. + */ +void CloudSyncController::quitThread() +{ + // disabled coco begin validated: CloudSync termination is not correctly done in coco!!! + // it has been tested and works perfectly fine in normal run. + + if ( ! _thread ) return; + + // runs in thread + moveToThread(qApp->thread()); // validated +} +// disabled coco end + +/*! + * \brief CloudSyncController::timerEvent + * \details The timer event handler which currently is triggered on each second to check for the date change, + * Which caused the watched file change and needs to updated the watched list. + * The check-in (watch dog) also needs to be here. + */ +void CloudSyncController::timerEvent(QTimerEvent *) +{ + TIME_CALL(sendCheckIn(), _checkinIntervalSend); // call every x times/second - will be called on first call. + TIME_CALL(testCheckIn(), _checkinIntervalTest); // call every x times/second - will be called on first call. + testWatchBuffDate(); + testDeviceInfoWait(); +} + +/*! + * \brief CloudSyncController::event + * \details The override method of QObject event to handle the ThreadChange. + * \param vEvent - the QObject event + * \return true if the event e was recognized and processed + */ +bool CloudSyncController::event(QEvent *vEvent) { + if (vEvent->type() == QEvent::ThreadChange) { + emit didInitComplete(); + } + // Make sure the rest of events are handled + return QObject::event(vEvent); +} + +/*! + * \brief CloudSyncController::onInitComplete + * \details The slot to be called when the CloudSync initialization is complete + * Does nothing for now + */ +void CloudSyncController::onInitComplete() { + /* Development testability: + For testing if -C (gDisableCloudSyncFailStop) is used call the testReady + which is called + - when the encrypted partition is mounted + - a request for credential save received + testReady will set ok = true if -C (gDisableCloudSyncFailStop) is used. + */ + if ( gDisableCloudSyncFailStop ) testReady(); +} + +/*! + * \brief CloudSyncController::onPOSTCloudSync + * \details This the handler for the ApplicationController::didPOSTCloudSync(bool) + * \param vPass - will be true if the POST test of CloudSync passed and it is running. + */ +void CloudSyncController::onPOSTCloudSync(bool vPass) +{ + _postPass = vPass; +} + +/*! + * \brief CloudSyncController::onCryptSetupMount + * \details This the handler for the DeviceController::onCryptSetupMount() + */ +void CloudSyncController::onCryptSetupMount(bool vPass) +{ + if ( vPass ) { + testReady(); + } +} + +/*! + * \brief CloudSyncController::onFactoryReset + * \details this slot will be called when the DeviceController is done with the Factory Reset + * to let the UI request CS to do the Factory Reset and clean up all the Logs. + * \param vPass - Device controller factory reset was successful. + */ +void CloudSyncController::onFactoryReset(bool vPass) +{ + if ( vPass ) { + csFactoryReset(); + } +} + +/*! + * \brief CloudSyncController::onDecommissioning + * \details this slot will be called when the DeviceController is done with the Decommissioning + * to let the UI request CS to do the Decommissioning and clean up all the Tokens. + * \param vPass - Device controller Decommissioning was successful. + */ +void CloudSyncController::onDecommissioning(bool vPass) +{ + if ( vPass ) { + csDecommissioning(); + } +} + +/*! + * \brief CloudSyncController::onWatchFileChange + * \details This slot will be called when the Device Controller identifies any changes in the watched files. + * \param vFile - watched file + * \note The DeviceController will emit the signal on any watched file update, it's up to the CloudSyncController to filter the result. + */ +void CloudSyncController::onWatchFileChange(const QString &vFile) +{ + // TODO: It may improve the performance of the code to make it more specific. + // Meaning, Device controller has only one file watcher and it will call all the slots of all the classes watching for a file change. + // then ignore what is not important, but it may effect, the call queue and the threading performance. + // Later investigation. + if ( vFile != _date_out_File ) return; // ignore unwanted file updates. + QString content; + Storage::FileHandler::read(vFile, content); + sendUIResponse(content); +} + +/*! + * \brief CloudSyncController::addCSBuffWatch + * \details Adds a watcher on the CloudSync Application output file. + * \sa _out_File + */ +bool CloudSyncController::addCSBuffWatch() +{ + bool ok = true; + QVariantList args {}; + Errors_Enum error = eError_Unknown; + QString dateFormatted; + + // -------------------------------------------------- check the folder + // this makeFolder function call investigated for permissions + // during setup the folder if does not exists will be created (root) + // the lockdown.sh script will set the permissions for it. + // on power cycle to normal operation the folder with the correct exists. + // *** NOTE: the makeFolder returns true if the folder already exists. *** + ok = Storage::FileHandler::makeFolder(_location); + if ( ! ok ) { error = eError_LogFolder; args = {{ _location }}; ok = false; goto lErr; } + + // -------------------------------------------------- Check the out file + // check the date time for the file to watch + dateFormatted = _datetime.toString(_dateFormat); + if (_dateFormatted != dateFormatted ) { + _dateFormatted = dateFormatted; + _isWatching = false; // first time the date changes and CSctrl needs a new watch this flag need to be reset until the watch is added. + } + _date_out_File = _location + _dateFormatted + _dateSeparator + _out_File; + // watching/wait for the cloud sync output file buffer. + // if the file does not exists, send a check-in to the CS and wait for the response. + // by CS sending the response it will create the out file and next time this function with start watching the file. + // since this class has a one second timer set, next call is next second + // TODO: during this less that 1s UI will not see messages from CS, since the file was not there to watch. + // send device state to make the CloudSync send back a message to create the out buff with its user to own the file + ok = QFileInfo(_date_out_File).exists(); + if ( ! ok ) { + _isWatching = false; + sendCheckIn(); + } + if ( ! ok ) { error = eError_OutFileExist; args = {{ _location }}; ok = false; goto lErr; } + + // -------------------------------------------------- return if already watching + if ( _isWatching ) { goto lOut; } + + // -------------------------------------------------- add the watch + _DeviceController.doAddWatch(_date_out_File, false); + _isWatching = true; // when the watch is added then the flag sets until next time the date changes. + // since the buff files will be deleted on each power cycle, when the out buf is created it means the CloudSync is running. + // we emit the ApplicationController to check the post.log for the CloudSync status check. + goto lOut; + +lErr: + toLog(error, args); + +lOut: + return ok; +} + +/*! + * \brief CloudSyncController::interpret + * \details Checks the received buffer to make sure it has all the required parameters + * \param vIndex + * \return true if the buffer is correct. + */ +bool CloudSyncController::interpret(const QString &vContent, Message &vMessage) +{ + bool ok = true; + QVariantList args {}; + Errors_Enum error = eError_Unknown; + + QStringList lines; + QString buffer; + + int index = -1; + quint32 count = 0; + + Message message; + QStringList items; + quint32 id; + + if ( vContent.trimmed().isEmpty() ) { error = eError_OutFileEmpty ; ok = false; goto lErr; } + + lines = vContent.split('\n',Qt::SkipEmptyParts); + buffer = lines.last(); + // DEBUG: LOG_DEBUG(QString("CS [%1]").arg(buffer)); + + items = buffer.split(_separator); + count = items.count(); + + // check the required message length + if ( count < eMessage_Count ) { error = eError_HeaderCount ; ok = false; goto lErr; } + index = eMessage_Timestamp ; message.timestamp = items[index].toUInt(&ok); if (!ok) { error = eError_Timestamp ; ok = false; goto lErr; } + index = eMessage_Sequence ; message.sequence = items[index].toUInt(&ok); if (!ok) { error = eError_Sequence ; ok = false; goto lErr; } + index = eMessage_CRC ; message.crc = items[index].toUInt(&ok); if (!ok) { error = eError_CSCRC ; ok = false; goto lErr; } + index = eMessage_MessageID ; message.id = items[index].toInt (&ok); if (!ok) { error = eError_MessageID ; ok = false; goto lErr; } + index = eMessage_ParamCount; message.paramCount = items[index].toUInt(&ok); if (!ok) { error = eError_ParamCount ; ok = false; goto lErr; } + + // check the parameters count + if ( count - eMessage_Count != message.paramCount ) { error = eError_ParamMismatch ; ok = false; goto lErr; } + + // check missing parameters + id = CS2UI(message.id); + if ( ! paramCount.contains(id)) paramCount[id] = 0; + if ( message.paramCount < paramCount[id] ) { error = eError_ParamMissing ; ok = false; goto lErr; } + + // convert the message id and check its validity + id = message.id; // keep the original recevied message id after we are done using the id for loggging. + message.id = CS2UI(static_cast(message.id)); + if ( eMessageID_Start > message.id || message.id > eMessageID_Count ) { error = eError_InvalidID ; ok = false; goto lErr; } + + // getting the parameters + for ( quint32 i = eMessage_Count; i < eMessage_Count + message.paramCount; i++ ) { + message.params.append( items[i] ); + } + + vMessage = message; + LOG_APPED_CS(QString("%1,%2").arg(id).arg(message.params.join(','))); + + return true; + +lErr: + // building the error info for each error + switch (error) { + case eError_Unknown : args = { }; break; + case eError_OutFileExist : args = { }; break; + case eError_OutFileEmpty : args = { }; break; + case eError_HeaderCount : args = { count , eMessage_Count }; break; + case eError_Timestamp : args = { items[index].trimmed() }; break; + case eError_Sequence : args = { items[index].trimmed() }; break; + case eError_CSCRC : args = { items[index].trimmed() }; break; + case eError_MessageID : args = { items[index].trimmed() }; break; + case eError_InvalidID : args = { items[index].trimmed() }; break; + case eError_ParamCount : args = { items[index].trimmed() }; break; + case eError_ParamMismatch : args = { count - eMessage_Count , message.paramCount }; break; + case eError_ParamMissing : args = { paramCount[message.id] , message.paramCount }; break; + // Interpreter function only handles the message parsing errors. So default can be used. + default : break; + } + toLog(error, args); + return false; +} + +/*! + * \brief CloudSyncController::toText + * \details returns the error message of the error id. + * \param vErrorID - Error id + * \param vMessage - error message + * \return the error message or empty string if the error is 0 (no error), or Unknown Error if not found + */ +QString CloudSyncController::toText(CloudSyncController::Errors_Enum vErrorID) +{ + QString text = tr( "CS Unknown Error" ) ; + if ( vErrorID == 0 ) return text; + switch (vErrorID) { + case eError_Unknown : /* "CS Unknown Error" */ ; break; + // CS Errors + case eError_Registration : text = tr( "CS The device registration failed" ) ; break; + case eError_DeviceState : text = tr( "CS Invalid Device State" ) ; break; + case eError_TxReport : text = tr( "CS The treatment report delivery failed" ) ; break; + case eError_CheckIn : text = tr( "CS The device check-in failed" ) ; break; + case eError_Decommission : text = tr( "CS The device decommissioning failed" ) ; break; + case eError_UICRC : text = tr( "CS Invalid UI Message CRC" ) ; break; + case eError_DeviceValidation : text = tr( "CS DRT device registration failed" ) ; break; + case eError_PatientAssociation : text = tr( "CS Patient association failed" ) ; break; + case eError_GetNewTokenCert : text = tr( "CS New token certification failed" ) ; break; + case eError_VerifyToken : text = tr( "CS Token verification failed" ) ; break; + case eError_ValidateDevice : text = tr( "CS Cloud device validation failed" ) ; break; + case eError_PatientIdExists : text = tr( "CS Patient ID does not exists" ) ; break; + case eError_TemporaryPatient : text = tr( "CS Temporary patient ID creation failed" ) ; break; + case eError_SaveCredentials : text = tr( "CS Save credentials failed" ) ; break; + case eError_UnknownDeviceState : text = tr( "CS Unknown device state" ) ; break; + case eError_ConfigSave : text = tr( "CS Config file save failed" ) ; break; + case eError_DeviceLog : text = tr( "CS Log upload failed" ) ; break; + case eError_Logging : text = tr( "CS Log upload failed" ) ; break; + case eError_FactoryReset : text = tr( "CS The device factory reset failed" ) ; break; + case eError_Retention : text = tr( "CS The log retention failed" ) ; break; + // UI Errors + case eError_OutFileExist : text = tr( "CS Out buffer file does not exist" ) ; break; + case eError_OutFileEmpty : text = tr( "CS Out buffer empty" ) ; break; + case eError_HeaderCount : text = tr( "CS Incorrect header" ) ; break; + case eError_Timestamp : text = tr( "CS Incorrect timestamp" ) ; break; + case eError_Sequence : text = tr( "CS Incorrect sequence" ) ; break; + case eError_CSCRC : text = tr( "CS Incorrect CRC" ) ; break; + case eError_MessageID : text = tr( "CS Incorrect ID" ) ; break; + case eError_ParamCount : text = tr( "CS Incorrect parameter count" ) ; break; + case eError_InvalidID : text = tr( "CS Invalid ID" ) ; break; + case eError_ParamMismatch : text = tr( "CS Mismatch parameter count" ) ; break; + case eError_ParamMissing : text = tr( "CS Missing parameter" ) ; break; + case eError_NoHistory : text = tr( "CS No history available" ) ; break; + case eError_Duplicate : text = tr( "CS Duplicate data" ) ; break; + case eError_LogFolder : text = tr( "CS The log folder cannot be created." ) ; break; + case eError_LogFileInp : text = tr( "CS Error writing to the input file." ) ; break; + case eError_CredentialFile : text = tr( "CS The credentials file does not exist." ) ; break; + case eError_CredentialPath : text = tr( "CS The credentials folder is incorrect." ) ; break; + case eError_CredentialCount : text = tr( "CS No credential file name provided." ) ; break; + case eError_CredentialEmpty : text = tr( "CS The credentials folder is empty." ) ; break; + case eError_TxCodeNoParam : text = tr( "CS No Treatment Code provided." ) ; break; + case eError_TxCodeEmpty : text = tr( "CS The provided Treatment Code is empty." ) ; break; + case eError_LogNameNoParam : text = tr( "CS No Log Name provided." ) ; break; + case eError_LogNameEmpty : text = tr( "CS The provided Log Name is empty." ) ; break; + case eError_NotRegistered : text = tr( "CS Not Sent, Device not registered." ) ; break; + case eError_LogRetentionNoParam : text = tr( "CS No Log Retention summary provided." ) ; break; + + } + return text; +} + +/*! + * \brief CloudSyncController::toInfo + * \details Provides extra information, related to each error, to be concatenated later to the error description. + * \param vErrorID - the error id + * \param vInfoItems - the information items to be used in creating the info. + * \return the extra info for the error as string + */ +QString CloudSyncController::toInfo(CloudSyncController::Errors_Enum vErrorID, const QVariantList &vInfoItems) +{ + // IMPORTANT: Please be careful here used QVariantList::value to act as a loose list. + // It means it is designed to not throw out of bound error and just use "~" as a missing info argument. + auto item = [=](uint i) { return vInfoItems.value(i,"~").toString(); }; + + QString info = QString( "[%1]" ).arg( vErrorID ) ; + switch (vErrorID) { + case eError_Unknown : ; break; + // CS Errors + case eError_Registration : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_DeviceState : ; break; + case eError_TxReport : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_CheckIn : ; break; + case eError_Decommission : ; break; + case eError_UICRC : /* info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) */ ; break; + case eError_DeviceValidation : ; break; + case eError_PatientAssociation : ; break; + case eError_GetNewTokenCert : ; break; + case eError_VerifyToken : ; break; + case eError_ValidateDevice : ; break; + case eError_PatientIdExists : ; break; + case eError_TemporaryPatient : ; break; + case eError_SaveCredentials : ; break; + case eError_UnknownDeviceState : ; break; + case eError_ConfigSave : ; break; + case eError_DeviceLog : ; break; + case eError_Logging : ; break; + case eError_FactoryReset : ; break; + case eError_Retention : ; break; + // UI Errors + case eError_OutFileExist : ; break; + case eError_OutFileEmpty : ; break; + case eError_HeaderCount : info = QString( "[%1:%2/%3]" ).arg( vErrorID ).arg( item(0) ).arg( item(1) ) ; break; + case eError_Timestamp : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_Sequence : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_CSCRC : /* info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) */ ; break; + case eError_MessageID : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_InvalidID : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_ParamCount : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_ParamMismatch : info = QString( "[%1:%2/%3]" ).arg( vErrorID ).arg( item(0) ).arg( item(1) ) ; break; + case eError_ParamMissing : info = QString( "[%1:%2/%3]" ).arg( vErrorID ).arg( item(0) ).arg( item(1) ) ; break; + case eError_NoHistory : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_Duplicate : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_LogFolder : ; break; + case eError_LogFileInp : ; break; + case eError_CredentialFile : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_CredentialPath : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_CredentialCount : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_CredentialEmpty : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_TxCodeNoParam : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_TxCodeEmpty : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_LogNameNoParam : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_LogNameEmpty : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_NotRegistered : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + case eError_LogRetentionNoParam : info = QString( "[%1:%2]" ).arg( vErrorID ).arg( item(0) ) ; break; + } + return info; +} + +/*! + * \brief CloudSyncController::errorOut + * \details the function to send out the error message to the cloudsync inp buffer. + * \param vErrorID - the error id from CloudSyncController::Errors_Enum in range of 950 to 999 + * \param vInfoItems - + */ +void CloudSyncController::errorOut(CloudSyncController::Errors_Enum vErrorID, const QVariantList &vInfoItems) { + QString msg = QString::number(UI2CS(eMessageID_Error)); + QString len = QString::number(1 + vInfoItems.count()); + QString prm = QString::number(vErrorID); + QStringList buf = { msg, len, prm }; + for (const auto &item: vInfoItems) { + buf += item.toString(); + } + sendUIBuff(buf); +} + +/*! + * \brief CloudSyncController::toLog + * \details logs the error in debug mode (service log) + * \param vErrorID - error id + * \param vInfoItems - extra information + */ +void CloudSyncController::toLog(CloudSyncController::Errors_Enum vErrorID, const QVariantList &vInfoItems) +{ + errorOut(vErrorID, vInfoItems); + LOG_DEBUG(toText(vErrorID) + " " + toInfo(vErrorID, vInfoItems)); +} + +/*! + * \brief CloudSyncController::sendUIResponse + * \details the function to be called after reading the CloudSync out file to interpret the content of the file. + * \param vContent - the content to be interpreted. + * \return true if the content has a meaning for the interpreter, false otherwise. + */ +bool CloudSyncController::sendUIResponse(const QString &vContent) +{ + // IMPORTANT: + // please note the following in development testing it has been found out that. + // Do not use gedit. + // if the out.buf is edited by the "gedit" application the watch will be broken. + // The "nano" application works fine. + // A simple python3 code to open file and write to file works as well and that's sufficient for UI<=>CS communication. + // TODO: messages have to have a sequence. + // if the seq is duplicate it will be ignored. + // seq, id, payload + // DEBUG: qDebug() << vContent; + + bool ok = true; + Message message; + if ( ! interpret(vContent, message) ) return false; // The error handling internal to interpret method. + ok = sendMessage(message); + + return ok; +} + +/*! + * \brief CloudSyncController::testWatchBuffDate + * \details Checks the date and updated the watched file in case the date changed. + */ +void CloudSyncController::testWatchBuffDate() +{ + // prepare date values for addCSBufWatch + _datetime = QDateTime::currentDateTime().toUTC(); + _secSinceEpoch = _datetime.toSecsSinceEpoch(); + _timeFormatted = _datetime.toString(_timeFormat); + + addCSBuffWatch(); // bool out is not used here and error handling is internal to the addCSBuffWatch +} + +/*! + * \brief CloudSyncController::makeUIBuff + * \details make formatted UI buffer to send out. + * \param vMessage - The message id with destination added. 2k, 1K + * \return the formatted buffer + */ +QStringList CloudSyncController::makeUIBuff(const qint32 vMessageID, const QStringList &vPrm) +{ + int count = vPrm.count(); + QStringList prm = count ? vPrm : _uiHistory[ vMessageID ]; + QString msg = QString::number(vMessageID); + QString len = QString::number(prm.count()); + + QStringList dataList; + dataList += msg; + dataList += len; + dataList += prm; + + return dataList; +} + +/*! + * \brief CloudSyncController::isDuplicate + * \param vMessage - current action/messageID received. + * \param vData - current data to compare with the history + * \return true if duplicate + */ +bool CloudSyncController::isDuplicate(const qint32 vMessageID, const QStringList &vData) +{ + return _uiHistory.contains(vMessageID) && _uiHistory[vMessageID] == vData; +} + +/*! + * \brief CloudSyncController::writeInpFile + * \details Writes to the CS Input buffer + * \param vBuffer - the string out buffer. + * \return true if successful + */ +bool CloudSyncController::writeInpFile(const QString &vInpBuff) +{ + bool ok = true; + QVariantList args ; + Errors_Enum error = eError_Unknown; + + _date_inp_File = _location + // The location + _dateFormatted + _dateSeparator + _inp_File; // The file name + + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + // writing the message into the buffer. + LOG_APPED_UI( vInpBuff ); + if(!QFile::exists(_date_inp_File)){ + Storage::FileHandler::makeFolder(_location); + } + if ( ! Storage::FileHandler::write(_date_inp_File, vInpBuff + "\n") ) { error = eError_LogFileInp; args = { _date_inp_File }; ok = false; goto lErr; } + return ok; + +lErr: + // don't send the error back to the CS + // it calls this same function if the error is in this function + // and creates a loop + LOG_DEBUG(toText(error) + " " + toInfo(error, args)); + return ok; +} + +/*! + * \brief CloudSyncController::sendUIBuff + * \details Sends the UI Buffer to the UI input file. + * \param vData - the data to be sent out. + * \return true on successful writing to the file buffer. + * \sa _inp_File + */ +bool CloudSyncController::sendUIBuff(const QStringList &vDataList) +{ + bool ok = true; + QString inpBuff = "%1,%2,%3,%4"; + + inpBuff = inpBuff + .arg( _secSinceEpoch ) + .arg( Types::safeIncrement(_seq)) + .arg( generateCRC(_secSinceEpoch, _seq, vDataList)) + .arg( vDataList.join(_separator)); + + ok = writeInpFile(inpBuff); + return ok; +} + +/*! + * \brief CloudSyncController::saveUIHistory + * \details stores the action data in history, if vData is provided. + * \param vAction - the request id, which in current design is same as the Message comes to the UI. + * \param vData - The message data + * \return true if a message history is available, false otherwise. + */ +bool CloudSyncController::saveUIHistory(const qint32 vAction, const QVariantList &vData) +{ + bool ok = true; + QVariantList args ; + Errors_Enum error = eError_Unknown; + + qint32 messageID = UI2CS(static_cast(vAction)); + QStringList data; + + if ( vData.isEmpty() ) { error = eError_NoHistory; args = { messageID }; ok = false; goto lErr; } + + data = Format::fromVariantList(vData); + + if ( isDuplicate(messageID, data) ) { error = eError_Duplicate; args = { messageID }; ok = false; return ok; } // TODO: goto lErr; } don't log it just ignore and return false. + + // store the last message data + _uiHistory[messageID] = data; + + return ok; + +lErr: + toLog(error, args); + return ok; +} + +/*! + * \brief CloudSyncController::sendUIHistory + * \details sends the saved history of the message as a response to the cloud sync upon request. + * \param vAction - the request id, which in current design is same as the Message comes to the UI. + * \return true if a message history is available, false otherwise. + */ +bool CloudSyncController::sendUIHistory(const qint32 vAction) +{ + bool ok = true; + QVariantList args ; + Errors_Enum error = eError_Unknown; + + // only sends messages if device has been registered + qint32 messageID = UI2CS(static_cast(vAction)); + if ( ! isRegistered() && vAction != eMessageID_DeviceRegister ) { error = eError_NotRegistered ; args = { messageID }; ok = false; goto lErr; } + if ( ! _uiHistory.contains( messageID ) ) { error = eError_NoHistory ; args = { messageID }; ok = false; goto lErr; } + + sendUIBuff(makeUIBuff(messageID)); + + return ok; + +lErr: + toLog(error, args); + return ok; +} + +/*! + * \brief CloudSyncController::onActionReceive + * \details The slot which will be called when a CANBus message is received, and will be sent to CloudSync if related. + * \param vAction - The message action + * \param vData - The message data + */ +void CloudSyncController::onActionReceive(GuiActionType vAction, const QVariantList &vData) +{ + // TODO: This section is the translation/mapping section + // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + // preparing the message + // Same parameters will be sent for these messages for now, so data is not changed. + + switch (vAction) { + case GuiActionType::ID_HDOperationModeData : { + // ---------------------------------------------------------------------------------------- + // DEBUG : disable the HD HW message on the device on CloudSync integration testing. + // currently it is always on fault and resets CloudSync inp log + QVariantList varData = vData; + QStringList strData = Format::fromVariantList(vData); + if ( strData.length() == 2 ) { + if ( strData[0] == "0" ) { + if ( strData[1] == "1") { varData = {0,0}; } // use Fault, wait4Tx instead of 0,0 to send fault. to able to simulate and bypass HD. + else { return; } + } + } + // ---------------------------------------------------------------------------------------- + + if (saveDeviceState(varData)) // if not empty, nor duplicate, and saved + sendDeviceState(); + } + break; + + case GuiActionType::ID_AdjustSerialHDRsp : + case GuiActionType::ID_AdjustSerialDGRsp : + // this message is not complete in one step and saves only the received info and waits for the other if complete will send. + saveDeviceInfo(vAction, vData); + break; + + default: + break; + } +} + +void CloudSyncController::sendPendingTxr(const QString &vFileName) +{ + bool ok = true; Q_UNUSED(ok) + QVariantList args ; + Errors_Enum error = eError_Unknown; + qint32 messageID = UI2CS(static_cast( eMessageID_TxReport )); + // DEBUG ok = false; // using the ok bool which is true as the debug flag to bypass the registration on debug testing. + if ( ok && ! isRegistered() ) { error = eError_NotRegistered ; args = { vFileName }; ok = false; goto lErr; } + sendUIBuff(makeUIBuff( messageID , { vFileName } )); + + return; +lErr: + toLog(error, args); +} + +void CloudSyncController::onPendingTxr(const QString &vFileName) +{ + sendPendingTxr(vFileName); +} + +/*! + * \brief CloudSyncController::onPendingLog + * \details The signal handler to call the function to send the CloudSync a message to upload the pending file. + * \param vFileName - The pending file name + * \param vChecksum - The sha256sum of the file content + */ +void CloudSyncController::onPendingLog(const QString &vFileName, const QString vChecksum) +{ + sendPendingLog(vFileName, vChecksum); +} + +/*! + * \brief CloudSyncController::sendPendingLog + * \details The function to send CloudSync a message to uplaod the pending log file. + * \param vFileName - The pending file name + * \param vChecksum - The sha256sum of the file content + */ +void CloudSyncController::sendPendingLog(const QString &vFileName, const QString vChecksum) +{ + bool ok = true; Q_UNUSED(ok) + QVariantList args ; + Errors_Enum error = eError_Unknown; + qint32 messageID = UI2CS(static_cast( eMessageID_SendLogUpload )); + // DEBUG ok = false; // using the ok bool which is true as the debug flag to bypass the registration on debug testing. + if ( ok && ! isRegistered() ) { error = eError_NotRegistered ; args = { vFileName }; ok = false; goto lErr; } + sendUIBuff(makeUIBuff( messageID , { vFileName, vChecksum } )); + + return; +lErr: + toLog(error, args); +} + +/*! + * \brief CloudSyncController::rcvdPendingLog + * \details reads the received Log Name from CloudSync app and notifies with a signal. + * \param vMessage : message containing the uploaded Log name. + * \return true on successful extracting the Log Name. + */ +bool CloudSyncController::rcvdPendingLog(const Message &vMessage) +{ + bool ok = true; + QString mLogName; + // although it has been checked in the interpreter, we won't risk the crash and check the list empty. + if ( vMessage.params.isEmpty() ) { toLog(eError_LogNameNoParam , {}); ok = false; goto lOut; } + mLogName = vMessage.params[0].trimmed(); + if ( mLogName.isEmpty() ) { toLog(eError_LogNameEmpty , {}); ok = false; goto lOut; } + //DEBUG qDebug() << " ---------- " << mLogName; + emit didLogUpload( mLogName ); + + lOut: + return ok; +} + +/// -------------------------------------------------- Retention Log +/*! + * \brief CloudSyncController::onRetentionLog + * \details The slot tha handles the received even to request for the log retention + * \param vMaxUsePercent - the maximum size of the SD-Card (log storage device) cloudsync can get for the logs + */ +void CloudSyncController::onRetentionLog(quint8 vMaxUsePercent) +{ + sendRetentionLog(vMaxUsePercent); +} + +void CloudSyncController::sendRetentionLog(quint8 vMaxUsePercent) +{ + bool ok = true; Q_UNUSED(ok) + QVariantList args ; + Errors_Enum error = eError_Unknown; + qint32 messageID = UI2CS(static_cast( eMessageID_SendLogRetention )); + // DEBUG ok = false; // using the ok bool which is true as the debug flag to bypass the registration on debug testing. + if ( ok && ! isRegistered() ) { error = eError_NotRegistered ; args = { eMessageID_SendLogRetention, vMaxUsePercent }; ok = false; goto lErr; } + sendUIBuff(makeUIBuff( messageID , { QString::number(vMaxUsePercent) } )); + + return; +lErr: + toLog(error, args); +} + +bool CloudSyncController::rcvdRetentionLog(const Message &vMessage) +{ + bool ok = true; + QString tmp; + quint16 mLogsCount; // number of deleted logs + quint32 mLogsSize ; // total current logs size + // although it has been checked in the interpreter, we won't risk the crash and check the list empty. + if ( vMessage.params.isEmpty() ) { toLog(eError_LogRetentionNoParam , {eMessageID_SendLogRetention }); ok = false; goto lOut; } + if ( vMessage.params.count () < paramCount[eMessageID_SendLogRetention]) { toLog(eError_ParamCount , {eMessageID_SendLogRetention }); ok = false; goto lOut; } + + tmp = vMessage.params[0]; + mLogsCount = tmp.toUInt(&ok); + if ( ! ok ) { toLog(eError_ParamMismatch , {eMessageID_SendLogRetention, 0}); ok = false; goto lOut; } + + tmp = vMessage.params[1]; + mLogsSize = tmp.toUInt(&ok); + if ( ! ok ) { toLog(eError_ParamMismatch , {eMessageID_SendLogRetention, 1}); ok = false; goto lOut; } + + //DEBUG qDebug() << " ---------- " << mLogsCount << mLogsSize; + emit didLogRetention( mLogsCount, mLogsSize ); + + LOG_APPED_CS(QString("Log retention deleted %1 files of total %2 MB.").arg(mLogsCount).arg(mLogsSize)); + + lOut: + return ok; +} +/// -------------------------------------------------- + +/*! + * \brief CloudSyncController::sendMessage + * \details Makes and Sends the appropriate message for the vAction. + * Some messages are sent out upon request form the last received on the history and will not be asked from FW. + * \return true if there is a history for that message and no error happened. + */ +bool CloudSyncController::sendMessage(const Message &vMessage) { + bool ok = false; + // we are using the file system for the UI<=>CS communication, + // and the file events are multiple during the write to the file. + // if a write to the _out.buf trigeres the message to be sent more than once, + // ignore the same message, with the same sequence number. + static quint32 sequence ; + if ( sequence == vMessage.sequence ) return ok; + sequence = vMessage.sequence ; + + //DEBUG qDebug() << Q_FUNC_INFO << vMessage.id; + // this function is used in sendUIResponse, therefore the message IDs which are responses should be implemented here. + switch (vMessage.id) { + case eMessageID_DeviceRegister : /* No Request/Response */ break; + case eMessageID_CheckIn : ok = takeCheckIn ( ); break; + case eMessageID_DeviceInfo : ok = sendDeviceInfo ( ); break; + case eMessageID_CredentialsSave : ok = sendCredentialsSave( vMessage ); break; + case eMessageID_UIFactoryReset : ok = sendFactoryReset ( ); break; + case eMessageID_DeviceState : ok = sendDeviceState ( ); break; + + case eMessageID_TxCodeDisplay : ok = sendTxCodeDisplay ( vMessage ); break; + case eMessageID_SendLogUpload : ok = rcvdPendingLog ( vMessage ); break; + case eMessageID_SendLogRetention : ok = rcvdRetentionLog ( vMessage ); break; + + case eMessageID_TxReport : /* No Req/Rsp, it is event based */ break; // This message doesn't have the response since there is no request. UI will send when the data ready by HD. + + case eMessageID_Error : ok = errorHandler ( vMessage ); break; + + } + return ok; +} + +/*! + * \brief CloudSyncController::saveDeviceState + * \details Saves the device state in the history for later request + * \param vData - the device information + * \return + */ +bool CloudSyncController::saveDeviceState(const QVariantList &vData) +{ + bool ok = false; + ok = saveUIHistory(eMessageID_DeviceState, vData); + return ok; +} + +/*! + * \brief CloudSyncController::sendDeviceState + * \return Sends the last received device state from history to CloudSync + */ +bool CloudSyncController::sendDeviceState() +{ + bool ok = false; + ok = sendUIHistory(eMessageID_DeviceState); + return ok; +} + +/*! + * \brief CloudSyncController::csFactoryReset + * \details This function is requesting CloudSync to remove all the logs + * in the logs folder (/media/sd-card/cloudsync/log/) + * during Factory Reset + * It is a request from UI to CS since UI Linux user (denali) should not have access + * to remove the CloudSync logs. + */ +bool CloudSyncController::csFactoryReset() +{ + + bool ok = true; + return ok; // NOT IMPLEMENTED + + QVariantList args ; + Errors_Enum error = eError_Unknown; + qint32 messageID = UI2CS(static_cast( eMessageID_CSFactoryReset )); + + if ( ! isRegistered() ) { error = eError_NotRegistered ; args = {}; ok = false; goto lErr; } + sendUIBuff(makeUIBuff( messageID , { } )); + + return ok; +lErr: + toLog(error, args); + return ok; +} + +/*! + * \brief CloudSyncController::Decommissioning + * \details This function is requesting CloudSync to remove all the credentials and configurations + * in the settings partition (/var/configurations/CloudSync) + * during decommissioning + * which then it means the device needs to be re-registered to able to communicate with cloud. + * It is a request from UI to CS since UI Linux user (denali) should not have access + * to remove the CloudSync credentials. + */ +bool CloudSyncController::csDecommissioning() +{ + bool ok = true; + QVariantList args ; + Errors_Enum error = eError_Unknown; + qint32 messageID = UI2CS(static_cast( eMessageID_CSDecommissioning )); + + if ( ! isRegistered() ) { error = eError_NotRegistered ; args = {}; ok = false; goto lErr; } + sendUIBuff(makeUIBuff( messageID , { } )); + + return ok; +lErr: + toLog(error, args); + return ok; +} + +/*! + * \brief CloudSyncController::factoryReset + * \details does the reset factory + * \return true on successful reset + */ +bool CloudSyncController::uiFactoryReset() +{ + // reset factory has not been implemented yet. + bool ok = true; + // TODO: call the UI Software Reset Factory here when it has implemented. + LOG_DEBUG("CloudSync Reset factory request has not been implemented yet."); + return ok; +} + +/*! + * \brief CloudSyncController::sendFactoryReset + * \details sends the factory reset response to CloudSync + * \return true on successful send. + */ +bool CloudSyncController::sendFactoryReset() +{ + enum { eSucceed, eFailed }; + bool ok = false; + ok = uiFactoryReset(); + // if ( ! ok ) { } /* Not defined */ + qint32 messageID = UI2CS(eMessageID_UIFactoryReset); + // TODO : Store registration success in here + ok = sendUIBuff({ QString("%1").arg( messageID ) ,"1", QString("%1").arg( ok ? eSucceed : eFailed ) }); + return ok; +} + +/*! + * \brief CloudSyncController::sendCredentialsSave + * \details validates the credentials files which their sent location. + * \param vMessage - the message received from CloudSync + * \return true on successfully validate the files. + */ +bool CloudSyncController::sendCredentialsSave( const Message &vMessage) +{ + bool ok = true; + QString destination = QString(Storage::CloudSync_Base_Path_Name) + Storage::CloudSync_Credentials_Folder_Name; + + // file existence has been separated from copy remove to avoid partial copy. + if ( ! vMessage.params.count() ) { toLog(eError_CredentialCount , { }); ok = false; goto lOut; } + for ( auto fileName : vMessage.params ) { + QFileInfo fileinfo(fileName); + if ( ! fileinfo.exists() ) { toLog(eError_CredentialFile , {fileName }); ok = false; goto lOut; } + if ( fileinfo.absolutePath() != destination ) { toLog(eError_CredentialPath , {fileName }); ok = false; goto lOut; } + } + // no need to call for isRegistered() function, we are testing for the count, location, and existence. + +lOut: + if ( ok ) sendCredentialsResponse(); + emit didRegisterDone(ok); + testReady(); + return ok; +} + +/*! + * \brief CloudSyncController::sendCredentialsResponse + * \return send the confirmation of the credential save on the device from UI to CS to let CS know when to delete them. + */ +bool CloudSyncController::sendCredentialsResponse() +{ + enum { eSucceed, eFailed }; + bool ok = false; + qint32 messageID = UI2CS(eMessageID_CredentialsSave); + ok = sendUIBuff({ QString("%1").arg( messageID ) ,"1", QString("%1").arg( ok ? eSucceed : eFailed ) }); + return ok; +} + +/*! + * \brief CloudSyncController::sendCheckIn + * \details Send a check-in message and expects the same check-in message from CS + * \return + */ +bool CloudSyncController::sendCheckIn() +{ + _checkinRcvd = false; + qint32 messageID = UI2CS(eMessageID_CheckIn); + return sendUIBuff( { QString("%1").arg( messageID ) ,"0" } ); +} + +/*! + * \brief CloudSyncController::testCheckIn + * \details + * \return + */ +void CloudSyncController::testCheckIn() +{ + if ( ! _checkinRcvd ) { + LOG_APPED_UI(QString("CloudSync check-in failed")); + } +} + +/*! + * \brief CloudSyncController::takeCheckIn + * \details if the check-in received this method will be called + * \return true - + */ +bool CloudSyncController::takeCheckIn() +{ + _checkinRcvd = true; + emit didCheckInReceive(); + return true; +} + +/*! + * \brief CloudSyncController::sendTxCodeDisplay + * \details reads the received Tx Code from CloudSync app and notifies with a signal. + * \param vMessage : message containing the Tx Code. + * \return true on successful extracting the Tc Code. + */ +bool CloudSyncController::sendTxCodeDisplay(const CloudSyncController::Message &vMessage) +{ + bool ok = true; + QString mTxCode; + + // although it has been checked in the interpreter, we won't risk the crash and check the list empty. + if ( vMessage.params.isEmpty() ) { toLog(eError_TxCodeNoParam , {}); ok = false; goto lOut; } + + mTxCode = vMessage.params[0].trimmed(); + if ( mTxCode.isEmpty() ) { toLog(eError_TxCodeEmpty , {}); ok = false; goto lOut; } + + //DEBUG qDebug() << " ---------- " << mTxCode; + emit didTxCodeReceive ( mTxCode ); + +lOut: + return ok; +} + +/*! + * \brief CloudSyncController::errorHandler + * \details nothing for now. + * \param vMessage - the received message + * \return always true for now. + */ +bool CloudSyncController::errorHandler(const Message &vMessage) +{ + qDebug() << "ERR: " << vMessage.params; + return true; +} + +/*! + * \brief CloudSyncController::sendDeviceRegister + * \details sends the device registration request + * \return true on successful send. + */ +bool CloudSyncController::sendDeviceRegister() +{ + bool ok = false; + ok = sendUIHistory(eMessageID_DeviceRegister); + return ok; +} + +/*! + * \brief CloudSyncController::isRegistered + * \details checks if the device is registered by looking for existing credentials. + * \return true if device has been registered. + */ +bool CloudSyncController::isRegistered() +{ +#ifdef BUILD_FOR_DESKTOP + return true; +#else + QString source = QString(Storage::CloudSync_Base_Path_Name) + Storage::CloudSync_Credentials_Folder_Name; + QFileInfoList fileInfos = QDir(source).entryInfoList(QDir::NoDotAndDotDot|QDir::Files); + return !fileInfos.isEmpty(); +#endif +} + +/*! + * \brief CloudSyncController::testReady + * \details Checks if the CloudSync POST was passed and the device registration is complete. + */ +void CloudSyncController::testReady() +{ + bool ok = _postPass && isRegistered(); +#ifdef BUILD_FOR_DESKTOP + ok = true; +#endif + emit didCloudSyncStatus( ok + || gDisableCloudSyncFailStop // Development testability + ); +} + +/*! + * \brief CloudSyncController::saveDeviceInfo + * \details keeps the received device information and set a flag to wait for the next message. + * \param vAction - the action enum which identifies information source of HD or DG. + * \param vData - the device information + * \param vTimedOut - if true the missing device information will be filled by zero and will be sent anyway. + * \return + */ +bool CloudSyncController::saveDeviceInfo(GuiActionType vAction, const QVariantList &vData) +{ + bool ok = false; + + // the messages are coming from different sources and the order of receiving could not be guessed. + // so for each of these two we check and fill the designated variable + // if both values received + initDeviceInfoWait(); + + if ( vAction == GuiActionType::ID_AdjustSerialHDRsp ) { + if ( vData.count() ) { + _deviceInfoHD = vData[eDeviceInfo_Ix].toString(); + } else { + _deviceInfoHD = ""; + } + } + if ( vAction == GuiActionType::ID_AdjustSerialDGRsp ) { + if ( vData.count() ) { + _deviceInfoDG = vData[eDeviceInfo_Ix].toString(); + } else { + _deviceInfoDG = ""; + } + } + + if ( !_deviceInfoHD.isEmpty() && !_deviceInfoDG.isEmpty() ) { + saveDeviceInfoTimeOut(); + ok = true; + } + return ok; +} + +/*! + * \brief CloudSyncController::saveDeviceInfoTimeOut + * \details send the Device information regardless of the information filled or not. + * \return true on successful save and send. + */ +bool CloudSyncController::saveDeviceInfoTimeOut() +{ + bool ok = false; + if ( _deviceInfoUI.isEmpty() ) { _deviceInfoUI = qApp->applicationVersion(); } + saveUIHistory(eMessageID_DeviceInfo , { _deviceInfoHD, _deviceInfoDG, _deviceInfoUI } ); + saveUIHistory(eMessageID_DeviceRegister , { _deviceInfoHD, _deviceInfoDG, _deviceInfoUI } ); // the device registration request format is the same as Device info with different message id. + + sendDeviceInfo (); // this one may need to be removed and only will be sent on the request + + stopDeviceInfoWait(); + + return ok; +} + +/*! + * \brief CloudSyncController::sendDeviceInfo + * \details sends the devices information if both the HD and DG information are ready otherwise will fill the missing with 0 if the vTimeout is set to true. + * \return + */ +bool CloudSyncController::sendDeviceInfo() +{ + bool ok = false; + ok = sendUIHistory(eMessageID_DeviceInfo); + return ok; +} + +/*! + * \brief CloudSyncController::testDeviceInfoWait + * \details tests the wait conditions if there is a wait, decrements until times out and sends the device info. + */ +void CloudSyncController::testDeviceInfoWait() +{ + if (_deviceInfoStop ) return; + // DEBUG: qDebug() << _deviceInfoWait; + if (_deviceInfoWait ){ + _deviceInfoWait -- ; + } + else { + saveDeviceInfoTimeOut(); + } +} + +/*! + * \brief CloudSyncController::stopDeviceInfoWait + * \details stops waiting for the device info. + */ +void CloudSyncController::stopDeviceInfoWait() { + _deviceInfoStop = true; + // NOTE: if it is accepted to use the last received info just comment these 3 cleanup lines. + // so the last message will update the history only and it will be sent out. + _deviceInfoHD = ""; + _deviceInfoDG = ""; + _deviceInfoUI = ""; +} + +/*! + * \brief CloudSyncController::initDeviceInfoWait + * \details if currently not in wait, then set the wait to the secs of wait. + */ +void CloudSyncController::initDeviceInfoWait() { + if ( _deviceInfoStop ) { // if timer is stopped + _deviceInfoWait = _deviceInfoSecs; // enable the timer. + _deviceInfoStop = false; + } +} + +/*! + * \brief CloudSyncController::generateCRC + * \details The crc algorithm is to get + * all the message sections including, epoch, seq, and the parameters, + * without any separator + * concatenate them together like a one long string + * and run the crc on them + * \example 1674193951,4,,1001,3,HD1234567890123,DG1234567890123,DEN-14517-UI-BN-S88.01192111.1 + * str: 1674193951410013HD1234567890123DG1234567890123DEN-14517-UI-BN-S88.01192111.1 + * out: 145 + * \note the parameters values will keep untouched, meaning, if a parameter has space it will not be removed. + * \param vSecSinceEpoch + * \param vSeq - the message sequence + * \param vData - the message payload in list of strings + * \return - quint8 crc code + */ +quint8 CloudSyncController::generateCRC(quint64 vSecSinceEpoch, quint64 vSeq, const QStringList &vDataList) +{ + quint8 crc = 0; + QByteArray buf; + buf += QByteArray::number(vSecSinceEpoch); + buf += QByteArray::number(vSeq); + buf += vDataList.join("").toLatin1(); + crc = crc8(buf); + return crc; +} Index: sources/gui/GuiController.cpp =================================================================== diff -u -r2ef03b2ce51b4dc507f66e9671953a8e0824bde9 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/gui/GuiController.cpp (.../GuiController.cpp) (revision 2ef03b2ce51b4dc507f66e9671953a8e0824bde9) +++ sources/gui/GuiController.cpp (.../GuiController.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -159,7 +159,7 @@ initConnections(); - LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); + LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); return true; } Index: sources/gui/qml/pages/pretreatment/create/PreTreatmentCreate.qml =================================================================== diff -u -r83b9d737cd495b34a7b42f5409962a9442f3b8f4 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/gui/qml/pages/pretreatment/create/PreTreatmentCreate.qml (.../PreTreatmentCreate.qml) (revision 83b9d737cd495b34a7b42f5409962a9442f3b8f4) +++ sources/gui/qml/pages/pretreatment/create/PreTreatmentCreate.qml (.../PreTreatmentCreate.qml) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -427,7 +427,7 @@ SliderCreateTreatment { id: _salineBolus objectName : "_salineBolus" - label : "Saline Bolus" + label : qsTr("Saline Bolus") flickable : _flickable unit : Variables.unitTextFluid minimum : vTreatmentRanges.salineBolusVolumeMin Index: sources/storage/Logger.cpp =================================================================== diff -u -r5687815256ae070a9a207107088e3f72dd464da0 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/storage/Logger.cpp (.../Logger.cpp) (revision 5687815256ae070a9a207107088e3f72dd464da0) +++ sources/storage/Logger.cpp (.../Logger.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -91,8 +91,8 @@ if ( ! checkThread() ) return; ADD_APPED_HEADER; ADD_DEBUG_HEADER; - LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); - LOG_DEBUG(tr("Application %1 Started").arg(qApp->applicationName())); + LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); + LOG_DEBUG(QString("Application %1 Started").arg(qApp->applicationName())); LOG_APPED_UI(qApp-> applicationVersion()); } Index: sources/storage/Settings.cpp =================================================================== diff -u -ra522e6aa7a36ac696a9a956200e89d838f319e25 -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/storage/Settings.cpp (.../Settings.cpp) (revision a522e6aa7a36ac696a9a956200e89d838f319e25) +++ sources/storage/Settings.cpp (.../Settings.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -306,7 +306,7 @@ .arg(Storage::Settings_Path()) .arg(Storage::Settings_Category_Translation) .arg("qm") - .arg(_settingsLocalSeparator + QString("de")); // locale); + .arg(_settingsLocalSeparator + QString("es")); // locale); qDebug() << __FUNCTION__ << ":" << __LINE__ << "-------------qmFile:" << qmFile; Index: sources/storage/TreatmentLog.cpp =================================================================== diff -u -r3b323bd6a1a03429c2321a889049de1c3b11302f -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/storage/TreatmentLog.cpp (.../TreatmentLog.cpp) (revision 3b323bd6a1a03429c2321a889049de1c3b11302f) +++ sources/storage/TreatmentLog.cpp (.../TreatmentLog.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -495,7 +495,7 @@ lOut: if ( ! ok ) { - LOG_DEBUG(status); + LOG_DEBUG(status); // The log debug order in this block is by design status = "Unable to export treatment log '" + srcFileName +"'"; } else { Index: sources/wifi/WifiInterface.cpp =================================================================== diff -u -r14e9940ccba0c2d64b5e16aa34edcb995f0563fd -r4947841e8cdd7e72d4fe26e604f7e5061fb86d64 --- sources/wifi/WifiInterface.cpp (.../WifiInterface.cpp) (revision 14e9940ccba0c2d64b5e16aa34edcb995f0563fd) +++ sources/wifi/WifiInterface.cpp (.../WifiInterface.cpp) (revision 4947841e8cdd7e72d4fe26e604f7e5061fb86d64) @@ -205,7 +205,7 @@ _init = true; initConnections(); - LOG_DEBUG(tr("%1 Initialized").arg(metaObject()->className())); + LOG_DEBUG(QString("%1 Initialized").arg(metaObject()->className())); return true; }