Browse Source

BLOCKS: Request version number from old firmware

tags/2021-05-28
dimitri ed 6 years ago
parent
commit
4f7137cc08
12 changed files with 716 additions and 115 deletions
  1. +230
    -0
      modules/juce_blocks_basics/blocks/juce_BlocksVersion.cpp
  2. +82
    -0
      modules/juce_blocks_basics/blocks/juce_BlocksVersion.h
  3. +3
    -0
      modules/juce_blocks_basics/juce_blocks_basics.cpp
  4. +1
    -0
      modules/juce_blocks_basics/juce_blocks_basics.h
  5. +23
    -20
      modules/juce_blocks_basics/protocol/juce_BlocksProtocolDefinitions.h
  6. +2
    -2
      modules/juce_blocks_basics/protocol/juce_HostPacketDecoder.h
  7. +4
    -4
      modules/juce_blocks_basics/topology/internal/juce_BlockImplementation.cpp
  8. +224
    -84
      modules/juce_blocks_basics/topology/internal/juce_ConnectedDeviceGroup.cpp
  9. +128
    -0
      modules/juce_blocks_basics/topology/internal/juce_DepreciatedVersionReader.cpp
  10. +5
    -4
      modules/juce_blocks_basics/topology/internal/juce_Detector.cpp
  11. +1
    -1
      modules/juce_blocks_basics/topology/internal/juce_MidiDeviceConnection.cpp
  12. +13
    -0
      modules/juce_blocks_basics/topology/juce_PhysicalTopologySource.cpp

+ 230
- 0
modules/juce_blocks_basics/blocks/juce_BlocksVersion.cpp View File

