/// <summary>
        /// Gets the one and only instance of this class that is allowed to exist.
        /// </summary>
        /// <returns>Instance of Microcontroller class</returns>
        public static Microcontroller GetInstance()
        {
            if (_instance == null)
            {
                lock (_instance_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new Microcontroller();
                    }
                }
            }

            return(_instance);
        }
Beispiel #2
0
        private void _background_thread_DoWork(object sender, DoWorkEventArgs e)
        {
            //If a stage has not been defined, return immediately. We cannot proceed.
            if (CurrentStage == null)
            {
                return;
            }

            //Get an instance of the microcontroller that is connected to this computer
            var microcontroller = Microcontroller.GetInstance();

            microcontroller.ConnectToMicrocontroller();

            //Initialize variables for this behavior session
            LeftFeedCount  = 0;
            RightFeedCount = 0;
            TrialState     = MMazeTrialState.NoTrialStarted;
            IsSoundPlaying = false;

            //Open a file for this session
            _session_file_writer = new MMazeFileWriter();
            _session_file_writer.CreateFile(RatName);
            _session_file_writer.WriteFileHeader(
                RatName,
                DateTime.Now.ToFileTime(),
                CurrentStage.StageName,
                MMazeConfiguration.GetInstance().BoothName
                );

            //Make hard copies of the timer lists for the current stage so we can use them this session
            _this_session_timer_map     = CurrentStage.StageRefractoryPeriods.ToList();
            _this_session_max_timer_map = CurrentStage.StageMaxSoundDelays.ToList();

            //Start a timer for the session.
            timer.Restart();

            //Start timer 1 - the refractory period timer
            StartTimer1();

            //Set the initial value of the "most recent feed" to be the current time
            _most_recent_feed = DateTime.Now;

            //Initialize the "feed lists"
            FeedList_TimeSincePreviousFeed = new List <int>();
            FeedList_TimeSinceSessionStart = new List <int>();

            lock (sound_list_lock)
            {
                SoundList_TimeSinceSessionStart = new List <int>();
            }

            //Loop until the session is ended
            while (!_background_thread.CancellationPending)
            {
                //Get the total seconds elapsed so far during this session
                SecondsElapsed = Convert.ToInt32(timer.Elapsed.TotalSeconds);

                //Read in the most recent event from the microcontroller
                var latest_event = microcontroller.ReadStream();
                if (latest_event != null && latest_event.EventType != MMazeEventNames.Undefined)
                {
                    //Write the latest event to the file
                    _session_file_writer.WriteEvent(latest_event);

                    //If it was a feeder event, update the feed lists we are maintaining (which will also be used to update
                    //the plot)
                    if (latest_event.EventType == MMazeEventNames.LeftFeederTriggered ||
                        latest_event.EventType == MMazeEventNames.RightFeederTriggered)
                    {
                        var time_since_last_feed = DateTime.Now - _most_recent_feed;
                        _most_recent_feed = DateTime.Now;

                        switch (latest_event.EventType)
                        {
                        case MMazeEventNames.LeftFeederTriggered:
                            LeftFeedCount++;
                            break;

                        case MMazeEventNames.RightFeederTriggered:
                            RightFeedCount++;
                            break;
                        }

                        FeedList_TimeSincePreviousFeed.Add(Convert.ToInt32(time_since_last_feed.TotalSeconds));
                        FeedList_TimeSinceSessionStart.Add(Convert.ToInt32(timer.Elapsed.TotalSeconds));
                        _background_properties_to_update.Add("FeedList");
                    }

                    //Set the user-facing nosepoke and prox-sensor state variables based upon the most recent event
                    //that we have received from the microcontroller
                    switch (latest_event.EventType)
                    {
                    case MMazeEventNames.LeftNosepokeEnter:
                        LeftNosepokeState = true;
                        break;

                    case MMazeEventNames.LeftNosepokeLeave:
                        LeftNosepokeState = false;
                        break;

                    case MMazeEventNames.RightNosepokeEnter:
                        RightNosepokeState = true;
                        break;

                    case MMazeEventNames.RightNosepokeLeave:
                        RightNosepokeState = false;
                        break;

                    case MMazeEventNames.LeftProxEnter:
                        LeftProxState = true;
                        break;

                    case MMazeEventNames.LeftProxLeave:
                        LeftProxState = false;
                        break;

                    case MMazeEventNames.RightProxEnter:
                        RightProxState = true;
                        break;

                    case MMazeEventNames.RightProxLeave:
                        RightProxState = false;
                        break;
                    }

                    //Handle the trial state based upon the most recent event we received from the microcontroller
                    switch (TrialState)
                    {
                    case MMazeTrialState.NoTrialStarted:

                        //Set the trial state based upon the nosepoke that has been exited
                        if (latest_event.EventType == MMazeEventNames.LeftNosepokeLeave)
                        {
                            TrialState = MMazeTrialState.LeftToRight;
                        }
                        else if (latest_event.EventType == MMazeEventNames.RightNosepokeLeave)
                        {
                            TrialState = MMazeTrialState.RightToLeft;
                        }

                        break;

                    case MMazeTrialState.LeftToRight:

                        //This is a "left to right" trial, handle a beam break in the left prox area
                        if (latest_event.EventType == MMazeEventNames.LeftProxEnter)
                        {
                            TrialState = MMazeTrialState.LeftToRight_EnterLeftProx;

                            if (CurrentStage.StageCueType == MMazeStageCueType.ProximitySensor)
                            {
                                HandleBeamBreak();
                            }
                        }

                        break;

                    case MMazeTrialState.RightToLeft:

                        //This is a "right to left" trial, handle a beam break in the right prox area
                        if (latest_event.EventType == MMazeEventNames.RightProxEnter)
                        {
                            TrialState = MMazeTrialState.RightToLeft_EnterRightProx;

                            if (CurrentStage.StageCueType == MMazeStageCueType.ProximitySensor)
                            {
                                HandleBeamBreak();
                            }
                        }

                        break;

                    case MMazeTrialState.LeftToRight_EnterLeftProx:

                        //This is the end of a "left to right" trial, reset the trial state
                        if (latest_event.EventType == MMazeEventNames.RightNosepokeEnter)
                        {
                            TrialState = MMazeTrialState.NoTrialStarted;

                            if (CurrentStage.StageCueType == MMazeStageCueType.Nosepoke)
                            {
                                HandleBeamBreak();
                            }
                        }

                        break;

                    case MMazeTrialState.RightToLeft_EnterRightProx:

                        //This is the end of a "right to left" trial, reset the trial state
                        if (latest_event.EventType == MMazeEventNames.LeftNosepokeEnter)
                        {
                            TrialState = MMazeTrialState.NoTrialStarted;

                            if (CurrentStage.StageCueType == MMazeStageCueType.Nosepoke)
                            {
                                HandleBeamBreak();
                            }
                        }

                        break;
                    }
                }

                //Update the GUI based on what is happening in the background thread
                _background_properties_to_update.Add("SoundList");
                _background_thread.ReportProgress(0);

                //Sleep the thread
                Thread.Sleep(33);
            }

            //Close the file for this session
            _session_file_writer.WriteFileFooter(DateTime.Now.ToFileTime());
            _session_file_writer.CloseFile();

            //Stop the session timer
            timer.Stop();

            //Stop the sound timers
            if (_timer1 != null)
            {
                _timer1.Stop();
                _timer1.Close();
            }

            if (_timer2 != null)
            {
                _timer2.Stop();
                _timer2.Close();
            }

            //Close up
            SecondsElapsed = 0;
            _background_thread.ReportProgress(0);

            //Report the thread being canceled
            e.Cancel = true;
        }