root/juggler/branches/2.2/modules/gadgeteer/gadget/InputManager.cpp

Revision 20500, 36.3 kB (checked in by patrick, 1 year ago)

Merges from the trunk:

r20490: Instead of using a different name to distinguish between

debug-enabled and optimized DLLS linked against the release runtime
on Windows, use directories in much the same way that we always
have on non-Windows platforms. This allows users to switch between
optimized and debug-enabled code at run time simply by changing the
PATH environment variable. No relinking or recompiling is required.
This is something that we have always been able to do on
non-Windows platofrms, and we can finally do it on Windows, too.

r20491: When we are running a debug build (not linking against the debug

runtime on Windows), prepend the "debug" subdirectory to the
plug-in search path by default.

r20492: Get the non-Windows build and installation in sync with the Windows

build with regard to debug-enabled plug-ins. Instead of using an
"_d" name variant, we are now separating the plug-ins using
directories. The debug-enabled plug-ins go in the "debug"
subdirectory of the directory containing the optimized plug-ins. In
cases where the plug-in search path is configurable, users can load
the debug plug-ins into optimized or debug-enabled code by changing
the search path in the configuration. Now, the "debug" subdirectory
is searched before the optimized directory for debug builds. This
retains backwards compatibility with previous versions and keeps
things simple when developers are only making debug builds.

JCCL, Gadgeteer, Sonix, and VR Juggler load plug-ins using vpr::LibraryLoader?.
While there has been no API change to that class that these modules depend on,
they do need to get the proper run-time behavior when searching for plug-ins.
As such, they now all need VPR 1.1.49 (i.e., this revision) or newer.

