-
Nadeem Shehzad authoredNadeem Shehzad authored
DeviceModule.cc 8.34 KiB
/*
* DeviceModule.cc
*
* Created on: Jun 27, 2016
* Author: Martin Hierholzer
*/
#include <ChimeraTK/DeviceBackend.h>
#include <ChimeraTK/Device.h>
#include "Application.h"
#include "DeviceModule.h"
namespace ChimeraTK {
DeviceModule::DeviceModule(const std::string& _deviceAliasOrURI, const std::string& _registerNamePrefix)
: Module(nullptr,
_registerNamePrefix.empty() ? "<Device:"+_deviceAliasOrURI+">"
: _registerNamePrefix.substr(_registerNamePrefix.find_last_of("/")+1),
""),
deviceAliasOrURI(_deviceAliasOrURI),
registerNamePrefix(_registerNamePrefix)
{
}
/*********************************************************************************************************************/
DeviceModule::DeviceModule(Application *application, const std::string& _deviceAliasOrURI, const std::string& _registerNamePrefix)
: Module(nullptr,
_registerNamePrefix.empty() ? "<Device:"+_deviceAliasOrURI+">"
: _registerNamePrefix.substr(_registerNamePrefix.find_last_of("/")+1),
""),
deviceAliasOrURI(_deviceAliasOrURI),
registerNamePrefix(_registerNamePrefix)
{
std::cout<<"deviceModule"<<std::endl;
application->registerDeviceModule(this);
}
/*********************************************************************************************************************/
VariableNetworkNode DeviceModule::operator()(const std::string& registerName, UpdateMode mode,
const std::type_info &valueType, size_t nElements) const {
return {registerName, deviceAliasOrURI, registerNamePrefix/registerName, mode, {VariableDirection::invalid, false}, valueType, nElements};
}
/*********************************************************************************************************************/
Module& DeviceModule::operator[](const std::string& moduleName) const {
std::cout<<"DeviceModule:"<<moduleName<<std::endl;
if(subModules.count(moduleName) == 0) {
subModules[moduleName] = {deviceAliasOrURI, registerNamePrefix/moduleName};
}
return subModules[moduleName];
}
/*********************************************************************************************************************/
const Module& DeviceModule::virtualise() const {
return *this;
}
/*********************************************************************************************************************/
void DeviceModule::connectTo(const Module &target, VariableNetworkNode trigger) const {
auto &cat = virtualiseFromCatalog();
cat.connectTo(target, trigger);
}
/*********************************************************************************************************************/
VirtualModule& DeviceModule::virtualiseFromCatalog() const {
if(virtualisedModuleFromCatalog_isValid) return virtualisedModuleFromCatalog;
virtualisedModuleFromCatalog = VirtualModule(deviceAliasOrURI, "Device module", ModuleType::Device);
// obtain register catalogue
std::cout<<"DeviceModule::virtualiseFromCatalog"<<std::endl;
Device d;
d.open(deviceAliasOrURI); /// @todo: do not actually open the device (needs extension of DeviceAccess)!
auto catalog = d.getRegisterCatalogue();
// iterate catalogue, create VariableNetworkNode for all registers starting with the registerNamePrefix
size_t prefixLength = registerNamePrefix.length();
for(auto ® : catalog) {
if(std::string(reg.getRegisterName()).substr(0,prefixLength) != std::string(registerNamePrefix)) continue;
// ignore 2D registers
if(reg.getNumberOfDimensions() > 1) continue;
// guess direction and determine update mode
VariableDirection direction;
UpdateMode updateMode;
if(reg.isWriteable()) {
direction = {VariableDirection::consuming, false};
updateMode = UpdateMode::push;
}
else {
direction = {VariableDirection::feeding, false};
if(reg.getSupportedAccessModes().has(AccessMode::wait_for_new_data)) {
updateMode = UpdateMode::push;
}
else {
updateMode = UpdateMode::poll;
}
}
// guess type
const std::type_info *valTyp{&typeid(AnyType)};
auto &dd = reg.getDataDescriptor(); //numeric, string, boolean, nodata, undefined
if(dd.fundamentalType() == RegisterInfo::FundamentalType::numeric) {
if(dd.isIntegral()) {
if(dd.isSigned()) {
if(dd.nDigits() > 11) {
valTyp = &typeid(int64_t);
}
else if(dd.nDigits() > 6) {
valTyp = &typeid(int32_t);
}
else if(dd.nDigits() > 4) {
valTyp = &typeid(int16_t);
}
else {
valTyp = &typeid(int8_t);
}
}
else {
if(dd.nDigits() > 10) {
valTyp = &typeid(uint64_t);
}
else if(dd.nDigits() > 5) {
valTyp = &typeid(uint32_t);
}
else if(dd.nDigits() > 3) {
valTyp = &typeid(uint16_t);
}
else {
valTyp = &typeid(uint8_t);
}
}
}
else { // fractional
valTyp = &typeid(double);
}
}
else if(dd.fundamentalType() == RegisterInfo::FundamentalType::boolean) {
valTyp = &typeid(int32_t);
}
else if(dd.fundamentalType() == RegisterInfo::FundamentalType::string) {
valTyp = &typeid(std::string);
}
auto name = std::string(reg.getRegisterName()).substr(prefixLength);
auto lastSlash = name.find_last_of("/");
auto dirname = name.substr(0,lastSlash);
auto basename = name.substr(lastSlash+1);
VariableNetworkNode node(basename, deviceAliasOrURI, reg.getRegisterName(), updateMode,
direction, *valTyp, reg.getNumberOfElements());
virtualisedModuleFromCatalog.createAndGetSubmoduleRecursive(dirname).addAccessor(node);
}
virtualisedModuleFromCatalog_isValid = true;
return virtualisedModuleFromCatalog;
}
/*********************************************************************************************************************/
void DeviceModule::reportException(std::string errMsg ){
deviceError.status = 1;
deviceError.message = errMsg;
deviceError.writeAll();
std::unique_lock<std::mutex> lk(errorMutex);
errorQueue.push(errMsg);
errorCondVar.wait(lk);
}
/*********************************************************************************************************************/
void DeviceModule::handleException(){
std::string error;
while(true)
{
try{
errorQueue.pop_wait(error);
Device d;
while(true)
{
d.open(deviceAliasOrURI);
if (d.isOpened())
{
break;
}
usleep(5000);
}
deviceError.status = 1;
deviceError.message = "";
//lk.unlock();
errorCondVar.notify_all();
}
catch(std::exception ex)
{
std::cout<<"caught exception:"<<ex.what()<<std::endl;
//deviceError.message = ex.what();
}
}
}
/*********************************************************************************************************************/
void DeviceModule::run() {
// start the module thread
std::cout<<"start the module thread"<<std::endl;
assert(!moduleThread.joinable());
moduleThread = boost::thread(&DeviceModule::handleException, this);
}
/*********************************************************************************************************************/
void DeviceModule::terminate() {
if(moduleThread.joinable()) {
moduleThread.interrupt();
// try joining the thread
while(!moduleThread.try_join_for(boost::chrono::milliseconds(10))) {
// if thread is not yet joined, send interrupt() to all variables.
for(auto &var : getAccessorListRecursive()) {
if(var.getDirection() == VariableDirection{VariableDirection::feeding,false}) continue;
var.getAppAccessorNoType().getHighLevelImplElement()->interrupt();
}
// it may not suffice to send interrupt() once, as the exception might get overwritten in the queue, thus we
// repeat this until the thread was joined.
}
}
assert(!moduleThread.joinable());
}
}