Skip to content

Commit

Permalink
Merge branch 'task/diagnostics' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
christophe-calmejane committed Apr 1, 2022
2 parents 41dfedf + ca663f2 commit 3352d51
Show file tree
Hide file tree
Showing 39 changed files with 1,021 additions and 112 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Possibility to push a news feed to Hive for important notices
- Warning popup for _Media Clock Management Dialog_ domain SampleRate changes that conflict with entity current StreamFormat settings
- Distinction between _Milan Compatible_ and _Milan Certified_ devices using new icons
- Steam Input Diagnostic: Detection of MSRP latency greater than Talker's presentation time
- Milan Redundancy Warning Diagnostic: Detection of both cables connected to the same network
- Added _Milan Warning_ Protocol Compatibility value, for Milan devices that have non-critical specification implementation errors

### Changed
- [Control descriptors now use a SpinBox instead of a ComboBox for improved performance and usability](https://github.com/christophe-calmejane/Hive/issues/116)
Expand Down
12 changes: 12 additions & 0 deletions include/hive/modelsLibrary/controllerManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,17 @@ class ControllerManager : public QObject
virtual StreamInputErrorCounters getStreamInputErrorCounters(la::avdecc::UniqueIdentifier const entityID, la::avdecc::entity::model::StreamIndex const streamIndex) const noexcept = 0;
virtual void clearStreamInputCounterValidFlags(la::avdecc::UniqueIdentifier const entityID, la::avdecc::entity::model::StreamIndex const streamIndex, la::avdecc::entity::StreamInputCounterValidFlag const flag) noexcept = 0;
virtual void clearAllStreamInputCounterValidFlags(la::avdecc::UniqueIdentifier const entityID) noexcept = 0;

/** Statistics */
virtual StatisticsErrorCounters getStatisticsCounters(la::avdecc::UniqueIdentifier const entityID) const noexcept = 0;
virtual void clearStatisticsCounterValidFlags(la::avdecc::UniqueIdentifier const entityID, StatisticsErrorCounterFlag const flag) noexcept = 0;
virtual void clearAllStatisticsCounterValidFlags(la::avdecc::UniqueIdentifier const entityID) noexcept = 0;

/** Diagnostics */
virtual la::avdecc::controller::ControlledEntity::Diagnostics getDiagnostics(la::avdecc::UniqueIdentifier const entityID) const noexcept = 0;
virtual bool isRedundancyWarning(la::avdecc::UniqueIdentifier const entityID) const noexcept = 0;
virtual bool getStreamInputLatencyError(la::avdecc::UniqueIdentifier const entityID, la::avdecc::entity::model::StreamIndex const streamIndex) const noexcept = 0;

/* Discovery Protocol (ADP) */
/** Enables entity advertising with available duration included between 2-62 seconds on the specified interfaceIndex if set, otherwise on all interfaces. */
virtual bool enableEntityAdvertising(std::uint32_t const availableDuration, std::optional<la::avdecc::entity::model::AvbInterfaceIndex> const interfaceIndex = std::nullopt) noexcept = 0;
Expand Down Expand Up @@ -334,6 +341,11 @@ class ControllerManager : public QObject
Q_SIGNAL void aecpResponseAverageTimeChanged(la::avdecc::UniqueIdentifier const entityID, std::chrono::milliseconds const& value);
Q_SIGNAL void aemAecpUnsolicitedCounterChanged(la::avdecc::UniqueIdentifier const entityID, std::uint64_t const value);
Q_SIGNAL void statisticsErrorCounterChanged(la::avdecc::UniqueIdentifier const entityID, hive::modelsLibrary::ControllerManager::StatisticsErrorCounters const& errorCounters);

/* Diagnostics signals */
Q_SIGNAL void diagnosticsChanged(la::avdecc::UniqueIdentifier const entityID, la::avdecc::controller::ControlledEntity::Diagnostics const& diagnostics);
Q_SIGNAL void redundancyWarningChanged(la::avdecc::UniqueIdentifier const entityID, bool const isRedundancyWarning);
Q_SIGNAL void streamInputLatencyErrorChanged(la::avdecc::UniqueIdentifier const entityID, la::avdecc::entity::model::StreamIndex const streamIndex, bool const isLatencyError);
};

} // namespace modelsLibrary
Expand Down
6 changes: 5 additions & 1 deletion include/hive/modelsLibrary/discoveredEntitiesModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ class DiscoveredEntitiesModel
IEEE,
Milan,
MilanCertified,
MilanWarning,
MilanRedundant,
MilanCertifiedRedundant,
MilanWarningRedundant,
Misbehaving,
};

