Skip to main content

can_bus_toolkit 0.1.0 copy "can_bus_toolkit: ^0.1.0" to clipboard
can_bus_toolkit: ^0.1.0 copied to clipboard

PlatformAndroid

CAN bus toolkit for Android over USB OTG: PCAN-USB and SLCAN adapters, candump logging, ISO-TP, OBD-II and UDS clients, and DBC signal decoding.

can_bus_toolkit #

A CAN bus toolkit for Flutter on Android. It connects to USB CAN adapters over USB OTG and supports monitoring and transmitting frames, candump logging (including from a foreground service), bus statistics, ISO-TP, OBD-II, UDS, and DBC signal decoding and encoding.

The diagnostic and DBC parts are pure Dart. They run on any CanBus implementation, including the built-in virtual bus, so you can develop and test without hardware.

Features #

The package has four libraries. Import package:can_bus_toolkit/can_bus_toolkit.dart for all of them, or import just one module.

core.dart (pure Dart, no Flutter)

  • CanFrame with 11-bit and 29-bit IDs, RTR and error frames, and the candump ID#DATA format.
  • A CanBus interface for sending, periodic sending, filters, state, statistics and closing.
  • VirtualCanBus and VirtualCanNetwork for tests and demos, with optional ACK and bitrate-mismatch simulation.
  • Statistics: frames per second, per-ID rates, and bus load with worst-case bit stuffing.
  • A candump -L log reader and writer.
  • CanLogReplayer with speed control, looping and pause. By default it skips OBD/UDS diagnostic frames.

usb.dart (Android USB host)

  • PEAK PCAN-USB, SLCAN (CANable and clones) and gs_usb (candleLight, experimental).
  • Listen-only mode, hardware timestamps, error counters and bus state where the adapter supports them.
  • Attach and detach events, the USB permission flow, and optional auto-reconnect.
  • Native frame batching, so high-rate buses don't flood the platform channel.
  • Background logging to a candump file from a connectedDevice foreground service.
  • Custom VID/PID registration for clone adapters.

obd.dart (pure Dart)

  • ISO-TP (ISO 15765-2) with flow control, block size, STmin and padding.
  • An OBD-II (SAE J1979) client:
    • modes 01, 02, 03, 04, 07, 09 and 0A
    • 11-bit and 29-bit addressing, and multi-ECU answers
    • PID polling
    • bitrate and addressing auto-detection that listens before it transmits
  • A UDS (ISO 14229) client: session control, read/write DID, DTCs, security access, tester present, and "response pending" handling.
  • ObdEcuSimulator that answers OBD and UDS requests on any bus.
  • Every service that changes ECU state needs allowWrites: true.

dbc.dart (pure Dart)

  • A DBC parser that reports errors with line and column.
  • Decode and encode for Intel and Motorola byte order, signed, float and double signals, value tables, and multiplexed messages.
  • Comments, attributes and node definitions.

Install #

flutter pub add can_bus_toolkit

Requirements: Android 7.0 (API 24) or later, a phone or tablet with USB host (OTG) support, and an OTG cable or adapter.

Quick start #

Monitor a bus over USB #

import 'package:can_bus_toolkit/can_bus_toolkit.dart';

Future<UsbCanBus?> startMonitor() async {
  final devices = await CanUsb.listDevices();
  if (devices.isEmpty) return null;
  final device = devices.first;
  if (!await CanUsb.requestPermission(device)) return null;

  // Listen-only does not transmit or acknowledge anything. Use it first on a vehicle.
  final bus = await CanUsb.open(
    device,
    config: const CanConfig(bitrate: CanBitrate.k500, listenOnly: true),
  );
  bus.frames.listen((frame) => print(frame.toCandumpString()));
  bus.statistics.listen(
    (s) => print('${s.framesPerSecond.round()} frames/s, '
        '${s.busLoadPercent.toStringAsFixed(1)} % load'),
  );
  return bus; // Call bus.close() when done.
}

OBD-II live data #

import 'package:can_bus_toolkit/can_bus_toolkit.dart';

