From 45d505b475addaa1651993df8262f4b9ae614497 Mon Sep 17 00:00:00 2001 From: bparks13 Date: Thu, 13 Mar 2025 11:28:32 -0400 Subject: [PATCH 1/2] Gracefully disconnect socket when acquisition stops - If the server was disconnected during acquisition, and the plugin is trying to automatically reconnect, it will now disconnect if acquisition stops to prevent it going into an unrecoverable state - Update the Python script so it waits to initialize the server until after the user provides keyboard input. This prevents the client from connecting, deciding it can't read any data, and disconnecting - Bump version to 0.4.1 --- CMakeLists.txt | 1 + Resources/python-example-tcp.py | 33 +++++++++++++++++++++------------ Source/EphysSocket.cpp | 6 ++++-- Source/OpenEphysLib.cpp | 2 +- Source/SocketThread.cpp | 11 +++++++++-- Source/SocketThread.h | 7 ++++++- 6 files changed, 42 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3776d29..295c20c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ if(MSVC) target_compile_options(${PLUGIN_NAME} PRIVATE /sdl- /W0) install(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION ${GUI_BIN_DIR}/plugins CONFIGURATIONS ${CMAKE_CONFIGURATION_TYPES}) + install(FILES $ DESTINATION ${GUI_BIN_DIR}/plugins OPTIONAL) set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../libs) elseif(LINUX) diff --git a/Resources/python-example-tcp.py b/Resources/python-example-tcp.py index 9c7d3a4..28ed96a 100644 --- a/Resources/python-example-tcp.py +++ b/Resources/python-example-tcp.py @@ -38,14 +38,14 @@ oneCycle = np.concatenate((intList_1, intList_2)) allData = np.tile(oneCycle, (numChannels, totalDuration)).T +# ---- WAIT FOR USER INPUT ---- # +value = input("Press enter key to start...") + # ---- CREATE THE SOCKET SERVER ---- # tcpServer = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM) tcpServer.bind(('localhost', 9001)) tcpServer.listen(1) -# ---- WAIT FOR USER INPUT ---- # -value = input("Press enter key to start...") - print("Waiting for external connection to start...") (tcpClient, address) = tcpServer.accept() print("Connected.") @@ -61,14 +61,23 @@ def currentTime(): return time.time_ns() / (10 ** 9) # ---- STREAM DATA ---- # -while (bufferIndex < totalBytes): - t1 = currentTime() - rc = tcpClient.sendto(header + bytesToSend[bufferIndex:bufferIndex+bytesPerBuffer], address) - t2 = currentTime() - - while ((t2 - t1) < bufferInterval): +try: + while (bufferIndex < totalBytes): + t1 = currentTime() + rc = tcpClient.sendto(header + bytesToSend[bufferIndex:bufferIndex+bytesPerBuffer], address) t2 = currentTime() - - bufferIndex += bytesPerBuffer + + while ((t2 - t1) < bufferInterval): + t2 = currentTime() + + bufferIndex += bytesPerBuffer + + print("Done") +except BrokenPipeError: + print("Connection closed by the server. Unable to send data. Exiting...") + +except ConnectionAbortedError: + print("Connection was aborted, unable to send data. Try disconnecting and reconnecting the remote client. Exiting...") -print("Done") +except ConnectionResetError: + print("Connection was aborted, unable to send data. Try disconnecting and reconnecting the remote client. Exiting...") \ No newline at end of file diff --git a/Source/EphysSocket.cpp b/Source/EphysSocket.cpp index 7a3362d..88a1fe7 100644 --- a/Source/EphysSocket.cpp +++ b/Source/EphysSocket.cpp @@ -12,7 +12,7 @@ DataThread* EphysSocket::createDataThread(SourceNode* sn) return new EphysSocket(sn); } -EphysSocket::EphysSocket(SourceNode* sn) : DataThread(sn), socket("socket_thread") +EphysSocket::EphysSocket(SourceNode* sn) : DataThread(sn), socket("socket_thread", this) { port = DEFAULT_PORT; sample_rate = DEFAULT_SAMPLE_RATE; @@ -39,7 +39,9 @@ EphysSocket::~EphysSocket() } void EphysSocket::disconnectSocket() -{ +{ + socket.signalThreadShouldExit(); + socket.waitForThreadToExit(1000); socket.disconnectSocket(); } diff --git a/Source/OpenEphysLib.cpp b/Source/OpenEphysLib.cpp index c887aa8..65fba98 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 = "0.4.0"; + info->libVersion = "0.4.1"; info->numPlugins = NUM_PLUGINS; } diff --git a/Source/SocketThread.cpp b/Source/SocketThread.cpp index d8add64..583a038 100644 --- a/Source/SocketThread.cpp +++ b/Source/SocketThread.cpp @@ -3,11 +3,12 @@ #endif #include "SocketThread.h" +#include "EphysSocket.h" using namespace EphysSocketNode; -SocketThread::SocketThread(String name) - : Thread(name), editor(NULL) +SocketThread::SocketThread(String name, EphysSocket* processor_) + : Thread(name), editor(NULL), processor(processor_) { lastPacketReceived = time(nullptr); @@ -51,6 +52,12 @@ void SocketThread::startAcquisition() void SocketThread::stopAcquisition() { acquiring = false; + + if (shouldReconnect) + { + processor->disconnectSocket(); + editor->enableInputs(); + } } bool SocketThread::connectSocket(int port, bool printOutput) diff --git a/Source/SocketThread.h b/Source/SocketThread.h index f1236cc..db025ff 100644 --- a/Source/SocketThread.h +++ b/Source/SocketThread.h @@ -32,11 +32,13 @@ namespace EphysSocketNode { + class EphysSocket; + class SocketThread : public Thread { public: - SocketThread(String name); + SocketThread(String name, EphysSocket*); ~SocketThread(); @@ -87,6 +89,9 @@ namespace EphysSocketNode /** Pointer to the editor */ EphysSocketEditor* editor; + /** Pointer to the plugin processor */ + EphysSocket* processor; + /** TCP Socket object */ std::unique_ptr socket; From b26a483c1306314f677625623432d982e7170a1d Mon Sep 17 00:00:00 2001 From: Anjal Doshi Date: Thu, 13 Mar 2025 13:11:38 -0700 Subject: [PATCH 2/2] Update workflows to use ARTIFACTORY_ACCESS_TOKEN Fix Windows workflow to use new endpoint for open-ephys library --- .github/workflows/linux.yml | 4 ++-- .github/workflows/mac.yml | 4 ++-- .github/workflows/windows.yml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 513b816..e732c79 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -6,7 +6,7 @@ on: pull_request: env: - artifactoryApiKey: ${{ secrets.artifactoryApiKey }} + ARTIFACTORY_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} build_dir: "Build" package: EphysSocket-linux @@ -43,4 +43,4 @@ jobs: cp -r $build_dir/*.so plugins zipfile=${package}_${new_plugin_ver}.zip zip -r -X $zipfile plugins - curl -H "X-JFrog-Art-Api:$artifactoryApiKey" -T $zipfile "https://openephys.jfrog.io/artifactory/EphysSocket-plugin/linux/$zipfile" + curl -H "X-JFrog-Art-Api:$ARTIFACTORY_ACCESS_TOKEN" -T $zipfile "https://openephys.jfrog.io/artifactory/EphysSocket-plugin/linux/$zipfile" diff --git a/.github/workflows/mac.yml b/.github/workflows/mac.yml index 2a72805..4b4d75b 100644 --- a/.github/workflows/mac.yml +++ b/.github/workflows/mac.yml @@ -6,7 +6,7 @@ on: pull_request: env: - artifactoryApiKey: ${{ secrets.artifactoryApiKey }} + ARTIFACTORY_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} build_dir: "Build/Release" package: EphysSocket-mac @@ -41,4 +41,4 @@ jobs: cp -r $build_dir/*.bundle plugins zipfile=${package}_${new_plugin_ver}.zip zip -r -X $zipfile plugins - curl -H "X-JFrog-Art-Api:$artifactoryApiKey" -T $zipfile "https://openephys.jfrog.io/artifactory/EphysSocket-plugin/mac/$zipfile" \ No newline at end of file + curl -H "X-JFrog-Art-Api:$ARTIFACTORY_ACCESS_TOKEN" -T $zipfile "https://openephys.jfrog.io/artifactory/EphysSocket-plugin/mac/$zipfile" \ No newline at end of file diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 61479df..6f50a1d 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -6,7 +6,7 @@ on: pull_request: env: - artifactoryApiKey: ${{ secrets.artifactoryApiKey }} + ARTIFACTORY_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} build_dir: "Build/Release" package: EphysSocket-windows @@ -28,7 +28,7 @@ jobs: cd plugin-GUI/Build cmake -G "Visual Studio 16 2019" -A x64 .. mkdir Release && cd Release - curl -L https://openephysgui.jfrog.io/artifactory/Libraries/open-ephys-lib-v0.6.0.zip --output open-ephys-lib.zip + curl -L https://openephys.jfrog.io/artifactory/GUI-binaries/Libraries/open-ephys-lib-v0.6.0.zip --output open-ephys-lib.zip unzip open-ephys-lib.zip shell: bash @@ -58,5 +58,5 @@ jobs: cp $build_dir/*.dll plugins zipfile=${package}_${new_plugin_ver}.zip powershell Compress-Archive -Path "plugins" -DestinationPath ${zipfile} - curl -H "X-JFrog-Art-Api:$artifactoryApiKey" -T $zipfile "https://openephys.jfrog.io/artifactory/EphysSocket-plugin/windows/$zipfile" + curl -H "X-JFrog-Art-Api:$ARTIFACTORY_ACCESS_TOKEN" -T $zipfile "https://openephys.jfrog.io/artifactory/EphysSocket-plugin/windows/$zipfile" shell: bash