Expand Down Expand Up @@ -120,7 +122,9 @@ class DiscoveredEntitiesAbstractTableModel : public QAbstractTableModel
enum class ChangedErrorCounterFlag : std::uint32_t
{
Statistics = 1u << 0,
StreamInput = 1u << 1,
RedundancyWarning = 1u << 1,
StreamInputCounters = 1u << 2,
StreamInputLatency = 1u << 3,
};
using ChangedErrorCounterFlags = la::avdecc::utils::EnumBitfield<ChangedErrorCounterFlag>;

Expand Down
229 changes: 173 additions & 56 deletions libs/modelsLibrary/controllerManager.cpp

Large diffs are not rendered by default.

77 changes: 72 additions & 5 deletions libs/modelsLibrary/discoveredEntitiesModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class DiscoveredEntitiesModel::pImpl : public QObject
connect(&controllerManager, &hive::modelsLibrary::ControllerManager::gptpChanged, this, &pImpl::handleGptpChanged);
connect(&controllerManager, &hive::modelsLibrary::ControllerManager::streamInputErrorCounterChanged, this, &pImpl::handleStreamInputErrorCounterChanged);
connect(&controllerManager, &hive::modelsLibrary::ControllerManager::statisticsErrorCounterChanged, this, &pImpl::handleStatisticsErrorCounterChanged);
connect(&controllerManager, &hive::modelsLibrary::ControllerManager::diagnosticsChanged, this, &pImpl::handleDiagnosticsChanged);
}

std::optional<std::reference_wrapper<Entity const>> entity(std::size_t const index) const noexcept
Expand Down Expand Up @@ -89,10 +90,12 @@ class DiscoveredEntitiesModel::pImpl : public QObject
struct EntityWithErrorCounter
{
bool statisticsError{ false };
bool redundancyWarning{ false };
std::set<la::avdecc::entity::model::StreamIndex> streamsWithErrorCounter{};
std::set<la::avdecc::entity::model::StreamIndex> streamsWithLatencyError{};
constexpr bool hasError() const noexcept
{
return statisticsError || !streamsWithErrorCounter.empty();
return statisticsError || redundancyWarning || !streamsWithErrorCounter.empty() || !streamsWithLatencyError.empty();
}
};

Expand All @@ -109,6 +112,12 @@ class DiscoveredEntitiesModel::pImpl : public QObject
{
auto const isRedundant = milanInfo && milanInfo->featuresFlags.test(la::avdecc::entity::MilanInfoFeaturesFlag::Redundancy);
auto const isCertifiedV1 = milanInfo && milanInfo->certificationVersion >= 0x01000000;
auto const isWarning = compatibilityFlags.test(la::avdecc::controller::ControlledEntity::CompatibilityFlag::MilanWarning);

if (isWarning)
{
return isRedundant ? ProtocolCompatibility::MilanWarningRedundant : ProtocolCompatibility::MilanWarning;
}

if (isCertifiedV1)
{
Expand Down Expand Up @@ -226,10 +235,12 @@ class DiscoveredEntitiesModel::pImpl : public QObject
// Update the cache
rebuildEntityRowMap();

// Initialize EntityWithError (only need to initialize Statistics which might change during enumeration and not trigger an event, contrary to Counters)
_entitiesWithErrorCounter[entityID].statisticsError = !manager.getStatisticsCounters(entityID).empty();

emit _model->endInsertRows();

// Trigger Error Counters, Statistics and Diagnostics
// TODO: Error Counters
handleStatisticsErrorCounterChanged(entityID, manager.getStatisticsCounters(entityID));
handleDiagnosticsChanged(entityID, manager.getDiagnostics(entityID));
}
}
catch (...)
Expand All @@ -250,6 +261,9 @@ class DiscoveredEntitiesModel::pImpl : public QObject
auto const it = std::next(std::begin(_entities), idx);
_entities.erase(it);

// Wipe Errors
_entitiesWithErrorCounter.erase(entityID);

// Update the cache
rebuildEntityRowMap();

Expand Down Expand Up @@ -487,7 +501,7 @@ class DiscoveredEntitiesModel::pImpl : public QObject
_entitiesWithErrorCounter[entityID].streamsWithErrorCounter.erase(descriptorIndex);
}

