Taking a different tack on proper ordering of routes

This commit is contained in:
Brad Davis 2015-10-23 12:56:03 -07:00
parent 4110324b35
commit 54c20a8dd7
3 changed files with 60 additions and 42 deletions

View file

@ -36,7 +36,6 @@ namespace controller {
using WriteLambda = std::function<void(float)>; using WriteLambda = std::function<void(float)>;
Endpoint(const Input& input) : _input(input) {} Endpoint(const Input& input) : _input(input) {}
virtual uint8_t priority() const { return 0x7f; }
virtual float value() = 0; virtual float value() = 0;
virtual void apply(float newValue, float oldValue, const Pointer& source) = 0; virtual void apply(float newValue, float oldValue, const Pointer& source) = 0;
virtual Pose pose() { return Pose(); } virtual Pose pose() { return Pose(); }

View file

@ -216,9 +216,6 @@ public:
} }
} }
// Process later than normal
virtual uint8_t priority() const override { return 0x6F; }
virtual float value() override { virtual float value() override {
float result = 0; float result = 0;
for (auto& child : _children) { for (auto& child : _children) {
@ -234,7 +231,15 @@ public:
qFatal("AnyEndpoint is read only"); qFatal("AnyEndpoint is read only");
} }
virtual bool writeable() const override { return false; } // AnyEndpoint is used for reading, so return false if any child returns false (has been written to)
virtual bool writeable() const override {
for (auto& child : _children) {
if (!child->writeable()) {
return false;
}
}
return true;
}
virtual bool readable() const override { virtual bool readable() const override {
for (auto& child : _children) { for (auto& child : _children) {
@ -286,13 +291,11 @@ public:
virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { } virtual void apply(const Pose& newValue, const Pose& oldValue, const Pointer& source) override { }
virtual bool writeable() const { return !_written; } virtual bool writeable() const { return false; }
virtual bool readable() const { return !_read; } virtual bool readable() const { return !_read; }
virtual void reset() { _written = _read = false; } virtual void reset() { _read = false; }
private: private:
bool _written { false };
bool _read { false }; bool _read { false };
}; };
@ -695,7 +698,6 @@ void UserInputMapper::runMappings() {
if (debugRoutes) { if (debugRoutes) {
qCDebug(controllers) << "Beginning mapping frame"; qCDebug(controllers) << "Beginning mapping frame";
} }
static auto deviceNames = getDeviceNames();
for (auto endpointEntry : this->_endpointsByInput) { for (auto endpointEntry : this->_endpointsByInput) {
endpointEntry.second->reset(); endpointEntry.second->reset();
} }
@ -704,22 +706,12 @@ void UserInputMapper::runMappings() {
qCDebug(controllers) << "Processing device routes"; qCDebug(controllers) << "Processing device routes";
} }
// Now process the current values for each level of the stack // Now process the current values for each level of the stack
for (const auto& route : _deviceRoutes) { applyRoutes(_deviceRoutes);
if (!route) {
continue;
}
applyRoute(route);
}
if (debugRoutes) { if (debugRoutes) {
qCDebug(controllers) << "Processing standard routes"; qCDebug(controllers) << "Processing standard routes";
} }
for (const auto& route : _standardRoutes) { applyRoutes(_standardRoutes);
if (!route) {
continue;
}
applyRoute(route);
}
if (debugRoutes) { if (debugRoutes) {
qCDebug(controllers) << "Done with mappings"; qCDebug(controllers) << "Done with mappings";
@ -727,21 +719,53 @@ void UserInputMapper::runMappings() {
debugRoutes = false; debugRoutes = false;
} }
void UserInputMapper::applyRoute(const Route::Pointer& route) { // Encapsulate the logic that routes should not be read before they are written
void UserInputMapper::applyRoutes(const Route::List& routes) {
Route::List deferredRoutes;
for (const auto& route : routes) {
if (!route) {
continue;
}
// Try all the deferred routes
deferredRoutes.remove_if([](Route::Pointer route) {
return UserInputMapper::applyRoute(route);
});
if (!applyRoute(route)) {
deferredRoutes.push_back(route);
}
}
bool force = true;
for (const auto& route : deferredRoutes) {
UserInputMapper::applyRoute(route, force);
}
}
bool UserInputMapper::applyRoute(const Route::Pointer& route, bool force) {
if (debugRoutes && route->debug) { if (debugRoutes && route->debug) {
qCDebug(controllers) << "Applying route " << route->json; qCDebug(controllers) << "Applying route " << route->json;
} }
// If the source hasn't been written yet, defer processing of this route
auto source = route->source;
if (!force && source->writeable()) {
return false;
}
if (route->conditional) { if (route->conditional) {
// FIXME for endpoint conditionals we need to check if they've been written
if (!route->conditional->satisfied()) { if (!route->conditional->satisfied()) {
if (debugRoutes && route->debug) { if (debugRoutes && route->debug) {
qCDebug(controllers) << "Conditional failed"; qCDebug(controllers) << "Conditional failed";
} }
return; return true;
} }
} }
auto source = route->source;
// Most endpoints can only be read once (though a given mapping can route them to // Most endpoints can only be read once (though a given mapping can route them to
// multiple places). Consider... If the default is to wire the A button to JUMP // multiple places). Consider... If the default is to wire the A button to JUMP
@ -752,7 +776,7 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
if (debugRoutes && route->debug) { if (debugRoutes && route->debug) {
qCDebug(controllers) << "Source unreadable"; qCDebug(controllers) << "Source unreadable";
} }
return; return true;
} }
auto destination = route->destination; auto destination = route->destination;
@ -762,14 +786,14 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
if (debugRoutes && route->debug) { if (debugRoutes && route->debug) {
qCDebug(controllers) << "Bad Destination"; qCDebug(controllers) << "Bad Destination";
} }
return; return true;
} }
if (!destination->writeable()) { if (!destination->writeable()) {
if (debugRoutes && route->debug) { if (debugRoutes && route->debug) {
qCDebug(controllers) << "Destination unwritable"; qCDebug(controllers) << "Destination unwritable";
} }
return; return true;
} }
// Fetch the value, may have been overriden by previous loopback routes // Fetch the value, may have been overriden by previous loopback routes
@ -805,6 +829,7 @@ void UserInputMapper::applyRoute(const Route::Pointer& route) {
destination->apply(value, 0, source); destination->apply(value, 0, source);
} }
return true;
} }
Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) { Endpoint::Pointer UserInputMapper::endpointFor(const QJSValue& endpoint) {
@ -910,12 +935,12 @@ void UserInputMapper::enableMapping(const QString& mappingName, bool enable) {
} }
} }
float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) const { float UserInputMapper::getValue(const Endpoint::Pointer& endpoint) {
Locker locker(_lock);
return endpoint->value(); return endpoint->value();
} }
float UserInputMapper::getValue(const Input& input) const { float UserInputMapper::getValue(const Input& input) const {
Locker locker(_lock);
auto endpoint = endpointFor(input); auto endpoint = endpointFor(input);
if (!endpoint) { if (!endpoint) {
return 0; return 0;
@ -923,7 +948,7 @@ float UserInputMapper::getValue(const Input& input) const {
return endpoint->value(); return endpoint->value();
} }
Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) const { Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) {
if (!endpoint->isPose()) { if (!endpoint->isPose()) {
return Pose(); return Pose();
} }
@ -931,6 +956,7 @@ Pose UserInputMapper::getPose(const Endpoint::Pointer& endpoint) const {
} }
Pose UserInputMapper::getPose(const Input& input) const { Pose UserInputMapper::getPose(const Input& input) const {
Locker locker(_lock);
auto endpoint = endpointFor(input); auto endpoint = endpointFor(input);
if (!endpoint) { if (!endpoint) {
return Pose(); return Pose();
@ -1207,12 +1233,6 @@ bool hasDebuggableRoute(const T& routes) {
return false; return false;
} }
void sortRoutes(Route::List& routes) {
std::stable_sort(routes.begin(), routes.end(), [](const Route::Pointer a, const Route::Pointer b) {
return a->source->priority() < b->source->priority();
});
}
void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) { void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
Locker locker(_lock); Locker locker(_lock);
@ -1225,14 +1245,12 @@ void UserInputMapper::enableMapping(const Mapping::Pointer& mapping) {
return (value->source->getInput().device != STANDARD_DEVICE); return (value->source->getInput().device != STANDARD_DEVICE);
}); });
_standardRoutes.insert(_standardRoutes.begin(), standardRoutes.begin(), standardRoutes.end()); _standardRoutes.insert(_standardRoutes.begin(), standardRoutes.begin(), standardRoutes.end());
sortRoutes(_standardRoutes);
Route::List deviceRoutes = mapping->routes; Route::List deviceRoutes = mapping->routes;
deviceRoutes.remove_if([](const Route::Pointer& value) { deviceRoutes.remove_if([](const Route::Pointer& value) {
return (value->source->getInput().device == STANDARD_DEVICE); return (value->source->getInput().device == STANDARD_DEVICE);
}); });
_deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end()); _deviceRoutes.insert(_deviceRoutes.begin(), deviceRoutes.begin(), deviceRoutes.end());
sortRoutes(_standardRoutes);
if (!debuggableRoutes) { if (!debuggableRoutes) {
debuggableRoutes = hasDebuggableRoute(_deviceRoutes) || hasDebuggableRoute(_standardRoutes); debuggableRoutes = hasDebuggableRoute(_deviceRoutes) || hasDebuggableRoute(_standardRoutes);

View file

@ -136,14 +136,15 @@ namespace controller {
int recordDeviceOfType(const QString& deviceName); int recordDeviceOfType(const QString& deviceName);
QHash<const QString&, int> _deviceCounts; QHash<const QString&, int> _deviceCounts;
float getValue(const EndpointPointer& endpoint) const; static float getValue(const EndpointPointer& endpoint);
Pose getPose(const EndpointPointer& endpoint) const; static Pose getPose(const EndpointPointer& endpoint);
friend class RouteBuilderProxy; friend class RouteBuilderProxy;
friend class MappingBuilderProxy; friend class MappingBuilderProxy;
void runMappings(); void runMappings();
void applyRoute(const RoutePointer& route); static void applyRoutes(const RouteList& route);
static bool applyRoute(const RoutePointer& route, bool force = false);
void enableMapping(const MappingPointer& mapping); void enableMapping(const MappingPointer& mapping);
void disableMapping(const MappingPointer& mapping); void disableMapping(const MappingPointer& mapping);
EndpointPointer endpointFor(const QJSValue& endpoint); EndpointPointer endpointFor(const QJSValue& endpoint);