Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Real Dart enums over FFI #11

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions lib/src/can/ffi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,23 @@ export "package:subsystems/src/generated/can_ffi_bindings.dart";
/// See `src/can.h` in this repository. Only supported on Linux.
final nativeLib = CanBindings(DynamicLibrary.open("burt_can.so"));

/// These values come from the [BurtCanStatus] enum.
String? getCanError(int value) => switch (value) {
1 => null,
2 => "Could not create socket",
3 => "Could not parse interface",
4 => "Could not bind to socket",
5 => "Could not close socket",
6 => "Invalid MTU",
7 => "CAN FD is not supported",
8 => "Could not switch to CAN FD",
9 => "Could not write data",
10 => "Could not read data",
11 => "Frame was not fully read",
_ => throw ArgumentError.value(value, "CanStatus", "Unknown CAN status"),
};
/// Helpful methods on [BurtCanStatus]es.
extension BurtCanStatusUtils on BurtCanStatus {
/// Whether this status represents an error.
bool get isError => this != BurtCanStatus.OK;

/// Produces a human-readable string for this error condition.
String? get error => switch (this) {
BurtCanStatus.OK => null,
BurtCanStatus.SOCKET_CREATE_ERROR => "Could not create socket",
BurtCanStatus.INTERFACE_PARSE_ERROR => "Could not parse interface",
BurtCanStatus.BIND_ERROR => "Could not bind to socket",
BurtCanStatus.CLOSE_ERROR => "Could not close socket",
BurtCanStatus.MTU_ERROR => "Invalid MTU",
BurtCanStatus.CANFD_NOT_SUPPORTED => "CAN FD is not supported",
BurtCanStatus.FD_MISC_ERROR => "Could not switch to CAN FD",
BurtCanStatus.WRITE_ERROR => "Could not write data",
BurtCanStatus.READ_ERROR => "Could not read data",
BurtCanStatus.FRAME_NOT_FULLY_READ => "Frame was not fully read",
};
}
14 changes: 7 additions & 7 deletions lib/src/can/socket_ffi.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ class CanFFI implements CanSocket {
hasError = true;
return false;
}
final error = getCanError(nativeLib.BurtCan_open(_can!));
if (error != null) {
final status = nativeLib.BurtCan_open(_can!);
if (status.isError) {
hasError = true;
logger.critical("Could not start the CAN bus", body: error);
logger.critical("Could not start the CAN bus", body: status.error);
return false;
}
_startListening();
Expand All @@ -86,8 +86,8 @@ class CanFFI implements CanSocket {
void sendMessage({required int id, required List<int> data}) {
if (hasError || _can == null) return;
final message = CanMessage(id: id, data: data);
final error = getCanError(nativeLib.BurtCan_send(_can!, message.pointer));
if (error != null) logger.warning("Could not send CAN message", body: "ID=$id, Data=$data, Error: $error");
final status = nativeLib.BurtCan_send(_can!, message.pointer);
if (status.isError) logger.warning("Could not send CAN message", body: "ID=$id, Data=$data, Error: ${status.error}");
message.dispose();
}

Expand All @@ -97,8 +97,8 @@ class CanFFI implements CanSocket {
int count = 0;
while (true) {
final pointer = nativeLib.NativeCanMessage_create();
final error = getCanError(nativeLib.BurtCan_receive(_can!, pointer));
if (error != null) logger.warning("Could not read the CAN bus", body: error);
final status = nativeLib.BurtCan_receive(_can!, pointer);
if (status.isError) logger.warning("Could not read the CAN bus", body: status.error);
if (pointer.ref.length == 0) break;
count++;
if (count % 10 == 0) {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/can/socket_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "socket_ffi.dart";

/// An exception that occurred while working with the CAN bus -- see [BurtCanStatus].
class CanException implements Exception {
/// The error that occurred, using [getCanError].
/// The error that occurred.
final String message;
/// A const constructor
const CanException(this.message);
Expand Down
94 changes: 61 additions & 33 deletions lib/src/generated/can_ffi_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ class CanBindings {
ffi.Pointer<BurtCan> BurtCan_create(
ffi.Pointer<pkg_ffi.Utf8> interface1,
int readTimeout,
int type,
BurtCanType type,
) {
return _BurtCan_create(
interface1,
readTimeout,
type,
type.value,
);
}

late final _BurtCan_createPtr = _lookup<
ffi.NativeFunction<
ffi.Pointer<BurtCan> Function(ffi.Pointer<pkg_ffi.Utf8>, ffi.Int32,
ffi.Int32)>>('BurtCan_create');
ffi.Uint8)>>('BurtCan_create');
late final _BurtCan_create = _BurtCan_createPtr.asFunction<
ffi.Pointer<BurtCan> Function(ffi.Pointer<pkg_ffi.Utf8>, int, int)>();

Expand All @@ -57,64 +57,64 @@ class CanBindings {
late final _BurtCan_free =
_BurtCan_freePtr.asFunction<void Function(ffi.Pointer<BurtCan>)>();

int BurtCan_open(
BurtCanStatus BurtCan_open(
ffi.Pointer<BurtCan> pointer,
) {
return _BurtCan_open(
return BurtCanStatus.fromValue(_BurtCan_open(
pointer,
);
));
}

late final _BurtCan_openPtr =
_lookup<ffi.NativeFunction<ffi.Int32 Function(ffi.Pointer<BurtCan>)>>(
_lookup<ffi.NativeFunction<ffi.Uint8 Function(ffi.Pointer<BurtCan>)>>(
'BurtCan_open');
late final _BurtCan_open =
_BurtCan_openPtr.asFunction<int Function(ffi.Pointer<BurtCan>)>();

int BurtCan_send(
BurtCanStatus BurtCan_send(
ffi.Pointer<BurtCan> pointer,
ffi.Pointer<NativeCanMessage> message,
) {
return _BurtCan_send(
return BurtCanStatus.fromValue(_BurtCan_send(
pointer,
message,
);
));
}

late final _BurtCan_sendPtr = _lookup<
ffi.NativeFunction<
ffi.Int32 Function(ffi.Pointer<BurtCan>,
ffi.Uint8 Function(ffi.Pointer<BurtCan>,
ffi.Pointer<NativeCanMessage>)>>('BurtCan_send');
late final _BurtCan_send = _BurtCan_sendPtr.asFunction<
int Function(ffi.Pointer<BurtCan>, ffi.Pointer<NativeCanMessage>)>();

int BurtCan_receive(
BurtCanStatus BurtCan_receive(
ffi.Pointer<BurtCan> pointer,
ffi.Pointer<NativeCanMessage> message,
) {
return _BurtCan_receive(
return BurtCanStatus.fromValue(_BurtCan_receive(
pointer,
message,
);
));
}

late final _BurtCan_receivePtr = _lookup<
ffi.NativeFunction<
ffi.Int32 Function(ffi.Pointer<BurtCan>,
ffi.Uint8 Function(ffi.Pointer<BurtCan>,
ffi.Pointer<NativeCanMessage>)>>('BurtCan_receive');
late final _BurtCan_receive = _BurtCan_receivePtr.asFunction<
int Function(ffi.Pointer<BurtCan>, ffi.Pointer<NativeCanMessage>)>();

int BurtCan_close(
BurtCanStatus BurtCan_close(
ffi.Pointer<BurtCan> pointer,
) {
return _BurtCan_close(
return BurtCanStatus.fromValue(_BurtCan_close(
pointer,
);
));
}

late final _BurtCan_closePtr =
_lookup<ffi.NativeFunction<ffi.Int32 Function(ffi.Pointer<BurtCan>)>>(
_lookup<ffi.NativeFunction<ffi.Uint8 Function(ffi.Pointer<BurtCan>)>>(
'BurtCan_close');
late final _BurtCan_close =
_BurtCan_closePtr.asFunction<int Function(ffi.Pointer<BurtCan>)>();
Expand Down Expand Up @@ -156,29 +156,57 @@ class _SymbolAddresses {
get NativeCanMessage_free => _library._NativeCanMessage_freePtr;
}

abstract class BurtCanType {
static const int CAN = 0;
static const int CANFD = 1;
enum BurtCanType {
CAN(0),
CANFD(1);

final int value;
const BurtCanType(this.value);

static BurtCanType fromValue(int value) => switch (value) {
0 => CAN,
1 => CANFD,
_ => throw ArgumentError("Unknown value for BurtCanType: $value"),
};
}

/// No 0 value to ensure we always set a status
abstract class BurtCanStatus {
static const int OK = 1;
enum BurtCanStatus {
OK(1),

/// Errors when opening and closing
static const int SOCKET_CREATE_ERROR = 2;
static const int INTERFACE_PARSE_ERROR = 3;
static const int BIND_ERROR = 4;
static const int CLOSE_ERROR = 5;
SOCKET_CREATE_ERROR(2),
INTERFACE_PARSE_ERROR(3),
BIND_ERROR(4),
CLOSE_ERROR(5),

/// CANFD errors
static const int MTU_ERROR = 6;
static const int CANFD_NOT_SUPPORTED = 7;
static const int FD_MISC_ERROR = 8;
MTU_ERROR(6),
CANFD_NOT_SUPPORTED(7),
FD_MISC_ERROR(8),

/// IO errors
static const int WRITE_ERROR = 9;
static const int READ_ERROR = 10;
WRITE_ERROR(9),
READ_ERROR(10),
FRAME_NOT_FULLY_READ(11);

final int value;
const BurtCanStatus(this.value);

static BurtCanStatus fromValue(int value) => switch (value) {
1 => OK,
2 => SOCKET_CREATE_ERROR,
3 => INTERFACE_PARSE_ERROR,
4 => BIND_ERROR,
5 => CLOSE_ERROR,
6 => MTU_ERROR,
7 => CANFD_NOT_SUPPORTED,
8 => FD_MISC_ERROR,
9 => WRITE_ERROR,
10 => READ_ERROR,
11 => FRAME_NOT_FULLY_READ,
_ => throw ArgumentError("Unknown value for BurtCanStatus: $value"),
};
}

final class NativeCanMessage extends ffi.Struct {
Expand Down
10 changes: 8 additions & 2 deletions pubspec.yaml
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All changes to this file can be reverted and are just for testing.

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version: 1.0.0
publish_to: none

environment:
sdk: 3.2.2
sdk: ^3.2.2

# Add regular dependencies here.
dependencies:
Expand All @@ -19,6 +19,12 @@ dependencies:
protobuf: ^3.1.0

dev_dependencies:
ffigen: ^11.0.0
ffigen: ^12.0.0
test: ^1.21.0
very_good_analysis: ^5.0.0+1

dependency_overrides:
ffigen:
git:
url: https://github.com/dart-lang/native
path: pkgs/ffigen
6 changes: 3 additions & 3 deletions src/burt_can/Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
shared: burt_can.so

burt_can.so: burt_can.cpp
g++ -Wall -Werror -c burt_can.cpp -o burt_can.o
g++ -Wall -Werror -c burt_can_ffi.cpp -o burt_can_ffi.o
g++ -shared burt_can.o burt_can_ffi.o -o burt_can.so
g++ -Wall -Werror -fPIC -c burt_can.cpp -o burt_can.o
g++ -Wall -Werror -fPIC -c burt_can_ffi.cpp -o burt_can_ffi.o
g++ -shared -fPIC burt_can.o burt_can_ffi.o -o burt_can.so

clean:
rm -rf *.o *.so
Expand Down
5 changes: 5 additions & 0 deletions src/burt_can/burt_can.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif
typedef enum BurtCanType {
CAN = 0,
CANFD = 1,
Expand Down Expand Up @@ -47,6 +49,9 @@ BurtCanStatus BurtCan_close(BurtCan* pointer);

NativeCanMessage* NativeCanMessage_create();
void NativeCanMessage_free(NativeCanMessage* pointer);

#ifdef __cplusplus
}
#endif

#endif
Loading