Future<void> readVehicle(UsbCanDevice device) async {
  // Probes 500 and 250 kbit/s listen-only first, then tries 11-bit and 29-bit.
  final detection = await ObdClient.autoDetect(
    (bitrate, {required listenOnly}) => CanUsb.open(
      device,
      config: CanConfig(bitrate: bitrate, listenOnly: listenOnly),
    ),
  );
  if (detection == null) return;

  final obd = ObdClient(detection.bus, addressing: detection.addressing);
  print('VIN: ${(await obd.readVin()).first}');
  print('Stored DTCs: ${(await obd.readStoredDtcs()).first}');

  // Engine speed, vehicle speed and coolant temperature every 500 ms.
  obd.poll([0x0C, 0x0D, 0x05]).listen((sample) => print(sample.value));
}

Decode signals with a DBC file #

import 'package:can_bus_toolkit/can_bus_toolkit.dart';
import 'package:flutter/services.dart' show rootBundle;

Future<void> decodeBus(CanBus bus) async {
  final db = DbcDatabase.parse(await rootBundle.loadString('assets/vehicle.dbc'));
  bus.frames.listen((frame) {
    final message = db.decode(frame);
    if (message == null) return;
    print(message); // EngineData: EngineSpeed = 1726 rpm, CoolantTemp = 83 degC
    final rpm = message['EngineSpeed']; // physical value as double, or null
  });
}

Without hardware #

final network = VirtualCanNetwork();
final ecu = ObdEcuSimulator(network.createBus())..start();
final obd = ObdClient(network.createBus());
print((await obd.readPid(0x0C)).first); // Engine speed in rpm

The example app has a demo vehicle mode that exercises every screen without an adapter.

Supported adapters #

Adapter USB ID Protocol Status
PEAK PCAN-USB 0C72:000C PCAN-USB (vendor protocol) Tested on a 250k bench (Android 16, firmware 2.8); vehicle testing pending
CANable, slcan firmware 16D0:117E SLCAN (Lawicel) over CDC-ACM Experimental
STM32 virtual COM port SLCAN clones 0483:5740 SLCAN over CDC-ACM Experimental
candleLight / CANable gs_usb firmware 1D50:606F gs_usb Experimental
Other clones any SLCAN or gs_usb Register with CanUsb.registerDevice

PCAN-USB means the original PEAK PCAN-USB with USB ID 0C72:000C. PCAN-USB FD and PCAN-USB Pro use different protocols and are not supported yet.

Capability matrix #

Adapter Listen-only Loopback Error counters HW timestamps Bus state
PCAN-USB yes (firmware 4+) no yes yes yes
SLCAN yes (L command) no no no best effort (F command)
gs_usb if the device reports it if the device reports it yes if the device reports it yes

UsbCanBus.capabilities reports what the connected device actually supports. CanUsb.open rejects options the adapter can't provide.

Platforms #

Platform USB transport core, obd, dbc
Android 7.0+ yes yes
iOS no yes, with your own CanBus
Web, desktop no yes, with your own CanBus

iOS has no public API that lets apps talk to arbitrary USB devices. Accessories need Apple's MFi program, and DriverKit is limited to iPadOS on M-series iPads, with entitlements granted by Apple. For iOS, use a Bluetooth LE or Wi-Fi CAN adapter and implement CanBus over its protocol (for example, SLCAN over a BLE serial service or over TCP). The OBD-II, UDS, ISO-TP, DBC, logging and statistics code then works unchanged. Built-in BLE/Wi-Fi transports are on the roadmap.