@@ -0,0 +1,230 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
BlocksVersion::BlocksVersion (const String& versionString)
{
evaluate (versionString);
}
String BlocksVersion::toString (bool extended) const
{
String output = String (major) + "." + String (minor) + "." + String (patch);
if (extended)
{
if (releaseType.isNotEmpty())
output += "-" + releaseType + "-" + String (releaseCount);
if (commit.isNotEmpty())
output += "-" + commit;
if (forced)
output += "-f";
}
return output;
}
static std::regex getRegEx()
{
static const std::string majorMinorPatchRegex { "([0-9]+)\\.([0-9]+)\\.([0-9]+)" };
static const std::string releaseAndCommitDetailsRegex { "(?:-(alpha|beta|rc))?(?:-([0-9]+))?(?:-g([A-Za-z0-9]+))?" };
static const std::string forcedUpdateRegex { "(-f)?" };
static const std::regex regEx ("(?:.+)?" + majorMinorPatchRegex + releaseAndCommitDetailsRegex + forcedUpdateRegex + "(?:.+)?");
return regEx;
}
bool BlocksVersion::isValidVersion (const String& versionString)
{
return std::regex_match (versionString.toRawUTF8(), getRegEx());
}
bool BlocksVersion::evaluate (const String& versionString)
{
std::cmatch groups;
const bool result = std::regex_match (versionString.toRawUTF8(), groups, getRegEx());
jassert (result);
auto toInt = [](const std::sub_match<const char*> match)
{
return std::atoi (match.str().c_str());
};
enum tags { FULL, MAJOR, MINOR, PATCH, RELEASE, COUNT, COMMIT, FORCED};
major = toInt (groups[MAJOR]);
minor = toInt (groups[MINOR]);
patch = toInt (groups[PATCH]);
releaseType = String (groups[RELEASE]);
releaseCount = toInt (groups[COUNT]);
commit = String (groups[COMMIT]);
forced = groups[FORCED].matched;
return result;
}
bool BlocksVersion::isEqualTo (const BlocksVersion& other) const
{
return major == other.major &&
minor == other.minor &&
patch == other.patch &&
releaseType == other.releaseType &&
releaseCount == other.releaseCount;
}
bool BlocksVersion::isGreaterThan (const BlocksVersion& other) const
{
if (major != other.major) return (major > other.major);
if (minor != other.minor) return (minor > other.minor);
if (patch != other.patch) return (patch > other.patch);
return releaseTypeGreaterThan (other);
}
bool BlocksVersion::releaseTypeGreaterThan (const BlocksVersion& other) const
{
auto getReleaseTypePriority = [](const juce::BlocksVersion& version)
{
String releaseTypes[4] = { "alpha", "beta", "rc", {} };
for (int i = 0; i < 4; ++i)
if (version.releaseType == releaseTypes[i])
return i;
return -1;
};
if (releaseType != other.releaseType)
return getReleaseTypePriority (*this) > getReleaseTypePriority (other);
return releaseCount > other.releaseCount;
}
bool BlocksVersion::operator== (const BlocksVersion& other) const
{
return isEqualTo (other);
}
bool BlocksVersion::operator!=(const BlocksVersion& other) const
{
return ! (*this == other);
}
bool BlocksVersion::operator> (const BlocksVersion& other) const
{
return isGreaterThan (other);
}
bool BlocksVersion::operator< (const BlocksVersion& other) const
{
return ! (*this > other) && (*this != other);
}
bool BlocksVersion::operator<= (const BlocksVersion& other) const
{
return (*this < other) || (*this == other);
}
bool BlocksVersion::operator>= (const BlocksVersion& other) const
{
return (*this > other) || (*this == other);
}
#if JUCE_UNIT_TESTS
class BlocksVersionUnitTests : public UnitTest
{
public:
BlocksVersionUnitTests() : UnitTest ("BlocksVersionUnitTests", "Blocks") {}
void runTest() override
{
beginTest ("Compare patch number");
expect (BlocksVersion ("4.6.7") < BlocksVersion ("4.6.11"));
expect (BlocksVersion ("4.6.6") > BlocksVersion ("4.6.2"));
expect (BlocksVersion ("4.6.5") <= BlocksVersion ("4.6.8"));
expect (BlocksVersion ("4.6.4") >= BlocksVersion ("4.6.3"));
beginTest ("Compare minor number");
expect (BlocksVersion ("4.5.9") < BlocksVersion ("4.6.7"));
expect (BlocksVersion ("4.15.2") > BlocksVersion ("4.6.6"));
expect (BlocksVersion ("4.4.8") <= BlocksVersion ("4.6.5"));
expect (BlocksVersion ("4.7.4") >= BlocksVersion ("4.6.3"));
beginTest ("Compare major number");
expect (BlocksVersion ("4.6.9") < BlocksVersion ("8.5.7"));
expect (BlocksVersion ("15.6.2") > BlocksVersion ("4.9.6"));
expect (BlocksVersion ("4.6.8") <= BlocksVersion ("7.4.5"));
expect (BlocksVersion ("5.6.4") >= BlocksVersion ("4.7.3"));
beginTest ("Compare build number");
expect (BlocksVersion ("0.3.2-alpha-3-gjduh") < BlocksVersion ("0.3.2-alpha-12-gjduh"));
expect (BlocksVersion ("0.3.2-alpha-4-gjduh") > BlocksVersion ("0.3.2-alpha-1-gjduh"));
expect (BlocksVersion ("0.3.2-beta-5-gjduh") <= BlocksVersion ("0.3.2-beta-6-gjduh"));
expect (BlocksVersion ("0.3.2-beta-6-gjduh") >= BlocksVersion ("0.3.2-beta-3-gjduh"));
beginTest ("Compare build type");
expect (BlocksVersion ("0.3.2-alpha-3-gjduhenf") < BlocksVersion ("0.3.2-beta-1-gjduhenf"));
expect (BlocksVersion ("0.3.2-beta-3-gjduhenf") < BlocksVersion ("0.3.2"));
expect (BlocksVersion ("0.3.2") > BlocksVersion ("0.3.2-alpha-3-gjduhenf"));
beginTest ("Compare equal numbers");
expect (BlocksVersion ("4.6.7") == BlocksVersion ("4.6.7"));
expect (BlocksVersion ("4.6.7-alpha-3-gsdfsf") == BlocksVersion ("4.6.7-alpha-3-gsdfsf"));
beginTest ("Identify forced version");
expect (BlocksVersion("0.2.2-2-g25eaec8a-f").forced);
expect (BlocksVersion("0.2.2-2-f").forced);
expect (! BlocksVersion("0.2.2-2-g25eaec8-d7").forced);
beginTest ("Valid Strings");
expect (BlocksVersion::isValidVersion ("Rainbow 0.4.5-beta-1-g4c36e"));
expect (! BlocksVersion::isValidVersion ("0.4-beta-1-g4c36e"));
expect (! BlocksVersion::isValidVersion ("a.0.4-beta-1-g4c36e"));
expect (BlocksVersion::isValidVersion ("BLOCKS control 0.2.2-2-g25eaec8a-f.syx"));
expect (BlocksVersion("BLOCKS control 0.2.2-2-g25eaec8a-f.syx") == BlocksVersion("0.2.2-2-g25eaec8a-f"));
beginTest ("Default constructors");
{
BlocksVersion v1 ("4.5.9");
BlocksVersion v2 (v1);
BlocksVersion v3;
v3 = v1;
expect (v2 == v1);
expect (v3 == v1);
BlocksVersion emptyVersion;
expect (emptyVersion == BlocksVersion ("0.0.0"));
}
}
};
static BlocksVersionUnitTests BlocksVersionUnitTests;
#endif
} // namespace juce

