healthrian_uart_support 1.1.1 copy "healthrian_uart_support: ^1.1.1" to clipboard
healthrian_uart_support: ^1.1.1 copied to clipboard

Healthrian library for supporting UART connector manager

example/lib/main.dart

import 'dart:async';
import 'dart:io';
import 'dart:math';

import 'package:file_picker/file_picker.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:healthrian_common_support/healthrian_common_support.dart';
import 'package:healthrian_uart_support/healthrian_uart_support.dart';
import 'package:intl/intl.dart';
import 'package:screenshot/screenshot.dart';

final uart = UartConnectorManager();

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await filter.waitForCompletion();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  StreamSubscription? _listener;
  DateTime? _recordedTime;
  String? _selectedDirectory;

  DataFilter _dataFilter = DataFilter(2)
    ..samplingRate = SamplingRate.freq500hz
    ..impulseType = ImpulseType.fir
    ..highPass = HighPass.hpf05
    ..lowPass = LowPass.lpf40;

  final _l1Raw = <double>[];
  final _l1 = <double>[];
  final _l2 = <double>[];
  final _l3 = <double>[];
  final _aVR = <double>[];
  final _aVL = <double>[];
  final _aVF = <double>[];

  void _clear() {
    _l1Raw.clear();
    _l1.clear();
    _l2.clear();
    _l3.clear();
    _aVR.clear();
    _aVL.clear();
    _aVF.clear();
  }

  void _add(double l1, double l2) {
    _l1Raw.add(l1);
    l1 = _dataFilter.applyFilter(0, l1);
    l2 = _dataFilter.applyFilter(1, l2);
    _l1.add(l1);
    _l2.add(l2);
    _l3.add(l2 - l1);
    _aVR.add(-l2 / 2 - l1 / 2);
    _aVL.add(l1 - l2 / 2);
    _aVF.add(l2 - l1 / 2);
  }

  @override
  void dispose() {
    super.dispose();
    _listener?.cancel();
    _clear();

    uart.closePort();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Column(
          children: [
            const Text('PACKET'),
            StreamBuilder(
              stream: uart.outStream,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            const Divider(),
            const Text('LA, RA, LL, CABLE'),
            StreamBuilder(
              stream: uart.la,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            StreamBuilder(
              stream: uart.ra,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            StreamBuilder(
              stream: uart.ll,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            StreamBuilder(
              stream: uart.cable,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            const Divider(),
            const Text('ADC'),
            StreamBuilder(
              stream: uart.adc,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            const Text('Distance'),
            StreamBuilder(
              stream: uart.distance,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            const Divider(),
            const Text('L1, L2, L3, AVR, AVL, AVF'),
            StreamBuilder(
              stream: uart.l1,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            StreamBuilder(
              stream: uart.l2,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            StreamBuilder(
              stream: uart.l3,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            StreamBuilder(
              stream: uart.aVR,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            StreamBuilder(
              stream: uart.aVL,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            StreamBuilder(
              stream: uart.aVF,
              builder: (context, snapshot) => Text(snapshot.data.toString()),
            ),
            const Divider(),
          ],
        ),
        floatingActionButton: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.end,
              children: [
                FloatingActionButton(
                  onPressed: () => uart.setCalibOpen(),
                  child: const Text('Calib\nOpen', style: TextStyle(color: Colors.red)),
                ),
                FloatingActionButton(
                  onPressed: () => uart.setCalib15cm(),
                  child: const Text('Calib\n15cm', style: TextStyle(color: Colors.red)),
                ),
                FloatingActionButton(
                  onPressed: () => uart.setCalib30cm(),
                  child: const Text('Calib\n30cm', style: TextStyle(color: Colors.red)),
                ),
                FloatingActionButton(
                  onPressed: () => uart.setCalib45cm(),
                  child: const Text('Calib\n45cm', style: TextStyle(color: Colors.red)),
                ),
                FloatingActionButton(
                  onPressed: () async {
                    final calibrations = await uart.getCalibration();
                    if (!context.mounted) return;
                    showDialog(
                      context: context,
                      builder: (context) => Dialog(
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Text(calibrations.join(',')),
                        ),
                      ),
                    );
                  },
                  child: const Text('Read\nCalib', style: TextStyle(color: Colors.green)),
                ),
              ],
            ),
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.end,
              children: [
                // FloatingActionButton(
                //   onPressed: uart.hideStatusBar,
                // ),
                // FloatingActionButton(
                //   onPressed: uart.showStatusBar,
                // ),
                FloatingActionButton(
                  onPressed: uart.turnOn,
                  child: const Icon(Icons.power),
                ),
                FloatingActionButton(
                  onPressed: uart.closePort,
                  child: const Icon(Icons.power_off),
                ),
                FloatingActionButton(
                  onPressed: uart.start,
                  child: const Icon(Icons.play_arrow),
                ),
                FloatingActionButton(
                  onPressed: uart.stop,
                  child: const Icon(Icons.stop),
                ),
                if (_listener == null)
                  FloatingActionButton(
                    onPressed: () async {
                      if (_selectedDirectory == null) {
                        await FilePicker.platform.getDirectoryPath().then((path) => _selectedDirectory = path);
                      }
                      if (_selectedDirectory == null) return;

                      _listener?.cancel();
                      _clear();

                      _dataFilter = DataFilter(2)
                        ..samplingRate = SamplingRate.freq500hz
                        ..impulseType = ImpulseType.fir
                        ..highPass = HighPass.hpf05
                        ..lowPass = LowPass.lpf40;

                      _recordedTime = DateTime.now();
                      _listener = uart.all.listen((x) => _add(x.l1, x.l2));
                      setState(() {});
                    },
                    tooltip: 'start record',
                    child: const Icon(Icons.emergency_recording),
                  ),
                if (_listener != null)
                  FloatingActionButton(
                    onPressed: () {
                      _listener?.cancel();
                      _listener = null;
                      setState(() {});

                      if (_selectedDirectory == null) return;
                      if (_recordedTime == null) return;

                      final recordedTimeText = DateFormat('yyyy-MM-dd_hh-mm-ss').format(_recordedTime!);
                      final totalStep = (_l1.length / 5000).ceil();

                      final rawFile = File('$_selectedDirectory/$recordedTimeText.txt');
                      rawFile.writeAsStringSync(_l1Raw.toString());

                      for (var step = 0; step < totalStep; step++) {
                        final file = File('$_selectedDirectory/${recordedTimeText}_$step.png');
                        ScreenshotController()
                            .captureFromWidget(
                              CapturedScreen(
                                size: Size(1000, 720),
                                l1: _l1,
                                l2: _l2,
                                l3: _l3,
                                aVR: _aVR,
                                aVL: _aVL,
                                aVF: _aVF,
                                samplingRate: 500,
                                gridColor: Colors.red,
                                strokeWidth: 1.5,
                                step: step,
                              ),
                              context: context,
                              targetSize: Size(1000, 720),
                            )
                            .then((bytes) async => await file.writeAsBytes(bytes));
                      }
                    },
                    tooltip: 'stop record',
                    child: const Icon(Icons.emergency_recording, color: Colors.red),
                  ),
                FloatingActionButton(
                  // onPressed: () => uart.updateLatestWithPassword(String.fromEnvironment('PASSWORD')),
                  onPressed: () => uart.updateLatestWithPassword('healthrian@2025'),
                  child: const Text('FW\nUpdate', style: TextStyle(color: Colors.red)),
                ),
                FloatingActionButton(
                  onPressed: () async {
                    final fwVersion = await uart.getFirmwareVersion();
                    if (!context.mounted) return;
                    showDialog(
                      context: context,
                      builder: (context) => Dialog(
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Text(fwVersion),
                        ),
                      ),
                    );
                  },
                  child: const Text('FW\nVersion', style: TextStyle(color: Colors.green)),
                ),
                FloatingActionButton(
                  onPressed: () async {
                    final serialNumber = await uart.getSerialNumber();
                    if (!context.mounted) return;
                    showDialog(
                      context: context,
                      builder: (context) => Dialog(
                        child: Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: Text(serialNumber),
                        ),
                      ),
                    );
                  },
                  child: const Text('Serial\nNo.', style: TextStyle(color: Colors.green)),
                ),
                FloatingActionButton(
                  onPressed: () => uart.enableReadLogger = !uart.enableReadLogger,
                  child: const Text('Read\nLogger'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class CapturedScreen extends StatelessWidget {
  const CapturedScreen({
    super.key,
    required this.size,
    required this.l1,
    required this.l2,
    required this.l3,
    required this.aVR,
    required this.aVL,
    required this.aVF,
    required this.samplingRate,
    required this.gridColor,
    required this.strokeWidth,
    required this.step,
  });

  final Size size;
  final List<double> l1;
  final List<double> l2;
  final List<double> l3;
  final List<double> aVR;
  final List<double> aVL;
  final List<double> aVF;
  final int samplingRate;
  final Color gridColor;
  final double strokeWidth;
  final int step;

  @override
  Widget build(BuildContext context) {
    return Container(
      width: size.width,
      height: size.height,
      color: Colors.white,
      child: Column(
        children: [
          for (final list in [l1, l2, l3, aVR, aVL, aVF])
            Expanded(
              child: LineChart(
                LineChartData(
                  minX: 0,
                  maxX: 5000,
                  minY: -1.5,
                  maxY: 1.5,
                  lineTouchData: const LineTouchData(enabled: false),
                  titlesData: const FlTitlesData(show: false),
                  borderData: FlBorderData(show: false),
                  gridData: FlGridData(
                    show: true,
                    checkToShowVerticalLine: (x) => x % (samplingRate / 25) == 0,
                    verticalInterval: 10,
                    getDrawingVerticalLine: (x) {
                      if (x % (samplingRate / 5) == 0) {
                        return FlLine(color: gridColor, strokeWidth: strokeWidth / 2);
                      }
                      return FlLine(color: gridColor, strokeWidth: strokeWidth / 4);
                    },
                    horizontalInterval: 0.1,
                    getDrawingHorizontalLine: (y) {
                      if ((y * 10).round() % 5 == 0) {
                        return FlLine(color: gridColor, strokeWidth: strokeWidth / 2);
                      }
                      return FlLine(color: gridColor, strokeWidth: strokeWidth / 4);
                    },
                  ),
                  lineBarsData: [
                    LineChartBarData(
                      spots: [
                        ...list
                            .getRange(step * 5000, min(list.length, step * 5000 + 5000))
                            .indexed
                            .map((x) => FlSpot(x.$1.toDouble(), x.$2))
                      ],
                      color: Colors.black,
                      dotData: const FlDotData(show: false),
                    )
                  ],
                ),
              ),
            ),
        ],
      ),
    );
  }
}
1
likes
120
points
95
downloads

Publisher

unverified uploader

Weekly Downloads

Healthrian library for supporting UART connector manager

Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

data, device_info_plus, encrypt, flutter, flutter_libserialport, healthrian_common_support, mobx, rxdart, shared_preferences, shell

More

Packages that depend on healthrian_uart_support