Wiring #

  • A CAN bus needs at least two active nodes. Every frame must be acknowledged by another node. An adapter that transmits alone on a cable sees ACK errors and goes error-passive. On a bench, use a second adapter or an ECU. In listen-only mode the adapter never acknowledges, so it can't be the only other node.

  • Terminate both ends with 120 ohm between CAN_H and CAN_L. With power off, you should measure about 60 ohm between CAN_H and CAN_L. Vehicles are already terminated, so don't add a resistor at the OBD-II port.

  • OBD-II to DB9 (PCAN-USB and most DB9 adapters, CiA 303-1 pinout):

    OBD-II (J1962) pin Signal DB9 pin
    6 CAN_H 7
    14 CAN_L 2
    4 and 5 Chassis and signal ground 3
    16 Battery +12 V do not connect

    Never connect OBD pin 16 to the adapter. Some adapters (PCAN-USB with its internal jumper set) put 5 V on DB9 pin 9, and battery voltage there can damage the adapter.

Step-by-step hardware tests are in docs/HARDWARE_TEST.md.

Safety #

Transmitting on a vehicle network can change how ECUs behave, set fault codes, or disturb safety systems.

  • Connect in listen-only mode first to confirm the bitrate. Transmitting at the wrong bitrate floods the bus with error frames.
  • Clearing DTCs, UDS session changes, writing DIDs and security access are blocked unless you pass allowWrites: true. UdsClient.request without allowWrites only sends read-only services. This guards against accidents. It is not access control.
  • Don't use the app while driving, and don't transmit on a moving vehicle.
  • Logs can contain the VIN and other vehicle identifiers, which count as personal data in many jurisdictions (for example, under GDPR). Store and share them accordingly.

This software is provided under the MIT license without warranty. You are responsible for how you use it on real vehicles and equipment.

Android setup #

The plugin declares android.hardware.usb.host as optional. To make your app installable only on devices with USB host, declare it as required:

<uses-feature android:name="android.hardware.usb.host" android:required="true" />

CanUsb.requestPermission asks for USB permission at runtime. No manifest permission is needed for USB access.

Background logging #

CanUsb.startBackgroundLogging runs a foreground service of type connectedDevice. Declare the service and permissions in your app's AndroidManifest.xml. If they are missing, the call throws CanConfigException with this snippet:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    <application>
        <service
            android:name="com.ahmadhussain.can_bus_toolkit.logging.BackgroundLoggingService"
            android:exported="false"
            android:foregroundServiceType="connectedDevice" />
    </application>
</manifest>
  • Start logging while the app is in the foreground. Android 12 and later block foreground-service starts from the background.
  • On Android 13 and later, request POST_NOTIFICATIONS before starting. Without it, logging still runs, but the notification is hidden.
  • Apps on Google Play that use a foreground service type must declare it in the Play Console (App content > Foreground service permissions).
  • Logs are written to app-internal storage (CanUsb.logDirectory()). They are not readable by other apps.

Open the app when an adapter is plugged in (optional) #

Add an intent filter to your activity, and a device filter in android/app/src/main/res/xml/device_filter.xml:

<intent-filter>
    <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
    android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
    android:resource="@xml/device_filter" />
<resources>
    <usb-device vendor-id="3186" product-id="12" />      <!-- PCAN-USB -->
    <usb-device vendor-id="5840" product-id="4478" />    <!-- CANable slcan -->
    <usb-device vendor-id="7504" product-id="24687" />   <!-- candleLight gs_usb -->
</resources>

If the user picks "always open" in the system dialog, Android also grants USB permission for that device.

Roadmap #

  • CAN FD (PCAN-USB FD, gs_usb FD)
  • SAE J1939 (transport protocol, address claiming, PGN decoding)
  • CANopen (NMT, SDO, PDO)
  • iOS and other platforms through BLE and Wi-Fi adapters

Android-CANBus-OTG-Debugger is a native Android CAN debugger app by the same author, and the origin of this package's PCAN-USB work.

License #

MIT. See LICENSE.

0
likes
160
points
63
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

CAN bus toolkit for Android over USB OTG: PCAN-USB and SLCAN adapters, candump logging, ISO-TP, OBD-II and UDS clients, and DBC signal decoding.

Repository (GitHub)
View/report issues

Topics

#can-bus #obd #automotive #usb #iot

License

MIT (license)

Dependencies

clock, flutter, meta

More

Packages that depend on can_bus_toolkit

Packages that implement can_bus_toolkit