+ 82
- 0
modules/juce_blocks_basics/blocks/juce_BlocksVersion.h View File

@@ -0,0 +1,82 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#pragma once
namespace juce
{
struct BlocksVersion
{
public:
/** The main value in a version number x.0.0 */
int major = 0;
/** The secondary value in a version number 1.x.0 */
int minor = 0;
/** The tertiary value in a version number 1.0.x */
int patch = 0;
/** The release tag for this version, such as "beta", "alpha", "rc", etc */
juce::String releaseType;
/** A numberical value assosiated with the release tag, such as "beta 4" */
int releaseCount = 0;
/** The assosiated git commit that generated this firmware version */
juce::String commit;
/** Identify "forced" firmware builds **/
bool forced = false;
juce::String toString (bool extended = false) const;
/** Constructs a version number from an formatted juce::String */
BlocksVersion (const juce::String&);
/** Constructs a version number from another BlocksVersion */
BlocksVersion (const BlocksVersion& other) = default;
/** Creates an empty version number **/
BlocksVersion() = default;
/** Returns true if string format is valid */
static bool isValidVersion (const juce::String& versionString);
bool operator == (const BlocksVersion&) const;
bool operator != (const BlocksVersion&) const;
bool operator < (const BlocksVersion&) const;
bool operator > (const BlocksVersion&) const;
bool operator <= (const BlocksVersion&) const;
bool operator >= (const BlocksVersion&) const;
private:
/** @internal */
bool evaluate (const juce::String& versionString);
bool releaseTypeGreaterThan (const BlocksVersion& otherReleaseType) const;
bool isGreaterThan (const BlocksVersion& other) const;
bool isEqualTo (const BlocksVersion& other) const;
};
} // namespace juce

+ 3
- 0
modules/juce_blocks_basics/juce_blocks_basics.cpp View File

