diff --git a/OpenEphys.Onix1/ConfigurePortController.cs b/OpenEphys.Onix1/ConfigurePortController.cs index 5e5bb63..f9587c5 100644 --- a/OpenEphys.Onix1/ConfigurePortController.cs +++ b/OpenEphys.Onix1/ConfigurePortController.cs @@ -51,7 +51,9 @@ public override IObservable Process(IObservable source var portShift = ((int)deviceAddress - 1) * 2; var passthroughState = (hubConfiguration == HubConfiguration.Passthrough ? 1 : 0) << portShift; context.HubState = (PassthroughState)(((int)context.HubState & ~(1 << portShift)) | passthroughState); - return Disposable.Empty; + + // leave in standard mode when finished + return Disposable.Create(() => context.HubState = (PassthroughState)((int)context.HubState & ~(1 << portShift))); }) .ConfigureLink(context => { diff --git a/OpenEphys.Onix1/ContextTask.cs b/OpenEphys.Onix1/ContextTask.cs index 1cdc27c..cefffa2 100644 --- a/OpenEphys.Onix1/ContextTask.cs +++ b/OpenEphys.Onix1/ContextTask.cs @@ -255,25 +255,64 @@ internal Task StartAsync(int blockReadSize, int blockWriteSize, CancellationToke if (!acquisition.IsCompleted) throw new InvalidOperationException("Acquisition already running in the current context."); - // NB: Configure context before starting acquisition + + // NB: Configure context before starting acquisition or the the settings (e.g. Block read + // and write sizes) will not be respected var contextConfiguration = ConfigureContext(); - ctx.BlockReadSize = blockReadSize; - ctx.BlockWriteSize = blockWriteSize; - - // TODO: Stuff related to sync mode is 100% ONIX, not ONI. Therefore, in the long term, - // another place to do this separation might be needed - int address = ctx.HardwareAddress; - int mode = (address & 0x00FF0000) >> 16; - if (mode == 0) // Standalone mode + + try + { + // set block read and write size + ctx.BlockReadSize = blockReadSize; + ctx.BlockWriteSize = blockWriteSize; + + // TODO: Stuff related to sync mode is 100% ONIX, not ONI. Therefore, in the long term, + // another place to do this separation might be needed + int address = ctx.HardwareAddress; + int mode = (address & 0x00FF0000) >> 16; + if (mode == 0) // Standalone mode + { + ctx.Start(true); + } + else // If synchronized mode, reset counter independently + { + ctx.ResetFrameClock(); + ctx.Start(false); + } + + } + catch (oni.ONIException ex) when (ex.Number == -20) + { + lock (regLock) + { + ctx.Stop(); + contextConfiguration.Dispose(); + } + throw new InvalidOperationException($"The requested read size of {blockReadSize} bytes is too small for the current " + + $"hardware configuration, which requires at least {ctx.MaxReadFrameSize} bytes.", ex); + } + catch (oni.ONIException ex) when (ex.Number == -24) { - ctx.Start(true); + lock (regLock) + { + ctx.Stop(); + contextConfiguration.Dispose(); + } + throw new InvalidOperationException($"The requested write size of {blockWriteSize} bytes is too small for the current " + + $"hardware configuration, which requires at least {ctx.MaxWriteFrameSize} bytes.", ex); } - else // If synchronized mode, reset counter independently + catch { - ctx.ResetFrameClock(); - ctx.Start(false); + lock (regLock) + { + ctx.Stop(); + contextConfiguration.Dispose(); + } + throw; } + // TODO: If during the creation of of collectFramesCancellation, collectFramesToken, frameQueue, readFrames, or distributeFrames + // an exception is thrown, contextConfiguration will not be disposed. The process will need to be restarted to get out of deadlock collectFramesCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); var collectFramesToken = collectFramesCancellation.Token; var frameQueue = new BlockingCollection(MaxQueuedFrames);