Skip to content

Commit

Permalink
Overhauled serial script
Browse files Browse the repository at this point in the history
  • Loading branch information
Levi-Lesches committed Nov 28, 2024
1 parent ba2209c commit eaf71ab
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 50 deletions.
8 changes: 4 additions & 4 deletions bin/data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ Future<void> main() async {
);
server.sendMessage(data);
final data2 = ArmData(
base: MotorData(angle: motor2.current),
shoulder: MotorData(angle: motor.current),
elbow: MotorData(angle: motor.current),
base: MotorData(currentAngle: motor2.current),
shoulder: MotorData(currentAngle: motor.current),
elbow: MotorData(currentAngle: motor.current),
version: Version(major: 1),
);
server.sendMessage(data2);
final data3 = GripperData(lift: MotorData(angle: pi + -1 * 2 * motor.current), version: Version(major: 1));
final data3 = GripperData(lift: MotorData(currentAngle: pi + -1 * 2 * motor.current), version: Version(major: 1));
server.sendMessage(data3);
final data4 = RoverPosition(
orientation: Orientation(
Expand Down
144 changes: 100 additions & 44 deletions bin/serial.dart
Original file line number Diff line number Diff line change
@@ -1,92 +1,148 @@
import "dart:io";
import "dart:typed_data";
import "package:args/args.dart";
import "package:collection/collection.dart";

import "package:burt_network/burt_network.dart";
import "package:libserialport/libserialport.dart";

typedef ProtoConstructor = Message Function(List<int> data);

const constructors = <Device, ProtoConstructor>{
Device.DRIVE: DriveData.fromBuffer,
Device.ARM: ArmData.fromBuffer,
Device.GRIPPER: GripperData.fromBuffer,
Device.SCIENCE: GripperData.fromBuffer,
Device.ANTENNA: AntennaFirmwareData.fromBuffer,
};

final deviceNames = {
for (final device in constructors.keys)
device.name.toLowerCase(): device,
};

final logger = BurtLogger();

bool ascii = false;
late bool ascii;
late bool rawMode;
ProtoConstructor? constructor;
String? messageName;

void handlePacket(Uint8List buffer) {
try {
if (rawMode) {
logger.debug("Got packet: $buffer");
} else if (constructor == null) {
final string = String.fromCharCodes(buffer).trim();
logger.debug("Got string: $string");
} else {
final message = constructor!(buffer);
logger.debug("Got $messageName message: ${message.toProto3Json()}");
}
} catch (error) {
logger.error("Could not decode packet: $error\n Buffer: $buffer");
}
}

Future<void> listenToDevice(String port) async {
Future<void> listenToDevice(String port, int baudRate) async {
logger.info("Connecting to $port...");
final device = SerialDevice(
portName: port,
readInterval: const Duration(milliseconds: 100),
logger: logger,
baudRate: baudRate,
);
if (!await device.init()) {
logger.critical("Could not connect to $port");
return;
}
logger.info("Connected. Listening...");
device.stream.listen(processAscii);
device.stream.listen(handlePacket);
device.startListening();
}

Future<void> listenToFirmware(String port) async {
Future<void> listenToFirmware(String port, int baudRate) async {
logger.info("Connecting to $port...");
final device = BurtFirmwareSerial(
port: port,
logger: logger,
baudRate: baudRate,
);
if (!await device.init()) {
logger.critical("Could not connect to $port");
await device.dispose();
return;
}
logger.info("Connected? ${device.isReady}. Listening...");
constructor = getDataConstructor(device.device);
constructor = constructors[device.device];
if (constructor == null) {
logger.error("Unsupported serial device: ${device.device.name}");
await device.dispose();
return;
}
device.rawStream.listen(processFirmware);
device.rawStream.listen(handlePacket);
}

typedef ProtoConstructor = Message Function(List<int> data);

ProtoConstructor? getDataConstructor(Device device) => switch (device) {
Device.DRIVE => DriveData.fromBuffer,
Device.ARM => ArmData.fromBuffer,
Device.GRIPPER => GripperData.fromBuffer,
Device.SCIENCE => GripperData.fromBuffer,
_ => null,
};
void printUsage(ArgParser parser) =>
// ignore: avoid_print
print("\nUsage: dart run :serial [-h] [-f] [-r | -d <device>] [-b <baud>] <port>\n${parser.usage}");

ProtoConstructor? constructor;
ArgParser buildParser() => ArgParser()
..addFlag("help", abbr: "h", negatable: false, help: "Show this help message")
..addFlag("firmware", abbr: "f", negatable: false, help: "Whether to perform the standard firmware handshake")
..addFlag("raw", abbr: "r", negatable: false, help: "Whether to print incoming packets as raw bytes")
..addOption("baud", abbr: "b", defaultsTo: "9600", help: "The baud rate to listen with")
..addOption(
"device", abbr: "d",
allowed: deviceNames.keys,
help: "The device being read. This will attempt to parse data as messages from that device\n"
" Note: If -f is passed, this will be ignored and the firmware will identify itself",
);

void main(List<String> args) async {
if (args.isEmpty) {
logger.info("Ports: ${SerialPort.availablePorts}");
return;
} else if (args.contains("-h") || args.contains("--help")) {
logger.info("Usage: dart run -r :serial [-a | --ascii] [port]");
Future<void> main(List<String> args) async {
// Basic arg parsing
final parser = buildParser();
final ArgResults results;
try {
results = buildParser().parse(args);
} on FormatException catch (error) {
logger.error(error.message);
printUsage(parser);
return;
}
var port = args.first;
if (!Platform.isWindows && !port.startsWith("/dev")) port = "/dev/$port";
if (args.contains("-a") || args.contains("--ascii")) {
logger.info("Running in ASCII mode");
ascii = true;
}
if (args.contains("-f") || args.contains("--firmware")) {
await listenToFirmware(port);
} else {
await listenToDevice(port);
final isFirmware = results.flag("firmware");
final showHelp = results.flag("help");
final deviceName = results.option("device");
final baudRateString = results.option("baud")!;
final baudRate = int.tryParse(baudRateString);
rawMode = results.flag("raw");
var port = results.rest.firstOrNull;
if (showHelp) {
printUsage(parser);
return;
} else if (port == null) {
logger.info("Ports: ${SerialDevice.allPorts}");
return;
} else if (baudRate == null) {
logger.critical("Could not parse baud rate as an integer: $baudRateString");
exit(1);
} else if (rawMode && deviceName != null) {
logger.critical("Cannot specify both --raw and --device");
exit(2);
}
}

void processFirmware(Uint8List buffer) {
try {
final data = constructor!(buffer);
logger.debug("Got data: ${data.toProto3Json()}");
} catch (error) {
logger.error("Could not decode DriveData: $error\n Buffer: $buffer");
// Try to identify a device, if passed.
final device = deviceNames[deviceName];
constructor = constructors[device];
if (constructor != null) {
final buffer = Uint8List(0);
messageName = constructor!(buffer).messageName;
logger.info("Parsing all data as $messageName messages");
}
}

void processAscii(Uint8List buffer) {
final s = String.fromCharCodes(buffer).trim();
logger.debug("Got string: $s");
if (!Platform.isWindows && !port.startsWith("/dev")) port = "/dev/$port";
if (isFirmware) {
await listenToFirmware(port, baudRate);
} else {
await listenToDevice(port, baudRate);
}
}
3 changes: 1 addition & 2 deletions lib/src/devices/firmware.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ class FirmwareManager extends Service {
logger.debug("Initializing device: ${device.port}");
result &= await device.init();
if (!device.isReady) continue;
final subscription = device.messages?.listen(collection.server.sendWrapper);
if (subscription == null) continue;
final subscription = device.messages.listen(collection.server.sendWrapper);
_subscriptions.add(subscription);
}
return result;
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ environment:

# Add regular dependencies here.
dependencies:
args: ^2.6.0
burt_network:
git: https://github.com/BinghamtonRover/Networking.git
collection: ^1.19.0
Expand Down

0 comments on commit eaf71ab

Please sign in to comment.