#连接库初步完成
This commit is contained in:
@@ -1,28 +0,0 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
/// 极简化的 Codec:只负责中间那段变化的“负载数据”
|
||||
class MachineProtocolCodec {
|
||||
/// 仅封装 0x00 指令的数据部分 (Byte 3 到 Byte 10,共 8 字节)
|
||||
static Uint8List encodeRemoteControlPayload({
|
||||
required int left,
|
||||
required int right,
|
||||
int lift = 0,
|
||||
int mower = 0,
|
||||
int ignition = 0,
|
||||
int emergency = 0,
|
||||
}) {
|
||||
final bd = ByteData(8); // 只分配 8 字节
|
||||
int pos = 0;
|
||||
|
||||
bd.setInt16(pos, left, Endian.little);
|
||||
pos += 2;
|
||||
bd.setInt16(pos, right, Endian.little);
|
||||
pos += 2;
|
||||
bd.setUint8(pos++, lift);
|
||||
bd.setUint8(pos++, mower);
|
||||
bd.setUint8(pos++, ignition);
|
||||
bd.setUint8(pos++, emergency);
|
||||
|
||||
return bd.buffer.asUint8List();
|
||||
}
|
||||
}
|
||||
12
lib/core/protocol/packet_entity.dart
Normal file
12
lib/core/protocol/packet_entity.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class PacketEntity extends Equatable{
|
||||
final int cmdType;
|
||||
final List<int> payload;
|
||||
final List<int>? crc; // 心跳包可能为 null
|
||||
|
||||
const PacketEntity({required this.cmdType, required this.payload, this.crc});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [cmdType, payload, crc];
|
||||
}
|
||||
83
lib/core/protocol/packet_parser_transformer.dart
Normal file
83
lib/core/protocol/packet_parser_transformer.dart
Normal file
@@ -0,0 +1,83 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data'; // 引入 Uint8List
|
||||
|
||||
import 'protocol_constants.dart';
|
||||
import 'packet_entity.dart';
|
||||
|
||||
class PacketParserTransformer extends StreamTransformerBase<Uint8List, PacketEntity> {
|
||||
@override
|
||||
Stream<PacketEntity> bind(Stream<Uint8List> stream) {
|
||||
final List<int> buffer = [];
|
||||
final StreamController<PacketEntity> controller = StreamController<PacketEntity>();
|
||||
|
||||
stream.listen(
|
||||
(data) {
|
||||
// 将接收到的数据追加到 buffer
|
||||
buffer.addAll(data);
|
||||
|
||||
while (buffer.length >= 5) { // 最小包长(心跳) AB AA FF AA AB
|
||||
// 找 Header
|
||||
int headIdx = -1;
|
||||
for (int i = 0; i < buffer.length - 1; i++) {
|
||||
if (buffer[i] == ProtocolConstants.header1 &&
|
||||
buffer[i + 1] == ProtocolConstants.header2) {
|
||||
headIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (headIdx == -1) {
|
||||
// 如果没有找到包头,丢弃已接收的数据,继续等待数据
|
||||
buffer.clear(); // 直接清空缓冲区,可以避免部分无效数据的积累
|
||||
break;
|
||||
}
|
||||
|
||||
if (headIdx > 0) {
|
||||
// 如果包头不是从缓冲区的开头开始,移除头部无效数据
|
||||
buffer.removeRange(0, headIdx);
|
||||
}
|
||||
|
||||
// 找 Footer
|
||||
int footIdx = -1;
|
||||
for (int i = 2; i < buffer.length - 1; i++) {
|
||||
if (buffer[i] == ProtocolConstants.endFlag1 &&
|
||||
buffer[i + 1] == ProtocolConstants.endFlag2) {
|
||||
footIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (footIdx != -1) {
|
||||
final packetBytes = buffer.sublist(0, footIdx + 2); // 处理数据包
|
||||
|
||||
final cmd = packetBytes[2]; // 获取命令字节
|
||||
|
||||
if (cmd == ProtocolConstants.cmdHeartbeat) {
|
||||
controller.add(PacketEntity(cmdType: cmd, payload: [])); // 心跳包没有负载
|
||||
} else if (packetBytes.length >= 7) {
|
||||
// 带 CRC 的包
|
||||
final payload = packetBytes.sublist(3, packetBytes.length - 4);
|
||||
final crc = packetBytes.sublist(packetBytes.length - 4, packetBytes.length - 2);
|
||||
controller.add(PacketEntity(cmdType: cmd, payload: payload, crc: crc)); // 解析命令和负载
|
||||
}
|
||||
|
||||
// 完成当前数据包的解析,移除已处理的包
|
||||
buffer.removeRange(0, footIdx + 2);
|
||||
} else {
|
||||
break; // 数据不完整,等待更多数据
|
||||
}
|
||||
}
|
||||
},
|
||||
onError: (error) {
|
||||
print("Stream error: $error");
|
||||
controller.addError(error); // 如果发生错误,报告错误
|
||||
},
|
||||
onDone: () {
|
||||
print("Stream closed.");
|
||||
controller.close(); // 流关闭时,关闭控制器
|
||||
},
|
||||
);
|
||||
|
||||
return controller.stream;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
class MachineProtocolConstants {
|
||||
class ProtocolConstants {
|
||||
// 固定字节
|
||||
static const int header1 = 0xAB;
|
||||
static const int header2 = 0xAA;
|
||||
Reference in New Issue
Block a user