@@ -28,6 +28,8 @@
#endif
#else
#include <regex>
namespace juce
{
#include "littlefoot/juce_LittleFootRemoteHeap.h"
@@ -41,6 +43,7 @@ namespace juce
#include "blocks/juce_BlockConfigManager.h"
#include "blocks/juce_Block.cpp"
#include "blocks/juce_BlocksVersion.cpp"
#include "topology/juce_PhysicalTopologySource.cpp"
#include "topology/juce_RuleBasedTopologySource.cpp"
#include "visualisers/juce_DrumPadLEDProgram.cpp"


+ 1
- 0
modules/juce_blocks_basics/juce_blocks_basics.h View File

@@ -73,6 +73,7 @@ namespace juce
#include "blocks/juce_ControlButton.h"
#include "blocks/juce_TouchList.h"
#include "blocks/juce_StatusLight.h"
#include "blocks/juce_BlocksVersion.h"
#include "topology/juce_Topology.h"
#include "topology/juce_TopologySource.h"
#include "topology/juce_PhysicalTopologySource.h"


+ 23
- 20
modules/juce_blocks_basics/protocol/juce_BlocksProtocolDefinitions.h View File

@@ -154,41 +154,44 @@ struct BlockSerialNumber
};
//==============================================================================
/** Structure for the version number
/** Structure for generic block data
@tags{Blocks}
*/
struct VersionNumber
*/
template <size_t MaxSize>
struct BlockStringData
{
uint8 version[21] = {};
uint8 data[MaxSize] = {};
uint8 length = 0;
juce::String asString() const
static const size_t maxLength { MaxSize };
bool isNotEmpty() const
{
return juce::String (reinterpret_cast<const char*> (version),
std::min (sizeof (version), static_cast<size_t> (length)));
return length > 0;
}
};
//==============================================================================
/** Structure for the block name
bool operator== (const BlockStringData& other) const
{
if (length != other.length)
return false;
@tags{Blocks}
*/
struct BlockName
{
uint8 name[33] = {};
uint8 length = 0;
for (int i = 0; i < length; ++i)
if (data[i] != other.data[i])
return false;
bool isValid() const { return length > 0; }
return true;
}
juce::String asString() const
bool operator!= (const BlockStringData& other) const
{
return juce::String (reinterpret_cast<const char*> (name),
std::min (sizeof (name), static_cast<size_t> (length)));
return ! ( *this == other );
}
};
using VersionNumber = BlockStringData<21>;
using BlockName = BlockStringData<33>;
//==============================================================================
/** Structure for the device status


+ 2
- 2
modules/juce_blocks_basics/protocol/juce_HostPacketDecoder.h View File

@@ -194,7 +194,7 @@ struct HostPacketDecoder
version.version.length = (uint8) reader.readBits (7);
for (uint32 i = 0; i < version.version.length; ++i)
version.version.version[i] = (uint8) reader.readBits (7);
version.version.data[i] = (uint8) reader.readBits (7);
handler.handleVersion (version);
return true;
@@ -208,7 +208,7 @@ struct HostPacketDecoder
name.name.length = (uint8) reader.readBits (7);
for (uint32 i = 0; i < name.name.length; ++i)
name.name.name[i] = (uint8) reader.readBits (7);
name.name.data[i] = (uint8) reader.readBits (7);
handler.handleName (name);
return true;


+ 4
- 4
modules/juce_blocks_basics/topology/internal/juce_BlockImplementation.cpp View File

@@ -40,8 +40,8 @@ public:
BlocksProtocol::BlockName blockName,
bool isMasterBlock)
: Block (juce::String ((const char*) serial.serial, sizeof (serial.serial)),
juce::String ((const char*) version.version, version.length),
juce::String ((const char*) blockName.name, blockName.length)),
juce::String ((const char*) version.data, version.length),
juce::String ((const char*) blockName.data, blockName.length)),
modelData (serial),
remoteHeap (modelData.programAndHeapSize),
detector (&detectorToUse),
@@ -81,8 +81,8 @@ public:
void markReconnected (const DeviceInfo& deviceInfo)
{
versionNumber = deviceInfo.version.asString();
name = deviceInfo.name.asString();
versionNumber = asString (deviceInfo.version);
name = asString (deviceInfo.name);
isMaster = deviceInfo.isMaster;
setProgram (nullptr);


+ 224
- 84
modules/juce_blocks_basics/topology/internal/juce_ConnectedDeviceGroup.cpp View File

@@ -29,6 +29,55 @@ namespace
{
return static_cast<Block::Timestamp> (timestamp);
}
template <typename V>
static int removeUnusedBlocksFromMap (std::map<Block::UID, V>& mapToClean, const juce::Array<DeviceInfo>& currentDevices)
{
int numRemoved = 0;
for (auto iter = mapToClean.begin(); iter != mapToClean.end();)
{
bool found = false;
for (auto& info : currentDevices)
{
if (info.uid == iter->first)
{
found = true;
break;
}
}
if (found)
{
++iter;
}
else
{
mapToClean.erase (iter++);
++numRemoved;
}
}
return numRemoved;
}
/* Returns true new element added to map or value of existing key changed */
template <typename V>
static bool insertOrAssign (std::map<Block::UID, V>& map, const Block::UID& key, const V& value)
{
const auto result = map.emplace (std::make_pair (key, value));
if (! result.second)
{
if (result.first->second == value)
return false;
result.first->second = value;
}
return true;
}
}
template <typename Detector>
@@ -44,14 +93,16 @@ struct ConnectedDeviceGroup : private juce::AsyncUpdater,
this->handleIncomingMessage (data, dataSize);
};
if (auto midiDeviceConnection = static_cast<MIDIDeviceConnection*> (deviceConnection.get()))
depreciatedVersionReader = std::make_unique<DepreciatedVersionReader> (*midiDeviceConnection);
startTimer (200);
sendTopologyRequest();
}
bool isStillConnected (const juce::StringArray& detectedDevices) const noexcept
{
return detectedDevices.contains (deviceName)
&& ! failedToGetTopology();
return detectedDevices.contains (deviceName) && ! failedToGetTopology();
}
int getIndexFromDeviceID (Block::UID uid) const noexcept
@@ -63,15 +114,6 @@ struct ConnectedDeviceGroup : private juce::AsyncUpdater,
return -1;
}
const DeviceInfo* getDeviceInfoFromUID (Block::UID uid) const noexcept
{
for (auto& d : currentDeviceInfo)
if (d.uid == uid)
return &d;
return nullptr;
}
const BlocksProtocol::DeviceStatus* getLastStatus (Block::UID deviceID) const noexcept
{
for (auto&& status : currentTopologyDevices)
@@ -114,37 +156,53 @@ struct ConnectedDeviceGroup : private juce::AsyncUpdater,
void endTopology()
{
currentDeviceInfo = getArrayOfDeviceInfo (incomingTopologyDevices);
currentDeviceConnections = getArrayOfConnections (incomingTopologyConnections);
currentTopologyDevices = incomingTopologyDevices;
lastTopologyReceiveTime = juce::Time::getCurrentTime();
const int numRemoved = blockPings.removeIf ([this] (auto& ping)
{
for (auto& info : currentDeviceInfo)
if (info.uid == ping.blockUID)
return false;
if (incomingTopologyDevices.isEmpty())
{
jassertfalse;
return;
}
LOG_CONNECTIVITY ("API Disconnected by topology update " << ping.blockUID);
return true;
});
currentTopologyDevices.swapWith (incomingTopologyDevices);
currentTopologyConnections.swapWith (incomingTopologyConnections);
if (numRemoved > 0)
detector.handleTopologyChange();
incomingTopologyDevices.clearQuick();
incomingTopologyConnections.clearQuick();
refreshCurrentDeviceInfo();
refreshCurrentDeviceConnections();
removeUnusedBlocksFromMap (versionNumbers, currentDeviceInfo);
removeUnusedBlocksFromMap (blockNames, currentDeviceInfo);
removePingForDisconnectedBlocks();
detector.handleTopologyChange();
}
void handleVersion (BlocksProtocol::DeviceVersion version)
{
for (auto& d : currentDeviceInfo)
if (d.index == version.index && version.version.length > 1)
d.version = version.version;
const auto uid = getDeviceIDFromIndex (version.index);
if (uid == Block::UID() || version.version.length <= 1)
return;
setVersion (uid, version.version);
}
void handleName (BlocksProtocol::DeviceName name)
{
for (auto& d : currentDeviceInfo)
if (d.index == name.index && name.name.length > 1)
d.name = name.name;
const auto uid = getDeviceIDFromIndex (name.index);
if (uid == Block::UID() || name.name.length <= 1)
return;
if (insertOrAssign (blockNames, uid, name.name))
{
refreshCurrentDeviceInfo();
detector.handleTopologyChange();
}
}
void handleControlButtonUpDown (BlocksProtocol::TopologyIndex deviceIndex, uint32 timestamp,
@@ -299,14 +357,19 @@ private:
std::unique_ptr<PhysicalTopologySource::DeviceConnection> deviceConnection;
juce::Array<BlocksProtocol::DeviceStatus> incomingTopologyDevices, currentTopologyDevices;
juce::Array<BlocksProtocol::DeviceConnection> incomingTopologyConnections;
juce::Array<BlocksProtocol::DeviceConnection> incomingTopologyConnections, currentTopologyConnections;
juce::CriticalSection incomingPacketLock;
juce::Array<juce::MemoryBlock> incomingPackets;
std::map<Block::UID, BlocksProtocol::VersionNumber> versionNumbers;
std::map<Block::UID, BlocksProtocol::BlockName> blockNames;
std::unique_ptr<DepreciatedVersionReader> depreciatedVersionReader;
struct TouchStart { float x, y; };
TouchList<TouchStart> touchStartPositions;
TouchList<TouchStart> touchStartPositions;
Block::UID masterBlock = 0;
//==============================================================================
@@ -338,11 +401,12 @@ private:
checkApiTimeouts (now);
startApiModeOnConnectedBlocks();
requestMasterBlockVersionIfNeeded();
}
bool failedToGetTopology() const noexcept
{
return numTopologyRequestsSent > 4 && lastTopologyReceiveTime == juce::Time();
return numTopologyRequestsSent >= 4 && lastTopologyReceiveTime == juce::Time();
}
bool sendCommandMessage (BlocksProtocol::TopologyIndex deviceIndex, uint32 commandID) const
@@ -354,11 +418,36 @@ private:
return sendMessageToDevice (p);
}
//==============================================================================
void requestMasterBlockVersionIfNeeded()
{
if (depreciatedVersionReader == nullptr)
return;
const auto masterVersion = depreciatedVersionReader->getVersionNumber();
if (masterVersion.isNotEmpty())
setVersion (masterBlock, masterVersion);
}
void setVersion (const Block::UID uid, const BlocksProtocol::VersionNumber versionNumber)
{
if (uid == masterBlock)
depreciatedVersionReader.reset();
if (insertOrAssign (versionNumbers, uid, versionNumber))
{
refreshCurrentDeviceInfo();
detector.handleTopologyChange();
}
}
//==============================================================================
struct BlockPingTime
{
Block::UID blockUID;
juce::Time lastPing;
juce::Time connected;
};
juce::Array<BlockPingTime> blockPings;
@@ -375,7 +464,7 @@ private:
else
{
LOG_CONNECTIVITY ("API Connected " << uid);
blockPings.add ({ uid, now });
blockPings.add ({ uid, now, now });
detector.handleTopologyChange();
}
}
@@ -408,6 +497,8 @@ private:
LOG_CONNECTIVITY ("API Disconnected " << uid << ", re-probing topology");
currentDeviceInfo.clearQuick();
blockPings.clearQuick();
blockNames.clear();
versionNumbers.clear();
detector.handleTopologyChange();
scheduleNewTopologyRequest();
}
@@ -432,6 +523,22 @@ private:
}
}
/* Returns true is ping was removed */
void removePingForDisconnectedBlocks()
{
const auto removed = [this] (auto& ping)
{
for (auto& info : currentDeviceInfo)
if (info.uid == ping.blockUID)
return false;
LOG_CONNECTIVITY ("API Disconnected by topology update " << ping.blockUID);
return true;
};
blockPings.removeIf (removed);
}
void startApiModeOnConnectedBlocks()
{
for (auto& info : currentDeviceInfo)
@@ -445,6 +552,21 @@ private:
}
}
//==============================================================================
void checkVersionNumberTimeouts()
{
for (const auto& device : currentDeviceInfo)
{
const auto version = versionNumbers.find (device.uid);
if (version == versionNumbers.end())
{
auto* ping = getPing (device.uid);
}
}
}
//==============================================================================
Block::UID getDeviceIDFromIndex (BlocksProtocol::TopologyIndex index) const noexcept
{
@@ -463,38 +585,7 @@ private:
if (uid == Block::UID())
scheduleNewTopologyRequest();
return uid;
}
juce::Array<BlockDeviceConnection> getArrayOfConnections (const juce::Array<BlocksProtocol::DeviceConnection>& connections)
{
juce::Array<BlockDeviceConnection> result;
for (auto&& c : connections)
{
BlockDeviceConnection dc;
dc.device1 = getDeviceIDFromIndex (c.device1);
dc.device2 = getDeviceIDFromIndex (c.device2);
if (dc.device1 <= 0 || dc.device2 <= 0)
continue;
dc.connectionPortOnDevice1 = convertConnectionPort (dc.device1, c.port1);
dc.connectionPortOnDevice2 = convertConnectionPort (dc.device2, c.port2);
result.add (dc);
}
return result;
}
Block::ConnectionPort convertConnectionPort (Block::UID uid, BlocksProtocol::ConnectorPort p) noexcept
{
if (auto* info = getDeviceInfoFromUID (uid))
return BlocksProtocol::BlockDataSheet (info->serial).convertPortIndexToConnectorPort (p);
jassertfalse;
return { Block::ConnectionPort::DeviceEdge::north, 0 };
return uid;
}
//==============================================================================
@@ -534,30 +625,79 @@ private:
}
//==============================================================================
juce::Array<DeviceInfo> getArrayOfDeviceInfo (const juce::Array<BlocksProtocol::DeviceStatus>& devices)
BlocksProtocol::VersionNumber getVersionNumber (Block::UID uid)
{
juce::Array<DeviceInfo> result;
const auto version = versionNumbers.find (uid);
return version == versionNumbers.end() ? BlocksProtocol::VersionNumber() : version->second;
}
BlocksProtocol::BlockName getName (Block::UID uid)
{
const auto name = blockNames.find (uid);
return name == blockNames.end() ? BlocksProtocol::BlockName() : name->second;
}
for (auto& device : devices)
//==============================================================================
const DeviceInfo* getDeviceInfoFromUID (Block::UID uid) const noexcept
{
for (auto& d : currentDeviceInfo)
if (d.uid == uid)
return &d;
return nullptr;
}
Block::ConnectionPort convertConnectionPort (Block::UID uid, BlocksProtocol::ConnectorPort p) noexcept
{
if (auto* info = getDeviceInfoFromUID (uid))
return BlocksProtocol::BlockDataSheet (info->serial).convertPortIndexToConnectorPort (p);
jassertfalse;
return { Block::ConnectionPort::DeviceEdge::north, 0 };
}
//==============================================================================
void refreshCurrentDeviceInfo()
{
currentDeviceInfo.clearQuick();
for (auto& device : currentTopologyDevices)
{
BlocksProtocol::VersionNumber version;
BlocksProtocol::BlockName name;
const auto uid = getBlockUIDFromSerialNumber (device.serialNumber);
// For backwards compatibility we assume the first device we see in a group is the master and won't change
if (masterBlock == 0)
const auto uid = getBlockUIDFromSerialNumber (device.serialNumber);
const auto version = getVersionNumber (uid);
const auto name = getName (uid);
// For backwards compatibility we assume the first device we see in a group is the master and won't change
if (masterBlock == 0)
masterBlock = uid;
result.add ({ uid,
device.index,
device.serialNumber,
version,
name,
masterBlock == uid });
currentDeviceInfo.add ({ uid,
device.index,
device.serialNumber,
version,
name,
masterBlock == uid });
}
}
return result;
void refreshCurrentDeviceConnections()
{
currentDeviceConnections.clearQuick();
for (auto&& c : currentTopologyConnections)
{
BlockDeviceConnection dc;
dc.device1 = getDeviceIDFromIndex (c.device1);
dc.device2 = getDeviceIDFromIndex (c.device2);
if (dc.device1 <= 0 || dc.device2 <= 0)
continue;
dc.connectionPortOnDevice1 = convertConnectionPort (dc.device1, c.port1);
dc.connectionPortOnDevice2 = convertConnectionPort (dc.device2, c.port2);
currentDeviceConnections.add (dc);
}
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConnectedDeviceGroup)


