IDS peak genericC++ v1.11.1
Loading...
Searching...
No Matches
peak_device_manager.hpp
Go to the documentation of this file.
1
10
11#pragma once
12
18#include <peak/generic/peak_t_callback_manager.hpp>
25#include <utility>
26
27
28#include <type_traits>
29#include <unordered_map>
30#include <unordered_set>
31#include <algorithm>
32#include <atomic>
33#include <cstdlib>
34#include <exception>
35#include <functional>
36#include <future>
37#include <iterator>
38#include <memory>
39#include <mutex>
40#include <new>
41#include <utility>
42#include <vector>
43
44
45namespace peak
46{
47
74
75class DeviceManager final
76{
77public:
87
97
99 using SystemFoundCallback = std::function<void(const std::shared_ptr<const core::System>& foundSystem)>;
100
103
105 using InterfaceFoundCallback = std::function<void(const std::shared_ptr<const core::Interface>& foundInterface)>;
106
109
111 using InterfaceLostCallback = std::function<void(const std::string& lostInterfaceKey)>;
112
115
117 using DeviceFoundCallback = std::function<void(const std::shared_ptr<core::DeviceDescriptor>& foundDevice)>;
118
121
123 using DeviceLostCallback = std::function<void(const std::string& lostDeviceKey)>;
124
127
130 std::function<void(const std::shared_ptr<core::DeviceDescriptor>& disconnectedDevice)>;
131
134
137 std::function<void(const std::shared_ptr<core::DeviceDescriptor>& reconnectedDevice,
138 core::DeviceReconnectInformation reconnectInformation)>;
139
142
144 using DeviceListChangedCallback = std::function<void()>;
145
148
150 using UpdateErrorCallback = std::function<void(const std::string& errorDescription)>;
151
157 static DeviceManager& Instance();
158
174 void AddProducerLibrary(const std::string& ctiPath);
175
195 void AddProducerLibrary(const std::shared_ptr<core::ProducerLibrary>& library);
196
216 const UpdateErrorCallback& errorCallback = UpdateErrorCallback());
217
237
248
263
274
288 void SetDeviceUpdateTimeout(core::Timeout timeout_ms);
289
299 std::vector<std::shared_ptr<const core::System>> Systems() const;
300
310 std::vector<std::shared_ptr<const core::Interface>> Interfaces() const;
311
321 std::vector<std::shared_ptr<core::DeviceDescriptor>> Devices() const;
322
340
353
371
384
402
415
433
446
464
477
493
506
522
535
551
564
565 DeviceManager(const DeviceManager& other) = delete;
566 DeviceManager& operator=(const DeviceManager& other) = delete;
567
568private:
569 friend class Library;
570
571 DeviceManager() = default;
573
574 void GetLostDevicesFromLostInterfaces(
575 const std::vector<std::string>& lostInterfaces, std::vector<std::string>& lostDevices);
576
577 void TriggerSystemFoundCallbacks(const std::shared_ptr<const core::System>& foundSystem) const;
578 void TriggerInterfaceFoundCallbacks(const std::shared_ptr<const core::Interface>& foundInterface) const;
579 void TriggerInterfaceLostCallbacks(const std::string& lostInterfaceKey) const;
580 void TriggerDeviceFoundCallbacks(const std::shared_ptr<core::DeviceDescriptor>& foundDevice) const;
581 void TriggerDeviceLostCallbacks(const std::string& lostDeviceKey) const;
582
583 void AddSystemCallbacks(const std::shared_ptr<core::System>& addSystem);
584 void RemoveSystemCallbacks(const std::shared_ptr<core::System>& removeSystem);
585 void AddInterfaceCallbacks(const std::shared_ptr<core::Interface>& addInterface);
586 void RemoveInterfaceCallbacks(const std::shared_ptr<core::Interface>& removeInterface);
587
588 void CheckDevicesOpened() const;
589
590 std::mutex m_updateMutex;
591 std::atomic<core::Timeout> m_interfaceUpdateTimeout_ms{ 100 };
592 std::atomic<core::Timeout> m_deviceUpdateTimeout_ms{ 300 };
593
594 std::vector<std::string> m_producerLibrariesToAdd;
595
596 std::unordered_map<std::string, std::shared_ptr<core::ProducerLibrary>> m_producerLibraries;
597 std::vector<std::shared_ptr<const core::System>> m_systems;
598 std::vector<std::shared_ptr<const core::Interface>> m_interfaces;
599 std::vector<std::shared_ptr<core::DeviceDescriptor>> m_devices;
600
601 struct SystemCallbackContainer
602 {
603 SystemCallbackContainer(
605 : foundCallbackHandle(foundHandle)
606 , lostCallbackHandle(lostHandle)
607 {}
608 ~SystemCallbackContainer() = default;
609 SystemCallbackContainer(const SystemCallbackContainer&) = delete;
610 SystemCallbackContainer& operator=(const SystemCallbackContainer&) = delete;
611
612 SystemCallbackContainer(SystemCallbackContainer&& a) noexcept
613 {
614 std::lock_guard<std::mutex> lock(a.mutex);
615
616 std::swap(foundCallbackHandle, a.foundCallbackHandle);
617 std::swap(lostCallbackHandle, a.lostCallbackHandle);
618 }
619
620 SystemCallbackContainer& operator=(SystemCallbackContainer&& a) noexcept
621 {
622 std::lock(a.mutex, mutex);
623
624 std::lock_guard<std::mutex> lock1(a.mutex, std::adopt_lock);
625 std::lock_guard<std::mutex> lock2(mutex, std::adopt_lock);
626
627 std::swap(foundCallbackHandle, a.foundCallbackHandle);
628 std::swap(lostCallbackHandle, a.lostCallbackHandle);
629
630 return *this;
631 }
632
633 mutable std::mutex mutex;
634 core::System::InterfaceFoundCallbackHandle foundCallbackHandle{};
635 InterfaceLostCallbackHandle lostCallbackHandle{};
636
637 std::vector<std::shared_ptr<core::Interface>> foundInterfaces;
638 std::vector<std::string> lostInterfaces;
639
640 // TL reports interface lost only with interface id part
641 // in order to get the full interface key we need to map it
642 std::unordered_map<std::string, std::string> interfaceIdKeyMap;
643 };
644
645 struct InterfaceCallbackContainer
646 {
647 InterfaceCallbackContainer(DeviceFoundCallbackHandle foundHandle, DeviceLostCallbackHandle lostHandle,
648 DeviceDisconnectedCallbackHandle disconnectedHandle, DeviceReconnectedCallbackHandle reconnectedHandle,
649 DeviceListChangedCallbackHandle listChangedHandle)
650 : foundCallbackHandle(foundHandle)
651 , lostCallbackHandle(lostHandle)
652 , disconnectedCallbackHandle(disconnectedHandle)
653 , reconnectedCallbackHandle(reconnectedHandle)
654 , deviceListChangedCallbackHandle(listChangedHandle)
655 {}
656
657 ~InterfaceCallbackContainer() = default;
658 InterfaceCallbackContainer(const InterfaceCallbackContainer&) = delete;
659 InterfaceCallbackContainer& operator=(const InterfaceCallbackContainer&) = delete;
660
661 InterfaceCallbackContainer(InterfaceCallbackContainer&& a) noexcept
662 {
663 std::lock_guard<std::mutex> lock(a.mutex);
664
665 std::swap(foundCallbackHandle, a.foundCallbackHandle);
666 std::swap(lostCallbackHandle, a.lostCallbackHandle);
667 std::swap(disconnectedCallbackHandle, a.disconnectedCallbackHandle);
668 std::swap(reconnectedCallbackHandle, a.reconnectedCallbackHandle);
669 std::swap(deviceListChangedCallbackHandle, a.deviceListChangedCallbackHandle);
670 }
671
672 InterfaceCallbackContainer& operator=(InterfaceCallbackContainer&& a) noexcept
673 {
674 std::lock(a.mutex, mutex);
675
676 std::lock_guard<std::mutex> lock1(a.mutex, std::adopt_lock);
677 std::lock_guard<std::mutex> lock2(mutex, std::adopt_lock);
678
679 std::swap(foundCallbackHandle, a.foundCallbackHandle);
680 std::swap(lostCallbackHandle, a.lostCallbackHandle);
681 std::swap(disconnectedCallbackHandle, a.disconnectedCallbackHandle);
682 std::swap(reconnectedCallbackHandle, a.reconnectedCallbackHandle);
683 std::swap(deviceListChangedCallbackHandle, a.deviceListChangedCallbackHandle);
684
685 return *this;
686 }
687
688 mutable std::mutex mutex;
689 DeviceFoundCallbackHandle foundCallbackHandle{};
690 DeviceLostCallbackHandle lostCallbackHandle{};
691 DeviceDisconnectedCallbackHandle disconnectedCallbackHandle{};
692 DeviceReconnectedCallbackHandle reconnectedCallbackHandle{};
693 DeviceListChangedCallbackHandle deviceListChangedCallbackHandle{};
694
695 std::vector<std::shared_ptr<core::DeviceDescriptor>> foundDevices;
696 std::vector<std::string> lostDevices;
697
698 // TL reports device lost only with device id part
699 // in order to get the full device key we need to map it
700 std::unordered_map<std::string, std::string> deviceIdKeyMap;
701 };
702
703 mutable std::mutex m_callbackContainerMutex;
704 std::unordered_map<std::string, SystemCallbackContainer> m_systemCallbackContainers;
705 std::unordered_map<std::string, InterfaceCallbackContainer> m_interfaceCallbackContainers;
706
707 struct OpenedDevice
708 {
709 std::weak_ptr<core::Device> device{};
710 std::string displayName;
711 };
712 std::vector<OpenedDevice> m_openedDevices;
713
714 core::TTriggerCallbackManager<SystemFoundCallbackHandle, SystemFoundCallback> m_systemFoundCallbackManager;
715 core::TTriggerCallbackManager<InterfaceFoundCallbackHandle, InterfaceFoundCallback> m_interfaceFoundCallbackManager;
716 core::TTriggerCallbackManager<InterfaceLostCallbackHandle, InterfaceLostCallback> m_interfaceLostCallbackManager;
717 core::TTriggerCallbackManager<DeviceFoundCallbackHandle, DeviceFoundCallback> m_deviceFoundCallbackManager;
718 core::TTriggerCallbackManager<DeviceLostCallbackHandle, DeviceLostCallback> m_deviceLostCallbackManager;
719 core::TTriggerCallbackManager<DeviceDisconnectedCallbackHandle, DeviceDisconnectedCallback>
720 m_deviceDisconnectedCallbackManager;
721 core::TTriggerCallbackManager<DeviceReconnectedCallbackHandle, DeviceReconnectedCallback>
722 m_deviceReconnectedCallbackManager;
723 core::TTriggerCallbackManager<DeviceListChangedCallbackHandle, DeviceListChangedCallback>
724 m_deviceListChangedCallbackManager;
725
726 std::mutex m_producerLibrariesToAddMutex;
727 mutable std::mutex m_systemsMutex;
728 mutable std::recursive_mutex m_interfacesMutex;
729 mutable std::recursive_mutex m_devicesMutex;
730 mutable std::mutex m_openedDevicesMutex;
731
732#ifndef _MSC_VER
733 template <typename T,
734 typename std::enable_if<(noexcept(std::declval<T>()())
735 || (std::is_pointer<typename std::decay<T>::type>::value && __cplusplus < 201703L)
736 // NOTE pre c++17 there is no way to check whether a function pointer is noexcept
737 )
738 && std::is_same<void, decltype(std::declval<T>()())>::value && std::is_move_constructible<T>::value
739 && std::is_nothrow_move_constructible<T>::value,
740 int>::type = 0>
741#else
742 template <typename T>
743#endif
744 class RAIIGuard
745 {
746 T m_fun;
747
748 public:
749 explicit RAIIGuard(T&& fun) noexcept
750 : m_fun(std::forward<T>(fun))
751 {}
752 RAIIGuard(RAIIGuard const&) = delete;
753 RAIIGuard(RAIIGuard&& other) noexcept
754 : m_fun(std::move(other.m_fun))
755 {}
756 ~RAIIGuard() noexcept
757 {
758 m_fun();
759 }
760 };
761 template <typename T>
762 static RAIIGuard<T> makeRAIIGuard(T&& fun) noexcept
763 {
764 return { std::forward<T>(fun) };
765 }
766
767 template <typename T = DeviceManager>
768 class LifetimeTracker
769 {
770 public:
771 static void Create();
772 static void Destroy();
773 static T& Instance();
774
775 private:
776 static T* m_instance;
777 static std::mutex m_mtx;
778 static size_t m_initializedCount;
779 };
780};
781
782} /* namespace peak */
783
784/* Implementation */
785namespace peak
786{
787
788template <typename T>
789T* DeviceManager::LifetimeTracker<T>::m_instance = {};
790
791template <typename T>
792std::mutex DeviceManager::LifetimeTracker<T>::m_mtx = {};
793
794template <typename T>
795size_t DeviceManager::LifetimeTracker<T>::m_initializedCount = {};
796
797template <typename T>
798void DeviceManager::LifetimeTracker<T>::Create()
799{
800 std::lock_guard<decltype(m_mtx)> lock{ m_mtx };
801
802 if (!m_instance)
803 {
804 m_instance = new T{};
805 }
806
807 m_initializedCount++;
808}
809
810template <typename T>
811void DeviceManager::LifetimeTracker<T>::Destroy()
812{
813 std::lock_guard<decltype(m_mtx)> lock{ m_mtx };
814
815 if (0 == m_initializedCount)
816 {
817 return;
818 }
819
820 m_initializedCount--;
821
822 if (0 == m_initializedCount)
823 {
824 if (m_instance)
825 {
826 delete m_instance;
827 m_instance = nullptr;
828 }
829 }
830}
831
832template <typename T>
833T& DeviceManager::LifetimeTracker<T>::Instance()
834{
835 if (m_instance == nullptr)
836 {
838 "Library is not initialized. Call peak::Library::Initalize() first!");
839 }
840 return *m_instance;
841}
842
844{
845 return LifetimeTracker<>::Instance();
846}
847
848inline DeviceManager::~DeviceManager()
849{
851}
852
853inline void DeviceManager::AddProducerLibrary(const std::string& ctiPath)
854{
855 std::lock_guard<std::mutex> lock(m_producerLibrariesToAddMutex);
856
857 m_producerLibrariesToAdd.emplace_back(ctiPath);
858}
859
860inline void DeviceManager::AddProducerLibrary(const std::shared_ptr<core::ProducerLibrary>& library)
861{
862 std::lock(m_updateMutex, m_systemsMutex);
863
864 std::lock_guard<std::mutex> lockUpdate(m_updateMutex, std::adopt_lock);
865
866 std::shared_ptr<core::System> newSystem{};
867 {
868 std::lock_guard<std::mutex> lockSystems(m_systemsMutex, std::adopt_lock);
869
870 const auto systemDescriptor = library->System();
871 const auto ctiPath = systemDescriptor->CTIFullPath();
872
873 // Check if system is already added
874 if (m_producerLibraries.count(ctiPath) == 0)
875 {
876 m_producerLibraries.emplace(ctiPath, library);
877
878 newSystem = systemDescriptor->IsOpened() ? systemDescriptor->OpenedSystem() : systemDescriptor->OpenSystem();
879 AddSystemCallbacks(newSystem);
880 m_systems.emplace_back(newSystem);
881 }
882 }
883
884 if (newSystem)
885 {
886 TriggerSystemFoundCallbacks(newSystem);
887 }
888}
889
890inline void DeviceManager::Update(UpdatePolicy updatePolicy /*= UpdatePolicy::ScanEnvironmentForProducerLibraries*/,
891 const UpdateErrorCallback& errorCallback /*= UpdateErrorCallback()*/)
892{
893 std::lock_guard<std::mutex> lockUpdate(m_updateMutex);
894
895 std::vector<std::shared_ptr<core::System>> allFoundSystems;
896 std::vector<std::shared_ptr<core::Interface>> allFoundInterfaces;
897 std::vector<std::string> allLostInterfaces;
898 std::vector<std::shared_ptr<core::DeviceDescriptor>> allFoundDevices;
899 std::vector<std::string> allLostDevices;
900
901 auto interfaceUpdateTimeout_ms = m_interfaceUpdateTimeout_ms.load();
902 auto deviceUpdateTimeout_ms = m_deviceUpdateTimeout_ms.load();
903
904 std::vector<std::string> ctiPaths;
905 // We look for all producer libraries in the current environment if we have to
907 {
909 }
910
911 // We look for the manually added producer libraries
912 {
913 std::lock_guard<std::mutex> lock(m_producerLibrariesToAddMutex);
914
915 ctiPaths.reserve(ctiPaths.size() + m_producerLibrariesToAdd.size());
916 std::move(
917 std::begin(m_producerLibrariesToAdd), std::end(m_producerLibrariesToAdd), std::back_inserter(ctiPaths));
918
919 m_producerLibrariesToAdd.clear();
920 }
921
922 for (const auto& ctiPath : ctiPaths)
923 {
924 if (m_producerLibraries.count(ctiPath) == 0)
925 {
926 try
927 {
928 auto producerLibrary = core::ProducerLibrary::Open(ctiPath);
929 auto system = producerLibrary->System()->OpenSystem();
930
931 AddSystemCallbacks(system);
932
933 m_producerLibraries.emplace(ctiPath, producerLibrary);
934 allFoundSystems.emplace_back(system);
935 }
936 catch (const core::NotAvailableException&)
937 {
938 // TL not available or not supported.
939 continue;
940 }
941 catch (const core::NotInitializedException&)
942 {
943 throw; // if this exception occurs, nothing else will work. so we stop here
944 }
945 catch (const core::Exception& ex)
946 {
947 if (errorCallback)
948 {
949 try
950 {
951 errorCallback("[CTI - " + ctiPath + "]: " + ex.what());
952 }
953 catch (...)
954 {}
955 }
956 }
957 }
958 }
959
960 auto systemUpdateChildren = [&](const std::shared_ptr<core::System>& system) {
961 try
962 {
963 system->UpdateInterfaces(interfaceUpdateTimeout_ms);
964 }
965 catch (const core::Exception& ex)
966 {
967 if (errorCallback)
968 {
969 try
970 {
971 errorCallback("[System - " + system->Key() + "]: " + ex.what());
972 }
973 catch (...)
974 {}
975 }
976 }
977 };
978
979 // We do an update on all available systems
980 constexpr auto launchPolicy = std::launch::async; // switching this to std::launch::deferred makes debugging easier
981
982 std::vector<std::future<void>> systemUpdateChildrenTasks;
983
984 // add already found systems
985 for (const auto& system : m_systems)
986 {
987 systemUpdateChildrenTasks.emplace_back(
988 std::async(launchPolicy, systemUpdateChildren, std::const_pointer_cast<core::System>(system)));
989 }
990
991 // now add newly found systems
992 for (const auto& system : allFoundSystems)
993 {
994 systemUpdateChildrenTasks.emplace_back(std::async(launchPolicy, systemUpdateChildren, system));
995 }
996
997 // wait for tasks to be done
998 systemUpdateChildrenTasks.clear();
999
1000 // copy results to our local lists
1001 for (auto& keyValue : m_systemCallbackContainers)
1002 {
1003 auto& container = keyValue.second;
1004
1005 std::lock_guard<std::mutex> lock(container.mutex);
1006
1007 allFoundInterfaces.reserve(allFoundInterfaces.size() + container.foundInterfaces.size());
1008 for (const auto& foundInterface : container.foundInterfaces)
1009 {
1010 AddInterfaceCallbacks(foundInterface);
1011 allFoundInterfaces.emplace_back(foundInterface);
1012 }
1013 container.foundInterfaces.clear();
1014
1015 allLostInterfaces.reserve(allLostInterfaces.size() + container.lostInterfaces.size());
1016 for (const auto& lostInterface : container.lostInterfaces)
1017 {
1018 auto interfaceIt = std::find_if(std::begin(m_interfaces), std::end(m_interfaces),
1019 [&lostInterface](const auto& intf) { return intf->Key() == lostInterface; });
1020
1021 if (interfaceIt != std::end(m_interfaces))
1022 {
1023 RemoveInterfaceCallbacks(std::const_pointer_cast<core::Interface>(*interfaceIt));
1024 }
1025
1026 allLostInterfaces.emplace_back(lostInterface);
1027 }
1028 container.lostInterfaces.clear();
1029 }
1030
1031 auto interfaceUpdateChildren = [&deviceUpdateTimeout_ms, &errorCallback](
1032 const std::shared_ptr<core::Interface>& iface) {
1033 try
1034 {
1035 iface->UpdateDevices(deviceUpdateTimeout_ms);
1036 }
1037 catch (const core::Exception& ex)
1038 {
1039 if (errorCallback)
1040 {
1041 try
1042 {
1043 errorCallback("[Interface - " + iface->Key() + "]: " + ex.what());
1044 }
1045 catch (...)
1046 {}
1047 }
1048 }
1049 };
1050
1051 // We do an update on all available interfaces
1052 std::vector<std::future<void>> interfaceUpdateChildrenTasks;
1053
1054 // add already found interfaces
1055 for (const auto& iface : m_interfaces)
1056 {
1057 interfaceUpdateChildrenTasks.emplace_back(
1058 std::async(launchPolicy, interfaceUpdateChildren, std::const_pointer_cast<core::Interface>(iface)));
1059 }
1060
1061 // add newly found interfaces
1062 for (const auto& iface : allFoundInterfaces)
1063 {
1064 interfaceUpdateChildrenTasks.emplace_back(std::async(launchPolicy, interfaceUpdateChildren, iface));
1065 }
1066
1067 // wait for tasks to be done
1068 interfaceUpdateChildrenTasks.clear();
1069
1070 // copy results to our local lists
1071 for (auto& keyValue : m_interfaceCallbackContainers)
1072 {
1073 auto& container = keyValue.second;
1074 std::lock_guard<std::mutex> lock(container.mutex);
1075
1076 decltype(container.foundDevices) foundDevices;
1077 std::swap(container.foundDevices, foundDevices);
1078 allFoundDevices.reserve(allFoundDevices.size() + foundDevices.size());
1079 std::move(std::begin(foundDevices), std::end(foundDevices), std::back_inserter(allFoundDevices));
1080
1081 decltype(container.lostDevices) lostDevices;
1082 std::swap(container.lostDevices, lostDevices);
1083 allLostDevices.reserve(allLostDevices.size() + lostDevices.size());
1084 std::move(std::begin(lostDevices), std::end(lostDevices), std::back_inserter(allLostDevices));
1085 }
1086
1087 // We apply the update changes to our internal lists
1088 {
1089 std::lock(m_systemsMutex, m_interfacesMutex, m_devicesMutex);
1090
1091 std::lock_guard<std::mutex> lockSystems(m_systemsMutex, std::adopt_lock);
1092 std::lock_guard<std::recursive_mutex> lockInterfaces(m_interfacesMutex, std::adopt_lock);
1093 std::lock_guard<std::recursive_mutex> lockDevices(m_devicesMutex, std::adopt_lock);
1094
1095 m_systems.reserve(m_systems.size() + allFoundSystems.size());
1096 std::copy(std::begin(allFoundSystems), std::end(allFoundSystems), std::back_inserter(m_systems));
1097
1098 for (const auto& lostInterfaceKey : allLostInterfaces)
1099 {
1100 m_interfaces.erase(std::remove_if(std::begin(m_interfaces), std::end(m_interfaces),
1101 [&lostInterfaceKey](const auto& interfaceToCheck) {
1102 return interfaceToCheck->Key() == lostInterfaceKey;
1103 }),
1104 std::end(m_interfaces));
1105 }
1106 m_interfaces.reserve(m_interfaces.size() + allFoundInterfaces.size());
1107 std::copy(std::begin(allFoundInterfaces), std::end(allFoundInterfaces), std::back_inserter(m_interfaces));
1108
1109 for (const auto& lostDeviceKey : allLostDevices)
1110 {
1111 m_devices.erase(
1112 std::remove_if(std::begin(m_devices), std::end(m_devices),
1113 [&lostDeviceKey](const auto& deviceToCheck) { return deviceToCheck->Key() == lostDeviceKey; }),
1114 std::end(m_devices));
1115 }
1116 m_devices.reserve(m_devices.size() + allFoundDevices.size());
1117 std::copy(std::begin(allFoundDevices), std::end(allFoundDevices), std::back_inserter(m_devices));
1118 }
1119
1120 // We trigger all callbacks
1121 for (const auto& foundSystem : allFoundSystems)
1122 {
1123 TriggerSystemFoundCallbacks(foundSystem);
1124 }
1125
1126 for (const auto& foundInterface : allFoundInterfaces)
1127 {
1128 TriggerInterfaceFoundCallbacks(foundInterface);
1129 }
1130
1131 for (const auto& lostInterfaceKey : allLostInterfaces)
1132 {
1133 TriggerInterfaceLostCallbacks(lostInterfaceKey);
1134 }
1135
1136 for (const auto& foundDevice : allFoundDevices)
1137 {
1138 TriggerDeviceFoundCallbacks(foundDevice);
1139 }
1140
1141 GetLostDevicesFromLostInterfaces(allLostInterfaces, allLostDevices);
1142 for (const auto& lostDeviceKey : allLostDevices)
1143 {
1144 TriggerDeviceLostCallbacks(lostDeviceKey);
1145 }
1146}
1147
1148inline void DeviceManager::Reset(ResetPolicy resetPolicy)
1149{
1150 std::lock_guard<std::mutex> lockUpdate(m_updateMutex);
1151
1152 if (resetPolicy == ResetPolicy::ErrorOnOpenDevices)
1153 {
1154 // check if any devices are running
1155 CheckDevicesOpened();
1156 }
1157
1158 {
1159 std::lock(m_systemsMutex, m_interfacesMutex, m_devicesMutex);
1160
1161 std::lock_guard<std::mutex> lockSystem(m_systemsMutex, std::adopt_lock);
1162 std::lock_guard<std::recursive_mutex> lockInterfaces(m_interfacesMutex, std::adopt_lock);
1163 std::lock_guard<std::recursive_mutex> lockDevices(m_devicesMutex, std::adopt_lock);
1164
1165 // Note: the list must be swapped because the devices must be removed from the list before the callback is
1166 // called
1167 decltype(m_devices) lostDevicesList{};
1168 std::swap(m_devices, lostDevicesList);
1169 for (const auto& lostDevice : lostDevicesList)
1170 {
1171 TriggerDeviceLostCallbacks(lostDevice->Key());
1172 }
1173
1174 decltype(m_interfaces) lostInterfacesList{};
1175 std::swap(m_interfaces, lostInterfacesList);
1176 for (const auto& lostInterface : lostInterfacesList)
1177 {
1178 TriggerInterfaceLostCallbacks(lostInterface->Key());
1179 RemoveInterfaceCallbacks(std::const_pointer_cast<core::Interface>(lostInterface));
1180 }
1181
1182 decltype(m_systems) lostSystemsList{};
1183 std::swap(m_systems, lostSystemsList);
1184 for (const auto& lostSystem : lostSystemsList)
1185 {
1186 RemoveSystemCallbacks(std::const_pointer_cast<core::System>(lostSystem));
1187 }
1188
1189 m_producerLibraries.clear();
1190 }
1191
1192 {
1193 std::lock_guard<std::mutex> lock(m_callbackContainerMutex);
1194
1195 m_systemCallbackContainers.clear();
1196 m_interfaceCallbackContainers.clear();
1197 }
1198
1199 {
1200 std::lock_guard<std::mutex> lock(m_producerLibrariesToAddMutex);
1201 m_producerLibrariesToAdd.clear();
1202 }
1203}
1204
1205inline void DeviceManager::AddSystemCallbacks(const std::shared_ptr<core::System>& addSystem)
1206{
1207 auto SystemKey = addSystem->Key();
1208
1209 const auto foundCallbackHandle = addSystem->RegisterInterfaceFoundCallback(
1210 [this, SystemKey](const std::shared_ptr<core::InterfaceDescriptor>& foundInterface) {
1211 const auto systemIt = m_systemCallbackContainers.find(SystemKey);
1212 if (systemIt != std::end(m_systemCallbackContainers))
1213 {
1214 try
1215 {
1216 auto& container = systemIt->second;
1217 std::lock_guard<std::mutex> lock(container.mutex);
1218
1219 const auto openedInterface = foundInterface->OpenInterface();
1220
1221 container.foundInterfaces.emplace_back(openedInterface);
1222 container.interfaceIdKeyMap.emplace(openedInterface->ID(), openedInterface->Key());
1223 }
1224 catch (const std::exception&)
1225 {}
1226 }
1227 });
1228
1229 const auto lostCallbackHandle = addSystem->RegisterInterfaceLostCallback(
1230 [this, SystemKey](const std::string& lostInterfaceId) {
1231 const auto systemIt = m_systemCallbackContainers.find(SystemKey);
1232 if (systemIt != std::end(m_systemCallbackContainers))
1233 {
1234 auto& container = systemIt->second;
1235 std::lock_guard<std::mutex> lock(container.mutex);
1236
1237 const auto interfaceKeyIt = container.interfaceIdKeyMap.find(lostInterfaceId);
1238 if (interfaceKeyIt != std::end(container.interfaceIdKeyMap))
1239 {
1240 container.lostInterfaces.emplace_back(interfaceKeyIt->second);
1241 container.interfaceIdKeyMap.erase(interfaceKeyIt);
1242 }
1243 }
1244 });
1245
1246 std::lock_guard<std::mutex> lock(m_callbackContainerMutex);
1247
1248 m_systemCallbackContainers.emplace(
1249 addSystem->Key(), SystemCallbackContainer{ foundCallbackHandle, lostCallbackHandle });
1250}
1251
1252inline void DeviceManager::RemoveSystemCallbacks(const std::shared_ptr<core::System>& removeSystem)
1253{
1254 std::lock_guard<std::mutex> lock(m_callbackContainerMutex);
1255
1256 const auto SystemKey = removeSystem->Key();
1257
1258 const auto systemIt = m_systemCallbackContainers.find(SystemKey);
1259
1260 if (systemIt != std::end(m_systemCallbackContainers))
1261 {
1262 const auto& container = systemIt->second;
1263 {
1264 std::lock_guard<std::mutex> lockContainer(container.mutex);
1265
1266 removeSystem->UnregisterInterfaceFoundCallback(container.foundCallbackHandle);
1267 removeSystem->UnregisterInterfaceLostCallback(container.lostCallbackHandle);
1268 }
1269
1270 m_systemCallbackContainers.erase(systemIt);
1271 }
1272}
1273
1274inline void DeviceManager::AddInterfaceCallbacks(const std::shared_ptr<core::Interface>& addInterface)
1275{
1276 auto InterfaceKey = addInterface->Key();
1277
1278 const auto foundCallbackHandle = addInterface->RegisterDeviceFoundCallback(
1279 [this, InterfaceKey](const std::shared_ptr<core::DeviceDescriptor>& foundDevice) {
1280 const auto interfaceIt = m_interfaceCallbackContainers.find(InterfaceKey);
1281
1282 if (interfaceIt != std::end(m_interfaceCallbackContainers))
1283 {
1284 auto& container = interfaceIt->second;
1285 std::lock_guard<std::mutex> lock(container.mutex);
1286
1287 container.foundDevices.emplace_back(foundDevice);
1288 container.deviceIdKeyMap.emplace(foundDevice->ID(), foundDevice->Key());
1289 }
1290
1291 // also keep track about opened devices
1292 foundDevice->RegisterDeviceOpenedCallback([this](const std::shared_ptr<core::Device>& openedDevice) {
1293 std::lock_guard<std::mutex> lock(m_openedDevicesMutex);
1294
1295 // clear out closed devices
1296 m_openedDevices.erase(std::remove_if(std::begin(m_openedDevices), std::end(m_openedDevices),
1297 [](const OpenedDevice& dev) { return dev.device.expired(); }),
1298 std::end(m_openedDevices));
1299
1300 // add the new one
1301 OpenedDevice device;
1302 device.device = openedDevice;
1303 device.displayName = openedDevice->DisplayName();
1304 m_openedDevices.push_back(device);
1305 });
1306 });
1307
1308 const auto lostCallbackHandle = addInterface->RegisterDeviceLostCallback(
1309 [this, InterfaceKey](const std::string& lostDeviceId) {
1310 const auto interfaceIt = m_interfaceCallbackContainers.find(InterfaceKey);
1311
1312 if (interfaceIt != std::end(m_interfaceCallbackContainers))
1313 {
1314 auto& container = interfaceIt->second;
1315 std::lock_guard<std::mutex> lock(container.mutex);
1316
1317 const auto lostDeviceKeyIt = container.deviceIdKeyMap.find(lostDeviceId);
1318 if (lostDeviceKeyIt != std::end(container.deviceIdKeyMap))
1319 {
1320 container.lostDevices.emplace_back(lostDeviceKeyIt->second);
1321 container.deviceIdKeyMap.erase(lostDeviceKeyIt);
1322 }
1323 }
1324 });
1325
1326 const auto reconnectedHandle = addInterface->RegisterDeviceReconnectedCallback(
1327 [this](const std::shared_ptr<core::DeviceDescriptor>& reconnectedDevice,
1328 core::DeviceReconnectInformation reconnectInformation) {
1329 return m_deviceReconnectedCallbackManager.TriggerCallbacks(reconnectedDevice, reconnectInformation);
1330 });
1331
1332 const auto disconnectedHandle = addInterface->RegisterDeviceDisconnectedCallback(
1333 [this](const std::shared_ptr<core::DeviceDescriptor>& disconnectedDevice) {
1334 return m_deviceDisconnectedCallbackManager.TriggerCallbacks(disconnectedDevice);
1335 });
1336
1337 const auto deviceListChangedHandle = addInterface->RegisterDeviceListChangedCallback(
1338 [this]() { return m_deviceListChangedCallbackManager.TriggerCallbacks(); });
1339
1340 std::lock_guard<std::mutex> lock(m_callbackContainerMutex);
1341
1342 m_interfaceCallbackContainers.emplace(addInterface->Key(),
1343 InterfaceCallbackContainer{
1344 foundCallbackHandle, lostCallbackHandle, disconnectedHandle, reconnectedHandle, deviceListChangedHandle });
1345}
1346
1347inline void DeviceManager::RemoveInterfaceCallbacks(const std::shared_ptr<core::Interface>& removeInterface)
1348{
1349 std::lock_guard<std::mutex> lock(m_callbackContainerMutex);
1350
1351 const auto interfaceIt = m_interfaceCallbackContainers.find(removeInterface->Key());
1352
1353 if (interfaceIt != std::end(m_interfaceCallbackContainers))
1354 {
1355 const auto& container = interfaceIt->second;
1356 {
1357 std::lock_guard<std::mutex> lockContainer(container.mutex);
1358
1359 removeInterface->UnregisterDeviceFoundCallback(container.foundCallbackHandle);
1360 removeInterface->UnregisterDeviceLostCallback(container.lostCallbackHandle);
1361 removeInterface->UnregisterDeviceDisconnectedCallback(container.disconnectedCallbackHandle);
1362 removeInterface->UnregisterDeviceReconnectedCallback(container.reconnectedCallbackHandle);
1363 removeInterface->UnregisterDeviceListChangedCallback(container.deviceListChangedCallbackHandle);
1364 }
1365 m_interfaceCallbackContainers.erase(interfaceIt);
1366 }
1367}
1368
1369inline void DeviceManager::CheckDevicesOpened() const
1370{
1371 size_t openDevicesFound = 0;
1372 std::string deviceDisplayNames;
1373
1374 {
1375 std::lock_guard<std::mutex> lock(m_openedDevicesMutex);
1376
1377 for (const auto& openedDevice : m_openedDevices)
1378 {
1379 auto openDevice = openedDevice.device.lock();
1380 if (openDevice)
1381 {
1382 ++openDevicesFound;
1383 deviceDisplayNames += openedDevice.displayName;
1384 deviceDisplayNames += " ";
1385 }
1386 }
1387 }
1388
1389 if (openDevicesFound > 0)
1390 {
1391 throw core::InternalErrorException(
1392 "Can't reset the device manager while there are devices open. The following devices ("
1393 + std::to_string(openDevicesFound) + ") are open: " + deviceDisplayNames);
1394 }
1395}
1396
1398{
1399 return m_interfaceUpdateTimeout_ms;
1400}
1401
1403{
1404 m_interfaceUpdateTimeout_ms = timeout_ms;
1405}
1406
1408{
1409 return m_deviceUpdateTimeout_ms;
1410}
1411
1413{
1414 m_deviceUpdateTimeout_ms = timeout_ms;
1415}
1416
1417inline std::vector<std::shared_ptr<const core::System>> DeviceManager::Systems() const
1418{
1419 std::lock_guard<std::mutex> lock(m_systemsMutex);
1420
1421 return m_systems;
1422}
1423
1424inline std::vector<std::shared_ptr<const core::Interface>> DeviceManager::Interfaces() const
1425{
1426 std::lock_guard<std::recursive_mutex> lock(m_interfacesMutex);
1427
1428 return m_interfaces;
1429}
1430
1431inline std::vector<std::shared_ptr<core::DeviceDescriptor>> DeviceManager::Devices() const
1432{
1433 std::lock_guard<std::recursive_mutex> lock(m_devicesMutex);
1434
1435 return m_devices;
1436}
1437
1439 const DeviceManager::SystemFoundCallback& callback)
1440{
1441 return m_systemFoundCallbackManager.RegisterCallback(callback);
1442}
1443
1445{
1446 m_systemFoundCallbackManager.UnregisterCallback(callbackHandle);
1447}
1448
1451{
1452 return m_interfaceFoundCallbackManager.RegisterCallback(callback);
1453}
1454
1456{
1457 m_interfaceFoundCallbackManager.UnregisterCallback(callbackHandle);
1458}
1459
1462{
1463 return m_interfaceLostCallbackManager.RegisterCallback(callback);
1464}
1465
1467{
1468 m_interfaceLostCallbackManager.UnregisterCallback(callbackHandle);
1469}
1470
1472 const DeviceManager::DeviceFoundCallback& callback)
1473{
1474 return m_deviceFoundCallbackManager.RegisterCallback(callback);
1475}
1476
1478{
1479 m_deviceFoundCallbackManager.UnregisterCallback(callbackHandle);
1480}
1481
1483 const DeviceManager::DeviceLostCallback& callback)
1484{
1485 return m_deviceLostCallbackManager.RegisterCallback(callback);
1486}
1487
1489{
1490 m_deviceLostCallbackManager.UnregisterCallback(callbackHandle);
1491}
1492
1495{
1496 return m_deviceDisconnectedCallbackManager.RegisterCallback(callback);
1497}
1498
1501{
1502 m_deviceDisconnectedCallbackManager.UnregisterCallback(callbackHandle);
1503}
1504
1507{
1508 return m_deviceReconnectedCallbackManager.RegisterCallback(callback);
1509}
1510
1513{
1514 m_deviceReconnectedCallbackManager.UnregisterCallback(callbackHandle);
1515}
1516
1519{
1520 return m_deviceListChangedCallbackManager.RegisterCallback(callback);
1521}
1522
1525{
1526 m_deviceListChangedCallbackManager.UnregisterCallback(callbackHandle);
1527}
1528
1529inline void DeviceManager::GetLostDevicesFromLostInterfaces(
1530 const std::vector<std::string>& lostInterfaces, std::vector<std::string>& lostDevices)
1531{
1532 std::lock_guard<std::recursive_mutex> lock(m_devicesMutex);
1533
1534 for (const auto& device : m_devices)
1535 {
1536 auto resultIt = std::find(
1537 std::begin(lostInterfaces), std::end(lostInterfaces), device->ParentInterface()->Key());
1538 if (resultIt != std::end(lostInterfaces))
1539 {
1540 lostDevices.emplace_back(device->Key());
1541 }
1542 }
1543}
1544
1545inline void DeviceManager::TriggerSystemFoundCallbacks(const std::shared_ptr<const core::System>& foundSystem) const
1546{
1547 m_systemFoundCallbackManager.TriggerCallbacks(foundSystem);
1548}
1549
1550inline void DeviceManager::TriggerInterfaceFoundCallbacks(
1551 const std::shared_ptr<const core::Interface>& foundInterface) const
1552{
1553 m_interfaceFoundCallbackManager.TriggerCallbacks(foundInterface);
1554}
1555
1556inline void DeviceManager::TriggerInterfaceLostCallbacks(const std::string& lostInterfaceKey) const
1557{
1558 m_interfaceLostCallbackManager.TriggerCallbacks(lostInterfaceKey);
1559}
1560
1561inline void DeviceManager::TriggerDeviceFoundCallbacks(const std::shared_ptr<core::DeviceDescriptor>& foundDevice) const
1562{
1563 m_deviceFoundCallbackManager.TriggerCallbacks(foundDevice);
1564}
1565
1566inline void DeviceManager::TriggerDeviceLostCallbacks(const std::string& lostDeviceKey) const
1567{
1568 m_deviceLostCallbackManager.TriggerCallbacks(lostDeviceKey);
1569}
1570
1571} /* namespace peak */
core::Timeout InterfaceUpdateTimeout() const
Returns the interface update timeout.
Definition peak_device_manager.hpp:1397
std::function< void(const std::string &lostInterfaceKey)> InterfaceLostCallback
Definition peak_device_manager.hpp:111
InterfaceFoundCallbackHandle RegisterInterfaceFoundCallback(const InterfaceFoundCallback &callback)
Registers a callback for signaling a found interface.
Definition peak_device_manager.hpp:1449
std::function< void(const std::shared_ptr< core::DeviceDescriptor > &disconnectedDevice)> DeviceDisconnectedCallback
Definition peak_device_manager.hpp:129
void UnregisterDeviceFoundCallback(DeviceFoundCallbackHandle callbackHandle)
Unregisters a device found callback.
Definition peak_device_manager.hpp:1477
void UnregisterDeviceDisconnectedCallback(DeviceDisconnectedCallbackHandle callbackHandle)
Unregisters a device disconnected callback.
Definition peak_device_manager.hpp:1499
std::function< void(const std::shared_ptr< core::DeviceDescriptor > &foundDevice)> DeviceFoundCallback
Definition peak_device_manager.hpp:117
std::vector< std::shared_ptr< const core::System > > Systems() const
Returns the found and opened systems.
Definition peak_device_manager.hpp:1417
DeviceReconnectedCallback * DeviceReconnectedCallbackHandle
Definition peak_device_manager.hpp:141
void UnregisterInterfaceLostCallback(InterfaceLostCallbackHandle callbackHandle)
Unregisters an interface lost callback.
Definition peak_device_manager.hpp:1466
void Reset(ResetPolicy resetPolicy=ResetPolicy::ErrorOnOpenDevices)
Resets the DeviceManager.
Definition peak_device_manager.hpp:1148
UpdatePolicy
Enum holding the possible update policies.
Definition peak_device_manager.hpp:80
@ DontScanEnvironmentForProducerLibraries
Definition peak_device_manager.hpp:85
@ ScanEnvironmentForProducerLibraries
Definition peak_device_manager.hpp:82
ResetPolicy
Enum holding the possible reset policies.
Definition peak_device_manager.hpp:90
@ ErrorOnOpenDevices
Definition peak_device_manager.hpp:92
@ IgnoreOpenDevices
Definition peak_device_manager.hpp:95
friend class Library
Definition peak_device_manager.hpp:569
InterfaceFoundCallback * InterfaceFoundCallbackHandle
Definition peak_device_manager.hpp:108
void UnregisterDeviceLostCallback(DeviceLostCallbackHandle callbackHandle)
Unregisters a device lost callback.
Definition peak_device_manager.hpp:1488
core::Timeout DeviceUpdateTimeout() const
Returns the device update timeout.
Definition peak_device_manager.hpp:1407
void Update(UpdatePolicy updatePolicy=UpdatePolicy::ScanEnvironmentForProducerLibraries, const UpdateErrorCallback &errorCallback=UpdateErrorCallback())
Starts an update.
Definition peak_device_manager.hpp:890
std::function< void()> DeviceListChangedCallback
Definition peak_device_manager.hpp:144
DeviceDisconnectedCallback * DeviceDisconnectedCallbackHandle
Definition peak_device_manager.hpp:133
std::function< void(const std::shared_ptr< const core::Interface > &foundInterface)> InterfaceFoundCallback
Definition peak_device_manager.hpp:105
DeviceManager & operator=(const DeviceManager &other)=delete
static DeviceManager & Instance()
Returns the global DeviceManager.
Definition peak_device_manager.hpp:843
std::function< void(const std::string &errorDescription)> UpdateErrorCallback
Definition peak_device_manager.hpp:150
std::function< void(const std::shared_ptr< const core::System > &foundSystem)> SystemFoundCallback
Definition peak_device_manager.hpp:99
DeviceReconnectedCallbackHandle RegisterDeviceReconnectedCallback(const DeviceReconnectedCallback &callback)
Registers a callback for signaling a reconnected device.
Definition peak_device_manager.hpp:1505
SystemFoundCallback * SystemFoundCallbackHandle
Definition peak_device_manager.hpp:102
DeviceManager(const DeviceManager &other)=delete
void UnregisterDeviceListChangedCallback(DeviceListChangedCallbackHandle callbackHandle)
Unregisters a device list change callback.
Definition peak_device_manager.hpp:1523
std::vector< std::shared_ptr< core::DeviceDescriptor > > Devices() const
Returns the found devices.
Definition peak_device_manager.hpp:1431
std::function< void(const std::string &lostDeviceKey)> DeviceLostCallback
Definition peak_device_manager.hpp:123
std::function< void(const std::shared_ptr< core::DeviceDescriptor > &reconnectedDevice, core::DeviceReconnectInformation reconnectInformation)> DeviceReconnectedCallback
Definition peak_device_manager.hpp:136
void AddProducerLibrary(const std::string &ctiPath)
Adds the given producer library (CTI).
Definition peak_device_manager.hpp:853
SystemFoundCallbackHandle RegisterSystemFoundCallback(const SystemFoundCallback &callback)
Registers a callback for signaling a found system.
Definition peak_device_manager.hpp:1438
InterfaceLostCallbackHandle RegisterInterfaceLostCallback(const InterfaceLostCallback &callback)
Registers a callback for signaling a lost interface.
Definition peak_device_manager.hpp:1460
DeviceDisconnectedCallbackHandle RegisterDeviceDisconnectedCallback(const DeviceDisconnectedCallback &callback)
Registers a callback for signaling a disconnected device.
Definition peak_device_manager.hpp:1493
InterfaceLostCallback * InterfaceLostCallbackHandle
Definition peak_device_manager.hpp:114
DeviceFoundCallbackHandle RegisterDeviceFoundCallback(const DeviceFoundCallback &callback)
Registers a callback for signaling a found device.
Definition peak_device_manager.hpp:1471
DeviceFoundCallback * DeviceFoundCallbackHandle
Definition peak_device_manager.hpp:120
void UnregisterDeviceReconnectedCallback(DeviceReconnectedCallbackHandle callbackHandle)
Unregisters a device reconnected callback.
Definition peak_device_manager.hpp:1511
DeviceListChangedCallbackHandle RegisterDeviceListChangedCallback(const DeviceListChangedCallback &callback)
Registers a callback for signaling a change in the device list.
Definition peak_device_manager.hpp:1517
DeviceListChangedCallback * DeviceListChangedCallbackHandle
Definition peak_device_manager.hpp:147
void UnregisterSystemFoundCallback(SystemFoundCallbackHandle callbackHandle)
Unregisters a system found callback.
Definition peak_device_manager.hpp:1444
void SetInterfaceUpdateTimeout(core::Timeout timeout_ms)
Sets the interface update timeout.
Definition peak_device_manager.hpp:1402
void SetDeviceUpdateTimeout(core::Timeout timeout_ms)
Sets the device update timeout.
Definition peak_device_manager.hpp:1412
DeviceLostCallbackHandle RegisterDeviceLostCallback(const DeviceLostCallback &callback)
Registers a callback for signaling a lost device.
Definition peak_device_manager.hpp:1482
std::vector< std::shared_ptr< const core::Interface > > Interfaces() const
Returns the found and opened interfaces.
Definition peak_device_manager.hpp:1424
DeviceLostCallback * DeviceLostCallbackHandle
Definition peak_device_manager.hpp:126
void UnregisterInterfaceFoundCallback(InterfaceFoundCallbackHandle callbackHandle)
Unregisters a interface found callback.
Definition peak_device_manager.hpp:1455
Definition reconnect_information.hpp:15
static std::vector< std::string > CollectCTIPaths()
Collects producer library paths found in the current environment.
Definition peak_environment_inspector.hpp:71
The base class for all exceptions thrown by the library.
Definition peak_exception.hpp:26
The exception thrown for signaling that a feature is not available in the device.
Definition peak_exception.hpp:98
The exception thrown for signaling that the library was not initialized.
Definition peak_exception.hpp:124
static std::shared_ptr< ProducerLibrary > Open(const std::string &ctiPath)
Opens the given producer library (CTI).
Definition peak_producer_library.hpp:109
InterfaceFoundCallback * InterfaceFoundCallbackHandle
Definition peak_system.hpp:56
Represents a timeout value in milliseconds.
Definition peak_timeout.hpp:31
The "peak" namespace directly contains convenience functionality like the DeviceManager as well as th...
Definition peak_dynamic_loader.h:33