Beispiel #1
0
    public bool Capture(string outputData1, EncoderRProcCapture encoderRProcCapture,
                        bool compujump, Preferences.TriggerTypes cutByTriggers, double restClustersSeconds, bool playSoundsFromFile)
    {
        /*
         * removed at 1.7.0
         * if(simulated) {
         *      bool success = initSimulated();
         *      if(! success)
         *              return false;
         * }
         */

        lastTriggerOn = 0;
        inertialCalibratedFirstCross0Pos = 0;

        //only for cutByTriggers == Preferences.TriggerTypes.START_AT_FIRST_ON
        bool firstTriggerHappened = false;

        //playSoundsFromFile
        DateTime lastTriggeredSound = DateTime.MinValue;

        if (capturingInertialBG)
        {
            /*
             * reset capture list. If not done here, list will grow at each set
             * also this fixes the initial 0s after a set
             */
            EncoderCaptureInertialBackgroundStatic.Initialize();
        }

        do
        {
            //1 read data
            try {
                byteReaded = readByte();
            } catch {
                if (!simulated)
                {
                    LogB.Error("Maybe encoder cable is disconnected");
                    cancel = true;
                }

                break;
            }

            //2 check if readed data is a trigger
            if (byteReaded == TRIGGER_ON)
            {
                if (playSoundsFromFile)
                {
                    TimeSpan ts = DateTime.Now.Subtract(lastTriggeredSound);
                    if (ts.TotalMilliseconds > 50)
                    {
                        Util.NextSongInList();
                        lastTriggeredSound = DateTime.Now;
                    }

                    continue;
                }

                Trigger trigger = new Trigger(Trigger.Modes.ENCODER, i, true);
                if (triggerList.IsSpurious(trigger))
                {
                    triggerList.RemoveLastOff();
                    continue;
                }

                //TriggerTypes.START_AT_FIRST_ON starts capture at first trigger. So when this happens, reset capture
                if (cutByTriggers == Preferences.TriggerTypes.START_AT_FIRST_ON && !firstTriggerHappened)
                {
                    LogB.Information("Cleaning on capture");

                    startCaptureFromHere();

                    firstTriggerHappened = true;
                    i = -1;                     //will be 0 on next loop start
                    continue;
                }

                if (cutByTriggers != Preferences.TriggerTypes.NO_TRIGGERS)
                {
                    ecc           = new EncoderCaptureCurve(lastTriggerOn, i);
                    lastTriggerOn = i;

                    double [] curve = new double[ecc.endFrame - ecc.startFrame];
                    //int mySum = 0;
                    for (int k = 0, j = ecc.startFrame; j < ecc.endFrame; j++)
                    {
                        curve[k] = encoderReaded[j];
                        k++;
                        //mySum += encoderReaded[j];
                    }
                    //ecc.up = (mySum >= 0);
                    ecc.up = true;                     //make all concentric for the swimming application
                    LogB.Debug("curve stuff" + ecc.startFrame + ":" + ecc.endFrame + ":" + encoderReaded.Count);

                    bool success = encoderRProcCapture.SendCurve(
                        ecc.startFrame,
                        UtilEncoder.CompressData(curve, 25)                                     //compressed
                        );
                    if (!success)
                    {
                        cancel = true;
                    }

                    Ecca.curvesAccepted++;
                    Ecca.ecc.Add(ecc);
                    LogB.Information(ecc.ToString());
                }
                triggerList.Add(trigger);
                continue;
            }
            else if (byteReaded == TRIGGER_OFF)
            {
                if (!playSoundsFromFile)
                {
                    Trigger trigger = new Trigger(Trigger.Modes.ENCODER, i, false);
                    triggerList.Add(trigger);
                }

                continue;
            }

            //3 if is not trigger: convertByte
            byteReaded = convertByte(byteReaded);
            //LogB.Information(" byte: " + byteReaded);

            i = i + 1;
            if (i >= 0)
            {
                if (cont)
                {
                    recordedTimeCont++;
                }

                if (byteReaded == 0)
                {
                    consecutiveZeros++;

                    //clean variables when we are on cont and long time elapsed
                    if (cont && Ecca.curvesAccepted == 0 && consecutiveZeros >= consecutiveZerosMax)
                    {
                        LogB.Information("Cleaning on capture");

                        //remove this time on existing trigger records
                        triggerList.Substract(consecutiveZeros);

                        startCaptureFromHere();

                        i = -1;                         //will be 0 on next loop start
                        continue;
                    }
                }
                else
                {
                    consecutiveZeros = -1;
                }

                //stop if n seconds of inactivity
                //but it has to be moved a little bit first, just to give time to the people
                //if(consecutiveZeros >= consecutiveZerosMax && sum > 0) #Not OK because sum maybe is 0: +1,+1,-1,-1
                //if(consecutiveZeros >= consecutiveZerosMax && ecca.ecc.Count > 0) #Not ok because when ecca is created, ecc.Count == 1

                /*
                 * process ends
                 * (
                 * when a curve has been found and then there are n seconds of inactivity, or
                 * when not in cont and a curve has not been found and then there are 2*n seconds of inactivity
                 * ) and if consecutiveZeros > restClustersSeconds * 1.500
                 *
                 * 1500 is conversion to milliseconds and * 1.5 to have enough time to move after clusters res
                 */
                if (
                    automaticallyEndByTime &&
                    (
                        (Ecca.curvesAccepted > 0 && consecutiveZeros >= consecutiveZerosMax) ||
                        (!cont && Ecca.curvesAccepted == 0 && consecutiveZeros >= (2 * consecutiveZerosMax))
                    ) &&
                    (restClustersSeconds == 0 || consecutiveZeros > restClustersSeconds * 1500)
                    )
                {
                    finish = true;
                    LogB.Information("SHOULD FINISH");
                }


                //on inertialCalibrated set mark where 0 is crossed for the first time
                if (inertialCalibrated && inertialCalibratedFirstCross0Pos == 0)
                {
                    if ((sumInertialDisc <= 0 && sumInertialDisc + byteReaded > 0) ||
                        (sumInertialDisc >= 0 && sumInertialDisc + byteReaded < 0))
                    {
                        inertialCalibratedFirstCross0Pos = i;
                    }
                }

                sumInertialDisc += byteReaded;
                encoderReadedInertialDisc.Add(byteReaded);

                if (inertialCalibrated && sumInertialDisc > 0)
                {
                    byteReaded *= -1;
                }

                sum += byteReaded;
                encoderReaded.Add(byteReaded);


                if (!showOnlyBars)
                {
                    assignEncoderCapturePoints();

                    EncoderCapturePointsCaptured = i;
                }

                if (!showOnlyBars)
                {
                    encoderCapturePointsAdaptativeDisplay();
                }

                // ---- prepare to send to R ----

                //if string goes up or down, store the direction
                //direction is only up or down
                if (byteReaded != 0)
                {
                    directionNow = (int)byteReaded / (int)Math.Abs(byteReaded);                       //1 (up) or -1 (down)
                }
                //if we don't have changed the direction, store the last non-zero that we can find
                if (directionChangeCount == 0 && directionNow == directionLastMSecond)
                {
                    //check which is the last non-zero value
                    //this is suitable to find where starts the only-zeros previous to the change
                    if (byteReaded != 0)
                    {
                        lastNonZero = i;
                    }
                }

                bool sendCurveMaybe = false;

                //if it's different than the last direction, mark the start of change
                if (directionNow != directionLastMSecond)
                {
                    directionLastMSecond = directionNow;
                    directionChangeCount = 0;
                }
                else if (directionNow != directionCompleted)
                {
                    //we are in a different direction than the last completed

                    //we cannot add byteReaded because then is difficult to come back n frames to know the max point
                    //directionChangeCount += byteReaded
                    directionChangeCount++;

                    if (directionChangeCount > directionChangePeriod)                           //count >= than change_period
                    {
                        sendCurveMaybe = true;
                    }
                }

                /*
                 * on inertialCalibrated don't send curve until 0 is crossed
                 * this ensures first stored phase will be ecc, that's what the rest of the program is expecting
                 * TODO: maybe this can be problematic with triggers maybe can be desinchronized, just move values
                 */
                if (inertialCalibrated && inertialCalibratedFirstCross0Pos == 0)
                {
                    sendCurveMaybe = false;
                }

                //if cutByTriggers, triggers send the curve at the beginning of this method
                if (cutByTriggers != Preferences.TriggerTypes.NO_TRIGGERS)
                {
                    sendCurveMaybe = false;
                }

                if (sendCurveMaybe)
                {
                    //int startFrame = previousFrameChange - directionChangeCount;	//startFrame

                    /*
                     * at startFrame we do the "-directionChangePeriod" because
                     * we want data a little bit earlier, because we want some zeros
                     * that will be removed by reduceCurveBySpeed
                     * if not done, then the data:
                     * 0 0 0 0 0 0 0 0 0 1
                     * will start at 10th digit (the 1)
                     * if done, then at speed will be like this:
                     * 0 0 0 0.01 0.04 0.06 0.07 0.08 0.09 1
                     * and will start at fourth digit
                     */

                    //this is better, takes a lot of time before, and then reduceCurveBySpeed will cut it
                    //but reduceCurveBySpeed is not implemented on inertial
                    //TODO: implement it
                    int startFrame = previousEnd;                       //startFrame
                    LogB.Debug("startFrame", startFrame.ToString());
                    if (startFrame < 0)
                    {
                        startFrame = 0;
                    }

                    //on inertial start when crossing 0 first time
                    if (inertialCalibrated && startFrame < inertialCalibratedFirstCross0Pos)
                    {
                        startFrame = inertialCalibratedFirstCross0Pos;
                    }

                    LogB.Information("TTTT - i," + i.ToString() +
                                     "; directionChangeCount: " +
                                     directionChangeCount.ToString() +
                                     "; lastNonZero: " +
                                     lastNonZero.ToString() +
                                     "; final: " +
                                     ((i - directionChangeCount + lastNonZero) / 2).ToString());

                    ecc = new EncoderCaptureCurve(
                        startFrame,
                        (i - directionChangeCount + lastNonZero) / 2                                    //endFrame
                        //to find endFrame, first substract directionChangePeriod from i
                        //then find the middle point between that and lastNonZero
                        //this means that the end is in central point at displacements == 0
                        );

                    //since 1.5.0 secundary thread is capturing and sending data to R process
                    //while main thread is reading data coming from R and updating GUI

                    LogB.Debug("curve stuff" + ecc.startFrame + ":" + ecc.endFrame + ":" + encoderReaded.Count);
                    if (ecc.endFrame - ecc.startFrame > 0)
                    {
                        double [] curve = new double[ecc.endFrame - ecc.startFrame];
                        int       mySum = 0;
                        for (int k = 0, j = ecc.startFrame; j < ecc.endFrame; j++)
                        {
                            curve[k] = encoderReaded[j];
                            k++;
                            mySum += encoderReaded[j];
                        }
                        ecc.up = (mySum >= 0);

                        previousEnd = ecc.endFrame;

                        //22-may-2015: This is done in R now

                        //1) check heightCurve in a fast way first to discard curves soon
                        //   only process curves with height >= min_height
                        //2) if it's concentric, only take the concentric curves,
                        //   but if it's concentric and inertial: take both.
                        //
                        //   When capturing on inertial, we have the first graph
                        //   that will be converted to the second.
                        //   we need the eccentric phase in order to detect the Ci2

                        /*
                         *             /\
                         *            /  \
                         *           /    \
                         *____      C1     \      ___
                         *    \    /        \    /
                         *     \  /          \  C2
                         *      \/            \/
                         *
                         * C1, C2: two concentric phases
                         */

                        /*
                         *____                    ___
                         *    \    /\      /\    /
                         *     \ Ci1 \   Ci2 \ Ci3
                         *      \/    \  /    \/
                         *             \/
                         *
                         * Ci1, Ci2, Ci3: three concentric phases on inertial
                         *
                         * Since 1.6.1:
                         * on inertial curve is sent when rope is fully extended,
                         * this will allow to see at the moment c or e. Not wait the change of direction to see both
                         */


                        //store in a boolean to not call shouldSendCurve() two times because it changes some variables
                        bool shouldSendCurveBool = shouldSendCurve();
                        if (shouldSendCurveBool)
                        {
                            //if compujump, wakeup screen if it's off
                            //do it on the first repetition because it will not be sleeping on the rest of repetitions
                            if (compujump && Ecca.curvesAccepted == 0)
                            {
                                Networks.WakeUpRaspberryIfNeeded();
                            }

                            bool success = encoderRProcCapture.SendCurve(
                                ecc.startFrame,
                                UtilEncoder.CompressData(curve, 25)                                             //compressed
                                );
                            if (!success)
                            {
                                cancel = true;
                            }

                            Ecca.curvesAccepted++;
                            Ecca.ecc.Add(ecc);
                            LogB.Information(ecc.ToString());

                            lastDirectionStoredIsUp = ecc.up;
                        }
                    }

                    //on inertial is different
                    markDirectionChanged();
                }

                //this is for visual feedback of remaining time
                msCount++;
                if (msCount >= 1000)
                {
                    Countdown--;
                    msCount = 1;
                }
            }
        } while ((cont || i < (recordingTime - 1)) && !cancel && !finish);

        LogB.Debug("runEncoderCaptureCsharp main bucle end");

        //leave some time to capture.R be able to paint data, and to create two Roptions.txt file correctly
        if (simulated)
        {
            System.Threading.Thread.Sleep(2000);
        }
        else if (!capturingInertialBG)
        {
            sp.Close();
        }

        if (cancel)
        {
            return(false);
        }

        saveToFile(outputData1);

        LogB.Debug("runEncoderCaptureCsharp ended");

        return(true);
    }