+ 128
- 0
modules/juce_blocks_basics/topology/internal/juce_DepreciatedVersionReader.cpp View File

@@ -0,0 +1,128 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
/**
Firmware below 0.2.5 does not report its version over the Blocks API.
This class can make requests and process responses to retreive the master Block version.
*/
class DepreciatedVersionReader : private MIDIDeviceConnection::Listener,
private Timer
{
public:
//==============================================================================
DepreciatedVersionReader (MIDIDeviceConnection& deviceConnectionToUse)
: deviceConnection (deviceConnectionToUse)
{
deviceConnection.addListener (this);
startTimer (10);
}
//==============================================================================
~DepreciatedVersionReader()
{
deviceConnection.removeListener (this);
}
//==============================================================================
BlocksProtocol::VersionNumber getVersionNumber()
{
if (! allRequestsComplete())
return {};
auto highestVersion = result[0];
for (size_t i = 1; i < numFirmwareApps; ++i)
{
const BlocksVersion highest { asString (highestVersion) };
const BlocksVersion test { asString ( result[i]) };
if (highest < test)
highestVersion = result[i];
}
return highestVersion;
}
private:
//==============================================================================
static constexpr size_t numFirmwareApps = 3;
BlocksProtocol::VersionNumber result[numFirmwareApps];
MIDIDeviceConnection& deviceConnection;
size_t currentRequest = 0;
//==============================================================================
bool allRequestsComplete() const { return currentRequest >= numFirmwareApps; }
//==============================================================================
void makeNextRequest()
{
static constexpr size_t requestSize { 8 };
static constexpr uint8 requests[][requestSize] = {{ 0xf0, 0x00, 0x21, 0x10, 0x47, 0x03, 0x00, 0xf7 }, // Main App
{ 0xf0, 0x00, 0x21, 0x10, 0x47, 0x03, 0x01, 0xf7 }, // Stm32
{ 0xf0, 0x00, 0x21, 0x10, 0x47, 0x03, 0x03, 0xf7 }}; // Bootloader
deviceConnection.sendMessageToDevice (&requests[currentRequest][0], requestSize);
}
//==============================================================================
void processVersionMessage (const uint8* data, const size_t size)
{
if (currentRequest >= numFirmwareApps || size < 1 || size - 1 > VersionNumber::maxLength)
return;
result[currentRequest].length = uint8 (size - 1);
memcpy (result[currentRequest].data, data, result[currentRequest].length);
++currentRequest;
allRequestsComplete() ? stopTimer() : startTimer (10);
}
//==============================================================================
void handleIncomingMidiMessage (const MidiMessage& message) override
{
const uint8 roliVersionHeader[] = { 0xf0, 0x00, 0x21, 0x10, 0x47, 0x03 };
const auto headerSize = sizeof (roliVersionHeader);
const auto data = message.getRawData();
const auto size = size_t (message.getRawDataSize());
if (memcmp (data, roliVersionHeader, headerSize) == 0)
processVersionMessage (data + headerSize, size - headerSize);
}
void connectionBeingDeleted (const MIDIDeviceConnection&) override {}
//==============================================================================
void timerCallback() override
{
startTimer (200);
makeNextRequest();
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DepreciatedVersionReader)
};
} // namespace juce

