performTUG method

Future<TugResult> performTUG()

Performs the Timed Up and Go (TUG) test.

Handles the detection of stand up, turns, and sit down events using sensor data. Returns a TugResult with the calculated duration and segment times. Handles cancellation and errors gracefully.

Implementation

Future<TugResult> performTUG() async {
  try {
    // Start probe
    await probe.start();

    var standUpIndex = -1;
    var firstTurnIndex = Turning(startIndex: -1, endIndex: -1);
    var secondTurnIndex = Turning(startIndex: -1, endIndex: -1);
    var sitDownIndex = -1;

    while (standUpIndex == -1) {
      if (kDebugMode) {
        print('[TugTestStep] Waiting for stand up detection...');
      }
      if (completer.isCanceled) {
        return TugResult(
          identifier: identifier,
          time: Duration.zero,
          segmentTimes: [],
        )..results['error'] = 'Cancelled';
      }
      await Future.delayed(const Duration(seconds: 1));
      standUpIndex = processor.detectStandUp(
        accData: probe.accelerometerData,
        accActualRate: probe.currentAccSamplingRate().toDouble(),
      );
    }

    if (kDebugMode) {
      print(
        '[TugTestStep] Stand up detected at index $standUpIndex, starting test...',
      );
    }

    while (firstTurnIndex.startIndex == -1 && firstTurnIndex.endIndex == -1) {
      if (kDebugMode) {
        print('[TugTestStep] Waiting for turn detection...');
      }
      if (completer.isCanceled) {
        return TugResult(
          identifier: identifier,
          time: Duration.zero,
          segmentTimes: [],
        )..results['error'] = 'Cancelled';
      }
      await Future.delayed(const Duration(seconds: 1));
      firstTurnIndex = processor.detectTurn(
        gyroData: probe.gyroscopeData,
        gyroActualRate: probe.currentGyroSamplingRate().toDouble(),
        startTime: probe.accelerometerData[standUpIndex].timestamp,
        angleThreshold: (maxAngle / 2) - 15.0,
      );
    }

    if (kDebugMode) {
      print(
        '[TugTestStep] Turn detected with start index ${firstTurnIndex.startIndex}, end index ${firstTurnIndex.endIndex}, waiting for second turn...',
      );
    }

    while (secondTurnIndex.startIndex == -1 &&
        secondTurnIndex.endIndex == -1) {
      if (kDebugMode) {
        print('[TugTestStep] Waiting for second turn detection...');
      }
      if (completer.isCanceled) {
        return TugResult(
          identifier: identifier,
          time: Duration.zero,
          segmentTimes: [],
        )..results['error'] = 'Cancelled';
      }
      await Future.delayed(const Duration(seconds: 1));
      secondTurnIndex = processor.detectTurn(
        gyroData: probe.gyroscopeData,
        gyroActualRate: probe.currentGyroSamplingRate().toDouble(),
        startTime: probe.gyroscopeData[firstTurnIndex.endIndex].timestamp,
        angleThreshold: (maxAngle / 2) - 15.0,
      );
    }

    if (kDebugMode) {
      print(
        '[TugTestStep] Second turn detected with start index ${secondTurnIndex.startIndex}, end index ${secondTurnIndex.endIndex}, waiting for sit down...',
      );
    }

    while (sitDownIndex == -1) {
      if (kDebugMode) {
        print('[TugTestStep] Waiting for sit down detection...');
      }
      if (completer.isCanceled) {
        return TugResult(
          identifier: identifier,
          time: Duration.zero,
          segmentTimes: [],
        )..results['error'] = 'Cancelled';
      }
      await Future.delayed(const Duration(seconds: 1));
      sitDownIndex = processor.detectSitDown(
        accData: probe.accelerometerData,
        accActualRate: probe.currentAccSamplingRate().toDouble(),
        startTime: probe.gyroscopeData[secondTurnIndex.startIndex].timestamp,
        minimumTime: probe.gyroscopeData[secondTurnIndex.endIndex].timestamp,
      );
    }

    if (kDebugMode) {
      print(
        '[TugTestStep] Sit down detected with index $sitDownIndex, stopping test...',
      );
    }

    // Stop probe
    await probe.stop();

    var duration = probe.accelerometerData[sitDownIndex].timestamp.difference(
      probe.accelerometerData[standUpIndex].timestamp,
    );

    var segmentTimes = [
      probe.gyroscopeData[firstTurnIndex.startIndex].timestamp.difference(
        probe.accelerometerData[standUpIndex].timestamp,
      ),
      probe.gyroscopeData[firstTurnIndex.endIndex].timestamp.difference(
        probe.gyroscopeData[firstTurnIndex.startIndex].timestamp,
      ),
      probe.gyroscopeData[secondTurnIndex.startIndex].timestamp.difference(
        probe.gyroscopeData[firstTurnIndex.endIndex].timestamp,
      ),
      probe.gyroscopeData[secondTurnIndex.endIndex].timestamp.difference(
        probe.gyroscopeData[secondTurnIndex.startIndex].timestamp,
      ),
      probe.accelerometerData[sitDownIndex].timestamp.difference(
        probe.gyroscopeData[secondTurnIndex.endIndex].timestamp,
      ),
    ];

    if (kDebugMode) {
      print('Detected duration: $duration');
    }

    final results = [
      TugResult.fromResults(time: duration, segmentTimes: segmentTimes),
    ];

    // Create WTResult
    if (results.isNotEmpty) {
      final result = results.first;
      return TugResult(
        identifier: identifier,
        time: result.time,
        segmentTimes: result.segmentTimes,
      );
    } else {
      return TugResult(
        identifier: identifier,
        time: Duration.zero,
        segmentTimes: [],
      )..results['error'] = 'No valid results found';
    }
  } catch (e) {
    if (kDebugMode) {
      print('Error in TUGStep.execute: $e');
    }
    return TugResult(
      identifier: identifier,
      time: Duration.zero,
      segmentTimes: [],
    )..results['error'] = e.toString();
  }
}