la::avdecc::utils::invokeProtectedMethod(&Model::entityErrorCountersChanged, _model, idx, Model::ChangedErrorCounterFlags{ Model::ChangedErrorCounterFlag::StreamInput });
la::avdecc::utils::invokeProtectedMethod(&Model::entityErrorCountersChanged, _model, idx, Model::ChangedErrorCounterFlags{ Model::ChangedErrorCounterFlag::StreamInputCounters });
}
}

Expand All @@ -503,6 +517,59 @@ class DiscoveredEntitiesModel::pImpl : public QObject
}
}

void handleDiagnosticsChanged(la::avdecc::UniqueIdentifier const entityID, la::avdecc::controller::ControlledEntity::Diagnostics const& diagnostics)
{
if (auto const index = indexOf(entityID))
{
auto const idx = *index;

auto const wasRedundancyWarning = _entitiesWithErrorCounter[entityID].redundancyWarning;
auto const wasStreamInputLatencyError = !_entitiesWithErrorCounter[entityID].streamsWithLatencyError.empty();

auto nowRedundancyWarning = false;
auto nowStreamInputLatencyError = false;

// Redundancy Warning
{
_entitiesWithErrorCounter[entityID].redundancyWarning = diagnostics.redundancyWarning;
nowRedundancyWarning = diagnostics.redundancyWarning;
}

// Stream Input Latency Error
{
// Clear previous streamsWithLatencyError values
_entitiesWithErrorCounter[entityID].streamsWithLatencyError.clear();

// Rebuild it entirely
for (auto const& [streamIndex, isError] : diagnostics.streamInputOverLatency)
{
if (isError)
{
_entitiesWithErrorCounter[entityID].streamsWithLatencyError.insert(streamIndex);
nowStreamInputLatencyError = true;
}
}
}

// Check what changed
auto errorCounterFlags = Model::ChangedErrorCounterFlags{};
if (wasRedundancyWarning != nowRedundancyWarning)
{
errorCounterFlags.set(Model::ChangedErrorCounterFlag::RedundancyWarning);
}
if (wasStreamInputLatencyError != nowStreamInputLatencyError)
{
errorCounterFlags.set(Model::ChangedErrorCounterFlag::StreamInputLatency);
}

// Notify if something changed
if (!errorCounterFlags.empty())
{
la::avdecc::utils::invokeProtectedMethod(&Model::entityErrorCountersChanged, _model, idx, errorCounterFlags);
}
}
}