+ 5
- 4
modules/juce_blocks_basics/topology/internal/juce_Detector.cpp View File

@@ -36,20 +36,20 @@ namespace
static bool versionNumberChanged (const DeviceInfo& device, juce::String version) noexcept
{
auto deviceVersion = device.version.asString();
auto deviceVersion = asString (device.version);
return deviceVersion != version && deviceVersion.isNotEmpty();
}
static void setVersionNumberForBlock (const DeviceInfo& deviceInfo, Block& block) noexcept
{
jassert (deviceInfo.uid == block.uid);
block.versionNumber = deviceInfo.version.asString();
block.versionNumber = asString (deviceInfo.version);
}
static void setNameForBlock (const DeviceInfo& deviceInfo, Block& block)
{
jassert (deviceInfo.uid == block.uid);
block.name = deviceInfo.name.asString();
block.name = asString (deviceInfo.name);
}
}
@@ -465,7 +465,7 @@ private:
if (versionNumberChanged (updatedInfo, blockToUpdate->versionNumber))
setVersionNumberForBlock (updatedInfo, *blockToUpdate);
if (updatedInfo.name.isValid())
if (updatedInfo.name.isNotEmpty())
setNameForBlock (updatedInfo, *blockToUpdate);
if (updatedInfo.isMaster != blockToUpdate->isMasterBlock())
@@ -692,6 +692,7 @@ private:
}
}
//==============================================================================
JUCE_DECLARE_WEAK_REFERENCEABLE (Detector)
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Detector)
};


