From bc58525b4897e2ba1ea8472fe29dea9612c883ab Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Mon, 8 Dec 2025 20:50:08 +0100 Subject: [PATCH 1/5] #26 Allow connecting through HTTP server * Added additional string parameter 'connection_state'. Allow modifying it through the HTTP config interface to connect/disconnect the socket --- Source/EphysSocket.cpp | 57 ++++++++++++++++++++++++++++++++++-------- Source/EphysSocket.h | 29 ++++++++++++--------- 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/Source/EphysSocket.cpp b/Source/EphysSocket.cpp index b8c353b..1031bfc 100644 --- a/Source/EphysSocket.cpp +++ b/Source/EphysSocket.cpp @@ -42,18 +42,20 @@ void EphysSocket::registerParameters() addFloatParameter (Parameter::PROCESSOR_SCOPE, "sample_rate", "Sample Rate", "Sample rate of incoming data", "Hz", DEFAULT_SAMPLE_RATE, MIN_SAMPLE_RATE, MAX_SAMPLE_RATE, 1.0f); addFloatParameter (Parameter::PROCESSOR_SCOPE, "data_scale", "Scale", "Scale of incoming data", "", DEFAULT_DATA_SCALE, MIN_DATA_SCALE, MAX_DATA_SCALE, 0.1f); addFloatParameter (Parameter::PROCESSOR_SCOPE, "data_offset", "Offset", "Offset of incoming data", "", DEFAULT_DATA_OFFSET, MIN_DATA_OFFSET, MAX_DATA_OFFSET, 1.0f); + addStringParameter (Parameter::PROCESSOR_SCOPE, "connection_state", "Connection State", "Set the socket connection state (CONNECTED/DISCONNECTED)", DEFAULT_CONNECTION_STATE); } void EphysSocket::disconnectSocket() { socket.signalThreadShouldExit(); - socket.waitForThreadToExit(1000); + socket.waitForThreadToExit (1000); socket.disconnectSocket(); getParameter ("port")->setEnabled (true); getParameter ("sample_rate")->setEnabled (true); getParameter ("data_scale")->setEnabled (true); getParameter ("data_offset")->setEnabled (true); + getParameter ("connection_state")->setNextValue (CONNECTION_STATE_DISCONNECTED); if (sn->getEditor() != nullptr) // check if headless static_cast (sn->getEditor())->disconnected(); @@ -61,7 +63,9 @@ void EphysSocket::disconnectSocket() bool EphysSocket::connectSocket (bool printOutput) { - if (socket.connectSocket (port, printOutput)) + const bool connected = socket.connectSocket (port, printOutput); + + if (connected) { getParameter ("port")->setEnabled (false); getParameter ("sample_rate")->setEnabled (false); @@ -70,11 +74,11 @@ bool EphysSocket::connectSocket (bool printOutput) if (sn->getEditor() != nullptr) // check if headless static_cast (sn->getEditor())->connected(); - - return true; } - return false; + getParameter ("connection_state")->setNextValue (connected ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED); + + return connected; } bool EphysSocket::errorFlag() @@ -176,6 +180,10 @@ void EphysSocket::parameterValueChanged (Parameter* parameter) { data_offset = (float) parameter->getValue(); } + else if (parameter->getName() == "connection_state") + { + parameter->setNextValue (socket.isConnected() ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED); + } } bool EphysSocket::startAcquisition() @@ -283,17 +291,13 @@ String EphysSocket::handleConfigMessage (const String& msg) // ES OFFSET - Updates the offset to data_offset // ES PORT - Updates the port number that EphysSocket connects to // ES FREQUENCY - Updates the sampling rate + // ES CONNECTED - Updates the connection state if (CoreServices::getAcquisitionStatus()) { return "Ephys Socket plugin cannot update settings while acquisition is active."; } - if (socket.isConnected()) - { - return "Ephys Socket plugin cannot update settings while connected to an active socket."; - } - StringArray parts = StringArray::fromTokens (msg, " ", ""); if (parts.size() > 0) @@ -302,6 +306,11 @@ String EphysSocket::handleConfigMessage (const String& msg) { if (parts.size() == 3) { + if (socket.isConnected() && ! parts[1].equalsIgnoreCase ("CONNECTION_STATE")) + { + return "Ephys Socket plugin cannot update settings while connected to an active socket."; + } + if (parts[1].equalsIgnoreCase ("SCALE")) { float scale = parts[2].getFloatValue(); @@ -354,6 +363,34 @@ String EphysSocket::handleConfigMessage (const String& msg) return "Invalid frequency requested. Frequency can be set between '" + String (MIN_SAMPLE_RATE) + "' and '" + String (MAX_SAMPLE_RATE) + "'"; } + else if (parts[1].equalsIgnoreCase ("CONNECTION_STATE")) + { + bool connected { false }; + const bool connected_state = parts[2].equalsIgnoreCase (CONNECTION_STATE_CONNECTED); + const bool disconnected_state = parts[2].equalsIgnoreCase (CONNECTION_STATE_DISCONNECTED); + + if ((! connected_state) && (! disconnected_state)) + { + LOGC ("Invalid connection state: ", parts[2]); + return String ("Connection state must be ") + CONNECTION_STATE_CONNECTED + " or " + CONNECTION_STATE_CONNECTED; + } + + if (connected_state) + { + LOGC ("Request socket connect"); + connected = connectSocket(); + LOGC (connected ? "Connection success" : "Connection failed"); + } + else + { + LOGC ("Request socket disconnect"); + disconnectSocket(); + LOGC ("Socket disconnected"); + connected = false; + } + + return connected ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED; + } else { return "ES command " + parts[1] + "not recognized."; diff --git a/Source/EphysSocket.h b/Source/EphysSocket.h index e15ef07..bcb71cd 100644 --- a/Source/EphysSocket.h +++ b/Source/EphysSocket.h @@ -11,21 +11,26 @@ namespace EphysSocketNode class EphysSocket : public DataThread { public: + /** Connection states */ + static const constexpr char const* CONNECTION_STATE_CONNECTED { "CONNECTED" }; + static const constexpr char const* CONNECTION_STATE_DISCONNECTED { "DISCONNECTED" }; + /** Default parameters */ - const int DEFAULT_PORT = 9001; - const float DEFAULT_SAMPLE_RATE = 30000.0f; - const float DEFAULT_DATA_SCALE = 1.0f; // 0.195f for Intan devices - const float DEFAULT_DATA_OFFSET = 0.0f; // 32768.0f for Intan devices + static constexpr int DEFAULT_PORT { 9001 }; + static constexpr float DEFAULT_SAMPLE_RATE { 30000.0f }; + static constexpr float DEFAULT_DATA_SCALE { 1.0f }; // 0.195f for Intan devices + static constexpr float DEFAULT_DATA_OFFSET { 0.0f }; // 32768.0f for Intan devices + static constexpr char const* DEFAULT_CONNECTION_STATE { CONNECTION_STATE_DISCONNECTED }; /** Parameter limits */ - const float MIN_DATA_SCALE = 0.0f; - const float MAX_DATA_SCALE = 9999.9f; - const float MIN_DATA_OFFSET = 0; - const float MAX_DATA_OFFSET = 65536; - const float MIN_PORT = 1023; - const float MAX_PORT = 65535; - const float MIN_SAMPLE_RATE = 0; - const float MAX_SAMPLE_RATE = 50000.0f; + static constexpr float MIN_DATA_SCALE { 0.0f }; + static constexpr float MAX_DATA_SCALE { 9999.9f }; + static constexpr float MIN_DATA_OFFSET { 0 }; + static constexpr float MAX_DATA_OFFSET { 65536 }; + static constexpr float MIN_PORT { 1023 }; + static constexpr float MAX_PORT { 65535 }; + static constexpr float MIN_SAMPLE_RATE { 0 }; + static constexpr float MAX_SAMPLE_RATE { 50000.0f }; /** Constructor */ EphysSocket (SourceNode* sn); From 67afee3b28ee7903be49d07c8143af6b2de7bf01 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 10 Dec 2025 17:45:16 +0100 Subject: [PATCH 2/5] #26 Allow connecting through HTTP server * Cleanup and a small clarification --- Source/EphysSocket.cpp | 6 +++++- Source/EphysSocket.h | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Source/EphysSocket.cpp b/Source/EphysSocket.cpp index 1031bfc..b953042 100644 --- a/Source/EphysSocket.cpp +++ b/Source/EphysSocket.cpp @@ -48,7 +48,7 @@ void EphysSocket::registerParameters() void EphysSocket::disconnectSocket() { socket.signalThreadShouldExit(); - socket.waitForThreadToExit (1000); + socket.waitForThreadToExit(1000); socket.disconnectSocket(); getParameter ("port")->setEnabled (true); @@ -182,6 +182,10 @@ void EphysSocket::parameterValueChanged (Parameter* parameter) } else if (parameter->getName() == "connection_state") { + // This is mainly useful when the application settings have + // for some reason saved connection_state DISCONNECTED. At + // startup, the connection state will be synced with the actual + // state of the socket parameter->setNextValue (socket.isConnected() ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED); } } diff --git a/Source/EphysSocket.h b/Source/EphysSocket.h index bcb71cd..a53be2f 100644 --- a/Source/EphysSocket.h +++ b/Source/EphysSocket.h @@ -12,8 +12,8 @@ class EphysSocket : public DataThread { public: /** Connection states */ - static const constexpr char const* CONNECTION_STATE_CONNECTED { "CONNECTED" }; - static const constexpr char const* CONNECTION_STATE_DISCONNECTED { "DISCONNECTED" }; + static const constexpr char* CONNECTION_STATE_CONNECTED { "CONNECTED" }; + static const constexpr char* CONNECTION_STATE_DISCONNECTED { "DISCONNECTED" }; /** Default parameters */ static constexpr int DEFAULT_PORT { 9001 }; From 7b035a012ea961499b0dfb4cd04ce5c752797cc0 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Wed, 10 Dec 2025 17:50:58 +0100 Subject: [PATCH 3/5] #26 Allow connecting through HTTP server * Cleanup --- Source/EphysSocket.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/EphysSocket.h b/Source/EphysSocket.h index a53be2f..e2d0c76 100644 --- a/Source/EphysSocket.h +++ b/Source/EphysSocket.h @@ -39,7 +39,7 @@ class EphysSocket : public DataThread ~EphysSocket(); /** Creates custom editor */ - std::unique_ptr createEditor (SourceNode* sn); + std::unique_ptr createEditor (SourceNode* sn) override; /** Create the DataThread object*/ static DataThread* createDataThread (SourceNode* sn); @@ -56,13 +56,13 @@ class EphysSocket : public DataThread OwnedArray* spikeChannels, OwnedArray* sourceStreams, OwnedArray* devices, - OwnedArray* configurationObjects); + OwnedArray* configurationObjects) override; /** Handles parameter value changes */ void parameterValueChanged (Parameter* parameter) override; /** Resizes buffers when input parameters are changed*/ - void resizeBuffers(); + void resizeBuffers() override; /** Disconnects the socket */ void disconnectSocket(); From 2db832514935317d84c24a9427f3c34bfa6a6ead Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Mon, 15 Dec 2025 10:37:55 +0100 Subject: [PATCH 4/5] #26 Allow connecting through HTTP server * Addressing review comments. Removed parameter to simplify code and process of connecting and disconnecting remotely * Update library version --- Source/EphysSocket.cpp | 67 ++++++++++++++--------------------------- Source/EphysSocket.h | 1 - Source/OpenEphysLib.cpp | 2 +- 3 files changed, 24 insertions(+), 46 deletions(-) diff --git a/Source/EphysSocket.cpp b/Source/EphysSocket.cpp index b953042..0c7301f 100644 --- a/Source/EphysSocket.cpp +++ b/Source/EphysSocket.cpp @@ -42,20 +42,18 @@ void EphysSocket::registerParameters() addFloatParameter (Parameter::PROCESSOR_SCOPE, "sample_rate", "Sample Rate", "Sample rate of incoming data", "Hz", DEFAULT_SAMPLE_RATE, MIN_SAMPLE_RATE, MAX_SAMPLE_RATE, 1.0f); addFloatParameter (Parameter::PROCESSOR_SCOPE, "data_scale", "Scale", "Scale of incoming data", "", DEFAULT_DATA_SCALE, MIN_DATA_SCALE, MAX_DATA_SCALE, 0.1f); addFloatParameter (Parameter::PROCESSOR_SCOPE, "data_offset", "Offset", "Offset of incoming data", "", DEFAULT_DATA_OFFSET, MIN_DATA_OFFSET, MAX_DATA_OFFSET, 1.0f); - addStringParameter (Parameter::PROCESSOR_SCOPE, "connection_state", "Connection State", "Set the socket connection state (CONNECTED/DISCONNECTED)", DEFAULT_CONNECTION_STATE); } void EphysSocket::disconnectSocket() { socket.signalThreadShouldExit(); - socket.waitForThreadToExit(1000); + socket.waitForThreadToExit (1000); socket.disconnectSocket(); getParameter ("port")->setEnabled (true); getParameter ("sample_rate")->setEnabled (true); getParameter ("data_scale")->setEnabled (true); getParameter ("data_offset")->setEnabled (true); - getParameter ("connection_state")->setNextValue (CONNECTION_STATE_DISCONNECTED); if (sn->getEditor() != nullptr) // check if headless static_cast (sn->getEditor())->disconnected(); @@ -76,8 +74,6 @@ bool EphysSocket::connectSocket (bool printOutput) static_cast (sn->getEditor())->connected(); } - getParameter ("connection_state")->setNextValue (connected ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED); - return connected; } @@ -180,14 +176,6 @@ void EphysSocket::parameterValueChanged (Parameter* parameter) { data_offset = (float) parameter->getValue(); } - else if (parameter->getName() == "connection_state") - { - // This is mainly useful when the application settings have - // for some reason saved connection_state DISCONNECTED. At - // startup, the connection state will be synced with the actual - // state of the socket - parameter->setNextValue (socket.isConnected() ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED); - } } bool EphysSocket::startAcquisition() @@ -290,12 +278,14 @@ bool EphysSocket::updateBuffer() String EphysSocket::handleConfigMessage (const String& msg) { // Available commands: - // ES INFO - Returns info on current variables that can be modified over HTTP + // ES INFO - Returns info on current variables that can be modified over HTTP // ES SCALE - Updates the data scale to data_scale // ES OFFSET - Updates the offset to data_offset // ES PORT - Updates the port number that EphysSocket connects to // ES FREQUENCY - Updates the sampling rate - // ES CONNECTED - Updates the connection state + // ES CONNECTION_STATE - Returns the connection state (CONNECTED/DISCONNECTED) + // ES CONNECT - Connect the socket + // ES DISCCONNECT - Disconnect the socket if (CoreServices::getAcquisitionStatus()) { @@ -310,7 +300,7 @@ String EphysSocket::handleConfigMessage (const String& msg) { if (parts.size() == 3) { - if (socket.isConnected() && ! parts[1].equalsIgnoreCase ("CONNECTION_STATE")) + if (socket.isConnected()) { return "Ephys Socket plugin cannot update settings while connected to an active socket."; } @@ -367,34 +357,6 @@ String EphysSocket::handleConfigMessage (const String& msg) return "Invalid frequency requested. Frequency can be set between '" + String (MIN_SAMPLE_RATE) + "' and '" + String (MAX_SAMPLE_RATE) + "'"; } - else if (parts[1].equalsIgnoreCase ("CONNECTION_STATE")) - { - bool connected { false }; - const bool connected_state = parts[2].equalsIgnoreCase (CONNECTION_STATE_CONNECTED); - const bool disconnected_state = parts[2].equalsIgnoreCase (CONNECTION_STATE_DISCONNECTED); - - if ((! connected_state) && (! disconnected_state)) - { - LOGC ("Invalid connection state: ", parts[2]); - return String ("Connection state must be ") + CONNECTION_STATE_CONNECTED + " or " + CONNECTION_STATE_CONNECTED; - } - - if (connected_state) - { - LOGC ("Request socket connect"); - connected = connectSocket(); - LOGC (connected ? "Connection success" : "Connection failed"); - } - else - { - LOGC ("Request socket disconnect"); - disconnectSocket(); - LOGC ("Socket disconnected"); - connected = false; - } - - return connected ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED; - } else { return "ES command " + parts[1] + "not recognized."; @@ -406,6 +368,23 @@ String EphysSocket::handleConfigMessage (const String& msg) { return "Port = " + String (port) + ". Sample rate = " + String (sample_rate) + "Scale = " + String (data_scale) + ". Offset = " + String (data_offset) + "."; } + else if (parts[1].equalsIgnoreCase ("CONNECTION_STATUS")) + { + return socket.isConnected() ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED; + } + else if (parts[1].equalsIgnoreCase ("CONNECT")) + { + LOGC ("Request socket connect"); + const auto connected = connectSocket(); + LOGC (connected ? "Connection success" : "Connection failed"); + return connected ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED; + } + else if (parts[1].equalsIgnoreCase ("DISCONNECT")) + { + disconnectSocket(); + LOGC ("Socket disconnected"); + return CONNECTION_STATE_DISCONNECTED; + } else { return "ES command " + parts[1] + "not recognized."; diff --git a/Source/EphysSocket.h b/Source/EphysSocket.h index e2d0c76..6f6cd86 100644 --- a/Source/EphysSocket.h +++ b/Source/EphysSocket.h @@ -20,7 +20,6 @@ class EphysSocket : public DataThread static constexpr float DEFAULT_SAMPLE_RATE { 30000.0f }; static constexpr float DEFAULT_DATA_SCALE { 1.0f }; // 0.195f for Intan devices static constexpr float DEFAULT_DATA_OFFSET { 0.0f }; // 32768.0f for Intan devices - static constexpr char const* DEFAULT_CONNECTION_STATE { CONNECTION_STATE_DISCONNECTED }; /** Parameter limits */ static constexpr float MIN_DATA_SCALE { 0.0f }; diff --git a/Source/OpenEphysLib.cpp b/Source/OpenEphysLib.cpp index f2c7f8c..c9e7100 100644 --- a/Source/OpenEphysLib.cpp +++ b/Source/OpenEphysLib.cpp @@ -38,7 +38,7 @@ extern "C" EXPORT void getLibInfo (Plugin::LibraryInfo* info) { info->apiVersion = PLUGIN_API_VER; info->name = "Ephys Socket"; - info->libVersion = "1.0.0"; + info->libVersion = "1.1.0"; info->numPlugins = NUM_PLUGINS; } From 586bf9684d96f18b046bf7f5e8c15f20d0ad9149 Mon Sep 17 00:00:00 2001 From: Timon Zijnge Date: Mon, 15 Dec 2025 10:44:54 +0100 Subject: [PATCH 5/5] #26 Allow connecting through HTTP server * revert unrelated changes --- Source/EphysSocket.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/EphysSocket.cpp b/Source/EphysSocket.cpp index 0c7301f..ee7dbc3 100644 --- a/Source/EphysSocket.cpp +++ b/Source/EphysSocket.cpp @@ -61,9 +61,7 @@ void EphysSocket::disconnectSocket() bool EphysSocket::connectSocket (bool printOutput) { - const bool connected = socket.connectSocket (port, printOutput); - - if (connected) + if (socket.connectSocket (port, printOutput)) { getParameter ("port")->setEnabled (false); getParameter ("sample_rate")->setEnabled (false); @@ -72,9 +70,11 @@ bool EphysSocket::connectSocket (bool printOutput) if (sn->getEditor() != nullptr) // check if headless static_cast (sn->getEditor())->connected(); + + return true; } - return connected; + return false; } bool EphysSocket::errorFlag()