public void ShouldSurfaceExceptionInPersistorTask()
        {
            var  c   = new Controller();
            bool evt = false;

            c.DAQController = new TestDAQController();
            c.Clock         = c.DAQController as IClock;
            var persistor = new AggregateExceptionThrowingEpochPersistor();

            c.SavedEpoch += (co, args) =>
            {
                evt = true;
            };

            var dev = new UnitConvertingExternalDevice(UNUSED_DEVICE_NAME, UNUSED_DEVICE_MANUFACTURER, UNUSED_BACKGROUND)
            {
                Controller = c,
                MeasurementConversionTarget = "V"
            };

            var outStream = new DAQOutputStream("outStream")
            {
                MeasurementConversionTarget = "V"
            };

            var inStream = new DAQInputStream("inStream")
            {
                MeasurementConversionTarget = "V"
            };

            (c.DAQController as IMutableDAQController).AddStream(outStream);
            (c.DAQController as IMutableDAQController).AddStream(inStream);

            var srate = new Measurement(10, "Hz");

            outStream.SampleRate = srate;
            inStream.SampleRate  = srate;

            dev.BindStream(outStream);
            dev.BindStream(inStream);

            var e       = new Epoch(UNUSED_PROTOCOL);
            var samples = new List <IMeasurement> {
                new Measurement(1.0m, "V"), new Measurement(1.0m, "V"), new Measurement(1.0m, "V")
            };
            var data = new OutputData(samples,
                                      srate,
                                      true);

            e.Stimuli[dev] = new RenderedStimulus((string)"stimID",
                                                  (IDictionary <string, object>) new Dictionary <string, object>(),
                                                  (IOutputData)data);
            e.Responses[dev]  = new Response();
            e.Background[dev] = new Epoch.EpochBackground(new Measurement(0, "V"), srate);

            ((TestDAQController)c.DAQController).AddStreamMapping(outStream, inStream);

            Assert.That(() => c.RunEpoch(e, persistor), Throws.TypeOf <SymphonyControllerException>());
        }
        public void ShouldNotPersistEpochGivenNullPersistor()
        {
            var  c   = new Controller();
            bool evt = false;

            c.DAQController = new TestDAQController();
            c.Clock         = c.DAQController as IClock;


            c.DiscardedEpoch += (co, args) => Assert.Fail("Run failed");

            var dev = new UnitConvertingExternalDevice(UNUSED_DEVICE_NAME, UNUSED_DEVICE_MANUFACTURER, UNUSED_BACKGROUND)
            {
                Controller = c,
                MeasurementConversionTarget = "V"
            };

            var outStream = new DAQOutputStream("outStream")
            {
                MeasurementConversionTarget = "V"
            };

            var inStream = new DAQInputStream("inStream")
            {
                MeasurementConversionTarget = "V"
            };

            (c.DAQController as IMutableDAQController).AddStream(outStream);
            (c.DAQController as IMutableDAQController).AddStream(inStream);

            var srate = new Measurement(10, "Hz");

            outStream.SampleRate = srate;
            inStream.SampleRate  = srate;

            dev.BindStream(outStream);
            dev.BindStream(inStream);

            var e       = new Epoch(UNUSED_PROTOCOL);
            var samples = new List <IMeasurement> {
                new Measurement(1.0m, "V"), new Measurement(1.0m, "V"), new Measurement(1.0m, "V")
            };
            var data = new OutputData(samples,
                                      srate,
                                      true);

            e.Stimuli[dev] = new RenderedStimulus((string)"stimID",
                                                  (IDictionary <string, object>) new Dictionary <string, object>(),
                                                  (IOutputData)data);
            e.Responses[dev]  = new Response();
            e.Background[dev] = new Epoch.EpochBackground(new Measurement(0, "V"), srate);

            ((TestDAQController)c.DAQController).AddStreamMapping(outStream, inStream);

            c.RunEpoch(e, null);


            Assert.Pass();
        }
        public void ExternalDeviceStreams()
        {
            var ed = new UnitConvertingExternalDevice("TestDevice", UNUSED_DEVICE_MANUFACTURER, UNUSED_BACKGROUND);

            DAQInputStream  in0  = new DAQInputStream("In-0");
            DAQOutputStream out0 = new DAQOutputStream("Out-0");

            ed.BindStream(in0).BindStream(out0);

            Assert.IsTrue(ed.Streams.ContainsKey(in0.Name));
            Assert.IsTrue(in0.Devices.Contains(ed));
            Assert.IsTrue(ed.Streams.ContainsKey(out0.Name));
            Assert.IsTrue(out0.Device == ed);

            ed.UnbindStream("In-0");
            Assert.IsFalse(ed.Streams.ContainsKey(in0.Name));
            Assert.IsFalse(in0.Devices.Contains(ed));
            Assert.IsTrue(ed.Streams.ContainsKey(out0.Name));
            Assert.IsTrue(out0.Device == ed);

            ed.UnbindStream("Out-0");
            Assert.IsFalse(ed.Streams.ContainsKey(in0.Name));
            Assert.IsFalse(in0.Devices.Contains(ed));
            Assert.IsFalse(ed.Streams.ContainsKey(out0.Name));
            Assert.IsFalse(out0.Device == ed);
        }
        public void OutputPipelineContinuity(
            [Values(1000, 5000, 10000, 15000, 20000)] double sampleRate,
            [Values(0.1, 0.5, 1, 5)] double blockDurationSeconds
            )
        {
            const double epochDuration = 2; //seconds
            var srate = new Measurement((decimal) sampleRate, "Hz");

            var daq = new TestDAQController();
            var outStream = new DAQOutputStream("OUT")
                                {
                                    SampleRate = srate,
                                    MeasurementConversionTarget = "V"
                                };
            var inStream = new DAQInputStream("IN")
                                {
                                    SampleRate = srate,
                                    MeasurementConversionTarget = "V"
                                };

            var controller = new Controller() { Clock = daq, DAQController = daq };

            var dev = new UnitConvertingExternalDevice("dev", "co", controller, new Measurement(0, "V"))
                          {
                              Clock = daq,
                              MeasurementConversionTarget = "V",
                              OutputSampleRate = srate,
                              InputSampleRate = srate
                          };
            dev.BindStream(outStream).BindStream(inStream);

            // Setup Epoch
            var e = new Epoch("OutputPipelineContinuity");

            var nSamples = (int)TimeSpan.FromSeconds(epochDuration).Samples(srate);
            IList<IMeasurement> stimData = (IList<IMeasurement>) Enumerable.Range(0, nSamples)
                                                       .Select(i => new Measurement((decimal) (8 * Math.Sin(((double)i) / (nSamples / 10.0))), "V") as IMeasurement)
                                                       .ToList();
            IOutputData stimOutputData = new OutputData(stimData, srate);

            var stim = new RenderedStimulus((string) "RenderedStimulus", (IDictionary<string, object>) new Dictionary<string, object>(),
                                            stimOutputData);
            e.Stimuli[dev] = stim;
            e.Responses[dev] = new Response();
            e.Backgrounds[dev] = new Background(new Measurement(0, "V"), srate);

            controller.EnqueueEpoch(e);

            var blockSpan = TimeSpan.FromSeconds(blockDurationSeconds);
            foreach (var stimBlock in stim.DataBlocks(blockSpan))
            {
                var cons = stimOutputData.SplitData(blockSpan);
                var expected = cons.Head.Data;
                stimOutputData = cons.Rest;

                Assert.That(stimBlock.Data, Is.EqualTo(expected));
            }
        }
        public void OutputPipelineContinuity(
            [Values(1000, 5000, 10000, 15000, 20000)] double sampleRate,
            [Values(0.1, 0.5, 1, 5)] double blockDurationSeconds
            )
        {

            const double epochDuration = 2; //seconds
            var srate = new Measurement((decimal) sampleRate, "Hz");

            var daq = new TestDAQController();
            var outStream = new DAQOutputStream("OUT")
                                {
                                    SampleRate = srate,
                                    MeasurementConversionTarget = "V"
                                };

            var controller = new Controller() { Clock = daq, DAQController = daq };

            var dev = new UnitConvertingExternalDevice("dev", "co", controller, new Measurement(0, "V"))
                          {
                              Clock = daq,
                              MeasurementConversionTarget = "V"
                          };
            dev.BindStream(outStream);

            // Setup Epoch
            var e = new Epoch("OutputPipelineContinuity");

            var nSamples = (int)TimeSpan.FromSeconds(epochDuration).Samples(srate);
            IList<IMeasurement> stimData = (IList<IMeasurement>) Enumerable.Range(0, nSamples)
                                                       .Select(i => new Measurement((decimal) (8 * Math.Sin(((double)i) / (nSamples / 10.0))), "V") as IMeasurement)
                                                       .ToList();
            IOutputData stimOutputData = new OutputData(stimData, srate);

            var stim = new RenderedStimulus((string) "RenderedStimulus", (IDictionary<string, object>) new Dictionary<string, object>(),
                                            stimOutputData);
            e.Stimuli[dev] = stim;
            e.Responses[dev] = new Response();
            e.Background[dev] = new Epoch.EpochBackground(new Measurement(0, "V"), srate);

            controller.EnqueueEpoch(e);
            controller.NextEpoch();

            var blockSpan = TimeSpan.FromSeconds(blockDurationSeconds);
            foreach (var stimBlock in stim.DataBlocks(blockSpan))
            {
                var cons = stimOutputData.SplitData(blockSpan);
                var expected = cons.Head.Data;
                stimOutputData = cons.Rest;

                Assert.That(stimBlock.Data, Is.EqualTo(expected));
            }

        }
