/*! * * Copyright (c) 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 UiSwUpdate.cpp * \author (last) Phil Braica * \date (last) 23-Jan-2023 * \author (original) Phil Braica * \date (original) 23-Jan-2023 * */ #include "UiSwUpdate.h" #include "IDataProvider.h" #include "IEnterBootLoader.h" #include namespace SwUpdate { /*! * \brief Create the instance. * * \return Instance reference. */ UiSwUpdate & UiSwUpdate::instance() { static UiSwUpdate inst; return inst; } /*! * \brief Constructor. * * \param target Target to go after for update. */ UiSwUpdate::UiSwUpdate(): _hdUpdate(HD), _hdFpgaUpdate(HDFPGA), _dgUpdate(DG), _dgFpgaUpdate(DGFPGA), _fileUpdate() { // Assign by target. _all[HD] = &_hdUpdate; _all[HDFPGA] = &_hdFpgaUpdate; _all[DG] = &_dgUpdate; _all[DGFPGA] = &_dgFpgaUpdate; _all[LINUX] = &_fileUpdate; } /*! * \brief Destructor (virtual). */ UiSwUpdate::~UiSwUpdate() { std::lock_guard lock(_mutexApi); // Abort all. for (auto it = _all.begin(); it != _all.end(); ++it) { it->second->abort(); } } /*! * \brief Start updating. * * \param dataProviders Vector of Data providers. * \param pEnterBL Class to call if need to enter bootloader. * * \return True on successfully started. */ bool UiSwUpdate::start( std::vector & dataProviders, SwUpdate::IEnterBootLoader * pEnterBL) { // Lock. std::lock_guard lock(_mutexApi); // We first need to do 2 things: // Make an order list of the things that are process based by target. // Get a list of the files, UI then linux. std::map aboutToStart; std::vector uiFiles; std::vector linuxFiles; std::vector priorTargets; // Make a list we can access via map to get ordering, and get the files. for (IDataProvider* pDp : dataProviders) { SwUpdateTargetEnum target = pDp->targetName; // Handle files. if (target == UI) { uiFiles.push_back(pDp); continue; } if (target == LINUX) { linuxFiles.push_back(pDp); continue; } // Set the provider. UiProtocol* pTarget = _all[target]; aboutToStart[target] = pTarget; _all[target]->setProvider(pDp, pEnterBL); // Ensure all non-file actions happen after the tasks. priorTargets.push_back(pTarget); } // Ensure we get the UI files then linux. uiFiles.insert(uiFiles.end(), linuxFiles.begin(), linuxFiles.end()); // Use the map to create the ordered set of tasks to do. _tasks.clear(); SwUpdateTargetEnum targetOrder[] = { HDFPGA, HD, DGFPGA, DG }; for (SwUpdateTargetEnum t : targetOrder) { auto it = aboutToStart.find(t); if (it != aboutToStart.end()) { _tasks.push_back(it->second); } } // Last is files. _tasks.push_back(&_fileUpdate); _fileUpdate.setup(uiFiles); // Kick the first task off. bool ok = true; if (_tasks.size() > 0) { ok = _tasks.front()->start(); } return ok; } /*! * \brief Is it completed? * * \return True if completed. */ bool UiSwUpdate::completedAll() { bool rv = true; std::lock_guard lock(_mutexApi); for (auto it = _all.begin(); it != _all.end(); ++it) { if (it->second->progress().inProgress) { rv = false; break; } } return rv; } /*! * \brief Abort update. */ void UiSwUpdate::abort() { std::lock_guard lock(_mutexApi); // Doing all causes things that "finished" to also be checked // in case of any possible thread race condition. for (auto it = _all.begin(); it != _all.end(); ++it) { it->second->abort(); } } /*! * \brief Current estimated progress. * * \return Vector of statuses. */ std::vector UiSwUpdate::progress() { std::lock_guard lock(_mutexApi); std::vector rv; for (auto it = _all.begin(); it != _all.end(); ++it) { rv.push_back(it->second->progress()); } return rv; } /*! * \brief Receive and check if matched. * * \param msgId Can message ID. * \param pData Data pointer. * * \return True if message was consumed. */ bool UiSwUpdate::receive(uint16 msgId, uint8 * pData) { bool rv = false; for (auto it = _all.begin(); it != _all.end(); ++it) { rv |= it->second->receive(msgId, pData); } return rv; } /*! * \brief This chains updates together, as a protocol completes, it calls this. * * \param ok The task completed ok. * \param pCompleted Which protocol completed. */ void UiSwUpdate::taskCompleted(bool ok, UiProtocol* pCompleted) { // Tasks are run in order: HDFPGA, HD, DGFPGA, DG, Linux, UI. if (!ok) { this->abort(); _tasks.clear(); } else { std::vector::iterator position = std::find(_tasks.begin(), _tasks.end(), pCompleted); if (position != _tasks.end()) { _tasks.erase(position); } if (_tasks.size() > 0) { _tasks.front()->start(); } } } } //namespace SwUpdate