Skip to content

Commit

Permalink
Test GenerateMoveCommand and rename Type
Browse files Browse the repository at this point in the history
  • Loading branch information
Codel1417 committed Jun 5, 2024
1 parent 225df74 commit 495e717
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 33 deletions.
4 changes: 2 additions & 2 deletions lib/Backend/Bluetooth/bluetooth_manager_plus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,8 @@ Future<void> initFlutterBluePlus(InitFlutterBluePlusRef ref) async {
for (var element in FlutterBluePlus.connectedDevices) {
BaseStatefulDevice? device = knownDevices[element.remoteId.str];
if (device != null) {
device.commandQueue.addCommand(BluetoothMessage(message: "PING", device: device, priority: Priority.low, type: Type.system));
device.commandQueue.addCommand(BluetoothMessage(message: "BATT", device: device, priority: Priority.low, type: Type.system));
device.commandQueue.addCommand(BluetoothMessage(message: "PING", device: device, priority: Priority.low, type: CommandType.system));
device.commandQueue.addCommand(BluetoothMessage(message: "BATT", device: device, priority: Priority.low, type: CommandType.system));
element.readRssi();
}
}
Expand Down
4 changes: 2 additions & 2 deletions lib/Backend/Bluetooth/bluetooth_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:tail_app/Backend/Definitions/Device/device_definition.dart';

enum Priority { low, normal, high }

enum Type { system, move, direct }
enum CommandType { system, move, direct }

class BluetoothMessage implements Comparable<BluetoothMessage> {
late final String message;
Expand All @@ -15,7 +15,7 @@ class BluetoothMessage implements Comparable<BluetoothMessage> {
Function? onCommandSent;
Function(String)? onResponseReceived;
double? delay;
Type type;
CommandType type;

BluetoothMessage({required this.message, required this.device, required this.priority, required this.type, this.responseMSG, this.onCommandSent, this.onResponseReceived});

Expand Down
8 changes: 4 additions & 4 deletions lib/Backend/Definitions/Device/device_definition.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ class BaseStatefulDevice extends ChangeNotifier {
} else if (deviceConnectionState.value == ConnectivityState.connected) {
// Add initial commands to the queue
Future.delayed(const Duration(seconds: 2), () {
commandQueue.addCommand(BluetoothMessage(message: "VER", device: this, priority: Priority.low, type: Type.system, responseMSG: "VER "));
commandQueue.addCommand(BluetoothMessage(message: "HWVER", device: this, priority: Priority.low, type: Type.system, responseMSG: "HWVER "));
commandQueue.addCommand(BluetoothMessage(message: "VER", device: this, priority: Priority.low, type: CommandType.system, responseMSG: "VER "));
commandQueue.addCommand(BluetoothMessage(message: "HWVER", device: this, priority: Priority.low, type: CommandType.system, responseMSG: "HWVER "));
});
}
});
Expand Down Expand Up @@ -376,8 +376,8 @@ class CommandQueue {
device.deviceState.value = DeviceState.standby; //Without setting state to standby, another command can not run
});
// preempt queue
if (bluetoothMessage.type == Type.direct) {
state.toUnorderedList().where((element) => [Type.move, Type.direct].contains(element.type)).forEach((element) => state.remove(element));
if (bluetoothMessage.type == CommandType.direct) {
state.toUnorderedList().where((element) => [CommandType.move, CommandType.direct].contains(element.type)).forEach((element) => state.remove(element));
}
state.add(bluetoothMessage);
}
Expand Down
30 changes: 16 additions & 14 deletions lib/Backend/move_lists.dart
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class Move {

Move();

Move.move(this.leftServo, this.rightServo, this.speed, this.easingType);
Move.move({this.leftServo = 0, this.rightServo = 0, this.speed = 50, this.easingType = EasingType.linear, this.moveType = MoveType.move});

Move.delay(this.time) {
moveType = MoveType.delay;
Expand Down Expand Up @@ -173,22 +173,24 @@ class MoveLists extends _$MoveLists {
return results;
}

void add(MoveList moveList) {
Future<void> add(MoveList moveList) async {
List<MoveList> state2 = List.from(state);
state2.add(moveList);
state = state2;
await store();
}

void remove(MoveList moveList) {
Future<void> remove(MoveList moveList) async {
List<MoveList> state2 = List.from(state);
state2.remove(moveList);
state = state2;
await store();
}

Future<void> store() async {
sequencesLogger.info("Storing sequences");
HiveProxy.clear<MoveList>('sequences');
HiveProxy.addAll<MoveList>('sequences', state);
await HiveProxy.clear<MoveList>('sequences');
await HiveProxy.addAll<MoveList>('sequences', state);
}
}

Expand All @@ -201,18 +203,18 @@ Future<void> runAction(BaseAction action, BaseStatefulDevice device) async {
Object element = action.commandMoves[i];
if (element is Move) {
if (element.moveType == MoveType.delay) {
BluetoothMessage message = BluetoothMessage.delay(delay: element.time, device: device, priority: Priority.normal, type: Type.move);
BluetoothMessage message = BluetoothMessage.delay(delay: element.time, device: device, priority: Priority.normal, type: CommandType.move);
device.commandQueue.addCommand(message);
}
} else if (element is CommandAction) {
//Generate move command
BluetoothMessage message = BluetoothMessage(message: element.command, device: device, priority: Priority.normal, type: Type.move, responseMSG: element.response);
BluetoothMessage message = BluetoothMessage(message: element.command, device: device, priority: Priority.normal, type: CommandType.move, responseMSG: element.response);
device.commandQueue.addCommand(message);
}
}
}
} else if (action is CommandAction) {
device.commandQueue.addCommand(BluetoothMessage(message: action.command, device: device, priority: Priority.normal, responseMSG: action.response, type: Type.move));
device.commandQueue.addCommand(BluetoothMessage(message: action.command, device: device, priority: Priority.normal, responseMSG: action.response, type: CommandType.move));
plausible.event(name: "Run Action", props: {"Action Name": action.name, "Action Type": action.actionCategory.name});
} else if (action is MoveList) {
sequencesLogger.info("Starting MoveList ${action.name}.");
Expand All @@ -233,8 +235,8 @@ Future<void> runAction(BaseAction action, BaseStatefulDevice device) async {
}
cmd = "$cmd E${move.easingType.num}F${move.easingType.num}A${move.leftServo.round().clamp(0, 128) ~/ 16}B${move.rightServo.round().clamp(0, 128) ~/ 16}L${move.speed.toInt()}";
}
device.commandQueue.addCommand(BluetoothMessage(message: cmd, device: device, priority: Priority.normal, type: Type.move));
device.commandQueue.addCommand(BluetoothMessage(message: "TAILU$preset", device: device, priority: Priority.normal, responseMSG: "TAILU$preset END", type: Type.move));
device.commandQueue.addCommand(BluetoothMessage(message: cmd, device: device, priority: Priority.normal, type: CommandType.move));
device.commandQueue.addCommand(BluetoothMessage(message: "TAILU$preset", device: device, priority: Priority.normal, responseMSG: "TAILU$preset END", type: CommandType.move));
} else {
List<Move> newMoveList = List.from(action.moves); //prevent home move from being added to original MoveList
if (action.repeat.toInt() > 1) {
Expand All @@ -246,11 +248,11 @@ Future<void> runAction(BaseAction action, BaseStatefulDevice device) async {
for (Move element in newMoveList) {
//run move command
if (element.moveType == MoveType.delay) {
BluetoothMessage message = BluetoothMessage.delay(delay: element.time, device: device, priority: Priority.normal, type: Type.move);
BluetoothMessage message = BluetoothMessage.delay(delay: element.time, device: device, priority: Priority.normal, type: CommandType.move);
device.commandQueue.addCommand(message);
} else {
//Generate move command
generateMoveCommand(element, device, Type.move).forEach(
generateMoveCommand(element, device, CommandType.move).forEach(
(element) {
device.commandQueue.addCommand(element);
},
Expand All @@ -265,7 +267,7 @@ Future<void> runAction(BaseAction action, BaseStatefulDevice device) async {
}
}

List<BluetoothMessage> generateMoveCommand(Move move, BaseStatefulDevice device, Type type) {
List<BluetoothMessage> generateMoveCommand(Move move, BaseStatefulDevice device, CommandType type) {
List<BluetoothMessage> commands = [];
if (move.moveType == MoveType.home) {
if (device.baseDeviceDefinition.deviceType == DeviceType.ears) {
Expand All @@ -276,7 +278,7 @@ List<BluetoothMessage> generateMoveCommand(Move move, BaseStatefulDevice device,
} else if (move.moveType == MoveType.move) {
if (device.baseDeviceDefinition.deviceType == DeviceType.ears) {
commands.add(BluetoothMessage(message: "SPEED ${move.speed > 60 ? Speed.fast.name.toUpperCase() : Speed.slow.name.toUpperCase()}", device: device, priority: Priority.normal, responseMSG: "SPEED ${move.speed > 60 ? Speed.fast.name.toUpperCase() : Speed.slow.name.toUpperCase()}", type: type));
commands.add(BluetoothMessage(message: "DSSP ${move.leftServo.round().clamp(0, 128)} ${move.rightServo.round().clamp(0, 128)} 000 000", device: device, priority: Priority.normal, responseMSG: "DSSP END", type: Type.move));
commands.add(BluetoothMessage(message: "DSSP ${move.leftServo.round().clamp(0, 128)} ${move.rightServo.round().clamp(0, 128)} 000 000", device: device, priority: Priority.normal, responseMSG: "DSSP END", type: CommandType.move));
} else {
commands.add(BluetoothMessage(
message: "DSSP E${move.easingType.num} F${move.easingType.num} A${move.leftServo.round().clamp(0, 128) ~/ 16} B${move.rightServo.round().clamp(0, 128) ~/ 16} L${move.speed.toInt()} M${move.speed.toInt()}", device: device, priority: Priority.normal, responseMSG: "OK", type: type));
Expand Down
12 changes: 6 additions & 6 deletions lib/Backend/sensors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ class EarMicTriggerDefinition extends TriggerDefinition {
}
rxSubscriptions = [];
ref.read(knownDevicesProvider).values.where((element) => element.deviceConnectionState.value == ConnectivityState.connected && element.baseDeviceDefinition.deviceType == DeviceType.ears).forEach((element) {
element.commandQueue.addCommand(BluetoothMessage(message: "ENDLISTEN", device: element, priority: Priority.low, responseMSG: "LISTEN OFF", type: Type.system));
element.commandQueue.addCommand(BluetoothMessage(message: "ENDLISTEN", device: element, priority: Priority.low, responseMSG: "LISTEN OFF", type: CommandType.system));
});
}

Expand All @@ -390,7 +390,7 @@ class EarMicTriggerDefinition extends TriggerDefinition {
return;
}
ref.read(knownDevicesProvider).values.where((element) => element.deviceConnectionState.value == ConnectivityState.connected && element.baseDeviceDefinition.deviceType == DeviceType.ears).forEach((element) {
element.commandQueue.addCommand(BluetoothMessage(message: "LISTEN FULL", device: element, priority: Priority.low, type: Type.system));
element.commandQueue.addCommand(BluetoothMessage(message: "LISTEN FULL", device: element, priority: Priority.low, type: CommandType.system));
});
//add listeners on new device paired
deviceRefSubscription = ref.listen(knownDevicesProvider, (previous, next) {
Expand All @@ -416,7 +416,7 @@ class EarMicTriggerDefinition extends TriggerDefinition {
//Store the current streams to keep them open
rxSubscriptions = ref.read(knownDevicesProvider).values.where((element) => element.deviceConnectionState.value == ConnectivityState.connected && element.baseDeviceDefinition.deviceType == DeviceType.ears).map(
(element) {
element.commandQueue.addCommand(BluetoothMessage(message: "LISTEN FULL", device: element, priority: Priority.low, type: Type.system));
element.commandQueue.addCommand(BluetoothMessage(message: "LISTEN FULL", device: element, priority: Priority.low, type: CommandType.system));
return element.rxCharacteristicStream.listen(
(msg) {
if (msg.contains("LISTEN_FULL BANG")) {
Expand Down Expand Up @@ -459,7 +459,7 @@ class EarTiltTriggerDefinition extends TriggerDefinition {
}
rxSubscriptions = [];
ref.read(knownDevicesProvider).values.where((element) => element.deviceConnectionState.value == ConnectivityState.connected && element.baseDeviceDefinition.deviceType == DeviceType.ears).forEach((element) {
element.commandQueue.addCommand(BluetoothMessage(message: "ENDTILTMODE", device: element, priority: Priority.low, type: Type.system));
element.commandQueue.addCommand(BluetoothMessage(message: "ENDTILTMODE", device: element, priority: Priority.low, type: CommandType.system));
});
}

Expand All @@ -469,7 +469,7 @@ class EarTiltTriggerDefinition extends TriggerDefinition {
return;
}
ref.read(knownDevicesProvider).values.where((element) => element.deviceConnectionState.value == ConnectivityState.connected && element.baseDeviceDefinition.deviceType == DeviceType.ears).forEach((element) {
element.commandQueue.addCommand(BluetoothMessage(message: "TILTMODE START", device: element, priority: Priority.low, type: Type.system));
element.commandQueue.addCommand(BluetoothMessage(message: "TILTMODE START", device: element, priority: Priority.low, type: CommandType.system));
});
//add listeners on new device paired
deviceRefSubscription = ref.listen(knownDevicesProvider, (previous, next) {
Expand All @@ -495,7 +495,7 @@ class EarTiltTriggerDefinition extends TriggerDefinition {
//Store the current streams to keep them open
rxSubscriptions = ref.read(knownDevicesProvider).values.where((element) => element.deviceConnectionState.value == ConnectivityState.connected && element.baseDeviceDefinition.deviceType == DeviceType.ears).map(
(element) {
element.commandQueue.addCommand(BluetoothMessage(message: "TILTMODE START", device: element, priority: Priority.low, type: Type.system));
element.commandQueue.addCommand(BluetoothMessage(message: "TILTMODE START", device: element, priority: Priority.low, type: CommandType.system));
return element.rxCharacteristicStream.listen(
(msg) {
if (msg.contains("TILT LEFT")) {
Expand Down
4 changes: 2 additions & 2 deletions lib/Frontend/pages/developer/bluetooth_console.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class _BluetoothConsoleState extends State<BluetoothConsole> {
autocorrect: false,
onEditingComplete: () {
widget.device.commandQueue.addCommand(
BluetoothMessage(message: cmd, device: widget.device, priority: Priority.high, type: Type.system),
BluetoothMessage(message: cmd, device: widget.device, priority: Priority.high, type: CommandType.system),
);
setState(() {
cmd = "";
Expand All @@ -53,7 +53,7 @@ class _BluetoothConsoleState extends State<BluetoothConsole> {
child: IconButton(
onPressed: () {
widget.device.commandQueue.addCommand(
BluetoothMessage(message: cmd, device: widget.device, priority: Priority.high, type: Type.system),
BluetoothMessage(message: cmd, device: widget.device, priority: Priority.high, type: CommandType.system),
);
setState(() {
cmd = "";
Expand Down
4 changes: 2 additions & 2 deletions lib/Frontend/pages/direct_gear_control.dart
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class _JoystickState extends ConsumerState<DirectGearControl> {
move.moveType = MoveType.home;
ref.read(knownDevicesProvider).values.forEach(
(element) {
generateMoveCommand(move, element, Type.direct).forEach(
generateMoveCommand(move, element, CommandType.direct).forEach(
(message) {
message.responseMSG = null;
message.priority = Priority.high;
Expand Down Expand Up @@ -186,7 +186,7 @@ class _JoystickState extends ConsumerState<DirectGearControl> {
move.leftServo = left;
ref.read(knownDevicesProvider).values.where((element) => deviceTypes.contains(element.baseDeviceDefinition.deviceType)).forEach(
(element) {
generateMoveCommand(move, element, Type.direct).forEach(
generateMoveCommand(move, element, CommandType.direct).forEach(
(message) {
message.responseMSG = null;
message.priority = Priority.high;
Expand Down
2 changes: 1 addition & 1 deletion lib/Frontend/pages/shell.dart
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ class _ManageGearState extends ConsumerState<ManageGear> {
TextButton(
onPressed: () {
setState(() {
widget.device.commandQueue.addCommand(BluetoothMessage(message: "SHUTDOWN", device: widget.device, priority: Priority.high, type: Type.system));
widget.device.commandQueue.addCommand(BluetoothMessage(message: "SHUTDOWN", device: widget.device, priority: Priority.high, type: CommandType.system));
});
Navigator.pop(context);
},
Expand Down
75 changes: 75 additions & 0 deletions test/Backend/move_lists_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import 'package:flutter_test/flutter_test.dart' as flTest;
import 'package:flutter_test/flutter_test.dart';
import 'package:riverpod/src/framework.dart';
import 'package:tail_app/Backend/Bluetooth/bluetooth_manager.dart';
import 'package:tail_app/Backend/Bluetooth/bluetooth_message.dart';
import 'package:tail_app/Backend/Definitions/Device/device_definition.dart';
import 'package:tail_app/Backend/move_lists.dart';

import '../testing_utils/gear_utils.dart';
import '../testing_utils/hive_utils.dart';

void main() {
setUp(() async {
flTest.TestWidgetsFlutterBinding.ensureInitialized();
await setupHive();
});
tearDown(() async {
await deleteHive();
});
group('GenerateMoveCommands', () {
test('Tail DSSP', () async {
ProviderContainer providerContainer = await testGearAdd('MiTail');
BaseStatefulDevice baseStatefulDevice = providerContainer.read(knownDevicesProvider).values.first;
Move move = Move.move(leftServo: 50, rightServo: 100);
CommandType type = CommandType.move;
List<BluetoothMessage> commands = generateMoveCommand(move, baseStatefulDevice, type);
expect(commands.length, 1);
expect(commands.first.message, 'DSSP E0 F0 A3 B6 L50 M50');
expect(commands.first.responseMSG, 'OK');
expect(commands.first.device, baseStatefulDevice);
expect(commands.first.type, type);
});
test('Tail Home', () async {
ProviderContainer providerContainer = await testGearAdd('MiTail');
BaseStatefulDevice baseStatefulDevice = providerContainer.read(knownDevicesProvider).values.first;
Move move = Move.home();
CommandType type = CommandType.move;
List<BluetoothMessage> commands = generateMoveCommand(move, baseStatefulDevice, type);
expect(commands.length, 1);
expect(commands.first.message, 'TAILHM');
expect(commands.first.responseMSG, 'END TAILHM');
expect(commands.first.device, baseStatefulDevice);
expect(commands.first.type, type);
});
test('EAR DSSP', () async {
ProviderContainer providerContainer = await testGearAdd('EG2');
BaseStatefulDevice baseStatefulDevice = providerContainer.read(knownDevicesProvider).values.first;
Move move = Move.move(leftServo: 50, rightServo: 100);
CommandType type = CommandType.move;
List<BluetoothMessage> commands = generateMoveCommand(move, baseStatefulDevice, type);
expect(commands.length, 2);
expect(commands[0].message, 'SPEED SLOW');
expect(commands[0].responseMSG, 'SPEED SLOW');
expect(commands[0].device, baseStatefulDevice);
expect(commands[0].type, type);

expect(commands[1].message, 'DSSP 50 100 000 000');
expect(commands[1].responseMSG, 'DSSP END');
expect(commands[1].device, baseStatefulDevice);
expect(commands[1].type, type);
});
test('Ear Home', () async {
ProviderContainer providerContainer = await testGearAdd('EG2');
BaseStatefulDevice baseStatefulDevice = providerContainer.read(knownDevicesProvider).values.first;
Move move = Move.home();
CommandType type = CommandType.move;
List<BluetoothMessage> commands = generateMoveCommand(move, baseStatefulDevice, type);
expect(commands.length, 1);
expect(commands.first.message, 'EARHOME');
expect(commands.first.responseMSG, 'EARHOME END');
expect(commands.first.device, baseStatefulDevice);
expect(commands.first.type, type);
});
});
}

0 comments on commit 495e717

Please sign in to comment.