|
|
@@ -1,7 +1,11 @@
|
|
|
// ignore_for_file: unused_import, unused_field, prefer_final_fields
|
|
|
|
|
|
+import 'dart:async';
|
|
|
import 'dart:typed_data';
|
|
|
import 'package:chicken_farm/components/vb_app_bar.dart';
|
|
|
+import 'package:chicken_farm/core/services/win/win_reader_channel.dart';
|
|
|
+import 'package:chicken_farm/core/services/win/win_reader_manager.dart';
|
|
|
+import 'package:chicken_farm/core/utils/logger.dart';
|
|
|
import 'package:chicken_farm/core/utils/toast.dart';
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
@@ -13,311 +17,548 @@ class SerialSettingPage extends StatefulWidget {
|
|
|
}
|
|
|
|
|
|
class _SerialSettingPageState extends State<SerialSettingPage> {
|
|
|
- // final SerialPortService _serialService = SerialPortService();
|
|
|
+ final WinReaderManager _readerManager = WinReaderManager();
|
|
|
List<String> _availablePorts = [];
|
|
|
String? _selectedPort;
|
|
|
- final TextEditingController _baudRateController = TextEditingController(
|
|
|
- text: '9600',
|
|
|
- );
|
|
|
final TextEditingController _dataController = TextEditingController();
|
|
|
final List<String> _receivedData = [];
|
|
|
bool _isConnected = false;
|
|
|
+ bool _isReading = false;
|
|
|
+
|
|
|
+ // 设备信息
|
|
|
+ String _deviceSN = '';
|
|
|
+ String _softVersion = '';
|
|
|
+ String _hardVersion = '';
|
|
|
+
|
|
|
+ // 功率相关状态
|
|
|
+ int? _currentPower;
|
|
|
+ int _selectedPower = 20; // 默认值
|
|
|
|
|
|
@override
|
|
|
void initState() {
|
|
|
super.initState();
|
|
|
- // _loadAvailablePorts();
|
|
|
- // _listenToSerialEvents();
|
|
|
+ // 注册回调函数
|
|
|
+ _readerManager.registerCallbacks(
|
|
|
+ onConnect: _onConnect,
|
|
|
+ onDataReceived: _onDataReceived,
|
|
|
+ onError: _onError,
|
|
|
+ );
|
|
|
+ _loadUsbPorts();
|
|
|
+ // 监听数据流 - 使用WinReaderManager内部处理,无需重复监听
|
|
|
}
|
|
|
|
|
|
- // /// 加载可用串口列表
|
|
|
- // void _loadAvailablePorts() {
|
|
|
- // setState(() {
|
|
|
- // _availablePorts = SerialPortService.getAvailablePorts();
|
|
|
- // if (_availablePorts.isNotEmpty) {
|
|
|
- // _selectedPort = _availablePorts.first;
|
|
|
- // }
|
|
|
- // });
|
|
|
- // }
|
|
|
+ /// 加载可用Usb列表
|
|
|
+ void _loadUsbPorts() async {
|
|
|
+ try {
|
|
|
+ final ports = await _readerManager.scanUsb();
|
|
|
+ if (mounted) {
|
|
|
+ // 检查组件是否仍然挂载
|
|
|
+ setState(() {
|
|
|
+ _availablePorts = ports ?? [];
|
|
|
+ if (_availablePorts.isNotEmpty) {
|
|
|
+ _selectedPort = _availablePorts.first;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ if (mounted) {
|
|
|
+ // 检查组件是否仍然挂载
|
|
|
+ logger.e(e);
|
|
|
+ ToastUtil.error("扫描USB设备失败: $e");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // /// 监听串口事件
|
|
|
- // void _listenToSerialEvents() {
|
|
|
- // _serialService.events.listen((event) {
|
|
|
- // switch (event.type) {
|
|
|
- // case VbSerialPortEventType.statusChanged:
|
|
|
- // final status = event.data as VbSerialPortStatus;
|
|
|
- // setState(() {
|
|
|
- // _isConnected = status == VbSerialPortStatus.opened;
|
|
|
- // });
|
|
|
- // break;
|
|
|
- // case VbSerialPortEventType.dataReceived:
|
|
|
- // final data = event.data as Uint8List;
|
|
|
- // final text = String.fromCharCodes(data);
|
|
|
- // setState(() {
|
|
|
- // _receivedData.add('RX: $text');
|
|
|
- // if (_receivedData.length > 100) {
|
|
|
- // _receivedData.removeAt(0);
|
|
|
- // }
|
|
|
- // });
|
|
|
- // break;
|
|
|
- // case VbSerialPortEventType.errorOccurred:
|
|
|
- // final errorMsg = event.errorMessage ?? '未知错误';
|
|
|
- // setState(() {
|
|
|
- // _receivedData.add('ERR: $errorMsg');
|
|
|
- // if (_receivedData.length > 100) {
|
|
|
- // _receivedData.removeAt(0);
|
|
|
- // }
|
|
|
- // });
|
|
|
- // break;
|
|
|
- // }
|
|
|
- // });
|
|
|
- // }
|
|
|
+ /// 连接状态回调
|
|
|
+ void _onConnect(bool connected) {
|
|
|
+ if (mounted) {
|
|
|
+ setState(() {
|
|
|
+ _isConnected = connected;
|
|
|
+ if (!connected) {
|
|
|
+ _isReading = false;
|
|
|
+ _deviceSN = '';
|
|
|
+ _softVersion = '';
|
|
|
+ _hardVersion = '';
|
|
|
+ _currentPower = null;
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
- // /// 连接/断开串口
|
|
|
- // void _toggleConnection() async {
|
|
|
- // if (!_isConnected) {
|
|
|
- // // 连接串口
|
|
|
- // if (_selectedPort == null) {
|
|
|
- // ToastUtil.warning("请选择串口");
|
|
|
- // return;
|
|
|
- // }
|
|
|
+ if (connected) {
|
|
|
+ _addLog("成功连接到设备: $_selectedPort");
|
|
|
+ // 连接成功后自动查询设备信息
|
|
|
+ _autoQueryDeviceInfo();
|
|
|
+ // 连接成功后自动查询功率
|
|
|
+ _autoQueryPower();
|
|
|
+ } else {
|
|
|
+ _addLog("已断开设备连接");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // final baudRate = int.tryParse(_baudRateController.text) ?? 9600;
|
|
|
- // final config = VbSerialPortConfig(baudRate: baudRate);
|
|
|
+ /// 自动查询设备信息
|
|
|
+ void _autoQueryDeviceInfo() async {
|
|
|
+ String? deviceInfo = await _readerManager.getDeviceInfo();
|
|
|
+ if (deviceInfo != null && mounted) {
|
|
|
+ // 解析设备信息
|
|
|
+ _parseDeviceInfo(deviceInfo);
|
|
|
+ _addLog("设备信息查询成功: $deviceInfo");
|
|
|
+ } else {
|
|
|
+ _addLog("设备信息查询失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // final result = await _serialService.openPort(_selectedPort!, config);
|
|
|
- // if (!result) {
|
|
|
- // ToastUtil.errorB("连接串口失败");
|
|
|
- // }
|
|
|
- // } else {
|
|
|
- // // 断开串口
|
|
|
- // await _serialService.closePort();
|
|
|
- // }
|
|
|
- // }
|
|
|
+ /// 自动查询功率
|
|
|
+ void _autoQueryPower() async {
|
|
|
+ int? power = await _readerManager.getPower();
|
|
|
+ if (power != null && mounted) {
|
|
|
+ setState(() {
|
|
|
+ _currentPower = power;
|
|
|
+ _selectedPower = power; // 设置下拉框的默认值为当前功率
|
|
|
+ });
|
|
|
+ _addLog("功率查询成功: ${power}dBm");
|
|
|
+ } else {
|
|
|
+ _addLog("功率查询失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // /// 发送数据
|
|
|
- // void _sendData() async {
|
|
|
- // if (!_isConnected) {
|
|
|
- // ToastUtil.errorB("请先连接串口");
|
|
|
- // return;
|
|
|
- // }
|
|
|
+ /// 解析设备信息字符串
|
|
|
+ void _parseDeviceInfo(String deviceInfo) {
|
|
|
+ if (mounted) {
|
|
|
+ // deviceInfo 格式: "SN:1234567890ABCDEF,SoftVer:1.2,HardVer:3.4"
|
|
|
+ List<String> parts = deviceInfo.split(',');
|
|
|
|
|
|
- // final data = _dataController.text;
|
|
|
- // if (data.isEmpty) {
|
|
|
- // ToastUtil.warning("请输入要发送的数据");
|
|
|
- // return;
|
|
|
- // }
|
|
|
+ for (String part in parts) {
|
|
|
+ if (part.startsWith('SN:')) {
|
|
|
+ setState(() {
|
|
|
+ _deviceSN = part.substring(3); // 去掉'SN:'前缀
|
|
|
+ });
|
|
|
+ } else if (part.startsWith('SoftVer:')) {
|
|
|
+ setState(() {
|
|
|
+ _softVersion = part.substring(8); // 去掉'SoftVer:'前缀
|
|
|
+ });
|
|
|
+ } else if (part.startsWith('HardVer:')) {
|
|
|
+ setState(() {
|
|
|
+ _hardVersion = part.substring(8); // 去掉'HardVer:'前缀
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // final result = await _serialService.sendString(data);
|
|
|
- // if (result) {
|
|
|
- // setState(() {
|
|
|
- // _receivedData.add('TX: $data');
|
|
|
- // if (_receivedData.length > 100) {
|
|
|
- // _receivedData.removeAt(0);
|
|
|
- // }
|
|
|
- // });
|
|
|
- // _dataController.clear();
|
|
|
- // } else {
|
|
|
- // ToastUtil.errorB("发送数据失败");
|
|
|
- // }
|
|
|
- // }
|
|
|
+ /// 数据接收回调
|
|
|
+ void _onDataReceived(String data) {
|
|
|
+ if (mounted) {
|
|
|
+ _addLog("读取标签: $data");
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // /// 清空接收区
|
|
|
- // void _clearReceivedData() {
|
|
|
- // setState(() {
|
|
|
- // _receivedData.clear();
|
|
|
- // });
|
|
|
- // }
|
|
|
+ /// 错误回调
|
|
|
+ void _onError(String error) {
|
|
|
+ if (mounted) {
|
|
|
+ _addLog("错误: $error");
|
|
|
+ ToastUtil.error("操作失败: $error");
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- @override
|
|
|
- Widget build(BuildContext context) {
|
|
|
- return Scaffold(
|
|
|
- appBar: VberAppBar(title: '串口调试工具'),
|
|
|
- body: Padding(
|
|
|
- padding: const EdgeInsets.all(16.0),
|
|
|
- // child: SingleChildScrollView(
|
|
|
- // physics: const BouncingScrollPhysics(),
|
|
|
- // child: Column(
|
|
|
- // crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
- // children: [
|
|
|
- // // 串口配置区域
|
|
|
- // Card(
|
|
|
- // child: Padding(
|
|
|
- // padding: const EdgeInsets.all(16.0),
|
|
|
- // child: Column(
|
|
|
- // crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
- // children: [
|
|
|
- // const Text(
|
|
|
- // '串口配置',
|
|
|
- // style: TextStyle(
|
|
|
- // fontSize: 18,
|
|
|
- // fontWeight: FontWeight.bold,
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // const SizedBox(height: 10),
|
|
|
- // Row(
|
|
|
- // children: [
|
|
|
- // const Text('串口:'),
|
|
|
- // const SizedBox(width: 10),
|
|
|
- // DropdownButton<String>(
|
|
|
- // value: _selectedPort,
|
|
|
- // items: _availablePorts.map((port) {
|
|
|
- // return DropdownMenuItem(
|
|
|
- // value: port,
|
|
|
- // child: Text(port),
|
|
|
- // );
|
|
|
- // }).toList(),
|
|
|
- // onChanged: (value) {
|
|
|
- // setState(() {
|
|
|
- // _selectedPort = value;
|
|
|
- // });
|
|
|
- // },
|
|
|
- // hint: const Text('选择串口'),
|
|
|
- // ),
|
|
|
- // const SizedBox(width: 20),
|
|
|
- // SizedBox(
|
|
|
- // height: 30,
|
|
|
- // child: ElevatedButton(
|
|
|
- // onPressed: _loadAvailablePorts,
|
|
|
- // child: const Text('刷新'),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
+ /// 连接USB
|
|
|
+ void _connectUsbPort() async {
|
|
|
+ if (_selectedPort == null) {
|
|
|
+ ToastUtil.error("请先选择一个USB设备");
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // const SizedBox(width: 20),
|
|
|
+ if (!_isConnected) {
|
|
|
+ // 获取当前选中设备的索引
|
|
|
+ int deviceIndex = _availablePorts.indexOf(_selectedPort!);
|
|
|
+ bool success = await _readerManager.connect(deviceIndex);
|
|
|
+ if (!success) {
|
|
|
+ ToastUtil.error("连接设备失败");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ await _readerManager.disconnect();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // const Text('波特率:'),
|
|
|
- // const SizedBox(width: 10),
|
|
|
- // SizedBox(
|
|
|
- // width: 100,
|
|
|
- // height: 40,
|
|
|
- // child: TextField(
|
|
|
- // controller: _baudRateController,
|
|
|
- // keyboardType: TextInputType.number,
|
|
|
- // decoration: const InputDecoration(
|
|
|
- // border: OutlineInputBorder(),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // const SizedBox(width: 20),
|
|
|
- // SizedBox(
|
|
|
- // height: 30,
|
|
|
- // child: ElevatedButton(
|
|
|
- // onPressed: _toggleConnection,
|
|
|
- // child: Text(
|
|
|
- // _isConnected ? '断开' : '连接',
|
|
|
- // style: TextStyle(
|
|
|
- // color: _isConnected
|
|
|
- // ? Colors.red
|
|
|
- // : Colors.green,
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ],
|
|
|
- // ),
|
|
|
- // ],
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
+ /// 开始读取
|
|
|
+ void _startRead() async {
|
|
|
+ bool success = await _readerManager.startRead();
|
|
|
+ if (success && mounted) {
|
|
|
+ setState(() {
|
|
|
+ _isReading = true;
|
|
|
+ });
|
|
|
+ _addLog("开始读取数据");
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // const SizedBox(height: 20),
|
|
|
+ /// 停止读取
|
|
|
+ void _stopRead() async {
|
|
|
+ await _readerManager.stopRead();
|
|
|
+ if (mounted) {
|
|
|
+ setState(() {
|
|
|
+ _isReading = false;
|
|
|
+ });
|
|
|
+ _addLog("已停止读取数据");
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // // 数据发送区域
|
|
|
- // Card(
|
|
|
- // child: Padding(
|
|
|
- // padding: const EdgeInsets.all(16.0),
|
|
|
- // child: Column(
|
|
|
- // crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
- // children: [
|
|
|
- // const Text(
|
|
|
- // '数据发送',
|
|
|
- // style: TextStyle(
|
|
|
- // fontSize: 18,
|
|
|
- // fontWeight: FontWeight.bold,
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // const SizedBox(height: 10),
|
|
|
- // Row(
|
|
|
- // children: [
|
|
|
- // Expanded(
|
|
|
- // child: SizedBox(
|
|
|
- // height: 50,
|
|
|
- // child: TextField(
|
|
|
- // controller: _dataController,
|
|
|
- // decoration: const InputDecoration(
|
|
|
- // hintText: '输入要发送的数据',
|
|
|
- // border: OutlineInputBorder(),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // const SizedBox(width: 10),
|
|
|
- // SizedBox(
|
|
|
- // height: 50,
|
|
|
- // child: ElevatedButton(
|
|
|
- // onPressed: _sendData,
|
|
|
- // child: const Text('发送'),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ],
|
|
|
- // ),
|
|
|
- // ],
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
+ /// 查询功率
|
|
|
+ void _queryPower() async {
|
|
|
+ if (!_isConnected) {
|
|
|
+ ToastUtil.error("请先连接设备");
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // const SizedBox(height: 20),
|
|
|
+ int? power = await _readerManager.getPower();
|
|
|
+ if (power != null && mounted) {
|
|
|
+ setState(() {
|
|
|
+ _currentPower = power;
|
|
|
+ _selectedPower = power;
|
|
|
+ });
|
|
|
+ _addLog("功率查询成功: ${power}dBm");
|
|
|
+ } else {
|
|
|
+ _addLog("功率查询失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 设置功率
|
|
|
+ void _setPower() async {
|
|
|
+ if (!_isConnected) {
|
|
|
+ ToastUtil.error("请先连接设备");
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // // 数据接收区域
|
|
|
- // Card(
|
|
|
- // child: Padding(
|
|
|
- // padding: const EdgeInsets.all(16.0),
|
|
|
- // child: Column(
|
|
|
- // crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
- // children: [
|
|
|
- // Row(
|
|
|
- // mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
- // children: [
|
|
|
- // const Text(
|
|
|
- // '数据接收',
|
|
|
- // style: TextStyle(
|
|
|
- // fontSize: 18,
|
|
|
- // fontWeight: FontWeight.bold,
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ElevatedButton(
|
|
|
- // onPressed: _clearReceivedData,
|
|
|
- // child: const Text('清空'),
|
|
|
- // ),
|
|
|
- // ],
|
|
|
- // ),
|
|
|
- // const SizedBox(height: 10),
|
|
|
- // Container(
|
|
|
- // height: 200,
|
|
|
- // decoration: BoxDecoration(
|
|
|
- // border: Border.all(color: Colors.grey),
|
|
|
- // ),
|
|
|
- // child: ListView.builder(
|
|
|
- // itemCount: _receivedData.length,
|
|
|
- // itemBuilder: (context, index) {
|
|
|
- // return Padding(
|
|
|
- // padding: const EdgeInsets.symmetric(
|
|
|
- // horizontal: 8.0,
|
|
|
- // vertical: 4.0,
|
|
|
- // ),
|
|
|
- // child: Text(_receivedData[index]),
|
|
|
- // );
|
|
|
- // },
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ],
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ),
|
|
|
- // ],
|
|
|
- // ),
|
|
|
- // ),
|
|
|
+ bool success = await _readerManager.setPower(_selectedPower);
|
|
|
+ if (success) {
|
|
|
+ ToastUtil.success("功率设置成功");
|
|
|
+ if (mounted) {
|
|
|
+ _addLog("功率设置成功: ${_selectedPower}dBm");
|
|
|
+ }
|
|
|
+ Future.delayed(const Duration(milliseconds: 500), () {
|
|
|
+ _queryPower();
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ _addLog("功率设置失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 添加日志
|
|
|
+ void _addLog(String log) {
|
|
|
+ if (mounted) {
|
|
|
+ setState(() {
|
|
|
+ _receivedData.add("${DateTime.now()}: $log");
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 清空日志
|
|
|
+ void _clearLogs() {
|
|
|
+ if (mounted) {
|
|
|
+ setState(() {
|
|
|
+ _receivedData.clear();
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return Scaffold(
|
|
|
+ appBar: VberAppBar(title: 'USB测试工具'),
|
|
|
+ body: Padding(
|
|
|
+ padding: const EdgeInsets.all(16.0),
|
|
|
+ child: SingleChildScrollView(
|
|
|
+ physics: const BouncingScrollPhysics(),
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ // 设备信息卡片
|
|
|
+ Card(
|
|
|
+ child: Padding(
|
|
|
+ padding: const EdgeInsets.all(16.0),
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ const Text('USB设备:'),
|
|
|
+ const SizedBox(width: 10),
|
|
|
+ Expanded(
|
|
|
+ child: DropdownButton<String>(
|
|
|
+ value: _selectedPort,
|
|
|
+ items: _availablePorts.map((port) {
|
|
|
+ return DropdownMenuItem(
|
|
|
+ value: port,
|
|
|
+ child: Text(
|
|
|
+ port,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }).toList(),
|
|
|
+ onChanged: (value) {
|
|
|
+ if (!_isConnected) {
|
|
|
+ setState(() {
|
|
|
+ _selectedPort = value;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ hint: const Text('选择USB'),
|
|
|
+ isExpanded: true,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 20),
|
|
|
+ SizedBox(
|
|
|
+ height: 30,
|
|
|
+ child: ElevatedButton(
|
|
|
+ onPressed: _loadUsbPorts,
|
|
|
+ child: const Text('刷新'),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 20),
|
|
|
+ if (_selectedPort != null) ...[
|
|
|
+ SizedBox(
|
|
|
+ height: 30,
|
|
|
+ child: ElevatedButton(
|
|
|
+ onPressed: _connectUsbPort,
|
|
|
+ child: Text(_isConnected ? '关闭连接' : '打开连接'),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ const SizedBox(width: 20),
|
|
|
+ if (_isConnected) ...[
|
|
|
+ SizedBox(
|
|
|
+ height: 30,
|
|
|
+ child: ElevatedButton(
|
|
|
+ onPressed: _isReading ? _stopRead : _startRead,
|
|
|
+ child: Text(_isReading ? '停止读取' : '开始读取'),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ if (_isConnected) ...[
|
|
|
+ const SizedBox(height: 10),
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ const Text(
|
|
|
+ '设备信息: ',
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 16,
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Expanded(
|
|
|
+ child: _deviceSN.isNotEmpty
|
|
|
+ ? Row(
|
|
|
+ children: [
|
|
|
+ const Text(
|
|
|
+ 'SN: ',
|
|
|
+ style: TextStyle(
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Text(
|
|
|
+ _deviceSN,
|
|
|
+ style: const TextStyle(
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 16),
|
|
|
+ const Text(
|
|
|
+ 'SoftVer: ',
|
|
|
+ style: TextStyle(
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Text(
|
|
|
+ _softVersion,
|
|
|
+ style: const TextStyle(
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 16),
|
|
|
+ const Text(
|
|
|
+ 'HardVer: ',
|
|
|
+ style: TextStyle(
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Text(
|
|
|
+ _hardVersion,
|
|
|
+ style: const TextStyle(
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ : const Text(
|
|
|
+ '未连接',
|
|
|
+ style: TextStyle(
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 20),
|
|
|
+ SizedBox(
|
|
|
+ height: 30,
|
|
|
+ child: ElevatedButton(
|
|
|
+ onPressed: _autoQueryDeviceInfo,
|
|
|
+ child: const Text('刷新设备信息'),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 10),
|
|
|
+ // 功率设置卡片
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ const Text(
|
|
|
+ '当前功率: ',
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 14,
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 10),
|
|
|
+ Text(
|
|
|
+ _currentPower != null
|
|
|
+ ? '${_currentPower}dBm'
|
|
|
+ : '未查询',
|
|
|
+ style: const TextStyle(
|
|
|
+ fontSize: 14,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 30),
|
|
|
+ SizedBox(
|
|
|
+ height: 30,
|
|
|
+ child: ElevatedButton(
|
|
|
+ onPressed: _queryPower,
|
|
|
+ child: const Text('查询功率'),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 50),
|
|
|
+ const Text(
|
|
|
+ '功率设置: ',
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 16,
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 10),
|
|
|
+ Expanded(
|
|
|
+ child: DropdownButton<int>(
|
|
|
+ value: _selectedPower,
|
|
|
+ items:
|
|
|
+ List.generate(
|
|
|
+ 26,
|
|
|
+ (index) => index + 5,
|
|
|
+ ) // 5-30的值
|
|
|
+ .map((value) {
|
|
|
+ return DropdownMenuItem(
|
|
|
+ value: value,
|
|
|
+ child: Text('${value}dBm'),
|
|
|
+ );
|
|
|
+ })
|
|
|
+ .toList(),
|
|
|
+ onChanged: (value) {
|
|
|
+ if (value != null && _isConnected) {
|
|
|
+ setState(() {
|
|
|
+ _selectedPower = value;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ isExpanded: true,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 20),
|
|
|
+
|
|
|
+ SizedBox(
|
|
|
+ height: 30,
|
|
|
+ child: ElevatedButton(
|
|
|
+ onPressed: _setPower,
|
|
|
+ child: const Text('设置功率'),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 5),
|
|
|
+ ],
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 20),
|
|
|
+ Card(
|
|
|
+ child: Padding(
|
|
|
+ padding: const EdgeInsets.all(16.0),
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ const Text(
|
|
|
+ '数据日志',
|
|
|
+ style: TextStyle(
|
|
|
+ fontSize: 16,
|
|
|
+ fontWeight: FontWeight.bold,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 10),
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ ElevatedButton(
|
|
|
+ onPressed: _clearLogs,
|
|
|
+ child: const Text('清空日志'),
|
|
|
+ ),
|
|
|
+ const SizedBox(width: 10),
|
|
|
+ Text(
|
|
|
+ '日志数量: ${_receivedData.length}',
|
|
|
+ style: const TextStyle(fontWeight: FontWeight.bold),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ const SizedBox(height: 10),
|
|
|
+ Container(
|
|
|
+ height: 250,
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ border: Border.all(color: Colors.grey),
|
|
|
+ borderRadius: BorderRadius.circular(4),
|
|
|
+ ),
|
|
|
+ child: _receivedData.isEmpty
|
|
|
+ ? const Center(child: Text('暂无日志数据'))
|
|
|
+ : ListView.builder(
|
|
|
+ itemCount: _receivedData.length,
|
|
|
+ itemBuilder: (context, index) {
|
|
|
+ return Padding(
|
|
|
+ padding: const EdgeInsets.all(8.0),
|
|
|
+ child: Text(
|
|
|
+ _receivedData[_receivedData.length -
|
|
|
+ 1 -
|
|
|
+ index],
|
|
|
+ style: const TextStyle(fontSize: 12),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
),
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+ @override
|
|
|
+ void dispose() {
|
|
|
+ // 在页面销毁时断开设备连接
|
|
|
+ if (_isConnected) {
|
|
|
+ _readerManager.disconnect();
|
|
|
+ }
|
|
|
+
|
|
|
+ _readerManager.clearCallbacks();
|
|
|
+ _readerManager.dispose();
|
|
|
+ _dataController.dispose();
|
|
|
+ super.dispose();
|
|
|
+ }
|
|
|
}
|