All of this is noted in the respective ChangeLog? files, and the version
number of each Juggler module to mark this significant change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
2  *
3  * VR Juggler is (C) Copyright 1998-2007 by Iowa State University
4  *
5  * Original Authors:
6  *   Allen Bierbaum, Christopher Just,
7  *   Patrick Hartling, Kevin Meinert,
8  *   Carolina Cruz-Neira, Albert Baker
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  *
25  *************** <auto-copyright.pl END do not edit this line> ***************/
26
27 #include <gadget/gadgetConfig.h>
28
29 #include <iomanip>
30 #include <sstream>
31 #include <boost/filesystem/path.hpp>
32 #include <boost/filesystem/exception.hpp>
33 #include <boost/filesystem/operations.hpp>
34
35 #include <vpr/vpr.h>
36 #include <vpr/System.h>
37 #include <vpr/DynLoad/LibraryFinder.h>
38 #include <vpr/DynLoad/LibraryLoader.h>
39 #include <vpr/Util/FileUtils.h>
40
41 #include <jccl/Config/ConfigElement.h>
42 #include <jccl/RTRC/ConfigManager.h>
43
44 #include <cluster/ClusterManager.h>
45 #include <gadget/InputLogger.h>
46 #include <gadget/ProxyFactory.h>
47 #include <gadget/Type/BaseTypeFactory.h>
48 #include <gadget/Type/DeviceFactory.h>
49 #include <gadget/Type/Proxy.h>
50 #include <gadget/Type/DeviceInterface.h>
51 #include <gadget/Util/Debug.h>
52 #include <gadget/Util/PluginVersionException.h>
53 #include <gadget/Util/PathHelpers.h>
54 #include <gadget/gadgetParam.h>
55
56 #include <gadget/InputManager.h>
57
58
59 namespace fs = boost::filesystem;
60
61 namespace gadget
62 {
63
64    vprSingletonImp( InputManager );    // Implementation of singleton
65
66 // Local helpers
67 static bool recognizeProxyAlias(jccl::ConfigElementPtr element);
68
69 /**
70  * InputManager Constructor
71  */
72 InputManager::InputManager()
73 {
74 }
75
76 /**
77  * InputManager Destructor
78  */
79 InputManager::~InputManager()
80 {
81    shutdown();
82 }
83
84 void InputManager::shutdown()
85 {
86    typedef tDevTableType::iterator dev_iter_t;
87
88    // Stop and delete all devices.
89    for ( dev_iter_t a = mDevTable.begin(); a != mDevTable.end(); ++a )
90    {
91       if ((*a).second != NULL)
92       {
93          (*a).second->stopSampling();
94          delete (*a).second;
95       }
96    }
97
98    mDevTable.clear();
99
100    // Delete all the proxies
101    typedef std::map<std::string, Proxy*>::iterator proxy_iter_t;
102    for ( proxy_iter_t j = mProxyTable.begin(); j != mProxyTable.end(); ++j )
103    {
104       delete (*j).second;
105    }
106
107    mProxyTable.clear();
108 }
109
110 /**
111  * This struct implements a callable object (a functor, basically).  An
112  * instance can be passed in where a boost::function1<bool, void*> is expected.
113  * In gadget::InputManager::configAdd(), instances are used to handle version
114  * checking of device driver plug-ins via vpr::LibraryLoader.
115  */
116 struct VersionCheckCallable
117 {
118    VersionCheckCallable()
119    {
120    }
121
122    /**
123     * This will be invoked as a callback by methods of vpr::LibraryLoader.
124     *
125     * @param func A function pointer for the entry point in a dynamically
126     *             loaded device driver.  This must be cast to the correct
127     *             signature before being invoked.
128     */
129    bool operator()(void* func)
130    {
131       vpr::Uint32 (*version_func)();
132       version_func = (vpr::Uint32 (*)()) func;
133
134       // Call the entry point function, which, in this case, returns the
135       // version of Gadgeteer against which the driver was compiled.
136       const vpr::Uint32 driver_gadget_ver = (*version_func)();
137
138       if ( driver_gadget_ver != mGadgetVersion )
139       {
140          std::ostringstream msg_stream;
141          msg_stream << "Gadgeteer version mismatch!\n"
142                     << "Driver was compiled against Gadgeteer version "
143                     << driver_gadget_ver << ",\n"
144                     << "but this is Gadgeteer version " << mGadgetVersion
145                     << std::endl;
146          throw gadget::PluginVersionException(msg_stream.str(), VPR_LOCATION);
147       }
148
149       return true;
150    }
151
152    static const vpr::Uint32 mGadgetVersion;
153 };
154
155 const vpr::Uint32 VersionCheckCallable::mGadgetVersion(__GADGET_version);
156
157 /**
158  * This struct implements a callable object (a functor, basically).  An
159  * instance can be passed in where a boost::function1<bool, void*> is expected.
160  * In gadget::InputManager::configAdd(), instances are used to handle dynamic
161  * loading of device drivers via vpr::LibraryLoader.
162  */
163 struct DriverInitCallable
164 {
165    DriverInitCallable(gadget::InputManager* inputMgr) : mgr(inputMgr)
166    {
167    }
168
169    /**
170     * This will be invoked as a callback by methods of vpr::LibraryLoader.
171     *
172     * @param func A function pointer for the entry point in a dynamically
173     *             loaded device driver.  This must be cast to the correct
174     *             signature before being invoked.
175     */
176    bool operator()(void* func)
177    {
178       void (*init_func)(InputManager*);
179
180       // Cast the entry point function to the correct signature so that we can
181       // call it.  All dynamically loaded drivers must have an entry point
182       // function that takes a pointer to a gadget::InputManager instance and
183       // returns nothing.
184       init_func = (void (*)(InputManager*)) func;
185
186       // Call the entry point function.
187       (*init_func)(mgr);
188
189       return true;
190    }
191
192    gadget::InputManager* mgr;
193 };
194
195 /** Adds the given config element to the input system. */
196 bool InputManager::configAdd(jccl::ConfigElementPtr element)
197 {
198 vpr::DebugOutputGuard dbg_output(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL,
199                               std::string("Input Manager: Adding pending config element.\n"),
200                               std::string("...done adding element.\n"));
201
202    vprASSERT(configCanHandle(element));
203
204    bool ret_val = false;      // Flag to return success
205
206    if (cluster::ClusterManager::instance()->recognizeRemoteDeviceConfig(element))
207    {
208       vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL)
209          << "InputManager can not handle remote devices, we must use Remote Input Manager."
210          << vprDEBUG_FLUSH;
211       ret_val = false;
212    }
213    else if (element->getID() == std::string( "input_window" ))
214    {
215       // Get the KeyboardMouseDevice that this window should send events to.
216       std::string keyboard_mouse_device_name =
217          element->getProperty<std::string>( "keyboard_mouse_device_name" );
218
219       // Get the KeyboardMouseDevice ConfigElement.
220       // NOTE: We can assume that this config element is in the active
221       //       list since the DependancyManager requires that all
222       //       ConfigElementPointers be resolved first.
223       jccl::ConfigManager* cfg_mgr = jccl::ConfigManager::instance();
224       cfg_mgr->lockActive();
225       jccl::ConfigElementPtr keyboard_mouse_element
226          = cfg_mgr->getActiveConfig()->get( keyboard_mouse_device_name );
227       cfg_mgr->unlockActive();
228
229       // If a KeyboardMouseDevice with this name exists and is remote, we do not want
230       // to start this device and open a window since this KeyboardMouseDevice will
231       // be invalid.
232       if (NULL != keyboard_mouse_element.get() &&
233          cluster::ClusterManager::instance()->recognizeRemoteDeviceConfig( keyboard_mouse_element ))
234       {
235          vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL)
236             << "InputManager::configAdd() InputWindow not being opened "
237             << "since it points to a remote KeyboardMouseDevice."
238             << vprDEBUG_FLUSH;
239          ret_val = true;
240       }
241       else
242       {
243          ret_val = configureDevice( element );
244       }
245    }
246    else if(DeviceFactory::instance()->recognizeDevice(element))
247    {
248       ret_val = configureDevice(element);
249    }
250    else if(ProxyFactory::instance()->recognizeProxy(element))
251    {
252       ret_val = configureProxy(element);
253    }
254    else if(recognizeProxyAlias(element))
255    {
256       ret_val = configureProxyAlias(element);
257    }
258    else if(element->getID() == std::string("display_system"))
259    {
260       // XXX: Put signal here to tell draw manager to lookup new stuff
261       mDisplaySystemElement = element;     // Keep track of the display system element
262       ret_val = true;
263    }
264    else if(element->getID() == std::string("gadget_logger"))
265    {
266       ret_val = configureInputLogger(element);
267    }
268    else if(element->getID() == std::string("input_manager"))
269    {
270       ret_val = configureInputManager(element);
271    }
272
273    //DumpStatus();                      // Dump the status
274    {
275       vpr::DebugOutputGuard dbg_output(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL,
276                               std::string("New Input Manager state:\n"),
277                               std::string("-- end state -- \n"));
278       vprDEBUG(gadgetDBG_INPUT_MGR,vprDBG_VERB_LVL) << (*this) << vprDEBUG_FLUSH;
279    }
280
281    if(ret_val)
282    {
283       resetAllDevicesAndProxies();
284       updateAllDevices();                             // Update all the input data
285       updateAllProxies();                             // Update all the input data
286       BaseDeviceInterface::refreshAllInterfaces();    // Refresh all the device interface handles
287       vprDEBUG(gadgetDBG_INPUT_MGR,vprDBG_STATE_LVL)
288          << "Updated all devices" << std::endl << vprDEBUG_FLUSH;
289    }
290
291    return ret_val;         // Return the success flag if we added at all
292 }
293
294
295 /**
296  * Removes the element from the current configuration.
297  */
298 bool InputManager::configRemove(jccl::ConfigElementPtr element)
299 {
300 vpr::DebugOutputGuard dbg_output(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL,
301                               std::string("InputManager: Removing config...\n"),
302                               std::string("done removing config.\n"));
303    vprASSERT(configCanHandle(element));
304
305    bool ret_val = false;      // Flag to return success
306
307    // NEED TO FIX!!!!
308    if (cluster::ClusterManager::instance()->recognizeRemoteDeviceConfig(element))
309    {
310       vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CONFIG_LVL)
311          << "InputManager can not handle remote devices, we must use Remote Input Manager."
312          << vprDEBUG_FLUSH;
313       ret_val = false;
314    }
315    else if(DeviceFactory::instance()->recognizeDevice(element))
316    {
317       ret_val = removeDevice(element);
318    }
319    else if(recognizeProxyAlias(element))
320    {
321       ret_val = removeProxyAlias(element);
322    }
323    else if(ProxyFactory::instance()->recognizeProxy(element))
324    {
325       ret_val = removeProxy(element);
326    }
327    else if(element->getID() == std::string("display_system"))
328    {
329       mDisplaySystemElement.reset();  // Keep track of the display system element
330       ret_val = true;                 // We successfully configured.
331                                        // This tell processPending to remove it to the active config
332    }
333    else
334    {
335       ret_val = false;
336    }
337
338    if(ret_val)
339    {
340       resetAllDevicesAndProxies();
341       updateAllDevices();                             // Update all the input data
342       updateAllProxies();                             // Update all the input data
343       BaseDeviceInterface::refreshAllInterfaces();      // Refresh all the device interface handles
344       vprDEBUG(gadgetDBG_INPUT_MGR,vprDBG_VERB_LVL)
345          << "InputManager::configRemove(): Updated all data" << std::endl
346          << vprDEBUG_FLUSH;
347    }
348
349    return ret_val;         // Return the success flag if we added at all
350 }
351
352
353 // Return true if:
354 //  It is recognized device, proxy, or alias.
355 bool InputManager::configCanHandle(jccl::ConfigElementPtr element)
356 {           // NEED TO FIX!!!!
357    return ( (DeviceFactory::instance()->recognizeDevice(element) &&
358              !cluster::ClusterManager::instance()->recognizeRemoteDeviceConfig(element)) ||
359             ProxyFactory::instance()->recognizeProxy(element) ||
360             recognizeProxyAlias(element) ||
361             (element->getID() == std::string("display_system")) ||
362             (element->getID() == std::string("input_manager")) ||
363             (element->getID() == std::string("gadget_logger"))
364           );
365 }
366
367 jccl::ConfigElementPtr InputManager::getDisplaySystemElement()
368 {
369    if ( mDisplaySystemElement.get() == NULL )
370    {
371       jccl::ConfigManager* cfg_mgr = jccl::ConfigManager::instance();
372
373       cfg_mgr->lockActive();
374       {
375          std::vector<jccl::ConfigElementPtr>::iterator i;
376          for( i = cfg_mgr->getActiveBegin(); i != cfg_mgr->getActiveEnd(); ++i)
377          {
378             if((*i)->getID() == std::string("display_system"))
379             {
380                mDisplaySystemElement = *i;
381                break;         // This guarantees that we get the first displaySystem element.
382             }
383          }
384       }
385       cfg_mgr->unlockActive();
386       //vprASSERT(mDisplaySystemElement.get() != NULL && "No Display Manager element found!");
387    }
388    return mDisplaySystemElement;
389 }
390
391 /**
392  * Check if the device factory or proxy factory can handle the element.
393  */
394 bool InputManager::configureDevice(jccl::ConfigElementPtr element)
395 {
396    bool ret_val;
397    std::string dev_name = element->getFullName();
398
399    vpr::DebugOutputGuard dbg_output(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL,
400                                  std::string("InputManager::configureDevice: device[") + dev_name + std::string("]\n"),
401                                  std::string("done configuring device\n"));
402
403    Input* new_device;
404    new_device = DeviceFactory::instance()->loadDevice(element);
405
406    if ((new_device != NULL) && (new_device->startSampling()))
407    {
408       addDevice(new_device);
409       ret_val = true;
410       vprDEBUG(gadgetDBG_INPUT_MGR,vprDBG_STATE_LVL)
411          << "   Successfully added device: " << dev_name << std::endl
412          << vprDEBUG_FLUSH;
413    }
414    else
415    {
416       vprDEBUG(vprDBG_ERROR,vprDBG_CRITICAL_LVL) << clrOutNORM(clrRED,"ERROR:")
417          << "New device " << clrSetBOLD(clrCYAN) << dev_name << clrRESET
418          << " failed to start.  Deleting instance" << std::endl
419          << vprDEBUG_FLUSH;
420       if ( NULL != new_device )
421       {
422          delete new_device;
423       }
424
425       ret_val = false;
426    }
427
428    return ret_val;
429 }
430
431 /**
432  * Check if the device factory or proxy factory can handle the element.
433  */
434 bool InputManager::configureProxy(jccl::ConfigElementPtr element)
435 {
436    std::string proxy_name = element->getFullName();
437
438 vpr::DebugOutputGuard dbg_output(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL,
439                                  std::string("gadget::InputManager::configureProxy: Named: ") + proxy_name + std::string("\n"),
440                                  std::string("done configuring proxy\n"));
441
442    Proxy* new_proxy;
443
444    // Tell the factory to load the proxy
445    // NOTE: The config for the proxy registers it with the input manager
446    new_proxy = ProxyFactory::instance()->loadProxy(element);
447
448    // Check for success
449    if(NULL == new_proxy)
450    {
451       vprDEBUG(vprDBG_ERROR,vprDBG_CRITICAL_LVL)
452          << clrOutNORM(clrRED,"ERROR:")
453          << " gadget::InputManager::configureProxy: Proxy construction failed:"
454          << proxy_name << std::endl << vprDEBUG_FLUSH;
455       return false;
456    }
457    vprASSERT(proxy_name == new_proxy->getName());
458
459    // -- Add to proxy table
460    if(false == addProxy(new_proxy))
461    {
462       return false;
463    }
464
465    return true;
466 }
467
468
469 /**
470  * Removes the device associated with the given element.
471  */
472 bool InputManager::removeDevice(jccl::ConfigElementPtr element)
473 {
474    return removeDevice(element->getFullName());
475 }
476
477
478 /**
479  * Dump the current Status of the InputManager, listing all
480  * the devices, proxies and internal settings
481  */
482 GADGET_IMPLEMENT(std::ostream&) operator<<(std::ostream& out, InputManager& iMgr)
483 {
484    out << "\n========== Input Manager Status ==========" << std::endl;
485    out << "Device List:\n";
486
487    // Dump DEVICES
488    for ( InputManager::tDevTableType::iterator i = iMgr.mDevTable.begin();
489          i != iMgr.mDevTable.end();
490          ++i)
491    {
492       if ((*i).second != NULL)
493       {
494          out << "    '" << i->first << "' (type: "
495              << typeid(*(i->second)).name() << ")" << std::endl;
496       }
497    }
498
499    out << "\nProxy List:\n";
500    for (std::map<std::string, Proxy*>::iterator i_p = iMgr.mProxyTable.begin();
501         i_p != iMgr.mProxyTable.end();
502         ++i_p)
503    {
504       out << "    '" << (*i_p).second->getName() << "' refers to ";
505       if(NULL != ((*i_p).second->getProxiedInputDevice()))
506       {
507          out << ((*i_p).second->getProxiedInputDevice())->getInstanceName();
508       }
509       else
510       {
511          out << "None (internal dummy)";
512       }
513       out << std::endl;
514    }
515
516    out << std::endl;
517
518    // Dump Alias list
519    out << "Alias List:" << std::endl;
520    for ( std::map<std::string, std::string>::iterator cur_alias = iMgr.mProxyAliases.begin();
521          cur_alias != iMgr.mProxyAliases.end();
522          ++cur_alias )
523    {
524       out << "    '" << (*cur_alias).first.c_str() << "' (alias for "
525           << (*cur_alias).second << ")" << std::endl;
526    }
527
528    out << "========== InputManager Status ==========" << std::endl;
529    return out;
530 }
531
532 /**
533  * Add a device to the InputManager, returns the index
534  * where the device was placed
535  */
536 bool InputManager::addDevice(Input* devPtr)
537 {
538    mDevTable[devPtr->getInstanceName()] = devPtr;
539
540    refreshAllProxies();
541
542    return true;
543 }
544
545 /**
546  *   Add a remote device to the InputManager that is being updated by a RemoteInputManager.
547  */
548 bool InputManager::addRemoteDevice(Input* devPtr, const std::string& device_name)
549 {
550    mDevTable[device_name] = devPtr;
551
552    refreshAllProxies();
553
554    return true;
555 }
556
557 void InputManager::resetAllDevicesAndProxies()
558 {
559    typedef std::map<std::string, Proxy*>::iterator iter_type;
560    for ( iter_type i_p = mProxyTable.begin(); i_p != mProxyTable.end(); ++i_p )
561    {
562       (*i_p).second->resetData();
563    }
564
565    // all DEVICES
566    for ( tDevTableType::iterator i = mDevTable.begin();
567          i != mDevTable.end();
568          ++i )
569    {
570       if ( (*i).second != NULL )
571       {
572          (*i).second->resetData();
573       }
574    }
575 }
576
577 void InputManager::updateAllProxies()
578 {
579    // Update proxies MIGHT NOT NEED
580    for (std::map<std::string, Proxy*>::iterator i_p = mProxyTable.begin();
581         i_p != mProxyTable.end();
582         ++i_p)
583    {
584       (*i_p).second->updateDataIfNeeded();
585    }
586 }
587
588
589 /**
590  * Call UpdateData() on all the devices and transform proxies.
591  */
592 void InputManager::updateAllDevices()
593 {
594    for (tDevTableType::iterator i = mDevTable.begin(); i != mDevTable.end(); ++i)      // all DEVICES
595    {
596       if ((*i).second != NULL)
597       {
598          i->second->updateDataIfNeeded();
599       }
600    }
601
602    // Update Logger - Done here so that device can be "rewritten" by logger
603    //                 before rim or proxies get their hands on the data
604    if(mInputLogger.get() != NULL)
605    {
606       mInputLogger->process();
607    }
608 }
609
610 /**
611  * Return a Input ptr to a deviced named
612  *
613  * @returns - NULL if not found.
614  */
615 Input* InputManager::getDevice(const std::string& deviceName)
616 {
617    // Look up in Input Manager
618    tDevTableType::iterator ret_dev;
619    ret_dev = mDevTable.find(deviceName);
620    if(ret_dev != mDevTable.end())
621    {
622       return ret_dev->second;
623    }
624    return NULL;
625 }
626
627 DeviceFactory* InputManager::getDeviceFactory()
628 {
629    return gadget::DeviceFactory::instance();
630 }
631
632 /**
633  * Remove the device that is pointed to by devPtr.
634  */
635 bool InputManager::removeDevice(const Input* devPtr)
636 {
637    for (tDevTableType::iterator i = mDevTable.begin(); i != mDevTable.end(); ++i)      // all DEVICES
638    {
639       if ((*i).second == devPtr)
640       {
641          return removeDevice((*i).first);
642       }
643    }
644
645    return false;
646 }
647
648
649 /**
650  * InputManager remove instName from the InputManager,
651  * currently stupefies all the proxies connected to it.
652  */
653 bool InputManager::removeDevice(const std::string& instName)
654 {
655    tDevTableType::iterator dev_found;
656    dev_found = mDevTable.find(instName);
657    if(dev_found == mDevTable.end())
658    {
659       return false;
660    }
661
662    Input* dev_ptr = dev_found->second;
663
664    if(NULL == dev_ptr)
665    {
666       return false;
667    }
668
669    // Find any proxies connected to the device
670    // Stupefy any proxies connected to device
671    // NOTE: Could just remove it and then refresh all, but this is a little safer
672    //       since we explicitly stupefy the one that we don't want anymore
673    for ( std::map<std::string, Proxy*>::iterator i_p = mProxyTable.begin();
674         i_p != mProxyTable.end();
675         ++i_p )
676    {
677       if((*i_p).second->getProxiedInputDevice() == dev_ptr)
678       {
679          (*i_p).second->stupefy(true);
680       }
681    }
682
683    // stop the device, delete it, set pointer to NULL
684    dev_ptr->stopSampling();
685    delete dev_ptr;
686    mDevTable.erase(dev_found);
687
688    // Refresh the proxies
689    refreshAllProxies();
690
691    return true;
692 }
693
694 bool InputManager::configureInputManager(jccl::ConfigElementPtr element)
695 {
696    bool have_bad_elt = (element->getID() != std::string("input_manager"));
697    vprASSERT(!have_bad_elt);
698    if(have_bad_elt)
699    {
700       return false;
701    }
702
703    bool ret_val = false;
704
705    vpr::DebugOutputGuard dbg_output(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL,
706                                     std::string("Handling input_manager element:\n"),
707                                     std::string("-- end state -- \n"));
708
709    // Keep this up to date with the version of the element definition we're
710    // expecting to handle.
711    const unsigned int cur_version(2);
712
713    // If the element version is less than cur_version, we will not try to
714    // proceed.  Instead, we'll print an error message and return false so
715    // that the Config Manager knows this element wasn't consumed.
716    if ( element->getVersion() < cur_version )
717    {
718       vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
719          << clrOutBOLD(clrRED, "ERROR")
720          << ": [gadget::InputManager::configureInputManager()] Element named '"
721          << element->getName() << "'" << std::endl << vprDEBUG_FLUSH;
722       vprDEBUG_NEXT(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
723          << "is version " << element->getVersion()
724          << ", but we require at least version " << cur_version
725          << std::endl << vprDEBUG_FLUSH;
726       vprDEBUG_NEXT(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
727          << "Ignoring this element and moving on." << std::endl
728          << vprDEBUG_FLUSH;
729       ret_val = false;
730    }
731    // We got the right version of the config element and can proceed.
732    else
733    {
734       const std::string driver_path_prop_name("driver_path");
735       const int path_count(element->getNum(driver_path_prop_name));
736       std::vector<fs::path> search_path(path_count);
737
738       for ( unsigned int i = 0; i < search_path.size(); ++i )
739       {
740          std::string temp_str =
741             vpr::replaceEnvVars(element->getProperty<std::string>(driver_path_prop_name, i));
742
743          try
744          {
745             search_path[i] = fs::path(temp_str, fs::native);
746          }
747          catch(fs::filesystem_error& fsEx)
748          {
749             vprDEBUG(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
750                << clrOutNORM(clrRED, "ERROR")
751                << ": [gadget::InputManager::configureInputManager()] File "
752                << "system exception caught while converting\n"
753                << vprDEBUG_FLUSH;
754             vprDEBUG_NEXT(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
755                << "'" << temp_str << "'\n" << vprDEBUG_FLUSH;
756             vprDEBUG_NEXT(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
757                << "to a Boost.Filesystem path.\n" << vprDEBUG_FLUSH;
758             vprDEBUG_NEXT(vprDBG_ERROR, vprDBG_CRITICAL_LVL)
759                << fsEx.what() << std::endl << vprDEBUG_FLUSH;
760          }
761       }
762
763       // Append a default driver search path to search_path.
764       const fs::path default_search_dir =
765          gadget::getDefaultPluginRoot() / std::string("drivers");
766
767       vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_VERB_LVL)
768          << "[gadget::InputManager::configureInputManager()] Appending "
769          << "default search path '"
770          << default_search_dir.native_directory_string() << "'\n"
771          << vprDEBUG_FLUSH;
772
773 #if defined(GADGET_DEBUG)
774       // For a debug build, search in the debug subdirectory of
775       // default_search_dir before looking in default_search_dir.
776       search_path.push_back(default_search_dir / std::string("debug"));
777 #endif
778
779       search_path.push_back(default_search_dir);
780
781       // --- Load device driver dsos -- //
782       // - Load individual drivers
783       const std::string driver_prop_name("driver");
784       const std::string get_version_func("getGadgeteerVersion");
785       const std::string driver_init_func("initDevice");
786
787       int driver_count = element->getNum(driver_prop_name);
788       std::string driver_dso_name;
789
790       for ( int i = 0; i < driver_count; ++i )
791       {
792          driver_dso_name =
793             element->getProperty<std::string>(driver_prop_name, i);
794
795          if ( ! driver_dso_name.empty() )
796          {
797             vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_STATE_LVL)
798                << "[gadget::InputManager::configureInputManager()] Loading "
799                << "driver DSO '" << driver_dso_name << "'\n" << vprDEBUG_FLUSH;
800
801             vpr::LibraryPtr dso = vpr::LibraryLoader::findDSO(driver_dso_name,
802                                                               search_path);
803
804             if ( dso.get() != NULL )
805             {
806                try
807                {
808                   VersionCheckCallable version_functor;
809                   vpr::LibraryLoader::callEntryPoint(dso, get_version_func,
810                                                      version_functor);
811
812                   DriverInitCallable init_functor(this);
813                   vpr::LibraryLoader::callEntryPoint(dso, driver_init_func,
814                                                      init_functor);
815
816                   mLoadedDrivers.push_back(dso);
817                }
818                catch (gadget::PluginVersionException& ex)
819                {
820                   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
821                      << clrOutBOLD(clrRED, "ERROR")
822                      << ": Version mismatch while loading driver DSO '"
823                      << driver_dso_name << "'\n" << vprDEBUG_FLUSH;
824                   vprDEBUG_NEXT(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
825                      << "This driver will not be usable.\n"
826                      << vprDEBUG_FLUSH;
827                   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
828                      << ex.getExtendedDescription() << std::endl
829                      << vprDEBUG_FLUSH;
830                }
831                catch (vpr::Exception& ex)
832                {
833                   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
834                      << clrOutBOLD(clrRED, "ERROR")
835                      << ": Failed to load driver DSO '"
836                      << driver_dso_name << "'\n" << vprDEBUG_FLUSH;
837                   vprDEBUG_NEXT(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
838                      << "This driver will not be usable.\n" << vprDEBUG_FLUSH;
839                   vprDEBUG(gadgetDBG_INPUT_MGR, vprDBG_CRITICAL_LVL)
840                      << ex.what() << std::endl << vprDEBUG_FLUSH;