660f0f0e73
This allows us to mirror the contents of the two lists into the unified list much more easily.
266 lines
7.3 KiB
C++
266 lines
7.3 KiB
C++
#include <iostream>
|
|
#include <stdexcept>
|
|
#include <optional>
|
|
#include <filesystem>
|
|
#include <senseApis/senseApiManager.h>
|
|
#include <senseApis/senseApiLib.h>
|
|
#include <opts.h>
|
|
#include <user/senseApiDesc.h>
|
|
#include <deviceManager/deviceManager.h>
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
namespace hk {
|
|
namespace sense_api {
|
|
|
|
static std::optional<std::string> findLibraryPath(
|
|
const std::string& libraryPath)
|
|
{
|
|
std::vector<std::string> searchPaths = {
|
|
fs::current_path().string(),
|
|
fs::path("/proc/self/exe").parent_path().string()
|
|
};
|
|
|
|
if (!OptionParser::getOptions().senseApiLibPath.empty())
|
|
{
|
|
searchPaths.insert(
|
|
searchPaths.begin(), OptionParser::getOptions().senseApiLibPath);
|
|
}
|
|
|
|
for (const auto& path : searchPaths)
|
|
{
|
|
fs::path fullPath = fs::path(path) / libraryPath;
|
|
if (fs::exists(fullPath))
|
|
{
|
|
return fullPath.string();
|
|
}
|
|
}
|
|
|
|
std::cerr << std::string(__func__) + ": library '"
|
|
+ libraryPath + "' isn't in search bespoke search paths: ";
|
|
for (const auto& path : searchPaths)
|
|
{
|
|
std::cerr << path << " ";
|
|
}
|
|
std::cerr << std::endl;
|
|
std::cerr << "Trying to load " + libraryPath + " from system default search "
|
|
"paths\n";
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
SenseApiLib& SenseApiManager::loadSenseApiLib(const std::string& libraryPath)
|
|
{
|
|
const CSenseApiDesc *libApiDesc;
|
|
std::optional<std::string> fullPath = findLibraryPath(libraryPath);
|
|
std::string resolvedPath = fullPath.value_or(libraryPath);
|
|
|
|
// Clear any existing error
|
|
dlerror();
|
|
auto dlopen_handle = std::unique_ptr<void, SenseApiLib::DlCloser>(
|
|
dlopen(resolvedPath.c_str(), RTLD_LAZY));
|
|
if (!dlopen_handle && fullPath.has_value())
|
|
{
|
|
// Fallback to using the supplied libraryPath
|
|
dlerror();
|
|
dlopen_handle.reset(dlopen(libraryPath.c_str(), RTLD_LAZY));
|
|
}
|
|
|
|
if (!dlopen_handle)
|
|
{
|
|
const char *dlerr = dlerror();
|
|
|
|
std::string error = (dlerr
|
|
? dlerr
|
|
: "Unknown error while opening shlib");
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": Cannot load library '"
|
|
+ libraryPath + "': "
|
|
+ error);
|
|
}
|
|
|
|
// Initialize getSenseApiDescriptor
|
|
auto func = reinterpret_cast<getSenseApiDescFn *>(
|
|
dlsym(dlopen_handle.get(), HK_GET_SENSE_API_DESC_FN_NAME_STR));
|
|
if (!func)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": dlsym('"
|
|
HK_GET_SENSE_API_DESC_FN_NAME_STR "') failed for library '"
|
|
+ libraryPath + "'");
|
|
}
|
|
|
|
libApiDesc = func();
|
|
if (!libApiDesc)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": getSenseApiDesc() returned NULL for "
|
|
"library '" + libraryPath + "'");
|
|
}
|
|
|
|
auto lib = std::make_unique<SenseApiLib>(
|
|
libraryPath, dlopen_handle.release(), func);
|
|
lib->setSenseApiDesc(libApiDesc);
|
|
senseApiLibs.push_back(std::move(lib));
|
|
return *senseApiLibs.back();
|
|
}
|
|
|
|
std::optional<std::reference_wrapper<SenseApiLib>>
|
|
SenseApiManager::getSenseApiLib(const std::string& libraryPath)
|
|
{
|
|
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
|
|
[&libPath = libraryPath](const std::unique_ptr<SenseApiLib>& lib) {
|
|
return lib->libraryPath == libPath;
|
|
}
|
|
);
|
|
|
|
if (it != senseApiLibs.end()) { return **it; }
|
|
return std::nullopt;
|
|
}
|
|
|
|
std::optional<std::reference_wrapper<SenseApiLib>>
|
|
SenseApiManager::getSenseApiLibByApiName(const std::string& apiName)
|
|
{
|
|
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
|
|
[&apiName](const std::unique_ptr<SenseApiLib>& lib) {
|
|
return lib->getSenseApiDesc()->name == apiName;
|
|
}
|
|
);
|
|
|
|
if (it != senseApiLibs.end()) { return **it; }
|
|
return std::nullopt;
|
|
}
|
|
|
|
void SenseApiManager::unloadSenseApiLib(const std::string& libraryPath)
|
|
{
|
|
auto it = std::find_if(senseApiLibs.begin(), senseApiLibs.end(),
|
|
[&lpath = libraryPath](const std::unique_ptr<SenseApiLib>& lib) {
|
|
return lib->libraryPath == lpath;
|
|
}
|
|
);
|
|
|
|
if (it != senseApiLibs.end())
|
|
{
|
|
senseApiLibs.erase(it);
|
|
return;
|
|
}
|
|
|
|
std::cerr << std::string(__func__) + ": Library not found: "
|
|
<< libraryPath << '\n';
|
|
}
|
|
|
|
void SenseApiManager::unloadAllSenseApiLibs(void)
|
|
{
|
|
senseApiLibs.clear();
|
|
}
|
|
|
|
void SenseApiManager::loadAllSenseApiLibsFromOptions()
|
|
{
|
|
const auto& options = OptionParser::getOptions();
|
|
for (const auto& libPath : options.senseApiLibs) {
|
|
loadSenseApiLib(libPath);
|
|
}
|
|
}
|
|
|
|
std::string SenseApiManager::stringifyLibs() const
|
|
{
|
|
std::string result;
|
|
for (const auto& lib : senseApiLibs) {
|
|
result += lib->stringify() + "\n";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void SenseApiManager::initializeSenseApiLib(SenseApiLib& lib)
|
|
{
|
|
if (!lib.getSenseApiDesc()->sal_mgmt_libOps->initializeInd)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": initializeInd() is NULL for library '"
|
|
+ lib.libraryPath + "'");
|
|
}
|
|
lib.getSenseApiDesc()->sal_mgmt_libOps->initializeInd();
|
|
}
|
|
|
|
void SenseApiManager::finalizeSenseApiLib(SenseApiLib& lib)
|
|
{
|
|
if (!lib.getSenseApiDesc()->sal_mgmt_libOps->finalizeInd)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": finalizeInd() is NULL for library '"
|
|
+ lib.libraryPath + "'");
|
|
}
|
|
lib.getSenseApiDesc()->sal_mgmt_libOps->finalizeInd();
|
|
}
|
|
|
|
void SenseApiManager::initializeAllSenseApiLibs(void)
|
|
{
|
|
for (auto& lib : senseApiLibs) {
|
|
initializeSenseApiLib(*lib);
|
|
}
|
|
}
|
|
|
|
void SenseApiManager::finalizeAllSenseApiLibs(void)
|
|
{
|
|
for (auto& lib : senseApiLibs) {
|
|
finalizeSenseApiLib(*lib);
|
|
}
|
|
}
|
|
|
|
void SenseApiManager::attachSenseDevice(const SenseDeviceSpec& spec)
|
|
{
|
|
auto libOpt = getSenseApiLibByApiName(spec.api);
|
|
if (!libOpt)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": No library found for API '"
|
|
+ spec.api + "'");
|
|
}
|
|
auto& lib = libOpt.value().get();
|
|
if (!lib.getSenseApiDesc()->sal_mgmt_libOps->attachDeviceReq)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": attachDeviceReq() is NULL for library '"
|
|
+ lib.libraryPath + "'");
|
|
}
|
|
CSenseDeviceSpec cSpec(spec);
|
|
lib.getSenseApiDesc()->sal_mgmt_libOps->attachDeviceReq(&cSpec);
|
|
}
|
|
|
|
void SenseApiManager::detachSenseDevice(const SenseDeviceSpec& spec)
|
|
{
|
|
auto libOpt = getSenseApiLibByApiName(spec.api);
|
|
if (!libOpt)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": No library found for API '"
|
|
+ spec.api + "'");
|
|
}
|
|
auto& lib = libOpt.value().get();
|
|
if (!lib.getSenseApiDesc()->sal_mgmt_libOps->detachDeviceReq)
|
|
{
|
|
throw std::runtime_error(
|
|
std::string(__func__) + ": detachDeviceReq() is NULL for library '"
|
|
+ lib.libraryPath + "'");
|
|
}
|
|
CSenseDeviceSpec cSpec(spec);
|
|
lib.getSenseApiDesc()->sal_mgmt_libOps->detachDeviceReq(&cSpec);
|
|
}
|
|
|
|
void SenseApiManager::attachAllSenseDevicesFromSpecs(void)
|
|
{
|
|
for (const auto& spec : DeviceManager::senseDeviceSpecs) {
|
|
attachSenseDevice(*spec);
|
|
}
|
|
}
|
|
|
|
void SenseApiManager::detachAllSenseDevices(void)
|
|
{
|
|
for (const auto& spec : DeviceManager::senseDeviceSpecs) {
|
|
detachSenseDevice(*spec);
|
|
}
|
|
}
|
|
|
|
} // namespace sense_api
|
|
} // namespace hk
|