You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

110 lines
4.4 KiB

import 'package:eaimar/devices/bes/bes_protocol.dart';
import 'package:flutter_test/flutter_test.dart';
/// 恒玄协议金测试:帧全部来自真机抓包或厂商文档样例,**一个字节都不能改**。
/// 这些测试红了,先怀疑改动、别怀疑帧。
void main() {
List<int> h(String s) => s
.trim()
.split(RegExp(r'\s+'))
.where((e) => e.isNotEmpty)
.map((e) => int.parse(e, radix: 16))
.toList();
group('BB 0A 状态帧', () {
test('Echo-one 0.0.2 真机帧:不在盒内,无属性 3,帧尾 MAC 逐字节吻合', () {
// 2026-09-01 真机抓帧(属性 6 那 12 字节按实测样本填)
final frame = h('BB 0A 25 '
'02 01 45 '
'02 02 56 '
'02 04 49 '
'02 05 6C '
'0D 06 00 01 01 70 B3 B1 4D 33 DC 00 00 00 '
'07 07 11 11 22 33 33 A4');
final st = BesProtocol.parseStatus(frame);
expect(st.batteryLeft, 69);
expect(st.batteryRight, 86);
expect(st.batteryCase, isNull, reason: '不在盒内时没有属性 3');
expect(st.chargingLeft, isFalse);
expect(st.chargingRight, isFalse);
expect(st.mac, '11:11:22:33:33:A4');
expect(st.summaryBattery, 69, reason: '左右取较低一侧');
});
test('厂商文档样例:三个电量都在', () {
final frame = h('BB 0A 28 02 01 2B 02 02 18 02 03 64 02 04 85 02 05 6E');
final st = BesProtocol.parseStatus(frame);
expect(st.batteryLeft, 43);
expect(st.batteryRight, 24);
expect(st.batteryCase, 100);
expect(st.summaryBattery, 24);
});
test('最高位是充电指示位,必须 & 0x7F', () {
final frame = h('BB 0A 09 02 01 C5 02 02 56');
final st = BesProtocol.parseStatus(frame);
expect(st.batteryLeft, 69);
expect(st.chargingLeft, isTrue);
expect(st.batteryRight, 86);
expect(st.chargingRight, isFalse);
});
test('属性 4/5 的值超过 100 不会被当成电量', () {
final frame = h('BB 0A 06 02 04 89 02 05 6E');
final st = BesProtocol.parseStatus(frame);
expect(st.hasBattery, isFalse);
});
test('从偏移 4 开始解(固件版本帧的写法)会一个值都解不出——守住起点是 3', () {
final frame = h('BB 0A 25 02 01 45 02 02 56 02 04 49 02 05 6C');
// 人为错位一格模拟旧 bug:第一个「块长度」读到的是属性号 0x01 < 2
final shifted = [frame[0], frame[1], frame[2], 0x00, ...frame.sublist(3)];
expect(BesProtocol.parseStatus(shifted).hasBattery, isFalse);
expect(BesProtocol.parseStatus(frame).hasBattery, isTrue);
});
});
group('固件版本帧', () {
test('BB 86 优先左耳,版本取块后 3 字节', () {
final frame = h('BB 86 14 00 '
'09 01 00 00 00 00 00 00 00 02 '
'09 02 00 00 00 00 00 00 00 03');
final fw = BesProtocol.parseFirmware(frame);
expect(fw.left, '0.0.2');
expect(fw.right, '0.0.3');
expect(fw.preferred, '0.0.2');
});
});
group('命令字节', () {
test('每个 feature 对应的字节序列固定', () {
expect(BesCmd.frame(BesCmd.firmwareVersion), [0xAA, 0x06]);
expect(BesCmd.frame(BesCmd.status), [0xAA, 0x09]);
expect(BesCmd.frame(BesCmd.callState), [0xAA, 0x0E]);
expect(BesCmd.frame(BesCmd.callModeStart), [0xAA, 0x51]);
expect(BesCmd.frame(BesCmd.callModeStop), [0xAA, 0x52]);
expect(BesCmd.frame(BesCmd.asrStarted), [0xAA, 0x57]);
expect(BesCmd.frame(BesCmd.asrStopped), [0xAA, 0x58]);
expect(BesCmd.frame(BesCmd.micRecordStart), [0xAA, 0x59]);
expect(BesCmd.frame(BesCmd.micRecordStop), [0xAA, 0x5A]);
expect(BesCmd.frame(BesCmd.aiExit), [0xAA, 0x65]);
expect(BesCmd.frame(BesCmd.faceToFaceStart), [0xAA, 0x66]);
expect(BesCmd.frame(BesCmd.faceToFaceStop), [0xAA, 0x67]);
expect(BesCmd.frame(BesCmd.aiAccept), [0xAA, 0x6A]);
});
test('电量请求是 09 不是 0A,也不是 |0x80 推出来的任何值', () {
expect(BesCmd.status, 0x09);
expect(BesResp.status, 0x0A);
expect(BesCmd.status | 0x80, isNot(BesResp.status));
});
test('0x51~0x6A 会切工作模式,探测时必须跳过', () {
for (var c = 0x51; c <= 0x6A; c++) {
expect(BesCmd.switchesMode(c), isTrue, reason: '0x${c.toRadixString(16)}');
}
expect(BesCmd.switchesMode(0x09), isFalse);
expect(BesCmd.switchesMode(0x06), isFalse);
});
});
}