| @@ -317,6 +317,18 @@ struct PhysicalTopologySource::Internal | |||
| bool isMaster; | |||
| }; | |||
| static juce::String getVersionString (const BlocksProtocol::VersionNumber& v) | |||
| { | |||
| return juce::String (reinterpret_cast<const char*> (v.version), | |||
| std::min (sizeof (v.version), static_cast<size_t> (v.length))); | |||
| } | |||
| static juce::String getNameString (const BlocksProtocol::BlockName& n) | |||
| { | |||
| return juce::String (reinterpret_cast<const char*> (n.name), | |||
| std::min (sizeof (n.name), static_cast<size_t> (n.length))); | |||
| } | |||
| static Block::Timestamp deviceTimestampToHost (uint32 timestamp) noexcept | |||
| { | |||
| return static_cast<Block::Timestamp> (timestamp); | |||
| @@ -363,41 +375,49 @@ struct PhysicalTopologySource::Internal | |||
| return false; | |||
| } | |||
| static bool versionNumberAddedToBlock (const juce::Array<DeviceInfo>& devices, Block::UID uid, juce::String version) noexcept | |||
| static bool versionNumberChanged (const DeviceInfo& device, juce::String version) noexcept | |||
| { | |||
| for (auto&& d : devices) | |||
| { | |||
| String deviceVersion (reinterpret_cast<const char*> (d.version.version), | |||
| jmin (static_cast<size_t> (d.version.length), sizeof (d.version.version))); | |||
| if (d.uid == uid && deviceVersion != version && deviceVersion.isNotEmpty()) | |||
| return true; | |||
| } | |||
| auto deviceVersion = getVersionString (device.version); | |||
| return deviceVersion != version && deviceVersion.isNotEmpty(); | |||
| } | |||
| return false; | |||
| static bool nameIsValid (const DeviceInfo& device) | |||
| { | |||
| return device.name.length > 0; | |||
| } | |||
| static bool nameAddedToBlock (const juce::Array<DeviceInfo>& devices, Block::UID uid) noexcept | |||
| static void setVersionNumberForBlock (const DeviceInfo& deviceInfo, Block& block) noexcept | |||
| { | |||
| for (auto&& d : devices) | |||
| if (d.uid == uid && d.name.length) | |||
| return true; | |||
| if (deviceInfo.uid != block.uid) | |||
| { | |||
| jassertfalse; | |||
| return; | |||
| } | |||
| return false; | |||
| block.versionNumber = getVersionString (deviceInfo.version); | |||
| } | |||
| static void setVersionNumberForBlock (const juce::Array<DeviceInfo>& devices, Block& block) noexcept | |||
| static void setNameForBlock (const juce::Array<DeviceInfo>& devices, Block& block) noexcept | |||
| { | |||
| for (auto&& d : devices) | |||
| { | |||
| if (d.uid == block.uid) | |||
| block.versionNumber = juce::String ((const char*) d.version.version, d.version.length); | |||
| { | |||
| setNameForBlock (d, block); | |||
| return; | |||
| } | |||
| } | |||
| } | |||
| static void setNameForBlock (const juce::Array<DeviceInfo>& devices, Block& block) noexcept | |||
| static void setNameForBlock (const DeviceInfo& deviceInfo, Block& block) | |||
| { | |||
| for (auto&& d : devices) | |||
| if (d.uid == block.uid) | |||
| block.name = juce::String ((const char*) d.name.name, d.name.length); | |||
| if (deviceInfo.uid != block.uid) | |||
| { | |||
| jassertfalse; | |||
| return; | |||
| } | |||
| block.name = getNameString (deviceInfo.name); | |||
| } | |||
| //============================================================================== | |||
| @@ -542,16 +562,9 @@ struct PhysicalTopologySource::Internal | |||
| void handleVersion (BlocksProtocol::DeviceVersion version) | |||
| { | |||
| for (auto i = 0; i < currentDeviceInfo.size(); ++i) | |||
| { | |||
| if (currentDeviceInfo[i].index == version.index && version.version.length > 1) | |||
| { | |||
| if (memcmp (currentDeviceInfo.getReference (i).version.version, version.version.version, sizeof (version.version))) | |||
| { | |||
| currentDeviceInfo.getReference(i).version = version.version; | |||
| } | |||
| } | |||
| } | |||
| for (auto& d : currentDeviceInfo) | |||
| if (d.index == version.index && version.version.length > 1) | |||
| d.version = version.version; | |||
| } | |||
| void notifyDetectorTopologyChanged() | |||
| @@ -561,16 +574,9 @@ struct PhysicalTopologySource::Internal | |||
| void handleName (BlocksProtocol::DeviceName name) | |||
| { | |||
| for (auto i = 0; i < currentDeviceInfo.size(); ++i) | |||
| { | |||
| if (currentDeviceInfo[i].index == name.index && name.name.length > 1) | |||
| { | |||
| if (memcmp (currentDeviceInfo.getReference (i).name.name, name.name.name, sizeof (name.name))) | |||
| { | |||
| currentDeviceInfo.getReference (i).name = name.name; | |||
| } | |||
| } | |||
| } | |||
| for (auto& d : currentDeviceInfo) | |||
| if (d.index == name.index && name.name.length > 1) | |||
| d.name = name.name; | |||
| } | |||
| void handleControlButtonUpDown (BlocksProtocol::TopologyIndex deviceIndex, uint32 timestamp, | |||
| @@ -928,29 +934,32 @@ struct PhysicalTopologySource::Internal | |||
| for (int i = currentTopology.blocks.size(); --i >= 0;) | |||
| { | |||
| auto block = currentTopology.blocks.getUnchecked (i); | |||
| auto currentBlock = currentTopology.blocks.getUnchecked (i); | |||
| auto newDeviceIter = std::find_if (newDeviceInfo.begin(), newDeviceInfo.end(), | |||
| [&] (DeviceInfo& info) { return info.uid == currentBlock->uid; }); | |||
| if (! containsBlockWithUID (newDeviceInfo, block->uid)) | |||
| if (newDeviceIter == newDeviceInfo.end()) | |||
| { | |||
| if (auto bi = BlockImplementation::getFrom (*block)) | |||
| if (auto bi = BlockImplementation::getFrom (*currentBlock)) | |||
| bi->invalidate(); | |||
| currentTopology.blocks.remove (i); | |||
| disconnectedBlocks.addIfNotAlreadyThere (currentTopology.blocks.removeAndReturn (i)); | |||
| } | |||
| else | |||
| { | |||
| if (versionNumberAddedToBlock (newDeviceInfo, block->uid, block->versionNumber)) | |||
| setVersionNumberForBlock (newDeviceInfo, *block); | |||
| if (nameAddedToBlock (newDeviceInfo, block->uid)) | |||
| setNameForBlock (newDeviceInfo, *block); | |||
| updateCurrentBlockInfo (currentBlock, *newDeviceIter); | |||
| } | |||
| } | |||
| static const int maxBlocksToSave = 100; | |||
| if (disconnectedBlocks.size() > maxBlocksToSave) | |||
| disconnectedBlocks.removeRange (0, 2 * (disconnectedBlocks.size() - maxBlocksToSave)); | |||
| for (auto& info : newDeviceInfo) | |||
| if (info.serial.isValid()) | |||
| if (! containsBlockWithUID (currentTopology.blocks, getBlockUIDFromSerialNumber (info.serial))) | |||
| currentTopology.blocks.add (new BlockImplementation (info.serial, *this, info.version, info.name, info.isMaster)); | |||
| if (info.serial.isValid() && ! containsBlockWithUID (currentTopology.blocks, getBlockUIDFromSerialNumber (info.serial))) | |||
| addBlock (info); | |||
| currentTopology.connections.swapWith (newDeviceConnections); | |||
| } | |||
| @@ -1136,6 +1145,7 @@ struct PhysicalTopologySource::Internal | |||
| juce::Array<TouchSurfaceImplementation*> activeTouchSurfaces; | |||
| BlockTopology currentTopology; | |||
| juce::ReferenceCountedArray<Block, CriticalSection> disconnectedBlocks; | |||
| private: | |||
| void timerCallback() override | |||
| @@ -1194,6 +1204,52 @@ struct PhysicalTopologySource::Internal | |||
| return false; | |||
| } | |||
| void addBlock (DeviceInfo info) | |||
| { | |||
| if (! reactivateBlockIfKnown (info)) | |||
| addNewBlock (info); | |||
| } | |||
| bool reactivateBlockIfKnown (DeviceInfo info) | |||
| { | |||
| auto uid = getBlockUIDFromSerialNumber (info.serial); | |||
| for (int i = 0; i < disconnectedBlocks.size(); ++i) | |||
| { | |||
| if (disconnectedBlocks.getUnchecked (i)->uid == uid) | |||
| { | |||
| auto block = disconnectedBlocks.removeAndReturn (i); | |||
| if (auto blockImpl = BlockImplementation::getFrom (*block)) | |||
| { | |||
| blockImpl->revalidate (info.version, info.name, info.isMaster); | |||
| currentTopology.blocks.add (block); | |||
| return true; | |||
| } | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| void addNewBlock (DeviceInfo info) | |||
| { | |||
| currentTopology.blocks.add (new BlockImplementation (info.serial, *this, info.version, | |||
| info.name, info.isMaster)); | |||
| } | |||
| void updateCurrentBlockInfo (Block::Ptr blockToUpdate, DeviceInfo& updatedInfo) | |||
| { | |||
| if (versionNumberChanged (updatedInfo, blockToUpdate->versionNumber)) | |||
| setVersionNumberForBlock (updatedInfo, *blockToUpdate); | |||
| if (nameIsValid (updatedInfo)) | |||
| setNameForBlock (updatedInfo, *blockToUpdate); | |||
| if (updatedInfo.isMaster != blockToUpdate->isMasterBlock()) | |||
| BlockImplementation::getFrom (*blockToUpdate)->setToMaster (updatedInfo.isMaster); | |||
| } | |||
| juce::OwnedArray<ConnectedDeviceGroup> connectedDeviceGroups; | |||
| //============================================================================== | |||
| @@ -1293,6 +1349,19 @@ struct PhysicalTopologySource::Internal | |||
| isStillConnected = false; | |||
| } | |||
| void revalidate (BlocksProtocol::VersionNumber newVersion, BlocksProtocol::BlockName newName, bool master) | |||
| { | |||
| versionNumber = getVersionString (newVersion); | |||
| name = getNameString (newName); | |||
| isMaster = master; | |||
| isStillConnected = true; | |||
| } | |||
| void setToMaster (bool shouldBeMaster) | |||
| { | |||
| isMaster = shouldBeMaster; | |||
| } | |||
| Type getType() const override { return modelData.apiType; } | |||
| juce::String getDeviceDescription() const override { return modelData.description; } | |||
| int getWidth() const override { return modelData.widthUnits; } | |||