Index: denali.qrc =================================================================== diff -u -rd26aff743bca7eceb609ce5b30cea7cbfa39748f -r59625af31d9009df82fa48310b54c0f247e829fc --- denali.qrc (.../denali.qrc) (revision d26aff743bca7eceb609ce5b30cea7cbfa39748f) +++ denali.qrc (.../denali.qrc) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -25,6 +25,7 @@ sources/gui/qml/pages/settings/SettingsManufacturingSetup.qml sources/gui/qml/pages/settings/SettingsFactoryReset.qml sources/gui/qml/pages/settings/SettingsDecommission.qml + sources/gui/qml/pages/settings/SettingsStartSoftwareUpdate.qml sources/gui/qml/dialogs/ConfirmDialog.qml Index: sources/device/DeviceController.cpp =================================================================== diff -u -r1bf8c894c5cc5ea6d62af0662fcf5a18e1a06459 -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/device/DeviceController.cpp (.../DeviceController.cpp) (revision 1bf8c894c5cc5ea6d62af0662fcf5a18e1a06459) +++ sources/device/DeviceController.cpp (.../DeviceController.cpp) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -1181,3 +1181,55 @@ // log error and exit return; } + +///////////////////////////////////////////// DeviceStartSoftwareUpdate +void DeviceController::onAttributeRequest(const DeviceStartSoftwareUpdateRequestData &vData) +{ + _deviceStartSoftwareUpdateRequest._data = vData; + + // ----- check that script exists. + QString script = Device_StartSoftwareUpdateScriptPath; + DeviceError::Scripts_Error_Enum err = DeviceError::eDevice_OK; + QFileInfo info(script); + if ( ! info.exists () ) { err = DeviceError::eDevice_Scripts_Error_NotFound ;} + if ( ! info.isExecutable() ) { err = DeviceError::eDevice_Scripts_Error_NotExecutable ;} + + if ( checkError(err, _deviceStartSoftwareUpdateResponse, script) ) + return; + + // ----- check if the process is not running + if ( _processStartSoftwareUpdate.state() != QProcess::NotRunning ) { + checkError(DeviceError::eDevice_Scripts_Error_IsRunning, _deviceStartSoftwareUpdateResponse); + return; + } + + // ----- run the process + int timeout_ms = 10000; + TimedProcess *timedProcess = new TimedProcess(&_processStartSoftwareUpdate, script, timeout_ms, { vData.mUpdateFilePath }); + timedProcess->start(); + + MDeviceStartSoftwareUpdateResponse model; + model._data.mAccepted = false; // will indirectly set the property startSoftwareUpdateEnabled + model._data.mMessage = tr("Software Update started."); + didAttributeResponse(model.data()); +} + +/*! + * \brief DeviceController::onProcessStartSoftwareUpdateExitCode + * \param vExitCode + * \param vStatus + */ +void DeviceController::onProcessStartSoftwareUpdateExitCode(int vExitCode, QProcess::ExitStatus vStatus) +{ + // The Exit code in this script is not used. + // any other checking is done by UI Software at the moment this script is called. + // The only thing matters is the paired device info in text and it will be empty string if error happens. + MDeviceStartSoftwareUpdateResponse model; + QByteArray deviceInfo; + if ( vStatus ) vExitCode = Device::DeviceError::eDevice_Scripts_Error_Status; + else deviceInfo = _processStartSoftwareUpdate.readAll(); + model.fromByteArray( deviceInfo, &vExitCode ); + // DEBUG: qDebug() << model._data.mMessage << deviceInfo; + didAttributeResponse(model.data()); + LOG_APPED_UI(model.data().mMessage); +} Index: sources/device/DeviceError.h =================================================================== diff -u -r1bf8c894c5cc5ea6d62af0662fcf5a18e1a06459 -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/device/DeviceError.h (.../DeviceError.h) (revision 1bf8c894c5cc5ea6d62af0662fcf5a18e1a06459) +++ sources/device/DeviceError.h (.../DeviceError.h) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -67,6 +67,7 @@ eDevice_FactoryReset_Error , eDevice_Decommission_Error , eDevice_USBMount_Error , + eDevice_StartSoftwareUpdate_Error , eDevice_Error_End Index: sources/device/DeviceGlobals.h =================================================================== diff -u -r80b5e8f1ebb90c03c37d90d90cd2da3bd95d6803 -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/device/DeviceGlobals.h (.../DeviceGlobals.h) (revision 80b5e8f1ebb90c03c37d90d90cd2da3bd95d6803) +++ sources/device/DeviceGlobals.h (.../DeviceGlobals.h) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -173,6 +173,7 @@ DEVICE_DEV_PARENT ( FactoryReset ) \ DEVICE_DEV_PARENT ( Decommission ) \ DEVICE_DEV_PARENT ( USBMount ) \ + DEVICE_DEV_PARENT ( StartSoftwareUpdate ) \ #define DEVICE_DEV_INIT_CONNECTIONS_LIST \ DEVICE_DEV_INIT_CONNECTIONS ( Brightness ) \ @@ -183,6 +184,7 @@ DEVICE_DEV_INIT_CONNECTIONS ( FactoryReset ) \ DEVICE_DEV_INIT_CONNECTIONS ( Decommission ) \ DEVICE_DEV_INIT_CONNECTIONS ( USBMount ) \ + DEVICE_DEV_INIT_CONNECTIONS ( StartSoftwareUpdate ) \ #define DEVICE_DEV_DEFINITION_LIST \ DEVICE_DEV_DEFINITION ( Brightness ) \ @@ -193,8 +195,10 @@ DEVICE_DEV_DEFINITION ( FactoryReset ) \ DEVICE_DEV_DEFINITION ( Decommission ) \ DEVICE_DEV_DEFINITION ( USBMount ) \ + DEVICE_DEV_DEFINITION ( StartSoftwareUpdate ) \ + /* ---------------------------- APP */ #define DEVICE_APP_INIT_CONNECTIONS_LIST \ DEVICE_APP_INIT_CONNECTIONS ( Brightness ) \ @@ -204,6 +208,7 @@ DEVICE_APP_INIT_CONNECTIONS ( RootSSHAccess ) \ DEVICE_APP_INIT_CONNECTIONS ( FactoryReset ) \ DEVICE_APP_INIT_CONNECTIONS ( Decommission ) \ + DEVICE_APP_INIT_CONNECTIONS ( StartSoftwareUpdate ) \ #define DEVICE_APP_BRIDGE_DEFINITION_LIST \ DEVICE_APP_BRIDGE_DEFINITION( Brightness ) \ @@ -214,6 +219,7 @@ DEVICE_APP_BRIDGE_DEFINITION( FactoryReset ) \ DEVICE_APP_BRIDGE_DEFINITION( Decommission ) \ DEVICE_APP_BRIDGE_DEFINITION( USBMount ) \ + DEVICE_APP_BRIDGE_DEFINITION( StartSoftwareUpdate ) \ /* ---------------------------- GUI */ #define DEVICE_GUI_BRIDGE_DEFINITION_LIST \ @@ -224,6 +230,7 @@ DEVICE_GUI_BRIDGE_DEFINITION( RootSSHAccess ) \ DEVICE_GUI_BRIDGE_DEFINITION( FactoryReset ) \ DEVICE_GUI_BRIDGE_DEFINITION( Decommission ) \ + DEVICE_GUI_BRIDGE_DEFINITION( StartSoftwareUpdate ) \ #define DEVICE_GUI_INIT_CONNECTIONS_LIST \ DEVICE_GUI_INIT_CONNECTIONS ( Brightness ) \ @@ -233,6 +240,7 @@ DEVICE_GUI_INIT_CONNECTIONS ( RootSSHAccess ) \ DEVICE_GUI_INIT_CONNECTIONS ( FactoryReset ) \ DEVICE_GUI_INIT_CONNECTIONS ( Decommission ) \ + DEVICE_GUI_INIT_CONNECTIONS ( StartSoftwareUpdate ) \ /* ---------------------------- VIEW */ #define DEVICE_VIEW_INIT_CONNECTIONS_LIST \ @@ -243,4 +251,5 @@ DEVICE_VIEW_INIT_CONNECTIONS( RootSSHAccess ) \ DEVICE_VIEW_INIT_CONNECTIONS( FactoryReset ) \ DEVICE_VIEW_INIT_CONNECTIONS( Decommission ) \ + DEVICE_VIEW_INIT_CONNECTIONS( StartSoftwareUpdate ) \ Index: sources/device/DeviceModels.cpp =================================================================== diff -u -r80b5e8f1ebb90c03c37d90d90cd2da3bd95d6803 -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/device/DeviceModels.cpp (.../DeviceModels.cpp) (revision 80b5e8f1ebb90c03c37d90d90cd2da3bd95d6803) +++ sources/device/DeviceModels.cpp (.../DeviceModels.cpp) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -282,3 +282,35 @@ lOut: return _data.mAccepted; } + + + +/*! + * \brief MDeviceStartSoftwareUpdateResponse::fromByteArray + * \details Checks the response and sets up the mode data. + * \param vExitCode - Passed script exit code + * \return true if passed. + */ +bool MDeviceStartSoftwareUpdateResponse::fromByteArray(const QByteArray &vByteArray, int *vExitCode) +{ + // initialize data + int error = 0; + _data.mAccepted = false; + + // check if the vExitCode passed and it has a value other than zero + if ( vExitCode && *vExitCode ){ _data.mReason = Device::DeviceError::eDevice_StartSoftwareUpdate_Error; error = *vExitCode; } + else _data.mReason = Device::DeviceError::eDevice_OK; + + // if vExitCode is not zero go to error since the data is no longer valid + if ( _data.mReason ) goto lError; // non-zero Exit code + + // Now everything is good to extract the data + _data.mAccepted = true; + _data.mMessage = QObject::tr("The Start Software Update Command Complete."); goto lOut ; // normal return + +lError: + _data.mMessage = Device::DeviceError::deviceErrorText(static_cast(_data.mReason), error) + "\n" + vByteArray; + +lOut: + return _data.mAccepted; +} Index: sources/device/DeviceModels.h =================================================================== diff -u -ra7c580f0998ee781c47314384f677249cea4c4b4 -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/device/DeviceModels.h (.../DeviceModels.h) (revision a7c580f0998ee781c47314384f677249cea4c4b4) +++ sources/device/DeviceModels.h (.../DeviceModels.h) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -368,6 +368,36 @@ Data data ( ) const { return _data; } bool fromByteArray(const QByteArray &vByteArray, int *vExitCode = nullptr) override; }; + +// ---------- MDeviceStartSoftwareUpdate ---------- // +/*! + * \brief The MDeviceStartSoftwareUpdateRequest class + * \details The model for the decommission script call. + */ +class MDeviceStartSoftwareUpdateRequest : public MDeviceRequestBase { +public: + struct Data { + QString mUpdateFilePath = ""; + } _data; + + QString toString() { + return MDeviceRequestBase::toString("StartSoftwareUpdate", { }); + } +}; + +/*! + * \brief The MDeviceStartSoftwareUpdateResponse class + * \details The model for the decommission script call returned value / response. + */ +class MDeviceStartSoftwareUpdateResponse : public MDeviceResponseBase { +public: + struct Data : MDeviceResponseBase::Data { + } _data; + QVariantList parameters ( ) const override { return { }; } + QString infoText ( ) const override { return QString("StartSoftwareUpdate"); } + Data data ( ) const { return _data; } + bool fromByteArray(const QByteArray &vByteArray, int *vExitCode = nullptr) override; +}; } typedef Model::MDeviceResponseBase ::Data DeviceResponseBaseData ; @@ -395,3 +425,7 @@ typedef Model::MDeviceUSBMountRequest ::Data DeviceUSBMountRequestData ; typedef Model::MDeviceUSBMountResponse::Data DeviceUSBMountResponseData; + +typedef Model::MDeviceStartSoftwareUpdateRequest ::Data DeviceStartSoftwareUpdateRequestData ; +typedef Model::MDeviceStartSoftwareUpdateResponse::Data DeviceStartSoftwareUpdateResponseData; + Index: sources/device/DeviceView.cpp =================================================================== diff -u -ra7c580f0998ee781c47314384f677249cea4c4b4 -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/device/DeviceView.cpp (.../DeviceView.cpp) (revision a7c580f0998ee781c47314384f677249cea4c4b4) +++ sources/device/DeviceView.cpp (.../DeviceView.cpp) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -258,6 +258,36 @@ response(true); } +// ================================================= Start Software Update +void VDevice::doInitStartSoftwareUpdate() { + // Nothing for now. +} + +void VDevice::startSoftwareUpdateRequest(const QString& vUpdateFilePath) { + // DEBUG : qDebug() << "HERE Request" << vUpdateFilePath; + + startSoftwareUpdateEnabled(true); + + DeviceStartSoftwareUpdateRequestData data; + data.mUpdateFilePath = vUpdateFilePath; + emit didAttributeRequest(data); +} + +void VDevice::onAttributeResponse(const DeviceStartSoftwareUpdateResponseData &vData) { + //QDEBUG : qDebug() << "HERE Response " << Q_FUNC_INFO << " accepted: "<< vData.mAccepted << vData.mReason; + // this has to be called to let Gui to set to old value that device controller provided. + status(vData.mMessage); + + accepted(vData.mAccepted); + reason (vData.mReason ); + + startSoftwareUpdateEnabled(isCompleteResponse(vData)); + + // has to be the last one + response(true); +} + + void VDevice::onPOSTOSVersionData(const QString &vOSVersion) { osVersion(vOSVersion); Index: sources/device/DeviceView.h =================================================================== diff -u -ra7c580f0998ee781c47314384f677249cea4c4b4 -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/device/DeviceView.h (.../DeviceView.h) (revision a7c580f0998ee781c47314384f677249cea4c4b4) +++ sources/device/DeviceView.h (.../DeviceView.h) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -60,6 +60,9 @@ ATTRIBUTE ( QString , decommission , "", Decommission ) PROPERTY ( bool , decommissionEnabled , true ) + ATTRIBUTE ( QString , startSoftwareUpdate , "", StartSoftwareUpdate ) + PROPERTY ( bool , startSoftwareUpdateEnabled , true ) + VIEW_DEC_CLASS(VDevice) private slots: Index: sources/gui/qml/pages/settings/SettingsStack.qml =================================================================== diff -u -ra7c580f0998ee781c47314384f677249cea4c4b4 -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/gui/qml/pages/settings/SettingsStack.qml (.../SettingsStack.qml) (revision a7c580f0998ee781c47314384f677249cea4c4b4) +++ sources/gui/qml/pages/settings/SettingsStack.qml (.../SettingsStack.qml) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -70,9 +70,8 @@ readonly property bool visibleSetDateTime : loggedIn || onlyUpdating readonly property bool visibleDeviceConfiguration : onlyManufacturing && loggedIn readonly property bool visibleDeviceRegistration : onlyManufacturing && loggedIn + readonly property bool visibleStartSoftwareUpdate : loggedIn - - enum ItemsIndex { Information , VolumeBrightness , @@ -91,7 +90,8 @@ SWUpdate , RootSSHAccess , FactoryReset , - Decommission + Decommission , + StartSoftwareUpdate } property var itemsText : [ qsTr("Information" ), // Information @@ -112,6 +112,7 @@ qsTr("Enable Root SSH" ), // RootSSHAccess qsTr("Factory Reset" ), // FactoryReset qsTr("Decommissioning" ), // Decommission + qsTr("Software Update" ), // Software Update Request ] property var itemsEnabled : [ true , // Information @@ -132,6 +133,7 @@ true , // RootSSHAccess true , // FactoryReset true , // Decommission + true , // Software Update Request ] property var itemsVisible : [ visibleInformation , // Information @@ -152,6 +154,7 @@ visibleRootSSHAccess , // RootSSHAccess visibleFactoryReset , // FactoryReset visibleDecommission , // Decommission + visibleStartSoftwareUpdate , // Software update request ] SettingsHome { id : _settingsHome @@ -246,6 +249,10 @@ push( _serviceDecommission ) break + case SettingsStack.StartSoftwareUpdate: + push( _serviceStartSoftwareUpdate ) + break + default: console.debug("Unknown Index", vIndex) break @@ -268,6 +275,7 @@ SettingsRootSSHAccess { id: _SettingsRootSSHAccess } SettingsFactoryReset { id: _serviceFactoryReset } SettingsDecommission { id: _serviceDecommission } + SettingsStartSoftwareUpdate { id: _serviceStartSoftwareUpdate } function gotoServiceMode( vservice ) { //DEBUG console.log (" 0 ---------- ", _GuiView.manufactMode, _GuiView.manufactSetup, vservice, stackView.initialItem, stackView.currentItem, stackView.depth) Index: sources/gui/qml/pages/settings/SettingsStartSoftwareUpdate.qml =================================================================== diff -u --- sources/gui/qml/pages/settings/SettingsStartSoftwareUpdate.qml (revision 0) +++ sources/gui/qml/pages/settings/SettingsStartSoftwareUpdate.qml (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -0,0 +1,119 @@ +/*! + * + * Copyright (c) 2023-2023 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file SettingsStartSoftwareUpdate.qml + * \author (last) Vy Duong + * \date (last) 04-Dec-2023 + * \author (original) Vy Duong + * \date (original) 04-Dec-2023 + * + */ + +// Qt +import QtQuick 2.12 +import Qt.labs.folderlistmodel 2.12 + +// Qml imports +import "qrc:/globals" +import "qrc:/pages" +import "qrc:/components" + +/*! + * \brief SettingsStartSoftwareUpdate is the screen + * which asks for confirmation of performing a software update with the selected file + */ +UserConfirmation { id : _root + message : vDevice.startSoftwareUpdateEnabled ? qsTr("Do you want to perform the %1?").arg(title.toLowerCase()) + : qsTr("Please wait ...") + itemIndex : SettingsStack.StartSoftwareUpdate + notificationText : vDevice.status + + confirmVisible : true + confirmEnabled : vDevice.startSoftwareUpdateEnabled + + backVisible : true + backEnabled : vDevice.startSoftwareUpdateEnabled + + Column { + width : 800 + height : 500 + spacing : 30 + + anchors.centerIn: parent + + Text { id : _message + text : _root.message + color : Colors.textMain + font.pixelSize : Fonts.fontPixelTitle + } + + Rectangle { id: _listViewBackground + color : Colors.backgroundMain + border.color : Colors.borderButton + radius : Variables.dialogRadius + border.width : Variables.borderWidth + width : 800 + height : 400 + + ListView { id : _usbFolderView + property string selectedFileName : "" + width : 750 + height : 350 + enabled : vDevice.startSoftwareUpdateEnabled + clip : true + anchors.centerIn : parent + spacing : 3 + // TODO need a CPP Class model for the files, only temp for demo + FolderListModel { id : _usbFolder + property string path : "/media/usb/" + showDirs : false + sortField : FolderListModel.Time + folder : "file:" + path // TODO need to be in CPP + nameFilters: ["*"] + } + model : _usbFolder + delegate :_folderDelegate + + Component{ id: _folderDelegate + Rectangle { id : _sdcFileRow + width : 775 + height : 50 + color: _usbFolderView.selectedFileName === fileName ? Colors.backgroundButtonSelect : Colors.backgroundMain + + Text { id : _sdcFileNameText + x : 2 + clip : true + width : _sdcFileRow.width + text : fileName + color : Colors.textMain + font.pixelSize : Fonts.fontPixelTextRectExtra + verticalAlignment : Text.AlignVCenter + horizontalAlignment : Text.AlignLeft + } + MouseArea { + anchors.fill: parent + onClicked : { console.log(fileName); _usbFolderView.selectedFileName = fileName; } + } + } + } + } + } + } + + onConfirmClicked : { + _confirmDialog.titleText = _root.title + _confirmDialog.open() + } + + Connections { target: _confirmDialog + function onAccepted() { + if ( _confirmDialog.titleText == _root.title ) { // use the title as the indication of what has been confirmed and if that is related to this function. + vDevice.startSoftwareUpdate = _usbFolder.path + _usbFolderView.selectedFileName // Need to set to something (ie: emtpy string) to trigger CPP code + } + } + } +} Index: sources/model/MModel.h =================================================================== diff -u -ra7c580f0998ee781c47314384f677249cea4c4b4 -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/model/MModel.h (.../MModel.h) (revision a7c580f0998ee781c47314384f677249cea4c4b4) +++ sources/model/MModel.h (.../MModel.h) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -299,6 +299,8 @@ REGISTER_METATYPE( DeviceDecommissionResponseData ) \ REGISTER_METATYPE( DeviceUSBMountRequestData ) \ REGISTER_METATYPE( DeviceUSBMountResponseData ) \ + REGISTER_METATYPE( DeviceStartSoftwareUpdateRequestData ) \ + REGISTER_METATYPE( DeviceStartSoftwareUpdateResponseData ) \ /* Settings */ \ REGISTER_METATYPE( SettingsData ) \ REGISTER_METATYPE( WifiNetworkData ) \ Index: sources/storage/StorageGlobals.cpp =================================================================== diff -u -r1a9eb2756f33ec0387dd360e5c051ed9a04b9c1c -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/storage/StorageGlobals.cpp (.../StorageGlobals.cpp) (revision 1a9eb2756f33ec0387dd360e5c051ed9a04b9c1c) +++ sources/storage/StorageGlobals.cpp (.../StorageGlobals.cpp) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -201,4 +201,7 @@ const char *USB_Unmount = "usb_unmount.sh"; const char *USB_Mount = "usb_mount.sh"; + // Start Software Update + const char *Device_StartSoftwareUpdateScriptPath = "/opt/bin/upgrade_install.sh"; + } Index: sources/storage/StorageGlobals.h =================================================================== diff -u -r1a9eb2756f33ec0387dd360e5c051ed9a04b9c1c -r59625af31d9009df82fa48310b54c0f247e829fc --- sources/storage/StorageGlobals.h (.../StorageGlobals.h) (revision 1a9eb2756f33ec0387dd360e5c051ed9a04b9c1c) +++ sources/storage/StorageGlobals.h (.../StorageGlobals.h) (revision 59625af31d9009df82fa48310b54c0f247e829fc) @@ -141,4 +141,7 @@ extern const char *USB_Unmount; extern const char *USB_Mount; + // Device Start Software Update + extern const char *Device_StartSoftwareUpdateScriptPath; + }