Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor grid state management and add grid mirror mode #176

Merged
merged 7 commits into from
Sep 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/common/core/ActionQueue.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include "rack.hpp"
#include <functional>

typedef std::function<void(void)> Action;
typedef rack::dsp::RingBuffer<Action, 4> ActionQueue;
18 changes: 7 additions & 11 deletions src/common/core/GridConnection/GridConnection.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
#include "GridConnection.hpp"

Grid::~Grid()
{
}

void GridConnectionManager::registerGrid(Grid* grid)
{
grids.insert(grid);

// Check if there's a consumer with a saved connection looking for this grid
GridConsumer* consumerToConnect = nullptr;
IGridConsumer* consumerToConnect = nullptr;
for (auto consumer : consumers)
{
if (!isConnected(consumer) && grid->getDevice().id == consumer->gridGetLastDeviceId(true))
Expand All @@ -25,7 +21,7 @@ void GridConnectionManager::registerGrid(Grid* grid)
}
}

void GridConnectionManager::registerGridConsumer(GridConsumer* consumer)
void GridConnectionManager::registerGridConsumer(IGridConsumer* consumer)
{
consumers.insert(consumer);

Expand Down Expand Up @@ -66,13 +62,13 @@ void GridConnectionManager::deregisterGrid(std::string id, bool deleteGrid)
}
}

void GridConnectionManager::deregisterGridConsumer(GridConsumer* consumer)
void GridConnectionManager::deregisterGridConsumer(IGridConsumer* consumer)
{
disconnect(consumer);
consumers.erase(consumer);
}

void GridConnectionManager::connect(Grid* grid, GridConsumer* consumer)
void GridConnectionManager::connect(Grid* grid, IGridConsumer* consumer)
{
disconnect(consumer, true);
disconnect(grid, true);
Expand All @@ -82,7 +78,7 @@ void GridConnectionManager::connect(Grid* grid, GridConsumer* consumer)
consumer->gridConnected(grid);
}

bool GridConnectionManager::isConnected(GridConsumer* consumer)
bool GridConnectionManager::isConnected(IGridConsumer* consumer)
{
return consumerToGridMap.find(consumer) != consumerToGridMap.end();
}
Expand All @@ -100,15 +96,15 @@ void GridConnectionManager::disconnect(Grid* grid, bool ownerChanged)
auto iter = idToConsumerMap.find(grid->getDevice().id);
if (iter != idToConsumerMap.end())
{
GridConsumer* consumer = iter->second;
auto consumer = iter->second;
consumer->gridDisconnected(ownerChanged);
idToConsumerMap.erase(grid->getDevice().id);
consumerToGridMap.erase(consumer);
}
}
}

