open method
Open the transport (idempotent).
Implementation
@override
Future<void> open() async {
if (!Platform.isLinux) {
throw UnsupportedError('SocketCanTransport requires Linux');
}
if (_isClosed) throw StateError('SocketCanTransport already closed');
if (_isOpen) return;
_fd = _bindings.socket(kPfCan, kSockRaw, kCanRaw);
if (_fd < 0) {
throw StateError(
'socket(PF_CAN, SOCK_RAW, CAN_RAW) failed (rc=$_fd) — '
'kernel CAN module not loaded?',
);
}
final ifReq = allocIfReq(interfaceName);
try {
final rc = _bindings.ioctl(_fd, kSiocgIfIndex, ifReq.cast<Void>());
if (rc != 0) {
throw StateError(
'ioctl(SIOCGIFINDEX, "$interfaceName") failed (rc=$rc) — '
'interface does not exist?',
);
}
final ifIndex = readIfReqIfIndex(ifReq);
final addr = allocSockaddrCan(ifIndex);
try {
final br =
_bindings.bind(_fd, addr.cast<Void>(), kSockAddrCanSize);
if (br != 0) {
throw StateError('bind(sockaddr_can) failed (rc=$br)');
}
} finally {
calloc.free(addr);
}
} finally {
calloc.free(ifReq);
}
if (enableFd) {
// Enable CAN-FD frames at the socket level. Failure here is
// typically a kernel-too-old / interface-not-FD-capable
// condition — fail loudly so the integrator catches it early.
final optval = calloc<Uint32>(1);
try {
optval.value = 1;
final rc = _bindings.setsockopt(
_fd, kSolCanRaw, kCanRawFdFrames,
optval.cast<Void>(), 4,
);
if (rc != 0) {
throw StateError(
'setsockopt(SOL_CAN_RAW, CAN_RAW_FD_FRAMES) failed (rc=$rc)',
);
}
} finally {
calloc.free(optval);
}
}
_readBufSize = enableFd ? kCanFdFrameSize : kCanFrameSize;
_readBuf = malloc<Uint8>(_readBufSize);
_isOpen = true;
_pollTimer = Timer.periodic(pollInterval, (_) => _drainOne());
}