+ 1
- 1
modules/juce_blocks_basics/topology/internal/juce_MidiDeviceConnection.cpp View File

@@ -76,7 +76,7 @@ struct MIDIDeviceConnection : public PhysicalTopologySource::DeviceConnection,
JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED // This method must only be called from the message thread!
jassert (dataSize > sizeof (BlocksProtocol::roliSysexHeader) + 2);
jassert (memcmp (data, BlocksProtocol::roliSysexHeader, sizeof (BlocksProtocol::roliSysexHeader)) == 0);
jassert (memcmp (data, BlocksProtocol::roliSysexHeader, sizeof (BlocksProtocol::roliSysexHeader) - 1) == 0);
jassert (static_cast<const uint8*> (data)[dataSize - 1] == 0xf7);
if (midiOutput != nullptr)


+ 13
- 0
modules/juce_blocks_basics/topology/juce_PhysicalTopologySource.cpp View File

@@ -25,6 +25,7 @@
#define LOG_BLOCKS_CONNECTIVITY 0
#define LOG_BLOCKS_PINGS 0
#define DUMP_BANDWIDTH_STATS 0
#define DUMP_TOPOLOGY 0
#define TOPOLOGY_LOG(text) \
JUCE_BLOCK_WITH_FORCED_SEMICOLON (juce::String buf ("Topology Src: "); \
@@ -46,9 +47,21 @@
#include "internal/juce_BandwidthStatsLogger.cpp"
#endif
namespace
{
/** Helper function to create juce::String from BlockStringData */
template <size_t MaxSize>
juce::String asString (juce::BlocksProtocol::BlockStringData<MaxSize> blockString)
{
return { reinterpret_cast<const char*> (blockString.data),
juce::jmin (sizeof (blockString.data), static_cast<size_t> (blockString.length))};
}
}
#include "internal/juce_MidiDeviceConnection.cpp"
#include "internal/juce_MIDIDeviceDetector.cpp"
#include "internal/juce_DeviceInfo.cpp"
#include "internal/juce_DepreciatedVersionReader.cpp"
#include "internal/juce_ConnectedDeviceGroup.cpp"
#include "internal/juce_BlockImplementation.cpp"
#include "internal/juce_Detector.cpp"


Loading…
Cancel
Save