void GridConnectionManager::disconnect(GridConsumer* consumer, bool ownerChanged)
void GridConnectionManager::disconnect(IGridConsumer* consumer, bool ownerChanged)
{
if (consumer)
{
Expand Down
24 changes: 14 additions & 10 deletions src/common/core/GridConnection/GridConnection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,40 @@ struct SerialOscInterface;

struct Grid
{
virtual ~Grid();
virtual ~Grid() {}
virtual const MonomeDevice& getDevice() = 0;
virtual void updateRow(int x_offset, int y, uint8_t bitfield) = 0;
virtual void updateQuadrant(int x, int y, uint8_t* leds) = 0;
virtual void updateRing(int n, uint8_t leds[64]) = 0;
virtual void clearAll() = 0;
virtual bool isHardware() = 0;
};

struct GridConsumer
struct IGridConsumer
{
virtual ~IGridConsumer() {}
virtual void gridConnected(Grid* grid) = 0;
virtual void gridDisconnected(bool ownerChanged) = 0;
virtual std::string gridGetCurrentDeviceId() = 0;
virtual std::string gridGetLastDeviceId(bool owned) = 0;
virtual void gridButtonEvent(int x, int y, bool state) = 0;
virtual void encDeltaEvent(int n, int d) = 0;
virtual Grid* gridGetDevice() = 0;
};

struct GridConnectionManager final
{
// Only call these from the UI thread
void registerGrid(Grid* grid);
void registerGridConsumer(GridConsumer* consumer);
void registerGridConsumer(IGridConsumer* consumer);
void deregisterGrid(std::string id, bool deleteGrid = false);
void deregisterGridConsumer(GridConsumer* consumer);
void deregisterGridConsumer(IGridConsumer* consumer);

void connect(Grid* grid, GridConsumer* consumer);
bool isConnected(GridConsumer* consumer);
void connect(Grid* grid, IGridConsumer* consumer);
bool isConnected(IGridConsumer* consumer);
bool isConnected(std::string id);
void disconnect(Grid* grid, bool ownerChanged = false);
void disconnect(GridConsumer* consumer, bool ownerChanged = false);
void disconnect(IGridConsumer* consumer, bool ownerChanged = false);

void dispatchButtonMessage(MonomeDevice* device, int x, int y, bool state);
void dispatchEncDeltaMessage(MonomeDevice* device, int n, int d);
Expand All @@ -54,8 +58,8 @@ struct GridConnectionManager final
GridConnectionManager(GridConnectionManager&&) = delete;
GridConnectionManager&& operator=(const GridConnectionManager&&) = delete;

std::set<GridConsumer*> consumers;
std::set<IGridConsumer*> consumers;
std::set<Grid*> grids;
std::map<std::string, GridConsumer*> idToConsumerMap;
std::map<GridConsumer*, Grid*> consumerToGridMap;
std::map<std::string, IGridConsumer*> idToConsumerMap;
std::map<IGridConsumer*, Grid*> consumerToGridMap;
};
126 changes: 126 additions & 0 deletions src/common/core/GridConnection/GridConnectionMenu.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#include "GridConnectionMenu.hpp"
#include "SerialOscInterface.hpp"

using namespace rack;

struct NewConnectGridItem : rack::ui::MenuItem
{
Grid* grid;
IGridConsumer* consumer;
ActionQueue* actionQueue;

void onAction(const rack::event::Action& e) override
{
if (actionQueue)
{
auto thisGrid = grid;
auto thisConsumer = consumer;

actionQueue->push([thisGrid, thisConsumer]()
{ GridConnectionManager::get().connect(thisGrid, thisConsumer); });
}
}
};

void menuUserReacquireGrid(IGridConsumer* consumer, std::string lastDeviceId, ActionQueue* actionQueue)
{
for (Grid* grid : GridConnectionManager::get().getGrids())
{
if (lastDeviceId == grid->getDevice().id)
{
if (actionQueue)
{
actionQueue->push([grid, consumer]()
{
GridConnectionManager::get().connect(grid, consumer);
}
);
}
return;
}
}
}

void appendDeviceConnectionMenu(rack::Menu* menu, IGridConsumer* consumer, ActionQueue* actionQueue, bool hardwareOnly)
{
std::string currentConnectedDeviceId = consumer->gridGetCurrentDeviceId();
std::string lastConnectedDeviceId = consumer->gridGetLastDeviceId(false);

menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Device Connection"));

if (SerialOscInterface::get()->isServiceDetected())
{
menu->addChild(
construct<MenuLabel>(
&MenuLabel::text,
"serialosc version " + SerialOscInterface::get()->getServiceVersion()));
}
else
{
menu->addChild(
createMenuItem("└ serialosc service not detected, click here to install", "",
[=]()
{
system::openBrowser("https://monome.org/docs/serialosc/setup/");
}));
}

// enumerate registered grid devices
int deviceCount = 0;
bool preferredDeviceFound = false;
for (Grid* grid : GridConnectionManager::get().getGrids())
{
if (hardwareOnly && !grid->isHardware())
{
continue;
}

auto connectItem = new NewConnectGridItem();
connectItem->text = "└ " + grid->getDevice().type + " (" + grid->getDevice().id + ") ";

auto rightText = "";
if (currentConnectedDeviceId == grid->getDevice().id)
{
rightText = "✔";
preferredDeviceFound = true;
}
else if (currentConnectedDeviceId == "" && lastConnectedDeviceId == grid->getDevice().id)
{
rightText = "⋯";
preferredDeviceFound = true;
}

connectItem->rightText = rightText;
connectItem->grid = grid;
connectItem->actionQueue = actionQueue;
connectItem->consumer = consumer;

menu->addChild(connectItem);
deviceCount++;
}

if (deviceCount == 0)
{
std::string message = hardwareOnly ? "no hardware devices found" : "no hardware or virtual devices found";
menu->addChild(construct<MenuLabel>(&MenuLabel::text, " (" + message + ")"));
}

if (currentConnectedDeviceId == "" && lastConnectedDeviceId != "")
{
if (preferredDeviceFound)
{
menu->addChild(createMenuItem("Reacquire grid", "", [=]()
{
if (lastConnectedDeviceId != "")
{
menuUserReacquireGrid(consumer, lastConnectedDeviceId, actionQueue);
}
}
));
}
else
{
menu->addChild(construct<MenuLabel>(&MenuLabel::text, "Can't reacquire grid (" + lastConnectedDeviceId + " not found)"));
}
}
}
7 changes: 7 additions & 0 deletions src/common/core/GridConnection/GridConnectionMenu.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#pragma once

#include "rack.hpp"
#include "GridConnection.hpp"
#include "ActionQueue.hpp"

void appendDeviceConnectionMenu(rack::Menu* menu, IGridConsumer* consumer, ActionQueue* queue, bool hardwareOnly = false);
106 changes: 106 additions & 0 deletions src/common/core/GridConnection/GridConsumerBase.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "GridConsumerBase.hpp"

GridConsumerBase::GridConsumerBase()
: lastConnectedDeviceId("")
, currentConnectedDeviceId("")
, gridConnection(nullptr)
{

}

void GridConsumerBase::gridConnected(Grid* newConnection)
{
gridConnection = newConnection;
if (gridConnection)
{
std::string id = gridConnection->getDevice().id;
lastConnectedDeviceId = id;
currentConnectedDeviceId = id;
connectionOwned = true;
}
}

void GridConsumerBase::gridDisconnected(bool ownerChanged)
{
gridConnection = nullptr;
currentConnectedDeviceId = "";

if (ownerChanged)
{
connectionOwned = false;
}
}

std::string GridConsumerBase::gridGetCurrentDeviceId()
{
return currentConnectedDeviceId;
}

std::string GridConsumerBase::gridGetLastDeviceId(bool owned)
{
if (owned && !connectionOwned)
{
return "";
}

return lastConnectedDeviceId;
}

Grid* GridConsumerBase::gridGetDevice()
{
return gridConnection;
}

void GridConsumerBase::userReacquireGrid()
{
if (lastConnectedDeviceId != "" && gridConnection == nullptr)
{
for (Grid* grid : GridConnectionManager::get().getGrids())
{
if (gridGetLastDeviceId(false) == grid->getDevice().id)
{
GridConnectionManager::get().connect(grid, this);
return;
}
}
}
}

void GridConsumerBase::toggleGridConnection(Grid* grid)
{
if (gridConnection == grid)
{
GridConnectionManager::get().disconnect(this, true);
lastConnectedDeviceId = "";
}
else
{
GridConnectionManager::get().connect(grid, this);
}
}

void GridConsumerBase::saveGridConnectionToJson(json_t* rootJ)
{
std::string deviceId = lastConnectedDeviceId;
if (gridConnection)
{
deviceId = gridConnection->getDevice().id;
}
json_object_set_new(rootJ, "connectedDeviceId", json_string(deviceId.c_str()));
json_object_set_new(rootJ, "connectionOwned", json_boolean(connectionOwned));
}

void GridConsumerBase::loadGridConnectionFromJson(json_t* rootJ)
{
json_t* id = json_object_get(rootJ, "connectedDeviceId");
if (id)
{
lastConnectedDeviceId = json_string_value(id);
}

json_t* owned = json_object_get(rootJ, "connectionOwned");
if (owned)
{
connectionOwned = json_boolean_value(owned);
}
}
Loading