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); }