blob: ce2e816b52e65f1d577aaa11b35142ee79e2a6c8 [file] [log] [blame]
/*
* 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;
}