1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    The code included in this file is provided under the terms of the ISC license
11    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12    To use, copy, modify, and/or distribute this software for any purpose with or
13    without fee is hereby granted provided that the above copyright notice and
14    this permission notice appear in all copies.
15 
16    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18    DISCLAIMED.
19 
20   ==============================================================================
21 */
22 
23 //==============================================================================
24 /** These can be useful when debugging the topology. */
25 
26 #ifndef LOG_BLOCKS_CONNECTIVITY
27   #define LOG_BLOCKS_CONNECTIVITY 0
28 #endif
29 
30 #ifndef LOG_BLOCKS_PINGS
31   #define LOG_BLOCKS_PINGS 0
32 #endif
33 
34 #ifndef DUMP_BANDWIDTH_STATS
35   #define DUMP_BANDWIDTH_STATS 0
36 #endif
37 
38 #ifndef DUMP_TOPOLOGY
39   #define DUMP_TOPOLOGY 0
40 #endif
41 
42 #define TOPOLOGY_LOG(text) \
43  JUCE_BLOCK_WITH_FORCED_SEMICOLON (juce::String buf ("Topology Src:   "); \
44  juce::Logger::outputDebugString (buf << text);)
45 
46 #if LOG_BLOCKS_CONNECTIVITY
47  #define LOG_CONNECTIVITY(text) TOPOLOGY_LOG(text)
48 #else
49  #define LOG_CONNECTIVITY(text)
50 #endif
51 
52 #if LOG_BLOCKS_PINGS
53  #define LOG_PING(text) TOPOLOGY_LOG(text)
54 #else
55  #define LOG_PING(text)
56 #endif
57 
58 #if DUMP_BANDWIDTH_STATS
59  #include "internal/juce_BandwidthStatsLogger.cpp"
60 #endif
61 
62 #include "internal/juce_MidiDeviceConnection.cpp"
63 #include "internal/juce_MIDIDeviceDetector.cpp"
64 #include "internal/juce_DeviceInfo.cpp"
65 #include "internal/juce_DepreciatedVersionReader.cpp"
66 #include "internal/juce_BlockSerialReader.cpp"
67 #include "internal/juce_ConnectedDeviceGroup.cpp"
68 #include "internal/juce_BlockImplementation.cpp"
69 #include "internal/juce_Detector.cpp"
70 #include "internal/juce_DetectorHolder.cpp"
71 
72 namespace juce
73 {
74 
75 //==============================================================================
PhysicalTopologySource(bool startDetached)76 PhysicalTopologySource::PhysicalTopologySource (bool startDetached)
77 {
78     if (! startDetached)
79         setActive (true);
80 }
81 
PhysicalTopologySource(DeviceDetector & detectorToUse,bool startDetached)82 PhysicalTopologySource::PhysicalTopologySource (DeviceDetector& detectorToUse, bool startDetached)
83     : customDetector (&detectorToUse)
84 {
85     if (! startDetached)
86         setActive (true);
87 }
88 
~PhysicalTopologySource()89 PhysicalTopologySource::~PhysicalTopologySource()
90 {
91     setActive (false);
92 }
93 
setActive(bool shouldBeActive)94 void PhysicalTopologySource::setActive (bool shouldBeActive)
95 {
96     JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
97 
98     if (isActive() == shouldBeActive)
99         return;
100 
101     if (shouldBeActive)
102     {
103         if (customDetector == nullptr)
104             detector = std::make_unique<DetectorHolder>(*this);
105         else
106             detector = std::make_unique<DetectorHolder>(*this, *customDetector);
107 
108         detector->detector->activeTopologySources.add (this);
109     }
110     else
111     {
112         detector->detector->detach (this);
113         detector.reset();
114     }
115 
116     listeners.call ([] (TopologySource::Listener& l){ l.topologyChanged(); });
117 }
118 
isActive() const119 bool PhysicalTopologySource::isActive() const
120 {
121     return detector != nullptr;
122 }
123 
isLockedFromOutside() const124 bool PhysicalTopologySource::isLockedFromOutside() const
125 {
126     if (detector != nullptr && detector->detector != nullptr)
127         return detector->detector->deviceDetector.isLockedFromOutside();
128 
129     return false;
130 }
131 
getCurrentTopology() const132 BlockTopology PhysicalTopologySource::getCurrentTopology() const
133 {
134     JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED // This method must only be called from the message thread!
135 
136     if (detector != nullptr)
137         return detector->detector->currentTopology;
138 
139     return {};
140 }
141 
cancelAllActiveTouches()142 void PhysicalTopologySource::cancelAllActiveTouches() noexcept
143 {
144     if (detector != nullptr)
145         detector->detector->cancelAllActiveTouches();
146 }
147 
hasOwnServiceTimer() const148 bool PhysicalTopologySource::hasOwnServiceTimer() const     { return false; }
handleTimerTick()149 void PhysicalTopologySource::handleTimerTick()
150 {
151     if (detector != nullptr)
152         detector->handleTimerTick();
153 }
154 
DeviceConnection()155 PhysicalTopologySource::DeviceConnection::DeviceConnection() {}
~DeviceConnection()156 PhysicalTopologySource::DeviceConnection::~DeviceConnection() {}
157 
DeviceDetector()158 PhysicalTopologySource::DeviceDetector::DeviceDetector() {}
~DeviceDetector()159 PhysicalTopologySource::DeviceDetector::~DeviceDetector() {}
160 
getStandardLittleFootFunctions()161 const char* const* PhysicalTopologySource::getStandardLittleFootFunctions() noexcept
162 {
163     return BlocksProtocol::ledProgramLittleFootFunctions;
164 }
165 
166 template <typename ListType>
collectionsMatch(const ListType & list1,const ListType & list2)167 static bool collectionsMatch (const ListType& list1, const ListType& list2) noexcept
168 {
169     if (list1.size() != list2.size())
170         return false;
171 
172     for (auto&& b : list1)
173         if (! list2.contains (b))
174             return false;
175 
176     return true;
177 }
178 
operator ==(const BlockTopology & other) const179 bool BlockTopology::operator== (const BlockTopology& other) const noexcept
180 {
181     return collectionsMatch (connections, other.connections) && collectionsMatch (blocks, other.blocks);
182 }
183 
operator !=(const BlockTopology & other) const184 bool BlockTopology::operator!= (const BlockTopology& other) const noexcept
185 {
186     return ! operator== (other);
187 }
188 
operator ==(const BlockDeviceConnection & other) const189 bool BlockDeviceConnection::operator== (const BlockDeviceConnection& other) const noexcept
190 {
191     return (device1 == other.device1 && device2 == other.device2
192              && connectionPortOnDevice1 == other.connectionPortOnDevice1
193              && connectionPortOnDevice2 == other.connectionPortOnDevice2)
194         || (device1 == other.device2 && device2 == other.device1
195              && connectionPortOnDevice1 == other.connectionPortOnDevice2
196              && connectionPortOnDevice2 == other.connectionPortOnDevice1);
197 }
198 
operator !=(const BlockDeviceConnection & other) const199 bool BlockDeviceConnection::operator!= (const BlockDeviceConnection& other) const noexcept
200 {
201     return ! operator== (other);
202 }
203 
204 } // namespace juce
205