Beispiel #6
0
        public void ShouldRaiseExceptionIfPullingLessThanOneSample()
        {
            var e      = new UnitConvertingExternalDevice(UNUSED_NAME, null, new Measurement(0, "V"));
            var stream = new DAQOutputStream(UNUSED_NAME);

            e.BindStream(stream);

            stream.SampleRate = new Measurement(1, "Hz");

            Assert.Throws <ExternalDeviceException>(() => e.PullOutputData(stream, TimeSpan.FromMilliseconds(0.1)));
        }
        public void ShouldConvertBackgoundUnits()
        {
            Converters.Register("xfromUnits", "toUnits", m => new Measurement(2 * m.Quantity, m.Exponent, m.BaseUnit));

            var bg = new Measurement(1, "xfromUnits");
            var e = new UnitConvertingExternalDevice(UNUSED_NAME,
                                                     null,
                                                     bg)
                        {
                            MeasurementConversionTarget = "toUnits"
                        };

            var stream = new DAQOutputStream(UNUSED_NAME);
            e.BindStream(stream);

            var expected = new Measurement(bg.Quantity * 2,
                                           bg.Exponent,
                                           bg.BaseUnit);

            Assert.That(e.OutputBackground, Is.EqualTo(expected));
        }
Beispiel #8
0
        public void ShouldConvertBackgoundUnits()
        {
            Converters.Register("xfromUnits", "toUnits", m => new Measurement(2 * m.Quantity, m.Exponent, m.BaseUnit));

            var bg = new Measurement(1, "xfromUnits");
            var e  = new UnitConvertingExternalDevice(UNUSED_NAME,
                                                      null,
                                                      bg)
            {
                MeasurementConversionTarget = "toUnits"
            };

            var stream = new DAQOutputStream(UNUSED_NAME);

            e.BindStream(stream);

            var expected = new Measurement(bg.Quantity * 2,
                                           bg.Exponent,
                                           bg.BaseUnit);

            Assert.That(e.OutputBackground, Is.EqualTo(expected));
        }
        public void RenderedStimulus(
            [Values(1000, 10000, 20000, 50000)] double sampleRate,
            [Values(2)] int nEpochs
            )
        {
            Converters.Clear();
            Converters.Register("V", "V",
                // just an identity conversion for now, to pass Validate()
                                (IMeasurement m) => m);
            HekaDAQInputStream.RegisterConverters();
            HekaDAQOutputStream.RegisterConverters();

            Assert.That(HekaDAQController.AvailableControllers().Count(), Is.GreaterThan(0));
            foreach (var daq in HekaDAQController.AvailableControllers())
            {

                const double epochDuration = 5; //s

                daq.InitHardware();
                try
                {
                    daq.SampleRate = new Measurement((decimal)sampleRate, "Hz");

                    var controller = new Controller { Clock = daq.Clock, DAQController = daq };

                    var dev0 = new UnitConvertingExternalDevice("Device0", "Manufacturer", controller, new Measurement(0, "V"))
                                   {
                                       MeasurementConversionTarget = "V",
                                       Clock = daq.Clock,
                                       OutputSampleRate = daq.SampleRate,
                                       InputSampleRate = daq.SampleRate
                                   };
                    dev0.BindStream((IDAQOutputStream)daq.GetStreams("ao0").First());
                    dev0.BindStream((IDAQInputStream)daq.GetStreams("ai0").First());

                    var dev1 = new UnitConvertingExternalDevice("Device1", "Manufacturer", controller, new Measurement(0, "V"))
                    {
                        MeasurementConversionTarget = "V",
                        Clock = daq.Clock,
                        OutputSampleRate = daq.SampleRate,
                        InputSampleRate = daq.SampleRate
                    };
                    dev1.BindStream((IDAQOutputStream)daq.GetStreams("ao1").First());
                    dev1.BindStream((IDAQInputStream)daq.GetStreams("ai1").First());

                    for (int j = 0; j < nEpochs; j++)
                    {
                        // Setup Epoch
                        var e = new Epoch("HekaIntegration" + j);

                        var nSamples = (int)TimeSpan.FromSeconds(epochDuration).Samples(daq.SampleRate);
                        IList<IMeasurement> stimData = (IList<IMeasurement>)Enumerable.Range(0, nSamples)
                                                                   .Select(i => new Measurement((decimal)(8 * Math.Sin(((double)i) / (nSamples / 10.0))), "V") as IMeasurement)
                                                                   .ToList();

                        e.Stimuli[dev0] = new RenderedStimulus((string) "RenderedStimulus", (IDictionary<string, object>) new Dictionary<string, object>(),
                                                        (IOutputData) new OutputData(stimData, daq.SampleRate));
                        e.Responses[dev0] = new Response();

                        e.Stimuli[dev1] = new RenderedStimulus((string) "RenderedStimulus", (IDictionary<string, object>) new Dictionary<string, object>(),
                                                       (IOutputData) new OutputData(Enumerable.Range(0, nSamples)
                                                                                        .Select(i => new Measurement((decimal)(8 * Math.Sin(((double)i) / (nSamples / 10.0))), "V"))
                                                                                        .ToList(),
                                                                                    daq.SampleRate));
                        e.Responses[dev1] = new Response();

                        //Run single epoch
                        var fakeEpochPersistor = new FakeEpochPersistor();

                        controller.RunEpoch(e, fakeEpochPersistor);

                        Assert.That((bool)e.StartTime, Is.True);
                        Assert.That((DateTimeOffset)e.StartTime, Is.LessThanOrEqualTo(controller.Clock.Now));
                        Assert.That(e.Responses[dev0].Duration, Is.EqualTo(((TimeSpan)e.Duration))
                                                                      .Within(TimeSpanExtensions.FromSamples(1,
                                                                                                             daq.
                                                                                                                 SampleRate)));
                        Assert.That(e.Responses[dev1].Duration, Is.EqualTo(((TimeSpan)e.Duration))
                                                                      .Within(TimeSpanExtensions.FromSamples(1,
                                                                                                             daq.
                                                                                                                 SampleRate)));
                        Assert.That(fakeEpochPersistor.PersistedEpochs, Contains.Item(e));

                        var failures0 =
                            e.Responses[dev0].Data.Select(
                                (t, i) => new { index = i, diff = t.QuantityInBaseUnits - stimData[i].QuantityInBaseUnits })
                                .Where(dif => Math.Abs(dif.diff) > (decimal)MAX_VOLTAGE_DIFF);

                        foreach (var failure in failures0.Take(10))
                            Console.WriteLine("{0}: {1}", failure.index, failure.diff);

                        /*
                         * According to Telly @ Heka, a patch cable may introduce 3-4 offset points
                         */
                        Assert.That(failures0.Count(), Is.LessThanOrEqualTo(4));

                        /*
                        //Since we only have one patch cable on the test rig,
                        //we're not checking second device response values

                        var failures1 =
                            e.Responses[dev1].Data.Data.Select(
                                (t, i) => new { index = i, diff = t.QuantityInBaseUnit - stimData[i].QuantityInBaseUnit })
                                .Where(dif => Math.Abs(dif.diff) > MAX_VOLTAGE_DIFF);

                        foreach (var failure in failures1.Take(10))
                            Console.WriteLine("{0}: {1}", failure.index, failure.diff);

                        Assert.That(failures1.Count(), Is.EqualTo(0));
                        */
                    }

                }
                finally
                {
                    if (daq.IsHardwareReady)
                        daq.CloseHardware();
                }

            }
        }
        public void ContinuousAcquisition(
            [Values(1000, 10000, 20000, 50000)] double sampleRate,
            [Values(20)] int nEpochs)
        {
            Converters.Clear();
            HekaDAQInputStream.RegisterConverters();
            HekaDAQOutputStream.RegisterConverters();

            Assert.That(HekaDAQController.AvailableControllers().Count(), Is.GreaterThan(0));
            foreach (var daq in HekaDAQController.AvailableControllers())
            {
                const double epochDuration = 1; //s

                try
                {
                    daq.InitHardware();
                    daq.SampleRate = new Measurement((decimal)sampleRate, "Hz");

                    var controller = new Controller { Clock = daq.Clock, DAQController = daq };

                    var dev0 = new UnitConvertingExternalDevice("Device0", "Manufacturer", controller, new Measurement(0, "V"))
                    {
                        MeasurementConversionTarget = "V",
                        Clock = daq.Clock,
                        OutputSampleRate = daq.SampleRate,
                        InputSampleRate = daq.SampleRate
                    };
                    dev0.BindStream((IDAQOutputStream)daq.GetStreams("ao0").First());
                    dev0.BindStream((IDAQInputStream)daq.GetStreams("ai0").First());

                    var dev1 = new UnitConvertingExternalDevice("Device1", "Manufacturer", controller, new Measurement(0, "V"))
                    {
                        MeasurementConversionTarget = "V",
                        Clock = daq.Clock,
                        OutputSampleRate = daq.SampleRate,
                        InputSampleRate = daq.SampleRate
                    };
                    dev1.BindStream((IDAQOutputStream)daq.GetStreams("ao1").First());
                    dev1.BindStream((IDAQInputStream)daq.GetStreams("ai1").First());

                    var nDAQStarts = 0;
                    daq.Started += (evt, args) =>
                        {
                            nDAQStarts++;
                        };

                    var completedEpochs = new Queue<Epoch>();
                    controller.CompletedEpoch += (evt, args) =>
                        {
                            completedEpochs.Enqueue(args.Epoch);
                            if (completedEpochs.Count >= nEpochs)
                            {
                                controller.RequestStop();
                            }
                        };

                    var epochs = new Queue<Epoch>();
                    var nSamples = (int)TimeSpan.FromSeconds(epochDuration).Samples(daq.SampleRate);

                    // Triangle wave
                    var data = Enumerable.Range(0, nSamples/2)
                                         .Select(k => new Measurement(k/(nSamples/2.0/10.0), "V") as IMeasurement)
                                         .ToList();
                    var stimData = data.Concat(Enumerable.Reverse(data)).ToList();

                    var fakeEpochPersistor = new FakeEpochPersistor();

                    bool start = true;

                    for (int j = 0; j < nEpochs; j++)
                    {
                        var e = new Epoch("HekaIntegration" + j);

                        e.Stimuli[dev0] = new RenderedStimulus("Stim",
                                                               new Dictionary<string, object>(),
                                                               new OutputData(stimData, daq.SampleRate));
                        e.Responses[dev0] = new Response();

                        e.SetBackground(dev1, new Measurement(1, "V"), daq.SampleRate);
                        e.Responses[dev1] = new Response();

                        epochs.Enqueue(e);

                        controller.EnqueueEpoch(e);

                        if (start)
                        {
                            controller.StartAsync(fakeEpochPersistor);
                            start = false;
                        }
                    }

                    while (controller.IsRunning)
                    {
                        Thread.Sleep(1);
                    }

                    controller.WaitForCompletedEpochTasks();
                    var stopTime = controller.Clock.Now;

                    Assert.That(nDAQStarts <= 1, "Epochs did not run continuously");

                    Assert.AreEqual(epochs, completedEpochs);
                    Assert.AreEqual(fakeEpochPersistor.PersistedEpochs, completedEpochs);

                    DateTimeOffset prevTime = completedEpochs.First().StartTime;
                    foreach (var e in completedEpochs)
                    {
                        Assert.That((bool)e.StartTime, Is.True);
                        Assert.That((DateTimeOffset)e.StartTime, Is.GreaterThanOrEqualTo(prevTime));
                        Assert.That((DateTimeOffset)e.StartTime, Is.LessThanOrEqualTo(stopTime));

                        Assert.That(e.Responses[dev0].Duration, Is.EqualTo(((TimeSpan)e.Duration))
                                              .Within(TimeSpanExtensions.FromSamples(1, daq.SampleRate)));

                        Assert.That(e.Responses[dev1].Duration, Is.EqualTo(((TimeSpan)e.Duration))
                                                                      .Within(TimeSpanExtensions.FromSamples(1, daq.SampleRate)));

                        var failures0 =
                            e.Responses[dev0].Data.Select(
                                (t, i) => new {index = i, diff = t.QuantityInBaseUnits - stimData[i].QuantityInBaseUnits})
                                             .Where(dif => Math.Abs(dif.diff) > (decimal) MAX_VOLTAGE_DIFF);

                        foreach (var failure in failures0.Take(10))
                            Console.WriteLine("{0}: {1}", failure.index, failure.diff);

                        /*
                         * According to Telly @ Heka, a patch cable may introduce 3-4 offset points
                         */
                        Assert.That(failures0.Count(), Is.LessThanOrEqualTo(4));

                        prevTime = e.StartTime;
                    }
                }
                finally
                {
                    if (daq.IsHardwareReady)
                    {
                        daq.CloseHardware();
                    }
                }
            }
        }
        public void MaxBandwidth(
            [Values(1000,10000,25000,50000)] decimal sampleRate,
            [Values(1,1,1,1)] int nEpochs,
            [Values(4,4,4,4)] int nOut,
            [Values(8,8,8,4)] int nIn
            )
        {
            Converters.Clear();
            HekaDAQInputStream.RegisterConverters();
            HekaDAQOutputStream.RegisterConverters();

            Assert.That(HekaDAQController.AvailableControllers().Count(), Is.GreaterThan(0));

            foreach (var daq in HekaDAQController.AvailableControllers())
            {

                const double epochDuration = 10; //s

                daq.InitHardware();
                try
                {
                    daq.SampleRate = new Measurement(sampleRate, "Hz");

                    var controller = new Controller { Clock = daq.Clock, DAQController = daq };

                    var outDevices = Enumerable.Range(0, nOut)
                        .Select(i =>
                                    {
                                        var dev0 = new UnitConvertingExternalDevice("Device_OUT_" + i, "Manufacturer", controller,
                                                                                    new Measurement(0, "V"))
                                                       {
                                                           MeasurementConversionTarget = "V",
                                                           Clock = daq.Clock,
                                                           OutputSampleRate = daq.SampleRate
                                                       };
                                        dev0.BindStream((IDAQOutputStream)daq.GetStreams("ao" + i).First());

                                        return dev0;
                                    })
                                    .ToList();

                    var inDevices = Enumerable.Range(0, nIn)
                        .Select(i =>
                        {
                            var dev0 = new UnitConvertingExternalDevice("Device_IN_" + i, "Manufacturer", controller,
                                                                        new Measurement(0, "V"))
                            {
                                MeasurementConversionTarget = "V",
                                Clock = daq.Clock,
                                InputSampleRate = daq.SampleRate
                            };
                            dev0.BindStream((IDAQInputStream)daq.GetStreams("ai" + i).First());

                            return dev0;
                        })
                                    .ToList();

                    for (int j = 0; j < nEpochs; j++)
                    {
                        // Setup Epoch
                        var e = new Epoch("HekaIntegration");

                        var nSamples = (int)TimeSpan.FromSeconds(epochDuration).Samples(daq.SampleRate);
                        IList<IMeasurement> stimData = Enumerable.Range(0, nSamples)
                                                                   .Select(i => new Measurement((decimal)(8 * Math.Sin(((double)i) / (nSamples / 10.0))), "V") as IMeasurement)
                                                                   .ToList();

                        foreach (var outDev in outDevices)
                        {
                            e.Stimuli[outDev] = new RenderedStimulus((string) "RenderedStimulus", (IDictionary<string, object>) new Dictionary<string, object>(),
                                                        (IOutputData) new OutputData(stimData, daq.SampleRate));

                            e.Backgrounds[outDev] = new Background(new Measurement(0, "V"), daq.SampleRate);
                        }

                        foreach (var inDev in inDevices)
                        {
                            e.Responses[inDev] = new Response();
                        }

                        //Run single epoch
                        var fakeEpochPersistor = new FakeEpochPersistor();

                        controller.RunEpoch(e, fakeEpochPersistor);

                        Assert.That((bool)e.StartTime, Is.True);
                        Assert.That((DateTimeOffset)e.StartTime, Is.LessThanOrEqualTo(controller.Clock.Now));
                        Assert.That(fakeEpochPersistor.PersistedEpochs, Contains.Item(e));

                    }

                }
                finally
                {
                    if (daq.IsHardwareReady)
                        daq.CloseHardware();
                }

            }
        }
        public void LongEpochPersistence(
            [Values(5,60)] double epochDuration, //seconds
            [Values(2)] int nEpochs
            )
        {
            const decimal sampleRate = 10000m;

            const string h5Path = "..\\..\\..\\LongEpochPersistence.h5";
            if (File.Exists(h5Path))
                File.Delete(h5Path);

            Converters.Clear();
            Converters.Register("V", "V",
                // just an identity conversion for now, to pass Validate()
                                (IMeasurement m) => m);
            HekaDAQInputStream.RegisterConverters();
            HekaDAQOutputStream.RegisterConverters();

            Assert.That(HekaDAQController.AvailableControllers().Count(), Is.GreaterThan(0));

            using (var persistor = H5EpochPersistor.Create(h5Path))
            {
                persistor.AddSource("source", null);
            }

            foreach (var daq in HekaDAQController.AvailableControllers())
            {

                try
                {

                    daq.InitHardware();
                    daq.SampleRate = new Measurement(sampleRate, "Hz");

                    var controller = new Controller {Clock = daq.Clock, DAQController = daq};

                    var dev0 = new UnitConvertingExternalDevice("Device0", "Manufacturer", controller,
                                                                new Measurement(0, "V"))
                                   {
                                       MeasurementConversionTarget = "V",
                                       Clock = daq.Clock,
                                       OutputSampleRate = daq.SampleRate,
                                       InputSampleRate = daq.SampleRate
                                   };
                    dev0.BindStream((IDAQOutputStream) daq.GetStreams("ao0").First());
                    dev0.BindStream((IDAQInputStream) daq.GetStreams("ai0").First());

                    for (int j = 0; j < nEpochs; j++)
                    {
                        // Setup Epoch
                        var e = new Epoch("HekaIntegration");

                        var nSamples = (int) TimeSpan.FromSeconds(epochDuration).Samples(daq.SampleRate);
                        IList<IMeasurement> stimData = (IList<IMeasurement>) Enumerable.Range(0, nSamples)
                                                                                 .Select(
                                                                                     i =>
                                                                                     new Measurement(
                                                                                         (decimal)
                                                                                         (8*
                                                                                          Math.Sin(((double) i)/
                                                                                                   (nSamples/10.0))),
                                                                                         "V") as IMeasurement)
                                                                                 .ToList();

                        e.Stimuli[dev0] = new RenderedStimulus((string) "RenderedStimulus", (IDictionary<string, object>) new Dictionary<string, object>(),
                                                               (IOutputData) new OutputData(stimData, daq.SampleRate));
                        e.Responses[dev0] = new Response();
                        e.Backgrounds[dev0] = new Background(new Measurement(0, "V"), daq.SampleRate);

                        //Run single epoch
                        using (var persistor = new H5EpochPersistor(h5Path))
                        {
                            var source = persistor.Experiment.Sources.First();

                            persistor.BeginEpochGroup("label", source, DateTimeOffset.Now);
                            persistor.BeginEpochBlock(e.ProtocolID, e.ProtocolParameters, DateTimeOffset.Now);

                            controller.RunEpoch(e, persistor);

                            persistor.EndEpochBlock(DateTimeOffset.Now);
                            persistor.EndEpochGroup();
                        }

                        Assert.That((bool) e.StartTime, Is.True);
                        Assert.That((DateTimeOffset) e.StartTime, Is.LessThanOrEqualTo(controller.Clock.Now));
                        Assert.That(e.Responses[dev0].Duration, Is.EqualTo(((TimeSpan) e.Duration))
                                                                    .Within(TimeSpanExtensions.FromSamples(1,
                                                                                                           daq.
                                                                                                               SampleRate)));
                        //Assert.That(e.Responses[dev1].Duration, Is.EqualTo(((TimeSpan) e.Duration))
                        //                                            .Within(TimeSpanExtensions.FromSamples(1,
                        //                                                                                   daq.
                        //                                                                                       SampleRate)));
                    }
                }
                finally
                {
                    if (File.Exists(h5Path))
                        File.Delete(h5Path);

                    if (daq.IsHardwareReady)
                        daq.CloseHardware();

                }
            }
        }
        public void PullOutputDataShouldReturnBackgroundStreamWithNoRemainingEpochs()
        {
            var daq = new SimpleDAQController();
            Controller c = new NonValidatingController() { DAQController = daq };
            IExternalDevice dev = new UnitConvertingExternalDevice(UNUSED_DEVICE_NAME, UNUSED_DEVICE_MANUFACTURER, c,
                                                                   UNUSED_BACKGROUND)
                {
                    OutputSampleRate = new Measurement(1000, "Hz")
                };
            dev.BindStream(new DAQOutputStream("out"));

            var srate = dev.OutputSampleRate;

            TimeSpan dur = TimeSpan.FromSeconds(0.5);
            var samples = (int)dur.Samples(srate);

            var e = new Epoch("");
            e.Stimuli[dev] = new RenderedStimulus("RenderedStimulus", new Dictionary<string, object>(), new OutputData(Enumerable.Repeat(new Measurement(0, "V"), samples), srate));

            IOutputData pull1 = null;
            IOutputData pull2 = null;
            bool pulled = false;
            daq.Started += (evt, args) =>
            {
                // Pull out epoch data
                c.PullOutputData(dev, dur);

                pull1 = c.PullOutputData(dev, dur);
                pull2 = c.PullOutputData(dev, dur);
                pulled = true;

                c.RequestStop();
            };

            c.EnqueueEpoch(e);
            c.StartAsync(null);

            while (!pulled)
            {
                Thread.Sleep(1);
            }

            var expected = Enumerable.Repeat(dev.Background, samples).ToList();

            Assert.AreEqual(expected, pull1.Data);
            Assert.AreEqual(expected, pull2.Data);
        }
        public void RunEpochThrowsWhenRunningSimultaneousEpochs()
        {
            Converters.Register("V", "V",
                // just an identity conversion for now, to pass Validate()
                                (IMeasurement m) => m);

            var c = new Controller { DAQController = new SimpleDAQController() };
            c.DAQController.Clock = c.DAQController as IClock;

            var sampleRate = new Measurement(1, "Hz");

            var e = new Epoch(UNUSED_PROTOCOL);
            var dev = new UnitConvertingExternalDevice("dev", "co", c, new Measurement(0, "V"))
            {
                MeasurementConversionTarget = "V",
                Clock = c.Clock,
                OutputSampleRate = sampleRate
            };
            var outStream = new DAQOutputStream("out")
            {
                MeasurementConversionTarget = "V",
                Clock = c.Clock
            };
            dev.BindStream(outStream);

            e.Stimuli[dev] = new DelegatedStimulus("ID1", "units", sampleRate, new Dictionary<string, object>(),
                                                    (parameters, duration) => null,
                                                    objects => Option<TimeSpan>.None());

            bool started = false;
            c.Started += (evt, args) =>
            {
                started = true;
            };

            c.EnqueueEpoch(e);
            c.StartAsync(null);

            while (!started)
            {
                Thread.Sleep(1);
            }

            Assert.That(() => c.RunEpoch(e, new FakeEpochPersistor()), Throws.Exception.TypeOf<SymphonyControllerException>());
        }
        public void ExternalDeviceStreams()
        {
            var ed = new UnitConvertingExternalDevice("TestDevice", UNUSED_DEVICE_MANUFACTURER, UNUSED_BACKGROUND);

            DAQInputStream in0 = new DAQInputStream("In-0");
            DAQOutputStream out0 = new DAQOutputStream("Out-0");
            ed.BindStream(in0).BindStream(out0);

            Assert.IsTrue(ed.Streams.ContainsKey(in0.Name));
            Assert.IsTrue(in0.Devices.Contains(ed));
            Assert.IsTrue(ed.Streams.ContainsKey(out0.Name));
            Assert.IsTrue(out0.Device == ed);

            ed.UnbindStream("In-0");
            Assert.IsFalse(ed.Streams.ContainsKey(in0.Name));
            Assert.IsFalse(in0.Devices.Contains(ed));
            Assert.IsTrue(ed.Streams.ContainsKey(out0.Name));
            Assert.IsTrue(out0.Device == ed);

            ed.UnbindStream("Out-0");
            Assert.IsFalse(ed.Streams.ContainsKey(in0.Name));
            Assert.IsFalse(in0.Devices.Contains(ed));
            Assert.IsFalse(ed.Streams.ContainsKey(out0.Name));
            Assert.IsFalse(out0.Device == ed);
        }
        public void PushesDataToEpoch()
        {
            const string UNUSED_NAME = "UNUSED";

            var daq = new SimpleDAQController();
            var c = new NonValidatingController { DAQController = daq };
            var dev = new UnitConvertingExternalDevice(UNUSED_NAME, UNUSED_DEVICE_MANUFACTURER, c, UNUSED_BACKGROUND);
            var outStream = new DAQOutputStream("out");
            var inStream = new DAQInputStream("in");

            dev.BindStream(outStream).BindStream(inStream);

            var srate = new Measurement(100, "Hz");
            var samples = Enumerable.Range(0, 100).Select(i => new Measurement(1, "V")).ToList();

            var e = new Epoch("PushesDataToEpoch");
            e.Responses[dev] = new Response();

            e.Stimuli[dev] = new RenderedStimulus((string) "ID1", (IDictionary<string, object>) new Dictionary<string, object>(), (IOutputData) new OutputData(samples, srate, false));

            var data = new InputData(samples, srate, DateTimeOffset.Now).DataWithStreamConfiguration(inStream, new Dictionary<string, object>());
            bool pushed = false;

            daq.Started += (evt, args) =>
                {
                    c.PushInputData(dev, data);
                    pushed = true;

                    c.RequestStop();
                };

            c.EnqueueEpoch(e);
            c.StartAsync(null);

            while (!pushed)
            {
                Thread.Sleep(1);
            }

            Assert.That(e.Responses[dev].Data, Is.EqualTo(data.Data));
            Assert.That(e.Responses[dev].InputTime, Is.EqualTo(data.InputTime));
            Assert.That(e.Responses[dev].DataConfigurationSpans.First().Nodes.First(),
                Is.EqualTo(data.NodeConfigurationWithName(inStream.Name)));
        }
        public void ShouldNotPersistEpochGivenNullPersistor()
        {
            var c = new Controller();
            bool evt = false;

            c.DAQController = new TestDAQController();
            c.Clock = c.DAQController as IClock;

            c.DiscardedEpoch += (co, args) => Assert.Fail("Run failed");

            var dev = new UnitConvertingExternalDevice(UNUSED_DEVICE_NAME, UNUSED_DEVICE_MANUFACTURER, UNUSED_BACKGROUND)
            {
                Controller = c,
                MeasurementConversionTarget = "V"
            };

            var outStream = new DAQOutputStream("outStream") { MeasurementConversionTarget = "V" };

            var inStream = new DAQInputStream("inStream") { MeasurementConversionTarget = "V" };

            (c.DAQController as IMutableDAQController).AddStream(outStream);
            (c.DAQController as IMutableDAQController).AddStream(inStream);

            var srate = new Measurement(10, "Hz");
            outStream.SampleRate = srate;
            inStream.SampleRate = srate;

            dev.BindStream(outStream);
            dev.BindStream(inStream);

            var e = new Epoch(UNUSED_PROTOCOL);
            var samples = new List<IMeasurement> { new Measurement(1.0m, "V"), new Measurement(1.0m, "V"), new Measurement(1.0m, "V") };
            var data = new OutputData(samples,
                srate,
                true);

            e.Stimuli[dev] = new RenderedStimulus((string) "stimID",
                                                  (IDictionary<string, object>) new Dictionary<string, object>(),
                                                  (IOutputData) data);
            e.Responses[dev] = new Response();
            e.Background[dev] = new Epoch.EpochBackground(new Measurement(0, "V"), srate);

            ((TestDAQController)c.DAQController).AddStreamMapping(outStream, inStream);

            c.RunEpoch(e, null);

            Assert.Pass();
        }
        public void ShouldTruncateResponseAtEpochBoundary()
        {
            Converters.Register("V", "V",
                (IMeasurement m) => m);

            var daq = new SimpleDAQController();
            var c = new NonValidatingController { DAQController = daq };
            var dev = new UnitConvertingExternalDevice("dev", UNUSED_DEVICE_MANUFACTURER, c, UNUSED_BACKGROUND);
            var outStream = new DAQOutputStream("out");
            var inStream = new DAQInputStream("in");
            dev.BindStream(outStream).BindStream(inStream);

            var sampleRate = new Measurement(1, "Hz");

            var samples = new List<IMeasurement> { new Measurement(1, "V"), new Measurement(2, "V"), new Measurement(3, "V") };

            var data = new OutputData(samples,
                                      sampleRate, true);

            var e = new Epoch(UNUSED_PROTOCOL);

            e.Stimuli[dev] = new RenderedStimulus((string) "ID1",
                                                   (IDictionary<string, object>) new Dictionary<string, object>(),
                                                   (IOutputData) data);
            e.Responses[dev] = new Response();

            bool pushed = false;
            daq.Started += (evt, args) =>
            {
                c.PullOutputData(dev, data.Duration);
                c.PushInputData(dev, new InputData(samples.Concat(samples).ToList(),
                                                   sampleRate,
                                                   DateTimeOffset.Now)
                                         .DataWithStreamConfiguration(streamFake, new Dictionary<string, object>())
                                         .DataWithExternalDeviceConfiguration(devFake, new Dictionary<string, object>()));
                pushed = true;

                c.RequestStop();
            };

            c.EnqueueEpoch(e);
            c.StartAsync(null);

            while (!pushed)
            {
                Thread.Sleep(1);
            }

            Assert.That(((TimeSpan)e.Responses[dev].Duration), Is.EqualTo((TimeSpan)e.Duration));
        }
        public void ShouldSupplyEpochBackgroundForExternalDevicesWithoutStimuli()
        {
            Converters.Register("V", "V",
                (IMeasurement m) => m);

            int baseSamples = 1000;

            var daq = new SimpleDAQController();
            var c = new NonValidatingController { DAQController = daq };

            var dev1 = new UnitConvertingExternalDevice("dev1", "co", c, new Measurement(0, "V"))
                {
                    OutputSampleRate = new Measurement(baseSamples, "Hz")
                };
            var dev2 = new UnitConvertingExternalDevice("dev2", "co", c, new Measurement(0, "V"))
                {
                    OutputSampleRate = new Measurement(baseSamples, "Hz")
                };

            dev1.BindStream(new DAQOutputStream("out1"));
            dev2.BindStream(new DAQOutputStream("out2"));

            IList<IMeasurement> data = (IList<IMeasurement>)Enumerable.Range(0, baseSamples)
                .Select(i => new Measurement(i, "V") as IMeasurement)
                .ToList();

            Measurement sampleRate = new Measurement(baseSamples, "Hz");

            var config = new Dictionary<string, object>();

            IOutputData data1 = new OutputData(data, sampleRate, true);

            var e = new Epoch("");
            e.Stimuli[dev1] = new RenderedStimulus((string) "RenderedStimulus", (IDictionary<string, object>) config, data1);

            var backgroundMeasurement = new Measurement(3.2m, "V");
            e.Backgrounds[dev2] = new Background(backgroundMeasurement, sampleRate);

            IOutputData out1 = null;
            IOutputData out2 = null;
            bool pulled = false;
            daq.Started += (evt, args) =>
            {
                out1 = c.PullOutputData(dev1, e.Duration);
                out2 = c.PullOutputData(dev2, e.Duration);
                pulled = true;

                c.RequestStop();
            };

            c.EnqueueEpoch(e);
            c.StartAsync(null);

            while (!pulled)
            {
                Thread.Sleep(1);
            }

            Assert.NotNull(out1);

            Assert.NotNull(out2);
            Assert.AreEqual((TimeSpan)e.Duration, out2.Duration);
            Assert.AreEqual(backgroundMeasurement, out2.Data.First());
        }
        public void ShouldPersistCompletedEpochs()
        {
            Converters.Register("V", "V",
                (IMeasurement m) => m);

            var c = new Controller();
            bool evt = false;

            c.DAQController = new TestDAQController();
            c.Clock = c.DAQController as IClock;
            var persistor = new FakeEpochPersistor();

            c.SavedEpoch += (co, args) =>
                                {
                                    evt = true;
                                };

            var srate = new Measurement(10, "Hz");

            var dev = new UnitConvertingExternalDevice(UNUSED_DEVICE_NAME, UNUSED_DEVICE_MANUFACTURER, c, UNUSED_BACKGROUND)
                          {
                              MeasurementConversionTarget = "V",
                              Clock = c.Clock,
                              OutputSampleRate = srate,
                              InputSampleRate = srate
                          };

            var outStream = new DAQOutputStream("outStream") { MeasurementConversionTarget = "V", Clock = c.Clock };

            var inStream = new DAQInputStream("inStream") { MeasurementConversionTarget = "V", Clock = c.Clock };

            (c.DAQController as IMutableDAQController).AddStream(outStream);
            (c.DAQController as IMutableDAQController).AddStream(inStream);

            outStream.SampleRate = srate;
            inStream.SampleRate = srate;

            dev.BindStream(outStream);
            dev.BindStream(inStream);

            var e = new Epoch(UNUSED_PROTOCOL);
            var samples = new List<IMeasurement> { new Measurement(1.0m, "V"), new Measurement(1.0m, "V"), new Measurement(1.0m, "V") };
            var data = new OutputData(samples,
                srate,
                true);

            e.Stimuli[dev] = new RenderedStimulus((string) "stimID",
                                                  (IDictionary<string, object>) new Dictionary<string, object>(),
                                                  (IOutputData) data);
            e.Responses[dev] = new Response();
            e.Backgrounds[dev] = new Background(new Measurement(0, "V"), srate);

            ((TestDAQController)c.DAQController).AddStreamMapping(outStream, inStream);

            c.RunEpoch(e, persistor);

            Assert.That(evt, Is.True.After(10*1000,100));
            Assert.That(persistor.PersistedEpochs, Has.Member(e));
        }
        public void SealLeak(
            [Values(10000, 20000, 50000)] double sampleRate
            )
        {
            Converters.Clear();
            Converters.Register("V", "V",
                // just an identity conversion for now, to pass Validate()
                                (IMeasurement m) => m);
            HekaDAQInputStream.RegisterConverters();
            HekaDAQOutputStream.RegisterConverters();

            Assert.That(HekaDAQController.AvailableControllers().Count(), Is.GreaterThan(0));

            foreach (var daq in HekaDAQController.AvailableControllers())
            {
                const double epochDuration = 10; //s

                //Configure DAQ
                daq.InitHardware();
                try
                {
                    daq.SampleRate = new Measurement((decimal)sampleRate, "Hz");

                    var controller = new Controller();
                    controller.Clock = daq.Clock;
                    controller.DAQController = daq;

                    const decimal expectedBackgroundVoltage = 3.2m;
                    var expectedBackground = new Measurement(expectedBackgroundVoltage, "V");
                    var dev0 = new UnitConvertingExternalDevice("Device0", "Manufacturer", controller, expectedBackground)
                                   {
                                       MeasurementConversionTarget = "V",
                                       Clock = daq.Clock,
                                       OutputSampleRate = daq.SampleRate,
                                       InputSampleRate = daq.SampleRate
                                   };
                    dev0.BindStream(daq.GetStreams("ao0").First() as IDAQOutputStream);
                    dev0.BindStream(daq.GetStreams("ai0").First() as IDAQInputStream);

                    controller.DiscardedEpoch += (c, args) => Console.WriteLine("Discarded epoch: " + args.Epoch);

                    // Setup Epoch
                    var e = new Epoch("HekaIntegration");

                    HekaDAQController cDAQ = daq;
                    var stim = new DelegatedStimulus("TEST_ID", "V", cDAQ.SampleRate, new Dictionary<string, object>(),
                                                     (parameters, duration) =>
                                                     DataForDuration(duration, cDAQ.SampleRate),
                                                     parameters => Option<TimeSpan>.None()
                        );

                    e.Stimuli[dev0] = stim;
                    e.Backgrounds[dev0] = new Background(expectedBackground, daq.SampleRate);

                    //Run single epoch
                    var fakeEpochPersistor = new FakeEpochPersistor();

                    new TaskFactory().StartNew(() =>
                                                   {
                                                       Thread.Sleep(TimeSpan.FromSeconds(epochDuration));
                                                       controller.RequestStop();
                                                   },
                                               TaskCreationOptions.LongRunning
                        );

                    controller.RunEpoch(e, fakeEpochPersistor);
                }
                finally
                {
                    if (daq.IsHardwareReady)
                        daq.CloseHardware();
                }
            }
        }
        public void ShouldSetStreamBackgroundOnStop(
            [Values(10000, 20000)] double sampleRate
            )
        {
            Converters.Clear();
            Converters.Register("V", "V",
                // just an identity conversion for now, to pass Validate()
                                (IMeasurement m) => m);
            HekaDAQInputStream.RegisterConverters();
            HekaDAQOutputStream.RegisterConverters();

            Assert.That(HekaDAQController.AvailableControllers().Count(), Is.GreaterThan(0));

            foreach (var daq in HekaDAQController.AvailableControllers())
            {

                const double epochDuration = 1; //s
                //Configure DAQ
                daq.InitHardware();
                try
                {
                    daq.SampleRate = new Measurement((decimal)sampleRate, "Hz");

                    var controller = new Controller();
                    controller.Clock = daq.Clock;
                    controller.DAQController = daq;

                    const decimal expectedBackgroundVoltage = -3.2m;
                    var expectedBackground = new Measurement(expectedBackgroundVoltage, "V");
                    var dev0 = new UnitConvertingExternalDevice("Device0", "Manufacturer", controller, expectedBackground)
                        {
                            MeasurementConversionTarget = "V",
                            OutputSampleRate = daq.SampleRate,
                            InputSampleRate = daq.SampleRate
                        };
                    dev0.BindStream(daq.GetStreams("ao0").First() as IDAQOutputStream);
                    dev0.BindStream(daq.GetStreams("ai0").First() as IDAQInputStream);
                    dev0.Clock = daq.Clock;

                    controller.DiscardedEpoch += (c, args) => Console.WriteLine("Discarded epoch: " + args.Epoch);

                    // Setup Epoch
                    var e = new Epoch("HekaIntegration");

                    var nSamples = (int)TimeSpanExtensions.Samples(TimeSpan.FromSeconds(epochDuration), daq.SampleRate);
                    IList<IMeasurement> stimData = (IList<IMeasurement>)Enumerable.Range(0, nSamples)
                                                               .Select(i => new Measurement((decimal)(8 * Math.Sin(((double)i) / (nSamples / 10.0))), "V") as IMeasurement)
                                                               .ToList();

                    var stim = new RenderedStimulus((string) "RenderedStimulus", (IDictionary<string, object>) new Dictionary<string, object>(),
                                                    (IOutputData) new OutputData(stimData, daq.SampleRate, false));
                    e.Stimuli[dev0] = stim;
                    e.Responses[dev0] = new Response();
                    e.Backgrounds[dev0] = new Background(expectedBackground, daq.SampleRate);

                    //Run single epoch
                    var fakeEpochPersistor = new FakeEpochPersistor();

                    controller.RunEpoch(e, fakeEpochPersistor);

                    Thread.Sleep(TimeSpan.FromMilliseconds(100)); //allow DAC to settle

                    var actual = ((HekaDAQController)controller.DAQController).ReadStreamAsync(
                        daq.GetStreams("ai0").First() as IDAQInputStream);

                    //Should be within +/- 0.025 volts
                    Assert.That(actual.Data.First().QuantityInBaseUnits, Is.InRange(expectedBackground.QuantityInBaseUnits - (decimal)0.025,
                        expectedBackground.QuantityInBaseUnits + (decimal)0.025));
                }
                finally
                {
                    if (daq.IsHardwareReady)
                        daq.CloseHardware();
                }

            }
        }
        public void PullsOutputData()
        {
            const int srate = 1000;
            var daq = new SimpleDAQController();
            var c = new NonValidatingController { DAQController = daq };
            var dev = new UnitConvertingExternalDevice(UNUSED_DEVICE_NAME, UNUSED_DEVICE_MANUFACTURER, c,
                                                       UNUSED_BACKGROUND)
                {
                    OutputSampleRate = new Measurement(srate, "Hz")
                };
            dev.BindStream(new DAQOutputStream("out"));

            IList<IMeasurement> data = (IList<IMeasurement>) Enumerable.Range(0, srate * 2).Select(i => new Measurement(i, "V") as IMeasurement).ToList();
            var sampleRate = new Measurement(srate, "Hz");

            IOutputData data1 = new OutputData(data, sampleRate, false);

            var e = new Epoch("");
            e.Stimuli[dev] = new RenderedStimulus((string) "RenderedStimulus", (IDictionary<string, object>) new Dictionary<string, object>(),
                data1);

            TimeSpan d1 = TimeSpan.FromSeconds(0.75);

            IOutputData pull1 = null;
            IOutputData pull2 = null;
            IOutputData pull3 = null;
            bool pulled = false;
            daq.Started += (evt, args) =>
            {
                pull1 = c.PullOutputData(dev, d1);
                pull2 = c.PullOutputData(dev, d1);
                pull3 = c.PullOutputData(dev, d1);
                pulled = true;

                c.RequestStop();
            };

            c.EnqueueEpoch(e);
            c.StartAsync(null);

            while (!pulled)
            {
                Thread.Sleep(1);
            }

            var samples = (int)d1.Samples(new Measurement(srate, "Hz"));
            Assert.AreEqual(data.Take(samples).ToList(),
                pull1.Data);
            Assert.AreEqual(data.Skip(samples).Take(samples).ToList(),
                pull2.Data);
            Assert.AreEqual(data.Skip(2 * samples)
                .Take(samples)
                .Concat(Enumerable.Range(0, srate - samples).Select(i => dev.Background))
                .ToList(),
                pull3.Data);
        }
        public void CreatePipeline()
        {
            // Based on the "Minimal Rig.pdf" in the docs folder
            Converters.Clear();

            // We need an IClock
            IClock clock = new FakeClock();

            // We need a controller ...
            Controller con = new Controller();

            Converters.Register("units", "units",
                // just an identity conversion for now, to pass Validate()
                (IMeasurement m) => m);
            Converters.Register("V", "units",
                // just an identity conversion for now, to pass Validate()
               (IMeasurement m) => m);

            con.Clock = clock;

            // Three ExternalDevices
            CoalescingDevice amp = new CoalescingDevice("Amp", UNUSED_DEVICE_MANUFACTURER, con, UNUSED_BACKGROUND)
                                       {
                                           MeasurementConversionTarget = "units"
                                       };
            var LED = new UnitConvertingExternalDevice("LED", UNUSED_DEVICE_MANUFACTURER, UNUSED_BACKGROUND)
            {
                MeasurementConversionTarget = "units"
            };
            var temp = new UnitConvertingExternalDevice("Temp", UNUSED_DEVICE_MANUFACTURER, UNUSED_BACKGROUND)
            {
                MeasurementConversionTarget = "units"
            };
            amp.Clock = clock;
            LED.Clock = clock;
            temp.Clock = clock;
            con.AddDevice(LED).AddDevice(temp);
            // There should be no difference whether we use the
            // ExternalDevice constructor to wire up the Controller
            // to the ExternalDevice, or the explicit Add() call

            Assert.IsNotNull(amp.Controller);
            Assert.IsNotNull(LED.Controller);
            Assert.IsNotNull(temp.Controller);

            Assert.IsTrue(amp.Controller == con);
            Assert.IsTrue(LED.Controller == con);
            Assert.IsTrue(temp.Controller == con);

            // Five DAQStreams
            DAQInputStream in0 = new DAQInputStream("In-0"); in0.Clock = clock;
            DAQInputStream in1 = new DAQInputStream("In-1"); in1.Clock = clock;
            DAQInputStream in2 = new DAQInputStream("In-2"); in2.Clock = clock;
            DAQOutputStream out0 = new DAQOutputStream("Out-0"); out0.Clock = clock;
            DAQOutputStream out1 = new DAQOutputStream("Out-1"); out1.Clock = clock;
            in0.MeasurementConversionTarget = "units";
            in1.MeasurementConversionTarget = "units";
            in2.MeasurementConversionTarget = "units";
            out0.MeasurementConversionTarget = "units";
            out1.MeasurementConversionTarget = "units";

            //amp.Coalesce = CoalescingDevice.OneItemCoalesce;
            amp.Configuration["CoalesceProc"] = "Symphony.Core.CoalescingDevice.OneItemCoalesce";

            LED.BindStream(out0);
            amp.BindStream(out1).BindStream(in0).BindStream(in1);
            amp.Connect(in0, in1);
            temp.BindStream(in2);

            Assert.IsTrue(LED.Streams.Count == 1);
            Assert.IsTrue(amp.Streams.Count == 3);
            Assert.IsTrue(temp.Streams.Count == 1);

            Assert.IsTrue(in0.Devices.Contains(amp));
            Assert.IsTrue(in1.Devices.Contains(amp));
            Assert.IsTrue(in2.Devices.Contains(temp));
            Assert.IsTrue(out0.Device == LED);
            Assert.IsTrue(out1.Device == amp);

            // One DAQController
            IDAQController dc =
                new SimpleDAQController(new IDAQStream[] { in0, in1, in2, out0, out1 });

            con.DAQController = dc;

            // DAQController-to-streams
            Assert.IsTrue(dc.InputStreams.Contains(in0));
            Assert.IsTrue(dc.InputStreams.Contains(in1));
            Assert.IsTrue(dc.InputStreams.Contains(in2));
            Assert.IsTrue(dc.OutputStreams.Contains(out0));
            Assert.IsTrue(dc.OutputStreams.Contains(out0));

            // Validate and report the validation results
            Maybe<string> conVal = con.Validate();
            Assert.IsTrue(conVal, conVal.Item2);

            Assert.IsTrue(amp.Coalesce == CoalescingDevice.OneItemCoalesce);
        }
        public void RunEpochShouldDiscardEpochWhenRequestStopCalled()
        {
            Converters.Register("V", "V",
                // just an identity conversion for now, to pass Validate()
                                (IMeasurement m) => m);

            var c = new Controller { DAQController = new SimpleDAQController2() };
            c.DAQController.Clock = c.DAQController as IClock;

            var sampleRate = new Measurement(1, "Hz");

            var e = new Epoch(UNUSED_PROTOCOL);
            var dev1 = new UnitConvertingExternalDevice("dev1", "co", c, new Measurement(0, "V"))
                {
                    MeasurementConversionTarget = "V",
                    Clock = c.Clock,
                    OutputSampleRate = sampleRate
                };
            var outStream = new DAQOutputStream("out")
                {
                    MeasurementConversionTarget = "V",
                    Clock = c.Clock
                };
            dev1.BindStream(outStream);

            e.Stimuli[dev1] = new DelegatedStimulus("ID1", "units", sampleRate, new Dictionary<string, object>(),
                                                    (parameters, duration) =>
                                                    new OutputData(new List<IMeasurement>(), sampleRate, false),
                                                    objects => Option<TimeSpan>.None());

            bool epochDiscarded = false;
            c.DiscardedEpoch += (sender, args) =>
                                    {
                                        epochDiscarded = true;
                                    };

            c.DAQController.ProcessIteration += (o, eventArgs) =>
                                       {
                                           Console.WriteLine("Process iteration");
                                           c.RequestStop();
                                       };

            c.RunEpoch(e, new FakeEpochPersistor());

            Assert.True(epochDiscarded);
        }
        public void ShouldSurfaceExceptionInPersistorTask()
        {
            var c = new Controller();
            bool evt = false;

            c.DAQController = new TestDAQController();
            c.Clock = c.DAQController as IClock;
            var persistor = new AggregateExceptionThrowingEpochPersistor();

            c.SavedEpoch += (co, args) =>
            {
                evt = true;
            };

            var dev = new UnitConvertingExternalDevice(UNUSED_DEVICE_NAME, UNUSED_DEVICE_MANUFACTURER, UNUSED_BACKGROUND)
            {
                Controller = c,
                MeasurementConversionTarget = "V"
            };

            var outStream = new DAQOutputStream("outStream") { MeasurementConversionTarget = "V" };

            var inStream = new DAQInputStream("inStream") { MeasurementConversionTarget = "V" };

            (c.DAQController as IMutableDAQController).AddStream(outStream);
            (c.DAQController as IMutableDAQController).AddStream(inStream);

            var srate = new Measurement(10, "Hz");
            outStream.SampleRate = srate;
            inStream.SampleRate = srate;

            dev.BindStream(outStream);
            dev.BindStream(inStream);

            var e = new Epoch(UNUSED_PROTOCOL);
            var samples = new List<IMeasurement> { new Measurement(1.0m, "V"), new Measurement(1.0m, "V"), new Measurement(1.0m, "V") };
            var data = new OutputData(samples,
                srate,
                true);

            e.Stimuli[dev] = new RenderedStimulus((string) "stimID",
                                                  (IDictionary<string, object>) new Dictionary<string, object>(),
                                                  (IOutputData) data);
            e.Responses[dev] = new Response();
            e.Background[dev] = new Epoch.EpochBackground(new Measurement(0, "V"), srate);

            ((TestDAQController)c.DAQController).AddStreamMapping(outStream, inStream);

            Assert.That(() => c.RunEpoch(e, persistor), Throws.TypeOf<SymphonyControllerException>());
        }
        public void CreatePipeline()
        {
            // Based on the "Minimal Rig.pdf" in the docs folder
            Converters.Clear();

            // We need an IClock
            IClock clock = new FakeClock();

            // We need a controller ...
            Controller con = new Controller();

            Converters.Register("units", "units",
                                // just an identity conversion for now, to pass Validate()
                                (IMeasurement m) => m);
            Converters.Register("V", "units",
                                // just an identity conversion for now, to pass Validate()
                                (IMeasurement m) => m);

            con.Clock = clock;

            // Three ExternalDevices
            CoalescingDevice amp = new CoalescingDevice("Amp", UNUSED_DEVICE_MANUFACTURER, con, UNUSED_BACKGROUND)
            {
                MeasurementConversionTarget = "units"
            };
            var LED = new UnitConvertingExternalDevice("LED", UNUSED_DEVICE_MANUFACTURER, UNUSED_BACKGROUND)
            {
                MeasurementConversionTarget = "units"
            };
            var temp = new UnitConvertingExternalDevice("Temp", UNUSED_DEVICE_MANUFACTURER, UNUSED_BACKGROUND)
            {
                MeasurementConversionTarget = "units"
            };

            amp.Clock  = clock;
            LED.Clock  = clock;
            temp.Clock = clock;
            con.AddDevice(LED).AddDevice(temp);
            // There should be no difference whether we use the
            // ExternalDevice constructor to wire up the Controller
            // to the ExternalDevice, or the explicit Add() call


            Assert.IsNotNull(amp.Controller);
            Assert.IsNotNull(LED.Controller);
            Assert.IsNotNull(temp.Controller);

            Assert.IsTrue(amp.Controller == con);
            Assert.IsTrue(LED.Controller == con);
            Assert.IsTrue(temp.Controller == con);

            // Five DAQStreams
            DAQInputStream  in0  = new DAQInputStream("In-0"); in0.Clock = clock;
            DAQInputStream  in1  = new DAQInputStream("In-1"); in1.Clock = clock;
            DAQInputStream  in2  = new DAQInputStream("In-2"); in2.Clock = clock;
            DAQOutputStream out0 = new DAQOutputStream("Out-0"); out0.Clock = clock;
            DAQOutputStream out1 = new DAQOutputStream("Out-1"); out1.Clock = clock;

            in0.MeasurementConversionTarget  = "units";
            in1.MeasurementConversionTarget  = "units";
            in2.MeasurementConversionTarget  = "units";
            out0.MeasurementConversionTarget = "units";
            out1.MeasurementConversionTarget = "units";

            //amp.Coalesce = CoalescingDevice.OneItemCoalesce;
            amp.Configuration["CoalesceProc"] = "Symphony.Core.CoalescingDevice.OneItemCoalesce";

            LED.BindStream(out0);
            amp.BindStream(out1).BindStream(in0).BindStream(in1);
            amp.Connect(in0, in1);
            temp.BindStream(in2);

            Assert.IsTrue(LED.Streams.Count == 1);
            Assert.IsTrue(amp.Streams.Count == 3);
            Assert.IsTrue(temp.Streams.Count == 1);

            Assert.IsTrue(in0.Devices.Contains(amp));
            Assert.IsTrue(in1.Devices.Contains(amp));
            Assert.IsTrue(in2.Devices.Contains(temp));
            Assert.IsTrue(out0.Device == LED);
            Assert.IsTrue(out1.Device == amp);

            // One DAQController
            IDAQController dc =
                new SimpleDAQController(new IDAQStream[] { in0, in1, in2, out0, out1 });

            con.DAQController = dc;

            // DAQController-to-streams
            Assert.IsTrue(dc.InputStreams.Contains(in0));
            Assert.IsTrue(dc.InputStreams.Contains(in1));
            Assert.IsTrue(dc.InputStreams.Contains(in2));
            Assert.IsTrue(dc.OutputStreams.Contains(out0));
            Assert.IsTrue(dc.OutputStreams.Contains(out0));

            // Validate and report the validation results
            Maybe <string> conVal = con.Validate();

            Assert.IsTrue(conVal, conVal.Item2);

            Assert.IsTrue(amp.Coalesce == CoalescingDevice.OneItemCoalesce);
        }
        public void ShouldRaiseExceptionIfPullingLessThanOneSample()
        {
            var e = new UnitConvertingExternalDevice(UNUSED_NAME, null, new Measurement(0, "V"));
            var stream = new DAQOutputStream(UNUSED_NAME);
            e.BindStream(stream);

            stream.SampleRate = new Measurement(1, "Hz");

            Assert.Throws<ExternalDeviceException>(() => e.PullOutputData(stream, TimeSpan.FromMilliseconds(0.1)));
        }
        private static Controller SetupController(double sampleRate, out Epoch e, out IExternalDevice dev0, out RenderedStimulus stim1, out IExternalDevice dev1, out RenderedStimulus stim2, out IList<IMeasurement> stimData, int nChannels)
        {
            Converters.Clear();
            Converters.Register("V", "V",
                // just an identity conversion for now, to pass Validate()
                                (IMeasurement m) => m);

            // use an incrementing clock so timestamps are predictable
            var incrementingClock = new IncrementingClock();

            var daq = new SimulationDAQController { Clock = incrementingClock };

            var out0 = new DAQOutputStream("Out0")
            {
                MeasurementConversionTarget = "V",
                Clock = daq.Clock,
                SampleRate = new Measurement((decimal)sampleRate, "Hz")
            };

            var out1 = new DAQOutputStream("Out1")
            {
                MeasurementConversionTarget = "V",
                Clock = daq.Clock,
                SampleRate = new Measurement((decimal)sampleRate, "Hz")
            };

            var in0 = new DAQInputStream("In0")
                {
                    MeasurementConversionTarget = "V",
                    Clock = daq.Clock,
                    SampleRate = new Measurement((decimal) sampleRate, "Hz")
                };

            var in1 = new DAQInputStream("In1")
            {
                MeasurementConversionTarget = "V",
                Clock = daq.Clock,
                SampleRate = new Measurement((decimal)sampleRate, "Hz")
            };

            daq.AddStream(out0);
            daq.AddStream(out1);
            daq.AddStream(in0);
            daq.AddStream(in1);

            var controller = new Controller(daq, daq.Clock);

            var streamNameMap = new Dictionary<string, string>();
            streamNameMap["Out0"] = "In0";
            if (nChannels > 1)
                streamNameMap["Out1"] = "In1";

            foreach (var stream in daq.Streams)
            {
                stream.SampleRate = new Measurement((decimal) sampleRate, "Hz");
            }

            daq.SimulationRunner += (output, timestep) =>
                                        {
                                            var input = new ConcurrentDictionary<IDAQInputStream, IInputData>();

                                            Parallel.ForEach(output, (kv) =>
                                                                         {
                                                                             var outData = kv.Value;
                                                                             var outStream = kv.Key;
                                                                             var inStream = daq.InputStreams.Where((s) =>
                                                                                                                   s.Name == streamNameMap[outStream.Name]).First();

                                                                             var data = outData.DataWithUnits("V").Data;
                                                                             var inData = new InputData(data,
                                                                                                        outData.SampleRate,
                                                                                                        incrementingClock.Now)
                                                                                                        .DataWithNodeConfiguration("SimulationController",daq.Configuration);

                                                                             input[inStream] = inData;
                                                                         }
                                                );

                                            return input;
                                        };

            var protocolParams = new Dictionary<string, object>(1);
            protocolParams["key1"] = "value1";

            e = new Epoch("LowGainSimulation", protocolParams);

            dev0 = new UnitConvertingExternalDevice("Device0", "Manufacturer", controller, new Measurement(0, "V"))
                {
                    MeasurementConversionTarget = "V",
                    Clock = daq.Clock,
                    InputSampleRate = new Measurement((decimal)sampleRate, "Hz"),
                    OutputSampleRate = new Measurement((decimal)sampleRate, "Hz")
                };
            dev0.BindStream(out0);
            dev0.BindStream(in0);

            dev1 = new UnitConvertingExternalDevice("Device1", "Manufacturer", controller, new Measurement(0, "V"))
                {
                    MeasurementConversionTarget = "V",
                    Clock = daq.Clock,
                    InputSampleRate = new Measurement((decimal)sampleRate, "Hz"),
                    OutputSampleRate = new Measurement((decimal)sampleRate, "Hz")
                };
            dev1.BindStream(out1);
            dev1.BindStream(in1);

            if (nChannels == 1)
            {
                dev1.UnbindStream(dev1.Streams.Values.First().Name);
            }

            stimData = Enumerable.Range(0, (int)(10 * sampleRate))
                                   .Select(i => new Measurement(i, -3, "V") as IMeasurement)
                                   .ToList();
            var srate = new Measurement((decimal) sampleRate, "Hz");

            stim1 = new RenderedStimulus((string) "RenderedStimulus",
                                         (IDictionary<string, object>) new Dictionary<string, object>(),
                                         (IOutputData) new OutputData(stimData, srate, false));
            stim2 = new RenderedStimulus((string) "RenderedStimulus",
                                         (IDictionary<string, object>) new Dictionary<string, object>(),
                                         (IOutputData) new OutputData(stimData, srate, false));

            e.Stimuli[dev0] = stim1;

            if (nChannels > 1)
                e.Stimuli[dev1] = stim2;

            e.Responses[dev0] = new Response();
            if (nChannels > 1)
                e.Responses[dev1] = new Response();

            e.Backgrounds[dev0] = new Background(new Measurement(0, "V"), srate);
            e.Backgrounds[dev1] = new Background(new Measurement(0, "V"), srate);

            return controller;
        }