// Private Members
Model* _model{ nullptr };
std::vector<Entity> _entities{};
Expand Down
11 changes: 9 additions & 2 deletions libs/widgetModelsLibrary/discoveredEntitiesTableModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,23 @@ static std::unordered_map<modelsLibrary::DiscoveredEntitiesModel::ProtocolCompat
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::IEEE, QImage{ ":/ieee.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::Milan, QImage{ ":/Milan_Compatible.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanCertified, QImage{ ":/Milan_Certified.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::Misbehaving, QImage{ ":/misbehaving.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanWarning, QImage{ ":/Milan_Compatible_Warning.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanRedundant, QImage{ ":/Milan_Redundant_Compatible.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanCertifiedRedundant, QImage{ ":/Milan_Redundant_Certified.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanWarningRedundant, QImage{ ":/Milan_Redundant_Compatible_Warning.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::Misbehaving, QImage{ ":/misbehaving.png" } },
};

static std::unordered_map<modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility, QImage> s_compatibilityImagesDark{
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::NotCompliant, QImage{ ":/not_compliant.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::IEEE, QImage{ ":/ieee.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::Milan, QImage{ ":/Milan_Compatible_inv.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanCertified, QImage{ ":/Milan_Certified_inv.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::Misbehaving, QImage{ ":/misbehaving.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanWarning, QImage{ ":/Milan_Compatible_Warning_inv.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanRedundant, QImage{ ":/Milan_Redundant_Compatible_inv.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanCertifiedRedundant, QImage{ ":/Milan_Redundant_Certified_inv.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanWarningRedundant, QImage{ ":/Milan_Redundant_Compatible_Warning_inv.png" } },
{ modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::Misbehaving, QImage{ ":/misbehaving.png" } },
};

DiscoveredEntitiesTableModel::DiscoveredEntitiesTableModel(EntityDataFlags const entityDataFlags)
Expand Down Expand Up @@ -265,6 +269,9 @@ QVariant DiscoveredEntitiesTableModel::data(QModelIndex const& index, int role)
case modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanCertified:
case modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanCertifiedRedundant:
return "MILAN certified";
case modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanWarning:
case modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::MilanWarningRedundant:
return "MILAN with warnings";
case modelsLibrary::DiscoveredEntitiesModel::ProtocolCompatibility::IEEE:
return "IEEE 1722.1 compatible";
default:
Expand Down
12 changes: 8 additions & 4 deletions resources/AEMDumper.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@
<file>unlocked.png</file>
<file>locked_by_other.png</file>
<file>lock_not_supported.png</file>
<file>Milan_Certified.png</file>
<file>Milan_Certified_inv.png</file>
<file>Milan_Compatible.png</file>
<file>Milan_Compatible_inv.png</file>
<file>Milan_Redundant_Certified.png</file>
<file>Milan_Redundant_Certified_inv.png</file>
<file>Milan_Certified.png</file>
<file>Milan_Certified_inv.png</file>
<file>Milan_Compatible_Warning.png</file>
<file>Milan_Compatible_Warning_inv.png</file>
<file>Milan_Redundant_Compatible.png</file>
<file>Milan_Redundant_Compatible_inv.png</file>
<file>Milan_Redundant_Certified.png</file>
<file>Milan_Redundant_Certified_inv.png</file>
<file>Milan_Redundant_Compatible_Warning.png</file>
<file>Milan_Redundant_Compatible_Warning_inv.png</file>
<file>ieee.png</file>
<file>not_compliant.png</file>
<file>misbehaving.png</file>
Expand Down
Binary file modified resources/Milan_Certified.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/Milan_Certified_inv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/Milan_Compatible.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/Milan_Compatible_Warning.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/Milan_Compatible_Warning_inv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/Milan_Compatible_inv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/Milan_Redundant_Certified.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/Milan_Redundant_Certified_inv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/Milan_Redundant_Compatible.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/Milan_Redundant_Compatible_Warning.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified resources/Milan_Redundant_Compatible_inv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 8 additions & 4 deletions resources/main.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@
<file>unlocked.png</file>
<file>locked_by_other.png</file>
<file>lock_not_supported.png</file>
<file>Milan_Certified.png</file>
<file>Milan_Certified_inv.png</file>
<file>Milan_Compatible.png</file>
<file>Milan_Compatible_inv.png</file>
<file>Milan_Redundant_Certified.png</file>
<file>Milan_Redundant_Certified_inv.png</file>
<file>Milan_Certified.png</file>
<file>Milan_Certified_inv.png</file>
<file>Milan_Compatible_Warning.png</file>
<file>Milan_Compatible_Warning_inv.png</file>
<file>Milan_Redundant_Compatible.png</file>
<file>Milan_Redundant_Compatible_inv.png</file>
<file>Milan_Redundant_Certified.png</file>
<file>Milan_Redundant_Certified_inv.png</file>
<file>Milan_Redundant_Compatible_Warning.png</file>
<file>Milan_Redundant_Compatible_Warning_inv.png</file>
<file>ieee.png</file>
<file>not_compliant.png</file>
<file>misbehaving.png</file>
Expand Down
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ set(HEADER_FILES_COMMON
counters/streamInputCountersTreeWidgetItem.hpp
counters/streamOutputCountersTreeWidgetItem.hpp
discoveredEntities/view.hpp
diagnostics/entityDiagnosticsTreeWidgetItem.hpp
diagnostics/streamInputDiagnosticsTreeWidgetItem.hpp
mediaClock/mediaClockManagementDialog.hpp
mediaClock/domainTreeModel.hpp
mediaClock/unassignedListModel.hpp
Expand Down Expand Up @@ -148,6 +150,8 @@ set(SOURCE_FILES_COMMON
counters/streamInputCountersTreeWidgetItem.cpp
counters/streamOutputCountersTreeWidgetItem.cpp
discoveredEntities/view.cpp
diagnostics/entityDiagnosticsTreeWidgetItem.cpp
diagnostics/streamInputDiagnosticsTreeWidgetItem.cpp
mediaClock/mediaClockManagementDialog.cpp
mediaClock/domainTreeModel.cpp
mediaClock/unassignedListModel.cpp
Expand Down
Loading

0 comments on commit 3352d51

Please sign in to comment.