| /* |
| * Copyright (c) 2017, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include <chrono> |
| #include <sstream> |
| |
| #include "DeviceManager.h" |
| #include "Utils.h" |
| #include "AccessLayerAPI.h" |
| #include "DebugLogger.h" |
| #include "Utils.h" |
| #include "Host.h" |
| |
| using namespace std; |
| |
| // Initialize translation maps for the front-end data |
| const static std::string sc_noRfStr("NO_RF"); |
| const std::unordered_map<int, std::string> DeviceManager::m_rfTypeToString = { {0, sc_noRfStr }, {1, "MARLON"}, {2, "SPR-R"}, {3, "TLN-A1"}, { 4, "TLN-A2" } }; |
| |
| const std::unordered_map<int, std::string> DeviceManager::m_basebandTypeToString = |
| { |
| { 0, "UNKNOWN" }, { 1, "MAR-DB1" }, { 2, "MAR-DB2" }, |
| { 3, "SPR-A0" }, { 4, "SPR-A1" }, { 5, "SPR-B0" }, |
| { 6, "SPR-C0" }, { 7, "SPR-D0" }, { 8, "TLN-M-A0" }, |
| { 9, "TLN-M-B0" } |
| }; |
| |
| const std::unordered_map<int, std::string> DeviceManager::m_boardfileTypeToString = |
| { |
| { 0, "UNDEFINED" }, |
| { 1, "generic_single_ant" }, |
| { 2, "generic_SIP" }, |
| { 3, "generic_reduced_size" }, |
| { 4, "generic_patches_only" }, |
| { 5, "generic_500mW" }, |
| { 6, "generic_500mW_removed_RF" }, |
| { 16, "ROGERS" }, |
| { 32, "GENERIC_LTCC" }, |
| { 48, "REGULATORY_LTCC" }, |
| { 64, "FeiDao_6430u" }, |
| { 80, "GENERIC_FALCON" }, |
| { 112, "DELL_E7440_non-touch" }, |
| { 113, "DELL_E7240_non" }, |
| { 114, "DELL_E7440_touch" }, |
| { 115, "DELL_E7240_touch" }, |
| { 128, "Corse" }, |
| { 144, "DELL_E5440" }, |
| { 160, "MURATA_DELL_D5000" }, |
| { 176, "DELL_XPS13" }, |
| { 192, "TOSHIBA_Z10" }, |
| { 208, "Semco_Sip" }, |
| { 209, "Semco_Sip_rev1_3" }, |
| { 224, "MTP-BStep" }, |
| { 225, "MTP-CStep" }, |
| { 240, "Liquid" }, |
| { 257, "Murata SI" } |
| }; |
| |
| DeviceManager::DeviceManager(std::promise<void>& eventsTCPServerReadyPromise) : |
| m_deviceManagerRestDurationMs(500), |
| m_terminate(false), |
| m_collectLogs(false) |
| { |
| m_deviceManager = thread(&DeviceManager::PeriodicTasks, this, std::ref(eventsTCPServerReadyPromise)); |
| } |
| |
| DeviceManager::~DeviceManager() |
| { |
| m_terminate = true; |
| m_deviceManager.join(); |
| } |
| |
| string DeviceManager::GetDeviceManagerOperationStatusString(DeviceManagerOperationStatus status) |
| { |
| switch (status) |
| { |
| case dmosSuccess: |
| return "Successful operation"; |
| case dmosNoSuchConnectedDevice: |
| return "Unknown device"; |
| case dmosFailedToReadFromDevice: |
| return "Read failure"; |
| case dmosFailedToWriteToDevice: |
| return "Write failure"; |
| case dmosFailedToResetInterface: |
| return "Reset interface failure"; |
| case dmosFailedToResetSw: |
| return "SW reset failure"; |
| case dmosFailedToAllocatePmc: |
| return "Allocate PMC failure"; |
| case dmosFailedToDeallocatePmc: |
| return "Deallocate PMC failure"; |
| case dmosFailedToCreatePmcFile: |
| return "Create PMC file failure"; |
| case dmosFailedToSendWmi: |
| return "Send WMI failure"; |
| case dmosFail: |
| return "Operation failure"; |
| case dmosSilentDevice: |
| return "Device is in silent mode"; |
| default: |
| return "DeviceManagerOperationStatus is unknown "; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::GetDevices(set<string>& devicesNames) |
| { |
| devicesNames.clear(); |
| m_connectedDevicesMutex.lock(); |
| for (auto& device : m_devices) |
| { |
| devicesNames.insert(device.first); |
| } |
| m_connectedDevicesMutex.unlock(); |
| return dmosSuccess; |
| } |
| |
| std::shared_ptr<Device> DeviceManager::GetDeviceByName(const std::string& deviceName) |
| { |
| m_connectedDevicesMutex.lock(); |
| for (auto& device : m_devices) |
| { |
| if (deviceName == device.first) |
| { |
| m_connectedDevicesMutex.unlock(); |
| return device.second; |
| } |
| } |
| m_connectedDevicesMutex.unlock(); |
| return nullptr; |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::OpenInterface(const string& deviceName) |
| { |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosSuccess; |
| } |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::CloseInterface(const string& deviceName) |
| { |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosSuccess; |
| } |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::Read(const string& deviceName, DWORD address, DWORD& value) |
| { |
| if (IsDeviceSilent(deviceName)) |
| { |
| return dmosSilentDevice; |
| } |
| |
| if ((0 == address) || (0 != address % 4) || (0xFFFFFFFF == address)) |
| { |
| return dmosInvalidAddress; |
| } |
| |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| bool success = m_devices[deviceName]->GetDriver()->Read(address, value); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| value = Utils::REGISTER_DEFAULT_VALUE; |
| status = dmosFailedToReadFromDevice; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| value = Utils::REGISTER_DEFAULT_VALUE; |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::Write(const string& deviceName, DWORD address, DWORD value) |
| { |
| if (IsDeviceSilent(deviceName)) |
| { |
| return dmosSilentDevice; |
| } |
| |
| if ((0 == address) || (0 != address % 4) || (0xFFFFFFFF == address)) |
| { |
| return dmosInvalidAddress; |
| } |
| |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| bool success = m_devices[deviceName]->GetDriver()->Write(address, value); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| status = dmosFailedToWriteToDevice; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::ReadBlock(const string& deviceName, DWORD address, DWORD blockSize, vector<DWORD>& values) |
| { |
| if (IsDeviceSilent(deviceName)) |
| { |
| return dmosSilentDevice; |
| } |
| |
| if ((0 == address) || (0 != address % 4) || (0xFFFFFFFF == address)) |
| { |
| return dmosInvalidAddress; |
| } |
| |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| bool success = m_devices[deviceName]->GetDriver()->ReadBlock(address, blockSize, values); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| vector<DWORD> defaultValues(blockSize, Utils::REGISTER_DEFAULT_VALUE); |
| status = dmosFailedToReadFromDevice; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| vector<DWORD> defaultValues(blockSize, Utils::REGISTER_DEFAULT_VALUE); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::WriteBlock(const string& deviceName, DWORD address, const vector<DWORD>& values) |
| { |
| if (IsDeviceSilent(deviceName)) |
| { |
| return dmosSilentDevice; |
| } |
| |
| if ((0 == address) || (0 != address % 4) || (0xFFFFFFFF == address)) |
| { |
| return dmosInvalidAddress; |
| } |
| |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| bool success = m_devices[deviceName]->GetDriver()->WriteBlock(address, values); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| status = dmosFailedToWriteToDevice; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::InterfaceReset(const string& deviceName) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| m_devices[deviceName]->GetDriver()->Reset(); // TODO - we need to separate between SW reset and interface reset |
| status = dmosSuccess; |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::SwReset(const string& deviceName) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| bool success = false; // m_devices[deviceName]->GetDriver()->Reset(); // TODO |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| status = dmosFailedToResetSw; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::SetDriverMode(const string& deviceName, int newMode, int& oldMode) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| bool success = m_devices[deviceName]->GetDriver()->SetDriverMode(newMode, oldMode); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| status = dmosFailedToResetSw; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::DriverControl(const string& deviceName, uint32_t Id, const void *inBuf, uint32_t inBufSize, void *outBuf, uint32_t outBufSize) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| bool success = m_devices[deviceName]->GetDriver()->DriverControl(Id, inBuf, inBufSize, outBuf, outBufSize); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| status = dmosFailedToReadFromDevice; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::AllocPmc(const string& deviceName, unsigned descSize, unsigned descNum, string& errorMsg) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| |
| bool success = m_devices[deviceName]->GetDriver()->AllocPmc(descSize, descNum, errorMsg); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| LOG_ERROR << "Failed to allocate PMC ring: " << errorMsg << std::endl; |
| status = dmosFailedToAllocatePmc; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| errorMsg = "No device found"; |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::DeallocPmc(const string& deviceName, std::string& outMessage) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| |
| bool success = m_devices[deviceName]->GetDriver()->DeallocPmc(outMessage); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| LOG_ERROR << "Failed to de-allocate PMC ring: " << outMessage << std::endl; |
| status = dmosFailedToDeallocatePmc; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::CreatePmcFile(const string& deviceName, unsigned refNumber, std::string& outMessage) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| bool success = m_devices[deviceName]->GetDriver()->CreatePmcFile(refNumber, outMessage); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| status = dmosFailedToCreatePmcFile; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::FindPmcFile(const string& deviceName, unsigned refNumber, std::string& outMessage) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| bool success = m_devices[deviceName]->GetDriver()->FindPmcFile(refNumber, outMessage); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| status = dmosFailedToCreatePmcFile; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::SendWmi(const string& deviceName, DWORD command, const vector<DWORD>& payload) |
| { |
| if (IsDeviceSilent(deviceName)) |
| { |
| return dmosSilentDevice; |
| } |
| |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| bool success = m_devices[deviceName]->SendWmi(command, payload); |
| if (success) |
| { |
| status = dmosSuccess; |
| } |
| else |
| { |
| status = dmosFailedToSendWmi; |
| } |
| m_devices[deviceName]->m_mutex.unlock(); |
| return status; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| return dmosNoSuchConnectedDevice; |
| } |
| } |
| |
| void DeviceManager::CreateDevice(const string& deviceName) |
| { |
| m_connectedDevicesMutex.lock(); |
| shared_ptr<Device> device(new Device(deviceName)); |
| device->Init(); |
| m_devices.insert(make_pair(deviceName, device)); |
| m_connectedDevicesMutex.unlock(); |
| |
| if (device->GetIsAlive()) |
| { |
| // Notify that new device discovered, also relevant for case of FW update |
| Host::GetHost().PushEvent(NewDeviceDiscoveredEvent(deviceName, device->GetFwVersion(), device->GetFwTimestamp())); |
| } |
| else |
| { |
| // Delete unresponsive device, lock is acquired inside |
| // Note: Can happen if device becomes unresponsive after enumeration |
| DeleteDevice(deviceName); |
| LOG_INFO << "Created unresponsive device '" << deviceName << "', removing..." << endl; |
| } |
| } |
| |
| void DeviceManager::DeleteDevice(const string& deviceName) |
| { |
| m_connectedDevicesMutex.lock(); |
| // make sure that no client is using this object |
| m_devices[deviceName]->m_mutex.lock(); |
| m_devices[deviceName]->Fini(); |
| // no need that the mutex will be still locked since new clients have to get m_connectedDevicesMutex before they try to get m_mutex |
| m_devices[deviceName]->m_mutex.unlock(); |
| m_devices.erase(deviceName); |
| m_connectedDevicesMutex.unlock(); |
| } |
| |
| void DeviceManager::UpdateConnectedDevices() |
| { |
| vector<string> devicesForRemove; |
| // Delete unresponsive devices |
| m_connectedDevicesMutex.lock(); |
| for (auto& connectedDevice : m_devices) |
| { |
| if (connectedDevice.second->GetSilenceMode()) //GetSilenceMode returns true if the device is silent the skip th update |
| { |
| continue; |
| } |
| |
| connectedDevice.second->m_mutex.lock(); |
| if (!connectedDevice.second->GetDriver()->IsValid()) |
| { |
| devicesForRemove.push_back(connectedDevice.first); |
| } |
| connectedDevice.second->m_mutex.unlock(); |
| } |
| m_connectedDevicesMutex.unlock(); |
| |
| for (auto& device : devicesForRemove) |
| { |
| DeleteDevice(device); |
| } |
| |
| devicesForRemove.clear(); |
| |
| set<string> currentlyConnectedDevices = AccessLayer::GetDrivers(); |
| |
| // delete devices that arn't connected anymore according to enumeration |
| for (auto& connectedDevice : m_devices) |
| { |
| if (connectedDevice.second->GetSilenceMode()) //GetSilenceMode retunrs true if the device is silent the skip th update |
| { |
| continue; |
| } |
| |
| if (0 == currentlyConnectedDevices.count(connectedDevice.first)) |
| { |
| devicesForRemove.push_back(connectedDevice.first); |
| } |
| } |
| for (auto& device : devicesForRemove) |
| { |
| DeleteDevice(device); |
| } |
| |
| // add new connected devices |
| vector<string> newDevices; |
| m_connectedDevicesMutex.lock(); |
| for (auto& currentlyConnectedDevice : currentlyConnectedDevices) |
| { |
| if (0 == m_devices.count(currentlyConnectedDevice)) |
| { |
| newDevices.push_back(currentlyConnectedDevice); |
| } |
| } |
| m_connectedDevicesMutex.unlock(); |
| |
| for (auto& device : newDevices) |
| { |
| CreateDevice(device); |
| } |
| } |
| |
| void DeviceManager::PeriodicTasks(std::promise<void>& eventsTCPServerReadyPromise) |
| { |
| // wait for events TCP server readiness before running the main loop |
| auto status = eventsTCPServerReadyPromise.get_future().wait_for(std::chrono::seconds(5)); |
| if (status == std::future_status::timeout) |
| { |
| LOG_ERROR << "DeviceManager: Events TCP Server did not become ready before timeout duration has passed"; |
| } |
| |
| while (!m_terminate) |
| { |
| UpdateConnectedDevices(); |
| |
| // get local copy of m_devices not to hold the lock |
| m_connectedDevicesMutex.lock(); |
| auto devices = m_devices; |
| m_connectedDevicesMutex.unlock(); |
| |
| for (auto& device : devices) |
| { |
| if (device.second->GetSilenceMode()) //GetSilenceMode retunrs true if the device is silent the skip the periodic task |
| { |
| continue; |
| } |
| |
| std::vector<unique_ptr<HostManagerEventBase>> events = device.second->Poll(); |
| for (const auto& event : events) |
| { |
| Host::GetHost().PushEvent(*event.get()); |
| } |
| } |
| this_thread::sleep_for(std::chrono::milliseconds(m_deviceManagerRestDurationMs)); |
| } |
| } |
| |
| bool DeviceManager::IsDeviceSilent(const string& deviceName) |
| { |
| bool isSilent = false; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) <= 0) |
| { |
| m_connectedDevicesMutex.unlock(); |
| return isSilent; |
| } |
| |
| if ((NULL == m_devices[deviceName].get()) || (!m_devices[deviceName]->IsValid())) |
| { |
| LOG_ERROR << "Invalid device pointer in IsDeviceSilent (NULL)" << endl; |
| m_connectedDevicesMutex.unlock(); |
| return isSilent; |
| } |
| |
| m_devices[deviceName]->m_mutex.lock(); |
| m_connectedDevicesMutex.unlock(); |
| |
| isSilent = m_devices[deviceName]->GetSilenceMode(); |
| |
| m_devices[deviceName]->m_mutex.unlock(); |
| |
| return isSilent; |
| } |
| |
| bool DeviceManager::GetDeviceStatus(vector<DeviceData>& devicesData) |
| { |
| // Lock the devices |
| lock_guard<mutex> lock(m_connectedDevicesMutex); |
| |
| auto devices = m_devices; |
| |
| for (auto& device : devices) |
| { |
| // Lock the specific device |
| lock_guard<mutex> lock(device.second->m_mutex); |
| |
| // Create device data |
| DeviceData deviceData; |
| |
| // Extract FW version |
| deviceData.m_fwVersion = device.second->GetFwVersion(); |
| |
| DWORD value = Utils::REGISTER_DEFAULT_VALUE; |
| |
| // Read FW assert code |
| device.second->GetDriver()->Read(FW_ASSERT_REG, value); |
| deviceData.m_fwAssert = value; |
| |
| // Read uCode assert code |
| device.second->GetDriver()->Read(UCODE_ASSERT_REG, value); |
| deviceData.m_uCodeAssert = value; |
| |
| // Read FW association state |
| device.second->GetDriver()->Read(FW_ASSOCIATION_REG, value); |
| deviceData.m_associated = (value == FW_ASSOCIATED_VALUE); |
| |
| // Read MCS value |
| device.second->GetDriver()->Read(MCS_REG, value); |
| deviceData.m_mcs = value; |
| |
| // Get FW compilation timestamp |
| deviceData.m_compilationTime = device.second->GetFwTimestamp(); |
| |
| // Get Device name |
| deviceData.m_deviceName = device.second->GetDeviceName(); |
| |
| // Get baseband name & RF type |
| // BB type is stored in 2 lower bytes of device type register |
| // RF type is stored in 2 upper bytes of device type register |
| device.second->GetDriver()->Read(DEVICE_TYPE_REG, value); |
| const auto basebandTypeIter = m_basebandTypeToString.find(value & 0xFFFF); |
| deviceData.m_hwType = basebandTypeIter != m_basebandTypeToString.cend() ? basebandTypeIter->second : std::string("UNKNOWN"); |
| const auto rfTypeIter = m_rfTypeToString.find((value & 0xFFFF0000) >> 16); |
| deviceData.m_rfType = rfTypeIter != m_rfTypeToString.cend() ? rfTypeIter->second : sc_noRfStr; |
| |
| // Get FW mode |
| device.second->GetDriver()->Read(FW_MODE_REG, value); |
| deviceData.m_mode = (value == 0) ? "Operational" : "WMI Only"; |
| |
| // Get boot loader version |
| device.second->GetDriver()->Read(BOOT_LOADER_VERSION_REG, value); |
| std::ostringstream oss; |
| oss << value; |
| deviceData.m_bootloaderVersion = oss.str(); |
| |
| // Get channel number |
| device.second->GetDriver()->Read(CHANNEL_REG, value); |
| int Channel = 0; |
| switch (value) |
| { |
| case 0x64FCACE: |
| Channel = 1; |
| break; |
| case 0x68BA2E9: |
| Channel = 2; |
| break; |
| case 0x6C77B03: |
| Channel = 3; |
| break; |
| default: |
| Channel = 0; |
| } |
| deviceData.m_channel = Channel; |
| |
| // Get board file version |
| device.second->GetDriver()->Read(BOARDFILE_REG, value); |
| const auto boardfileTypeIter = m_boardfileTypeToString.find((value & 0xFFF000) >> 12); |
| deviceData.m_boardFile = boardfileTypeIter != m_boardfileTypeToString.cend() ? boardfileTypeIter->second : std::string("UNDEFINED"); |
| |
| DWORD rfConnected = 0; |
| DWORD rfEnabled = 0; |
| device.second->GetDriver()->Read(RF_CONNECTED_REG, rfConnected); |
| device.second->GetDriver()->Read(RF_ENABLED_REG, rfEnabled); |
| rfEnabled = rfEnabled >> 8; |
| |
| // Get RF state of each RF |
| for (int rfIndex = 0; rfIndex < MAX_RF_NUMBER; rfIndex++) |
| { |
| int rfState = 0; |
| |
| if (rfConnected & (1 << rfIndex)) |
| { |
| rfState = 1; |
| } |
| |
| if (rfEnabled & (1 << rfIndex)) |
| { |
| rfState = 2; |
| } |
| |
| // TODO extract RF state for each RF |
| deviceData.m_rf.insert(deviceData.m_rf.end(), rfState); |
| } |
| |
| ////////// Get fixed registers values ////////////////////////// |
| RegisterData registerData; |
| |
| // uCode Rx on fixed reg |
| device.second->GetDriver()->Read(UCODE_RX_ON_REG, value); |
| DWORD UcRxonhexVal16 = value && 0xFFFF; |
| string UcRxon; |
| switch (UcRxonhexVal16) |
| { |
| case 0: |
| UcRxon = "RX_OFF"; |
| break; |
| case 1: |
| UcRxon = "RX_ONLY"; |
| break; |
| case 2: |
| UcRxon = "RX_ON"; |
| break; |
| default: |
| UcRxon = "Unrecognized"; |
| } |
| registerData.m_name = "uCodeRxOn"; |
| registerData.m_value = UcRxon; |
| deviceData.m_fixedRegisters.insert(deviceData.m_fixedRegisters.end(), registerData); |
| |
| // BF Sequence fixed reg |
| device.second->GetDriver()->Read(BF_SEQ_REG, value); |
| oss.str(""); |
| oss << value; |
| registerData.m_name = "BF_Seq"; |
| registerData.m_value = oss.str(); |
| deviceData.m_fixedRegisters.insert(deviceData.m_fixedRegisters.end(), registerData); |
| |
| // BF Trigger fixed reg |
| device.second->GetDriver()->Read(BF_TRIG_REG, value); |
| string BF_TRIG = ""; |
| switch (value) |
| { |
| case 1: |
| BF_TRIG = "MCS1_TH_FAILURE"; |
| break; |
| case 2: |
| BF_TRIG = "MCS1_NO_BACK"; |
| break; |
| case 4: |
| BF_TRIG = "NO_CTS_IN_TXOP"; |
| break; |
| case 8: |
| BF_TRIG = "MAX_BCK_FAIL_TXOP"; |
| break; |
| case 16: |
| BF_TRIG = "FW_TRIGGER "; |
| break; |
| case 32: |
| BF_TRIG = "MAX_BCK_FAIL_ION_KEEP_ALIVE"; |
| break; |
| default: |
| BF_TRIG = "UNDEFINED"; |
| } |
| registerData.m_name = "BF_Trig"; |
| registerData.m_value = BF_TRIG; |
| deviceData.m_fixedRegisters.insert(deviceData.m_fixedRegisters.end(), registerData); |
| |
| // Get NAV fixed reg |
| device.second->GetDriver()->Read(NAV_REG, value); |
| registerData.m_name = "NAV"; |
| oss.str(""); |
| oss << value; |
| registerData.m_value = oss.str(); |
| deviceData.m_fixedRegisters.insert(deviceData.m_fixedRegisters.end(), registerData); |
| |
| // Get TX Goodput fixed reg |
| device.second->GetDriver()->Read(TX_GP_REG, value); |
| string TX_GP = "NO_LINK"; |
| if (value != 0) |
| { |
| oss.str(""); |
| oss << value; |
| TX_GP = oss.str(); |
| } |
| registerData.m_name = "TX_GP"; |
| registerData.m_value = TX_GP; |
| deviceData.m_fixedRegisters.insert(deviceData.m_fixedRegisters.end(), registerData); |
| |
| // Get RX Goodput fixed reg |
| device.second->GetDriver()->Read(RX_GP_REG, value); |
| string RX_GP = "NO_LINK"; |
| if (value != 0) |
| { |
| oss.str(""); |
| oss << value; |
| TX_GP = oss.str(); |
| } |
| registerData.m_name = "RX_GP"; |
| registerData.m_value = RX_GP; |
| deviceData.m_fixedRegisters.insert(deviceData.m_fixedRegisters.end(), registerData); |
| |
| ////////////// Fixed registers end ///////////////////////// |
| |
| ////////////// Custom registers //////////////////////////// |
| for (auto& reg : device.second->GetCustomRegisters()) |
| { |
| registerData.m_name = reg.first; |
| device.second->GetDriver()->Read(reg.second, value); |
| oss.str(""); |
| oss << value; |
| registerData.m_value = oss.str(); |
| deviceData.m_customRegisters.insert(deviceData.m_customRegisters.end(), registerData); |
| } |
| |
| ////////////// Custom registers end //////////////////////// |
| |
| ////////////// Temperatures //////////////////////////////// |
| // Baseband |
| device.second->GetDriver()->Read(BASEBAND_TEMPERATURE_REG, value); |
| float temperature = (float)value / 1000; |
| oss.str(""); |
| oss.precision(2); |
| oss << fixed << temperature; |
| deviceData.m_hwTemp = oss.str(); |
| |
| // RF |
| if (deviceData.m_rfType != sc_noRfStr) |
| { |
| device.second->GetDriver()->Read(RF_TEMPERATURE_REG, value); |
| temperature = (float)value / 1000; |
| oss.str(""); |
| oss.precision(2); |
| oss << fixed << temperature; |
| deviceData.m_rfTemp = oss.str(); |
| } |
| else // no RF, temperature value is not relevant |
| { |
| deviceData.m_rfTemp = ""; |
| } |
| ////////////// Temperatures end /////////////////////////// |
| |
| // Add the device to the devices list |
| devicesData.insert(devicesData.end(), deviceData); |
| } |
| |
| return true; |
| } |
| |
| bool DeviceManager::AddRegister(const string& deviceName, const string& registerName, int address) |
| { |
| lock_guard<mutex> lock(m_connectedDevicesMutex); |
| |
| if (m_devices.count(deviceName) <= 0) |
| { |
| return false; |
| } |
| |
| if ((NULL == m_devices[deviceName].get()) || (!m_devices[deviceName]->AddCustomRegister(registerName, address))) |
| { |
| LOG_ERROR << "Trying to add an already existing custom register name" << endl; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool DeviceManager::RemoveRegister(const string& deviceName, const string& registerName) |
| { |
| lock_guard<mutex> lock(m_connectedDevicesMutex); |
| |
| if (m_devices.count(deviceName) <= 0) |
| { |
| return false; |
| } |
| |
| if ((NULL == m_devices[deviceName].get()) || (!m_devices[deviceName]->RemoveCustomRegister(registerName))) |
| { |
| LOG_ERROR << "Trying to remove a non-existing custom register name" << endl; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::SetDeviceSilentMode(const string& deviceName, bool silentMode) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| lock_guard<mutex> lock(m_devices[deviceName]->m_mutex); |
| m_connectedDevicesMutex.unlock(); |
| m_devices[deviceName]->SetSilenceMode(silentMode); |
| status = dmosSuccess; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| status = dmosNoSuchConnectedDevice; |
| } |
| |
| return status; |
| } |
| |
| |
| DeviceManagerOperationStatus DeviceManager::GetDeviceSilentMode(const string& deviceName, bool& silentMode) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| lock_guard<mutex> lock(m_devices[deviceName]->m_mutex); |
| m_connectedDevicesMutex.unlock(); |
| silentMode = m_devices[deviceName]->GetSilenceMode(); |
| status = dmosSuccess; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| status = dmosNoSuchConnectedDevice; |
| } |
| |
| return status; |
| } |
| |
| |
| // Log functions |
| bool DeviceManager::GetLogCollectionMode() const |
| { |
| return m_collectLogs; |
| } |
| |
| void DeviceManager::SetLogCollectionMode(bool collectLogs) |
| { |
| m_collectLogs = collectLogs; |
| |
| // Start/Stop log collector for all devices |
| m_connectedDevicesMutex.lock(); |
| for (auto& connectedDevice : m_devices) |
| { |
| connectedDevice.second->m_mutex.lock(); |
| |
| if (collectLogs == false) |
| { |
| connectedDevice.second->StopLogCollector(); |
| } |
| else |
| { |
| connectedDevice.second->StartLogCollector(); |
| } |
| |
| connectedDevice.second->m_mutex.unlock(); |
| } |
| m_connectedDevicesMutex.unlock(); |
| } |
| |
| bool DeviceManager::SetLogCollectionConfiguration(const vector<string>& deviceNames, const vector<string>& cpuTypeNames, const string& parameter, const string& value, string& errorMessage) |
| { |
| bool success = true; |
| errorMessage = ""; |
| stringstream errorMessageSs; |
| for (auto& deviceName : deviceNames) |
| { |
| shared_ptr<Device> d = GetDeviceByName(deviceName); |
| if (nullptr == d) |
| { |
| success = false; |
| errorMessageSs << "device name " << deviceName << " doesn't exist; "; |
| continue; |
| } |
| |
| for (auto& cpuTypeName : cpuTypeNames) |
| { |
| auto found = STRING_TO_CPU_TYPE.find(cpuTypeName); |
| if (STRING_TO_CPU_TYPE.end() == found) |
| { |
| success = false; |
| errorMessageSs << "no such cpu named " << cpuTypeName << ". Can be only FW/UCODE; "; |
| continue; |
| } |
| log_collector::LogCollector* pLogCollector = d->GetLogCollector(found->second); |
| if (nullptr == pLogCollector) |
| { |
| success = false; |
| errorMessageSs << "device " << deviceName << " has no active tracer for " << cpuTypeName << "; "; |
| continue; |
| } |
| pLogCollector->SetConfigurationParamerter(parameter, value); |
| } |
| } |
| errorMessageSs << endl; |
| errorMessage = errorMessageSs.str(); |
| return success; |
| } |
| |
| string DeviceManager::GetLogCollectionConfiguration(const vector<string>& deviceNames, const vector<string>& cpuTypeNames, string parameter) |
| { |
| stringstream res; |
| bool success; |
| for (auto& deviceName : deviceNames) |
| { |
| shared_ptr<Device> d = GetDeviceByName(deviceName); |
| if (nullptr == d) |
| { |
| res << "device name " << deviceName << " doesn't exist; "; |
| continue; |
| } |
| |
| for (auto& cpuTypeName : cpuTypeNames) |
| { |
| auto found = STRING_TO_CPU_TYPE.find(cpuTypeName); |
| if (STRING_TO_CPU_TYPE.end() == found) |
| { |
| res << "no such cpu named " << cpuTypeName << ". Can be only FW/UCODE; "; |
| continue; |
| } |
| log_collector::LogCollector* pLogCollector = d->GetLogCollector(found->second); |
| if (nullptr == pLogCollector) |
| { |
| res << "device " << deviceName << " has no active tracer for " << cpuTypeName << "; "; |
| continue; |
| } |
| |
| res << "device-" << deviceName << "-cpu-" << cpuTypeName << "-parameter-" << parameter << "=" << pLogCollector->GetConfigurationParameterValue(parameter, success) << ";"; // TODO - create constants for "=" and ";" |
| } |
| } |
| res << endl; |
| return res.str(); |
| } |
| |
| string DeviceManager::DumpLogCollectionConfiguration(const vector<string>& deviceNames, const vector<string>& cpuTypeNames) |
| { |
| stringstream res; |
| for (auto& deviceName : deviceNames) |
| { |
| shared_ptr<Device> d = GetDeviceByName(deviceName); |
| if (nullptr == d) |
| { |
| res << "device name " << deviceName << " doesn't exist; "; |
| continue; |
| } |
| |
| for (auto& cpuTypeName : cpuTypeNames) |
| { |
| auto found = STRING_TO_CPU_TYPE.find(cpuTypeName); |
| if (STRING_TO_CPU_TYPE.end() == found) |
| { |
| res << "no such cpu named " << cpuTypeName << ". Can be only FW/UCODE; "; |
| continue; |
| } |
| log_collector::LogCollector* pLogCollector = d->GetLogCollector(found->second); |
| if (nullptr == pLogCollector) |
| { |
| res << "device " << deviceName << " has no active tracer for " << cpuTypeName << "; "; |
| continue; |
| } |
| |
| res << "device-" << deviceName << "-cpu-" << cpuTypeName << ":" << pLogCollector->GetConfigurationDump() << ";"; // TODO - create constants for "=" and ";" |
| } |
| } |
| res << endl; |
| return res.str(); |
| } |
| |
| DeviceManagerOperationStatus DeviceManager::GetDeviceCapabilities(const string& deviceName, DWORD& capabilities) |
| { |
| DeviceManagerOperationStatus status; |
| m_connectedDevicesMutex.lock(); |
| if (m_devices.count(deviceName) > 0) |
| { |
| lock_guard<mutex> lock(m_devices[deviceName]->m_mutex); |
| m_connectedDevicesMutex.unlock(); |
| capabilities = m_devices[deviceName]->GetCapabilities(); |
| status = dmosSuccess; |
| } |
| else |
| { |
| m_connectedDevicesMutex.unlock(); |
| status = dmosNoSuchConnectedDevice; |
| } |
| |
| return status; |
| } |