更新
This commit is contained in:
parent
2ddf1bbad5
commit
3bde6954a1
@ -26,10 +26,10 @@ flutter build windows
|
|||||||
## 二、功能
|
## 二、功能
|
||||||
|
|
||||||
1. 展示
|
1. 展示
|
||||||
1.1 座椅调节
|
1. 座椅调节
|
||||||
1.2 座椅按摩
|
1. 座椅按摩
|
||||||
1.3 座椅加热
|
1. 座椅加热
|
||||||
1.4 座椅通风
|
1. 座椅通风
|
||||||
2. 报文
|
2. 报文
|
||||||
3. 日志
|
3. 日志
|
||||||
4. 设置
|
4. 设置
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'can_fd_msg.dart';
|
||||||
|
|
||||||
//CAN设备状态抽象类
|
//CAN设备状态抽象类
|
||||||
class CANDev {
|
class CANDev {
|
||||||
//CAN设备名称
|
//CAN设备名称
|
||||||
@ -14,6 +16,8 @@ class CANDev {
|
|||||||
String firmwareversion='0.0.0';
|
String firmwareversion='0.0.0';
|
||||||
//设备句柄
|
//设备句柄
|
||||||
int devhandle=0;
|
int devhandle=0;
|
||||||
|
|
||||||
|
int errCounter=0;
|
||||||
|
|
||||||
CANDev({
|
CANDev({
|
||||||
required this.devname,
|
required this.devname,
|
||||||
@ -43,14 +47,14 @@ abstract class AbstractCANDevice {
|
|||||||
List<CANDev> getDeviceList();
|
List<CANDev> getDeviceList();
|
||||||
|
|
||||||
// 启动CAN设备
|
// 启动CAN设备
|
||||||
bool start();
|
bool start({required int canIndex,required int canChannel , required int baudrate});
|
||||||
|
|
||||||
// 停止CAN设备
|
// 停止CAN设备
|
||||||
bool stop();
|
bool stop({required int canIndex});
|
||||||
|
|
||||||
// 发送CAN消息
|
// 发送CAN消息
|
||||||
Future<bool> sendMessage(List<int> data);
|
Future<bool> sendMessage({required int canIndex, required int canChannel, required int canid,required List<int> data});
|
||||||
|
|
||||||
// 接收CAN消息
|
// 接收CAN消息
|
||||||
Stream<List<int>> receiveMessage();
|
Stream<CanFdMsg> receiveMessage({required int canIndex, required int canChannel});
|
||||||
}
|
}
|
24
lib/CanLib/can_fd_msg.dart
Normal file
24
lib/CanLib/can_fd_msg.dart
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
final class CanFdMsg extends Struct {
|
||||||
|
@Uint32()
|
||||||
|
external int id; // 报文ID,bit[30]-RTR,bit[31]-IDE,bit[28..0]-ID
|
||||||
|
|
||||||
|
@Uint8()
|
||||||
|
external int dlc; // 数据字节长度,可设置为-0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64
|
||||||
|
|
||||||
|
@Uint8()
|
||||||
|
external int flags; // bit[0]-BRS,bit[1]-ESI,bit[2]-FDF,bit[6..5]-Channel,bit[7]-RXD
|
||||||
|
|
||||||
|
@Uint8()
|
||||||
|
external int res0; // 保留
|
||||||
|
|
||||||
|
@Uint8()
|
||||||
|
external int res1; // 保留
|
||||||
|
|
||||||
|
@Uint32()
|
||||||
|
external int timeStamp; // 帧接收或者发送时的时间戳,单位为10us
|
||||||
|
|
||||||
|
@Array<Uint8>(64)
|
||||||
|
external Array<Uint8> data;
|
||||||
|
}
|
49
lib/CanLib/canfd_init_config.dart
Normal file
49
lib/CanLib/canfd_init_config.dart
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
final class CanFdInitConfig extends Struct {
|
||||||
|
/// 0-正常模式,1-自发自收模式
|
||||||
|
@Uint8()
|
||||||
|
external int mode;
|
||||||
|
|
||||||
|
/// 0-禁止ISO CRC,1-使能ISO CRC
|
||||||
|
@Uint8()
|
||||||
|
external int isocrcEnable;
|
||||||
|
|
||||||
|
/// 0-禁止重发,1-无限制重发
|
||||||
|
@Uint8()
|
||||||
|
external int retrySend;
|
||||||
|
|
||||||
|
/// 0-不接入内部120欧终端电阻,1-接入内部120欧终端电阻
|
||||||
|
@Uint8()
|
||||||
|
external int resEnable;
|
||||||
|
|
||||||
|
/// 仲裁段波特率参数, 波特率=40M/NBT_BRP*(1+NBT_SEG1+NBT_SEG2)
|
||||||
|
@Uint8()
|
||||||
|
external int nbtBRP;
|
||||||
|
|
||||||
|
@Uint8()
|
||||||
|
external int nbtSEG1;
|
||||||
|
|
||||||
|
@Uint8()
|
||||||
|
external int nbtSEG2;
|
||||||
|
|
||||||
|
@Uint8()
|
||||||
|
external int nbtSJW;
|
||||||
|
|
||||||
|
/// 数据段波特率参数, 波特率=40M/DBT_BRP*(1+DBT_SEG1+DBT_SEG2)
|
||||||
|
@Uint8()
|
||||||
|
external int dbtBRP;
|
||||||
|
|
||||||
|
@Uint8()
|
||||||
|
external int dbtSEG1;
|
||||||
|
|
||||||
|
@Uint8()
|
||||||
|
external int dbtSEG2;
|
||||||
|
|
||||||
|
@Uint8()
|
||||||
|
external int dbtSJW;
|
||||||
|
|
||||||
|
/// 预留字段
|
||||||
|
@Array<Uint8>(8)
|
||||||
|
external Array<Uint8> res0;
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
import 'abstract_can_device.dart';
|
import 'abstract_can_device.dart';
|
||||||
import 'device_info.dart';
|
import 'device_info.dart';
|
||||||
|
import 'canfd_init_config.dart';
|
||||||
|
import 'can_fd_msg.dart';
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
@ -96,27 +98,147 @@ bool initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool start() {
|
bool start({required int canIndex,required int canChannel , required int baudrate}) {
|
||||||
// 实现启动逻辑
|
// 实现启动逻辑
|
||||||
|
try {
|
||||||
|
final canfdInit = _dll.lookupFunction<Int32 Function(Int32, Uint8, Pointer<CanFdInitConfig>), int Function(int, int, Pointer<CanFdInitConfig>)>('CANFD_Init');
|
||||||
|
// 假设这里使用第一个设备的句柄,可根据实际情况修改
|
||||||
|
if (_deviceList.isNotEmpty) {
|
||||||
|
var canConfig = calloc<CanFdInitConfig>(); // 初始化 CANFD_INIT_CONFIG
|
||||||
|
canConfig.ref.mode = 0; // 正常模式
|
||||||
|
canConfig.ref.isocrcEnable = 0; // 禁用 ISO CRC
|
||||||
|
canConfig.ref.retrySend = 0; // 禁止重发
|
||||||
|
canConfig.ref.resEnable = 1; // 接入内部 120 欧终端电阻
|
||||||
|
canConfig.ref.nbtBRP = 1; // 仲裁段波特率参数
|
||||||
|
canConfig.ref.nbtSEG1 = 59; // 仲裁段波特率参数
|
||||||
|
canConfig.ref.nbtSEG2 = 20; // 仲裁段波特率参数
|
||||||
|
canConfig.ref.nbtSJW = 2; // 仲裁段波特率参数
|
||||||
|
canConfig.ref.dbtBRP = 2; // 数据段波特率参数
|
||||||
|
canConfig.ref.dbtSEG1 = 29; // 数据段波特率参数
|
||||||
|
canConfig.ref.dbtSEG2 = 10; // 数据段波特率参数
|
||||||
|
canConfig.ref.dbtSJW = 2; // 数据段波特率参数
|
||||||
|
final result = canfdInit(_deviceList[canIndex].devhandle, canChannel, canConfig);
|
||||||
|
calloc.free(canConfig); // 释放内存
|
||||||
|
if (result != 1) {
|
||||||
|
_logger.severe('CANFD_Init 初始化失败,返回值: $result');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//初始化成功
|
||||||
|
_logger.info('CANFD_Init 初始化成功,返回值: $result');
|
||||||
|
_deviceList[canIndex].channelstatus[canChannel] = true;
|
||||||
|
_deviceList[canIndex].runstatus = true;
|
||||||
|
} else {
|
||||||
|
_logger.severe('无可用设备,无法初始化 CANFD_Init');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_logger.severe('调用 CANFD_Init 时发生异常: $e');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool stop() {
|
bool stop({required int canIndex}) {
|
||||||
// 实现停止逻辑
|
try {
|
||||||
return true;
|
if (_loadDll && _deviceList.isNotEmpty) {
|
||||||
|
final usbCloseDevice = _dll.lookupFunction<Bool Function(Int32), bool Function(int)>('USB_CloseDevice');
|
||||||
|
final result = usbCloseDevice(_deviceList[canIndex].devhandle);
|
||||||
|
if (!result) {
|
||||||
|
_logger.severe('USB_CloseDevice 调用失败,设备句柄: ${_deviceList[canIndex].devhandle.toRadixString(16).toUpperCase()}');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
_logger.severe('无法调用 USB_CloseDevice,可能 DLL 未加载或无可用设备。');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_logger.severe('调用 USB_CloseDevice 时发生异常: $e');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> sendMessage(List<int> data) {
|
Future<bool> sendMessage({required int canIndex, required int canChannel, required int canid,required List<int> data}) {
|
||||||
// 实现发送消息逻辑
|
if(_deviceList[canIndex].runstatus == false || _deviceList[canIndex].channelstatus[canChannel] == false) {
|
||||||
return Future.value(true);
|
return Future.value(false);//设备/通道未启动
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final canfdSendMsg = _dll.lookupFunction<Int32 Function(Int32, Uint8, Pointer<CanFdMsg>, Uint32), int Function(int, int, Pointer<CanFdMsg>, int)>('CANFD_SendMsg');
|
||||||
|
if (_deviceList.isNotEmpty) {
|
||||||
|
final devHandle = _deviceList[canIndex].devhandle;
|
||||||
|
var canMsg = calloc<CanFdMsg>();
|
||||||
|
canMsg.ref.id = canid;
|
||||||
|
canMsg.ref.dlc = data.length.toUnsigned(8);
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
canMsg.ref.data[i] = data[i].toUnsigned(8);
|
||||||
|
}
|
||||||
|
final result = canfdSendMsg(devHandle, canChannel, canMsg, 1);
|
||||||
|
calloc.free(canMsg);
|
||||||
|
if (result >= 0) {
|
||||||
|
//_logger.info('CANFD_SendMsg 发送成功,返回值: $result');
|
||||||
|
_deviceList[canIndex].errCounter = 0;
|
||||||
|
return Future.value(true);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
//函数返回值错误信息定义
|
||||||
|
#define CANFD_SUCCESS (0) //函数执行成功
|
||||||
|
#define CANFD_ERR_NOT_SUPPORT (-1) //适配器不支持该函数
|
||||||
|
#define CANFD_ERR_USB_WRITE_FAIL (-2) //USB写数据失败
|
||||||
|
#define CANFD_ERR_USB_READ_FAIL (-3) //USB读数据失败
|
||||||
|
#define CANFD_ERR_CMD_FAIL (-4) //命令执行失败
|
||||||
|
*/
|
||||||
|
_logger.severe('CANFD_SendMsg 发送失败,返回值: $result');
|
||||||
|
_deviceList[canIndex].errCounter++;
|
||||||
|
if(_deviceList[canIndex].errCounter > 5) {
|
||||||
|
_deviceList[canIndex].channelstatus[canChannel] = false;
|
||||||
|
_deviceList[canIndex].runstatus = false;
|
||||||
|
}
|
||||||
|
return Future.value(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_logger.severe('无可用设备,无法调用 CANFD_SendMsg');
|
||||||
|
return Future.value(false);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_logger.severe('调用 CANFD_SendMsg 时发生异常: $e');
|
||||||
|
_deviceList[canIndex].channelstatus[canChannel] = false;
|
||||||
|
_deviceList[canIndex].runstatus = false;
|
||||||
|
return Future.value(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<List<int>> receiveMessage() {
|
Stream<CanFdMsg> receiveMessage({required int canIndex, required int canChannel}) {
|
||||||
// 实现接收消息逻辑
|
return Stream.periodic(Duration(milliseconds: 10), (_) {
|
||||||
return Stream.empty();
|
if(_deviceList[canIndex].runstatus == false || _deviceList[canIndex].channelstatus[canChannel] == false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final canfdGetMsg = _dll.lookupFunction<Int32 Function(Int32, Uint8, Pointer<CanFdMsg>, Int32), int Function(int, int, Pointer<CanFdMsg>, int)>('CANFD_GetMsg');
|
||||||
|
final bufferSize = 100;
|
||||||
|
final canMsgs = calloc<CanFdMsg>(bufferSize);
|
||||||
|
final result = canfdGetMsg(_deviceList[canIndex].devhandle, canChannel, canMsgs, bufferSize);
|
||||||
|
if (result > 0) {
|
||||||
|
List<CanFdMsg> messages = [];
|
||||||
|
for (int i = 0; i < result; i++) {
|
||||||
|
// 复制消息数据,避免内存释放后访问问题
|
||||||
|
final msgCopy = calloc<CanFdMsg>();
|
||||||
|
msgCopy.ref = canMsgs[i];
|
||||||
|
messages.add(msgCopy.ref);
|
||||||
|
}
|
||||||
|
calloc.free(canMsgs);
|
||||||
|
return messages;
|
||||||
|
} else {
|
||||||
|
calloc.free(canMsgs);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_logger.severe('调用 CANFD_GetMsg 时发生异常: $e');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).where((messages) => messages != null).expand((messages) => messages!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
95
lib/device_managge.dart
Normal file
95
lib/device_managge.dart
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class DeviceManagementDialog extends StatelessWidget {
|
||||||
|
const DeviceManagementDialog({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// 定义CAN设备ID、CAN通道和波特率的选项列表
|
||||||
|
final List<String> canDeviceIds = ['ID1', 'ID2', 'ID3'];
|
||||||
|
final List<String> canChannels = ['通道1', '通道2'];
|
||||||
|
final List<String> baudRates = ['500K', '115200', '250000'];
|
||||||
|
|
||||||
|
// 定义选中的值的状态变量
|
||||||
|
String selectedCanDeviceId = canDeviceIds[0];
|
||||||
|
String selectedCanChannel = canChannels[0];
|
||||||
|
String selectedBaudRate = baudRates[0];
|
||||||
|
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('设备管理'),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
// CAN设备ID下拉框
|
||||||
|
DropdownButton<String>(
|
||||||
|
value: selectedCanDeviceId,
|
||||||
|
onChanged: (newValue) {
|
||||||
|
if (newValue != null) {
|
||||||
|
selectedCanDeviceId = newValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
items: canDeviceIds.map<DropdownMenuItem<String>>((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
// CAN通道下拉框
|
||||||
|
DropdownButton<String>(
|
||||||
|
value: selectedCanChannel,
|
||||||
|
onChanged: (newValue) {
|
||||||
|
if (newValue != null) {
|
||||||
|
selectedCanChannel = newValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
items: canChannels.map<DropdownMenuItem<String>>((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
// 波特率下拉框
|
||||||
|
DropdownButton<String>(
|
||||||
|
value: selectedBaudRate,
|
||||||
|
onChanged: (newValue) {
|
||||||
|
if (newValue != null) {
|
||||||
|
selectedBaudRate = newValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
items: baudRates.map<DropdownMenuItem<String>>((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: <Widget>[
|
||||||
|
// 刷新按钮
|
||||||
|
TextButton(
|
||||||
|
child: const Text('刷新'),
|
||||||
|
onPressed: () {
|
||||||
|
// 这里可以添加刷新的逻辑
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// 连接按钮
|
||||||
|
TextButton(
|
||||||
|
child: const Text('连接'),
|
||||||
|
onPressed: () {
|
||||||
|
// 这里可以添加连接的逻辑
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// 关闭按钮
|
||||||
|
TextButton(
|
||||||
|
child: const Text('关闭'),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'Page/display_page.dart';
|
import 'Page/display_page.dart';
|
||||||
import 'Page/message_page.dart';
|
import 'Page/message_page.dart';
|
||||||
import 'Page/log_page.dart';
|
import 'Page/log_page.dart';
|
||||||
|
import 'device_managge.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
@ -107,6 +108,19 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
_scaffoldKey.currentState?.openDrawer();
|
_scaffoldKey.currentState?.openDrawer();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.settings),
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return const DeviceManagementDialog();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||||
title: Text(widget.title),
|
title: Text(widget.title),
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user