forked from micro-manager/micro-manager
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMMCore.cpp
7362 lines (6477 loc) · 230 KB
/
MMCore.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//////////////////////////////////////////////////////////////////////////////
// FILE: MMCore.cpp
// PROJECT: Micro-Manager
// SUBSYSTEM: MMCore
//-----------------------------------------------------------------------------
// DESCRIPTION: The interface to the MM core services.
//
// COPYRIGHT: University of California, San Francisco, 2006-2014
// 100X Imaging Inc, www.100ximaging.com, 2008
//
// LICENSE: This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation.
//
// You should have received a copy of the GNU Lesser General Public
// License along with the source distribution; if not, write to
// the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
// Boston, MA 02111-1307 USA
//
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES.
//
// AUTHOR: Nenad Amodaj, [email protected], 06/07/2005
//
// NOTES:
// Public methods follow slightly different naming conventions than
// the rest of the C++ code, i.e we have:
// getConfiguration();
// instead of:
// GetConfiguration();
// The alternative (lowercase function names) convention is used
// because all public methods will most likely appear in other
// programming environments (Java or Python).
#include "../MMDevice/DeviceThreads.h"
#include "../MMDevice/DeviceUtils.h"
#include "../MMDevice/ImageMetadata.h"
#include "../MMDevice/ModuleInterface.h"
#include "CircularBuffer.h"
#include "ConfigGroup.h"
#include "Configuration.h"
#include "CoreCallback.h"
#include "CoreProperty.h"
#include "CoreUtils.h"
#include "DeviceManager.h"
#include "Devices/DeviceInstances.h"
#include "Host.h"
#include "LogManager.h"
#include "MMCore.h"
#include "MMEventCallback.h"
#include "PluginManager.h"
#include <boost/date_time/posix_time/posix_time.hpp>
#include <algorithm>
#include <assert.h>
#include <fstream>
#include <set>
#include <sstream>
#include <vector>
#ifndef _WINDOWS
// Needed on Unix for getcwd() and gethostname()
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#else
// for _getcwd
#include <direct.h>
#endif
using namespace std;
/*
* Important! Read this before changing this file:
*
* The following (major, minor, patch) triplet is the MMCore API version. Since
* 3.0.0, this is maintained according to the rules outlined at
* http://semver.org/ . Briefly,
*
* - Increment the major version when making backward-incompatible changes
* (changes that will require any existing code to be modified, or that may
* change behavior).
* - Increment the minor version when adding methods or functionality without
* breaking backward-compatibility.
* - Increment the patch version when fixing incorrect behavior in a
* backward-compatible manner.
*
* There is no need to increment the patch number when making changes that do
* not change behavior (such as internal refactoring).
*
* There is no particular correspondence between the Core API version number
* and the device/module interface version numbers or the MMStudio application
* version number (each version is incremented independently of each other).
*
* This applies to all classes exposed through the SWIG layer (i.e. the whole
* of the public API of the Core), not just CMMCore.
*
* (Keep the 3 numbers on one line to make it easier to look at diffs when
* merging/rebasing.)
*/
const int MMCore_versionMajor = 8, MMCore_versionMinor = 5, MMCore_versionPatch = 0;
///////////////////////////////////////////////////////////////////////////////
// CMMCore class
// -------------
/**
* Constructor.
* Initializes buffers and error message text. It does not load any hardware
* devices at this point.
*/
CMMCore::CMMCore() :
logManager_(new mm::LogManager()),
appLogger_(logManager_->NewLogger("App")),
coreLogger_(logManager_->NewLogger("Core")),
everSnapped_(false),
pollingIntervalMs_(10),
timeoutMs_(5000),
autoShutter_(true),
callback_(0),
configGroups_(0),
properties_(0),
externalCallback_(0),
pixelSizeGroup_(0),
cbuf_(0),
pluginManager_(new CPluginManager()),
deviceManager_(new mm::DeviceManager()),
pPostedErrorsLock_(NULL)
{
configGroups_ = new ConfigGroupCollection();
pixelSizeGroup_ = new PixelSizeConfigGroup();
pPostedErrorsLock_ = new MMThreadLock();
InitializeErrorMessages();
callback_ = new CoreCallback(this);
const unsigned seqBufMegabytes = (sizeof(void*) > 4) ? 250 : 25;
cbuf_ = new CircularBuffer(seqBufMegabytes);
CreateCoreProperties();
}
/**
* Destructor.
* Cleans-up and unloads all devices.
*/
CMMCore::~CMMCore()
{
try
{
// TODO We should attempt to continue cleanup beyond the first device
// that throws an error.
reset();
}
catch (...)
{
LOG_ERROR(coreLogger_) << "Exception caught in CMMCore destructor.";
}
delete callback_;
delete configGroups_;
delete properties_;
delete cbuf_;
delete pixelSizeGroup_;
delete pPostedErrorsLock_;
LOG_INFO(coreLogger_) << "Core session ended";
}
/**
* Set the primary Core log file.
*
* @param filename The log filename. If empty or null, the primary log file is
* disabled.
*/
void CMMCore::setPrimaryLogFile(const char* filename, bool truncate) throw (CMMError)
{
std::string filenameStr;
if (filename)
filenameStr = filename;
logManager_->SetPrimaryLogFilename(filenameStr, truncate);
}
/**
* Return the name of the primary Core log file.
*/
std::string CMMCore::getPrimaryLogFile() const
{
return logManager_->GetPrimaryLogFilename();
}
/**
* Record text message in the log file.
*/
void CMMCore::logMessage(const char* msg)
{
appLogger_(mm::logging::LogLevelInfo, msg);
}
/**
* Record text message in the log file.
*/
void CMMCore::logMessage(const char* msg, bool debugOnly)
{
appLogger_(debugOnly ? mm::logging::LogLevelDebug :
mm::logging::LogLevelInfo, msg);
}
/**
* Enable or disable logging of debug messages.
* @param enable if set to true, debug messages will be recorded in the log file
*/
void CMMCore::enableDebugLog(bool enable)
{
logManager_->SetPrimaryLogLevel(enable ? mm::logging::LogLevelTrace :
mm::logging::LogLevelInfo);
}
bool CMMCore::debugLogEnabled()
{
return (logManager_->GetPrimaryLogLevel() < mm::logging::LogLevelInfo);
}
/**
* Enables or disables log message display on the standard console.
* @param enable if set to true, log file messages will be echoed on the stderr.
*/
void CMMCore::enableStderrLog(bool enable)
{
logManager_->SetUseStdErr(enable);
}
bool CMMCore::stderrLogEnabled()
{
return logManager_->IsUsingStdErr();
}
/**
* Start capturing logging output into an additional file.
*
* @param filename The filename to which the log will be captured
* @param enableDebug Whether to include debug logging (regardless of whether
* debug logging is enabled for the primary log).
* @param truncate If false, append to the file.
* @param synchronous If true, enable synchronous logging for this file
* (logging calls will not return until the output is written to the file,
* facilitating the debugging of crashes in some cases, but with a performance
* cost).
* @returns A handle required when calling stopSecondaryLogFile().
*/
int CMMCore::startSecondaryLogFile(const char* filename, bool enableDebug,
bool truncate, bool synchronous) throw (CMMError)
{
if (!filename)
throw CMMError("Filename is null");
using namespace mm::logging;
typedef mm::LogManager::LogFileHandle LogFileHandle;
LogFileHandle handle = logManager_->AddSecondaryLogFile(
(enableDebug ? LogLevelTrace : LogLevelInfo),
filename, truncate,
(synchronous ? SinkModeSynchronous : SinkModeAsynchronous));
return static_cast<int>(handle);
}
/**
* Stop capturing logging output into an additional file.
*
* @param handle The secondary log handle returned by startSecondaryLogFile().
*/
void CMMCore::stopSecondaryLogFile(int handle) throw (CMMError)
{
typedef mm::LogManager::LogFileHandle LogFileHandle;
LogFileHandle h = static_cast<LogFileHandle>(handle);
logManager_->RemoveSecondaryLogFile(h);
}
/*!
Displays current user name.
*/
string CMMCore::getUserId() const
{
char buf[8192];
#ifndef _WINDOWS
struct passwd* ppw = getpwuid(geteuid());
strcpy( buf, ppw->pw_name);
#else
DWORD bufCharCount = 8192;
if( !GetUserName( buf, &bufCharCount ) )
buf[0] = 0;
#endif
return string(buf);
}
/**
* return current computer name.
*/
string CMMCore::getHostName() const
{
char buf[8192];
#ifndef _WINDOWS
gethostname(buf, 8192);
#else
DWORD bufCharCount = 8192;
if( !GetComputerName( buf, &bufCharCount ) )
buf[0] = 0;
#endif
return string(buf);
}
/**
* Displays core version.
*/
string CMMCore::getVersionInfo() const
{
ostringstream txt;
string debug;
txt << "MMCore version " << MMCore_versionMajor << "." << MMCore_versionMinor << "." << MMCore_versionPatch;
#ifdef _DEBUG
txt << " (debug)";
#endif
return txt.str();
}
/**
* Get available devices from the specified device library.
*/
std::vector<std::string>
CMMCore::getAvailableDevices(const char* moduleName) throw (CMMError)
{
boost::shared_ptr<LoadedDeviceAdapter> module =
pluginManager_->GetDeviceAdapter(moduleName);
return module->GetAvailableDeviceNames();
}
/**
* Get descriptions for available devices from the specified library.
*/
std::vector<std::string>
CMMCore::getAvailableDeviceDescriptions(const char* moduleName) throw (CMMError)
{
// XXX It is a little silly that we return the list of descriptions, rather
// than provide access to the description of each device.
boost::shared_ptr<LoadedDeviceAdapter> module =
pluginManager_->GetDeviceAdapter(moduleName);
std::vector<std::string> names = module->GetAvailableDeviceNames();
std::vector<std::string> descriptions;
descriptions.reserve(names.size());
for (std::vector<std::string>::const_iterator
it = names.begin(), end = names.end(); it != end; ++it)
{
descriptions.push_back(module->GetDeviceDescription(*it));
}
return descriptions;
}
/**
* Get type information for available devices from the specified library.
*/
std::vector<long>
CMMCore::getAvailableDeviceTypes(const char* moduleName) throw (CMMError)
{
// XXX It is a little silly that we return the list of types, rather than
// provide access to the type of each device.
boost::shared_ptr<LoadedDeviceAdapter> module =
pluginManager_->GetDeviceAdapter(moduleName);
std::vector<std::string> names = module->GetAvailableDeviceNames();
std::vector<long> types;
types.reserve(names.size());
for (std::vector<std::string>::const_iterator
it = names.begin(), end = names.end(); it != end; ++it)
{
MM::DeviceType devType = module->GetAdvertisedDeviceType(*it);
types.push_back(static_cast<long>(devType));
}
return types;
}
/**
* Returns the module and device interface versions.
*/
string CMMCore::getAPIVersionInfo() const
{
ostringstream txt;
txt << "Device API version " << DEVICE_INTERFACE_VERSION << ", " << "Module API version " << MODULE_INTERFACE_VERSION;
return txt.str();
}
/**
* Returns the entire system state, i.e. the collection of all property values from all devices.
* @return Configuration object containing a collection of device-property-value triplets
*/
Configuration CMMCore::getSystemState()
{
Configuration config;
vector<string> devices = deviceManager_->GetDeviceList();
for (vector<string>::const_iterator i = devices.begin(), end = devices.end(); i != end; ++i)
{
boost::shared_ptr<DeviceInstance> pDev = deviceManager_->GetDevice(*i);
mm::DeviceModuleLockGuard guard(pDev);
std::vector<std::string> propertyNames = pDev->GetPropertyNames();
for (std::vector<std::string>::const_iterator it = propertyNames.begin(), end = propertyNames.end();
it != end; ++it)
{
std::string val;
try
{
val = pDev->GetProperty(*it);
}
catch (const CMMError&)
{
// XXX BUG This should not be ignored, but the interface does not
// allow throwing from this function. Keeping old behavior for now.
}
bool readOnly = false;
try
{
readOnly = pDev->GetPropertyReadOnly(it->c_str());
}
catch (const CMMError&)
{
// XXX BUG This should not be ignored, but the interface does not
// allow throwing from this function. Keeping old behavior for now.
}
config.addSetting(PropertySetting(i->c_str(), it->c_str(), val.c_str(), readOnly));
}
}
// add core properties
vector<string> coreProps = properties_->GetNames();
for (unsigned i=0; i < coreProps.size(); i++)
{
string name = coreProps[i];
string val = properties_->Get(name.c_str());
config.addSetting(PropertySetting(MM::g_Keyword_CoreDevice, name.c_str(), val.c_str(), properties_->IsReadOnly(name.c_str())));
}
return config;
}
/**
* Returns the entire system state, i.e. the collection of all property values from all devices.
* This method will return cached values instead of querying each device
* @return Configuration object containing a collection of device-property-value triplets
*/
Configuration CMMCore::getSystemStateCache() const
{
MMThreadGuard scg(stateCacheLock_);
return stateCache_;
}
/**
* Returns a partial state of the system, only for devices included in the
* specified configuration.
*/
Configuration CMMCore::getConfigState(const char* group, const char* config) throw (CMMError)
{
Configuration cfgData = getConfigData(group, config);
Configuration state;
for (size_t i=0; i < cfgData.size(); i++)
{
PropertySetting cs = cfgData.getSetting(i); // config setting
string value = getProperty(cs.getDeviceLabel().c_str(), cs.getPropertyName().c_str());
PropertySetting ss(cs.getDeviceLabel().c_str(), cs.getPropertyName().c_str(), value.c_str()); // state setting
state.addSetting(ss);
}
return state;
}
/**
* Returns the partial state of the system, only for the devices included in the
* specified group. It will create a union of all devices referenced in a group.
*/
Configuration CMMCore::getConfigGroupState(const char* group) throw (CMMError)
{
return getConfigGroupState(group, false);
}
/**
* Returns the partial state of the system cache, only for the devices included in the
* specified group. It will create a union of all devices referenced in a group.
*/
Configuration CMMCore::getConfigGroupStateFromCache(const char* group) throw (CMMError)
{
return getConfigGroupState(group, true);
}
/**
* Returns the partial state of the system, only for the devices included in the
* specified group. It will create a union of all devices referenced in a group.
*/
Configuration CMMCore::getConfigGroupState(const char* group, bool fromCache) throw (CMMError)
{
CheckConfigGroupName(group);
std::vector<std::string> allPresets =
configGroups_->GetAvailableConfigs(group);
Configuration state;
// Loop over every property that appears in every preset, and collect the
// value (from cache or from devices).
for (std::vector<std::string>::const_iterator
it = allPresets.begin(), end = allPresets.end(); it != end; ++it)
{
Configuration preset = getConfigData(group, it->c_str());
for (size_t i = 0; i < preset.size(); i++)
{
PropertySetting cs = preset.getSetting(i);
std::string deviceLabel = cs.getDeviceLabel();
std::string propertyName = cs.getPropertyName();
// Skip properties that we have already added.
if (!state.isPropertyIncluded(deviceLabel.c_str(),
propertyName.c_str()))
{
std::string value;
if (fromCache)
{
value = getPropertyFromCache(deviceLabel.c_str(),
propertyName.c_str());
}
else
{
value = getProperty(deviceLabel.c_str(),
propertyName.c_str());
}
PropertySetting ss(deviceLabel.c_str(), propertyName.c_str(),
value.c_str());
state.addSetting(ss);
}
}
}
return state;
}
/**
* Sets all properties contained in the Configuration object.
* The procedure will attempt to set each property it encounters, but won't stop
* if any of the properties fail or if the requested device is not present. It will
* just quietly continue.
*
* @param conf the configuration object representing the desired system state
*/
void CMMCore::setSystemState(const Configuration& conf)
{
for (unsigned i=0; i<conf.size(); i++)
{
PropertySetting s = conf.getSetting(i);
if (!s.getReadOnly())
{
try
{
setProperty(s.getDeviceLabel().c_str(), s.getPropertyName().c_str(), s.getPropertyValue().c_str());
}
catch (CMMError&)
{
// Do not give up yet.
}
}
}
// TODO Should throw if any of the property setting failed.
updateSystemStateCache();
}
/**
* Return the current device adapter search paths.
*/
std::vector<std::string> CMMCore::getDeviceAdapterSearchPaths()
{
return pluginManager_->GetSearchPaths();
}
/**
* Set the device adapter search paths.
*
* Upon subsequent attempts to load device adapters, these paths (and only
* these paths) will be searched. Calling this function has no effect on device
* adapters that have already been loaded.
*
* If you want to simply add to the list of paths, you must first retrieve the
* current paths by calling getDeviceAdapterSearchPaths().
*
* @param paths the device adapter search paths
*/
void CMMCore::setDeviceAdapterSearchPaths(const std::vector<std::string>& paths)
{
pluginManager_->SetSearchPaths(paths.begin(), paths.end());
}
/**
* Return the names of discoverable device adapters.
*
* Note that this list is constructed based on filename matching in the current
* search paths. This method does not check whether the files are valid and
* compatible device adapters.
*/
std::vector<std::string> CMMCore::getDeviceAdapterNames() throw (CMMError)
{
return pluginManager_->GetAvailableDeviceAdapters();
}
/**
* Add a list of paths to the legacy device adapter search path list.
*
* Do not use in new code. This adds to a global (static) fallback list that is
* only searched when a device adapter is not located in any of the directories
* set by setDeviceAdapterSearchPaths(). The list is initially empty.
*
* @deprecated Use the non-static setDeviceAdapterSearchPaths() instead.
*
* @param path a list of search paths in a single string
*/
void CMMCore::addSearchPath(const char *path)
{
if (!path)
return;
CPluginManager::AddLegacyFallbackSearchPath(path);
}
/**
* Returns a list of library names available in the search path.
*
* Do not use in new code. For backward compatibility, this method returns the
* list of device adapters available in the default search path(s) and the
* paths added via addSearchPath(). For obvious reasons (since this method is
* static), it will not return device adapters found in the search paths set by
* setDeviceAdapterSearchPaths(). Thus, this method will only work as expected
* when called from legacy code that does not make use of
* setDeviceAdapterSearchPaths().
*
* @deprecated Use the non-static getDeviceAdapterNames() instead.
*/
vector<string> CMMCore::getDeviceLibraries() throw (CMMError)
{
return CPluginManager::GetModulesInLegacyFallbackSearchPaths();
}
/**
* Loads a device from the plugin library.
* @param label assigned name for the device during the core session
* @param moduleName the name of the device adapter module (short name, not full file name)
* @param deviceName the name of the device. The name must correspond to one of the names recognized
* by the specific plugin library.
*/
void CMMCore::loadDevice(const char* label, const char* moduleName, const char* deviceName) throw (CMMError)
{
CheckDeviceLabel(label);
if (!moduleName)
throw CMMError("Null device adapter name");
if (!deviceName)
throw CMMError("Null device name");
// Logger for logging from device adapter code
mm::logging::Logger deviceLogger =
logManager_->NewLogger("dev:" + std::string(label));
// Logger for logging related to the device, by us the Core
mm::logging::Logger coreLogger =
logManager_->NewLogger("Core:dev:" + std::string(label));
LOG_DEBUG(coreLogger_) << "Will load device " << deviceName <<
" from " << moduleName;
try
{
boost::shared_ptr<LoadedDeviceAdapter> module =
pluginManager_->GetDeviceAdapter(moduleName);
boost::shared_ptr<DeviceInstance> pDevice =
deviceManager_->LoadDevice(module, deviceName, label, this,
deviceLogger, coreLogger);
pDevice->SetCallback(callback_);
}
catch (const CMMError& e)
{
throw CMMError("Failed to load device " + ToQuotedString(deviceName) +
" from adapter module " + ToQuotedString(moduleName),
e);
}
LOG_INFO(coreLogger_) << "Did load device " << deviceName <<
" from " << moduleName << "; label = " << label;
}
void CMMCore::assignDefaultRole(boost::shared_ptr<DeviceInstance> pDevice)
{
// default special roles for particular devices
// The roles which are assigned at the load time will make sense for a simple
// configuration. More complicated configurations will typically override default settings.
mm::DeviceModuleLockGuard guard(pDevice);
const std::string label(pDevice->GetLabel());
switch(pDevice->GetType())
{
case MM::CameraDevice:
currentCameraDevice_ =
boost::static_pointer_cast<CameraInstance>(pDevice);
LOG_INFO(coreLogger_) << "Default camera set to " << label;
break;
case MM::ShutterDevice:
currentShutterDevice_ =
boost::static_pointer_cast<ShutterInstance>(pDevice);
LOG_INFO(coreLogger_) << "Default shutter set to " << label;
break;
case MM::XYStageDevice:
currentXYStageDevice_ =
boost::static_pointer_cast<XYStageInstance>(pDevice);
LOG_INFO(coreLogger_) << "Default xy stage set to " << label;
break;
case MM::AutoFocusDevice:
currentAutofocusDevice_ =
boost::static_pointer_cast<AutoFocusInstance>(pDevice);
LOG_INFO(coreLogger_) << "Default autofocus set to " << label;
break;
case MM::SLMDevice:
currentSLMDevice_ =
boost::static_pointer_cast<SLMInstance>(pDevice);
LOG_INFO(coreLogger_) << "Default SLM set to " << label;
break;
case MM::GalvoDevice:
currentGalvoDevice_ =
boost::static_pointer_cast<GalvoInstance>(pDevice);
LOG_INFO(coreLogger_) << "Default galvo set to " << label;
break;
default:
// no action on unrecognized device
break;
}
}
/**
* Unloads the device from the core and adjusts all configuration data.
*/
void CMMCore::unloadDevice(const char* label///< the name of the device to unload
) throw (CMMError)
{
boost::shared_ptr<DeviceInstance> pDevice = deviceManager_->GetDevice(label);
try {
mm::DeviceModuleLockGuard guard(pDevice);
LOG_DEBUG(coreLogger_) << "Will unload device " << label;
deviceManager_->UnloadDevice(pDevice);
LOG_DEBUG(coreLogger_) << "Did unload device " << label;
}
catch (CMMError& err) {
logError("MMCore::unloadDevice", err.getMsg().c_str());
throw;
}
}
/**
* Unloads all devices from the core and resets all configuration data.
*/
void CMMCore::unloadAllDevices() throw (CMMError)
{
try {
configGroups_->Clear();
//selected channel group is no longer valid
//channelGroup_ = "":
// clear pixel size configurations
if (!pixelSizeGroup_->IsEmpty())
{
std::vector<std::string> pixelSizes = pixelSizeGroup_->GetAvailable();
for (std::vector<std::string>::iterator it = pixelSizes.begin();
it != pixelSizes.end(); it++)
{
pixelSizeGroup_->Delete((*it).c_str());
}
}
LOG_DEBUG(coreLogger_) << "Will unload all devices";
deviceManager_->UnloadAllDevices();
LOG_INFO(coreLogger_) << "Did unload all devices";
properties_->Refresh();
// TODO
// clear equipment definitions ???
}
catch (CMMError& err) {
logError("MMCore::unloadAllDevices", err.getMsg().c_str());
throw;
}
}
/**
* Unloads all devices from the core, clears all configuration data and property blocks.
*/
void CMMCore::reset() throw (CMMError)
{
try
{
// before unloading everything try to apply shutdown configuration
if (isConfigDefined(MM::g_CFGGroup_System, MM::g_CFGGroup_System_Shutdown))
this->setConfig(MM::g_CFGGroup_System, MM::g_CFGGroup_System_Shutdown);
}
catch(...)
{
logError("MMCore::reset", "problem setting System Shutdown configuration");
}
// of course one reason to reset is that some device is not configured correctly,
// so we need to handle any exception thrown from here
try
{
waitForSystem();
}
catch (CMMError& ) {}
// unload devices
unloadAllDevices();
// clear property blocks
CPropBlockMap::const_iterator i;
for (i = propBlocks_.begin(); i != propBlocks_.end(); i++)
delete i->second;
propBlocks_.clear();
properties_->Refresh();
LOG_INFO(coreLogger_) << "System reset";
}
/**
* Calls Initialize() method for each loaded device.
* This method also initialized allowed values for core properties, based
* on the collection of loaded devices.
*/
void CMMCore::initializeAllDevices() throw (CMMError)
{
vector<string> devices = deviceManager_->GetDeviceList();
LOG_INFO(coreLogger_) << "Will initialize " << devices.size() << " devices";
for (size_t i=0; i<devices.size(); i++)
{
boost::shared_ptr<DeviceInstance> pDevice;
try {
pDevice = deviceManager_->GetDevice(devices[i]);
}
catch (CMMError& err) {
logError(devices[i].c_str(), err.getMsg().c_str());
throw;
}
mm::DeviceModuleLockGuard guard(pDevice);
LOG_INFO(coreLogger_) << "Will initialize device " << devices[i];
pDevice->Initialize();
LOG_INFO(coreLogger_) << "Did initialize device " << devices[i];
assignDefaultRole(pDevice);
}
LOG_INFO(coreLogger_) << "Finished initializing " << devices.size() << " devices";
updateCoreProperties();
}
void CMMCore::updateCoreProperties() throw (CMMError)
{
updateCoreProperty(MM::g_Keyword_CoreCamera, MM::CameraDevice);
updateCoreProperty(MM::g_Keyword_CoreShutter, MM::ShutterDevice);
updateCoreProperty(MM::g_Keyword_CoreFocus,MM::StageDevice);
updateCoreProperty(MM::g_Keyword_CoreXYStage,MM::XYStageDevice);
updateCoreProperty(MM::g_Keyword_CoreAutoFocus,MM::AutoFocusDevice);
updateCoreProperty(MM::g_Keyword_CoreImageProcessor,MM::ImageProcessorDevice);
updateCoreProperty(MM::g_Keyword_CoreSLM,MM::SLMDevice);
updateCoreProperty(MM::g_Keyword_CoreGalvo,MM::GalvoDevice);
properties_->Refresh();
}
void CMMCore::updateCoreProperty(const char* propName, MM::DeviceType devType) throw (CMMError)
{
CheckPropertyName(propName);
vector<string> devices = getLoadedDevicesOfType(devType);
devices.push_back(""); // add empty value
properties_->ClearAllowedValues(propName);
for (size_t i=0; i<devices.size(); i++)
properties_->AddAllowedValue(propName, devices[i].c_str());
}
/**
* Initializes specific device.
*
* @param label the device label
*/
void CMMCore::initializeDevice(const char* label ///< the device to initialize
) throw (CMMError)
{
boost::shared_ptr<DeviceInstance> pDevice = deviceManager_->GetDevice(label);
mm::DeviceModuleLockGuard guard(pDevice);
LOG_INFO(coreLogger_) << "Will initialize device " << label;
pDevice->Initialize();
LOG_INFO(coreLogger_) << "Did initialize device " << label;
updateCoreProperties();
}
/**
* Updates the state of the entire hardware.
*/
void CMMCore::updateSystemStateCache()
{
LOG_DEBUG(coreLogger_) << "Will update system state cache";
Configuration wk = getSystemState();
{
MMThreadGuard scg(stateCacheLock_);
stateCache_ = wk;
}
LOG_INFO(coreLogger_) << "Did update system state cache";
}
/**
* Returns device type.
*/
MM::DeviceType CMMCore::getDeviceType(const char* label) throw (CMMError)
{
if (IsCoreDeviceLabel(label))
return MM::CoreDevice;
boost::shared_ptr<DeviceInstance> pDevice = deviceManager_->GetDevice(label);
mm::DeviceModuleLockGuard guard(pDevice);
return pDevice->GetType();
}
/**
* Returns device library (aka module, device adapter) name.
*/
std::string CMMCore::getDeviceLibrary(const char* label) throw (CMMError)
{
if (IsCoreDeviceLabel(label))
return "";
boost::shared_ptr<DeviceInstance> pDevice = deviceManager_->GetDevice(label);
mm::DeviceModuleLockGuard guard(pDevice);
return pDevice->GetAdapterModule()->GetName();
}
/**
* Forcefully unload a library. Experimental. Don't use.
*/
void CMMCore::unloadLibrary(const char* moduleName) throw (CMMError)
{
if (moduleName == 0)
throw CMMError(errorText_[MMERR_NullPointerException], MMERR_NullPointerException);
try {
vector<string> devices = deviceManager_->GetDeviceList();
vector<string>::reverse_iterator it;
for (it=devices.rbegin(); it != devices.rend(); it++)
{
boost::shared_ptr<DeviceInstance> pDev = deviceManager_->GetDevice(*it);
mm::DeviceModuleLockGuard guard(pDev);
if (pDev->GetAdapterModule()->GetName() == moduleName)
{
try {
unloadDevice(pDev->GetLabel().c_str());
} catch (CMMError& /*e*/) {} // ignore error; device may already have been unloaded
}