An easy-to-use SocketCAN library for Python and C++, built in Rust.

Related tags

Command-line JCAN
Overview

JCAN

An easy-to-use SocketCAN library for Python and C++, built in Rust, using cxx-rs and pyo3.

Warning: I have never used Rust before and I don't know what I'm doing

Feature Status / TODO

  • Blocking send/receive in C++ (jcan.h) and Python (jcan)
  • aarch64 build for Jetson TX2
  • Replace maturin build system with manual scripts, or setuptools-rust
  • Rename of jcan_python to just jcan
  • Usage examples for C++ and Python
  • PyPi package release
  • Benchmark and speedtest against python-can (see utils/speedtest.sh, typically speedup is 200% with jcan)
  • Build an example of JCAN + ROS2 Foxy usage
  • Receive function for specific CAN IDs (e.g receive_with_id(id : u32))
  • Non-blocking receive functions, which return a list of buffered Frames
  • Implement asyncronous send/receive callback methods
  • Convenience methods for Frame building, e.g: setting specific bits in a byte, named IDs
  • TOML-based 'CAN device interface' files, which generate methods like set_motor_speed(0.5f) / set_heater(True), etc...

Installation

Download the latest builds from the Releases Page!

For python, it's as easy as...

pip install jcan

For C++, you'll need to download the latest build and add it to your include path manually - check the examples folder for cmake usage.

Examples

For local development, you can setup a virtual CAN interface with the vcan.sh script.
You can then use the can-utils package (apt install can-utils) to interact with the vcan0 interface, on the command line.

Python

Python example showing most of the JCAN features

#!/usr/bin/env python
import jcan
import time

if __name__ == "__main__":
    bus = jcan.Bus()

    # Set a filter, from list...
    # bus.set_id_filter([0x1A0,0x1A1,0x1A2,0x1A3])

    # .. or from a mask!
    bus.set_id_filter_mask(0x1A0, 0xFF0)

    # This is our callback function for new frames
    def on_frame_five(frame : jcan.Frame):
        print(f"FRAME 1A5: {frame.data}")

    def on_frame_d(frame : jcan.Frame):
        print(f"FRAME 1AD {frame.data}")
        # print(frame.data[0])

    bus.add_callback(0x1A5, on_frame_five)
    bus.add_callback(0x1AD, on_frame_d)

    bus.open("vcan0")

    while True:
        # The list of values will be cast to uint8's by JCAN library - so be careful to double check the values!
        # frameToSend = jcan.Frame(0x200, [time.time()%255, (time.time()*1000)%255])
        # print(f"Sending {frameToSend}")
        # bus.send(frameToSend)

        # Spin is required for our callbacks to be processed.
        # Make sure .spin is called from your MAIN THREAD
        bus.spin()

        # bus.spin is non-blocking if nothing is there - resulting in a 'busy' loop
        # this sleep is to prevent that. In your code, you will probably be doing more important things here!
        time.sleep(0.01)

C++ example showing Frame building and sending.

C++14

#include <stdint.h>
#include <stdio.h>
#include <vector>
#include "jcan/jcan.h"

using namespace org::jcan;

/* 
A basic example of sending and recieving CAN Frames with JCAN
*/

int main(int argc, char **argv) {
    // Build new Bus object, which is a unique pointer to a Bus object
    std::unique_ptr<Bus> bus = new_bus();

    // Set ID filter using a vector of allowed IDs we can receive
    // std::vector<uint32_t> allowed_ids = {0x100, 0x123, 0x456, 0x789};
    // bus->set_id_filter(allowed_ids);

    // We can also also set a mask of allowed IDs
    // The filter below will only accept frames who's ID is 0x1A#, where '#' can be anything.
    // Combinations of base+mask can be used to make a very flexible filter.. but it can get quite confusing, too!
    // The format used below, of the form 'base_id + part of ID we don't care about',
    // is a nice simple way to use this feature.
    bus->set_id_filter_mask(0x1A0,0xFF0);

    // Open the bus
    bus->open("vcan0");

    // Loop forever, sending frames and printing the ones we recieve
    unsigned char i = 0;

    while(true)
    {
        i++;
        Frame frameToSend = new_frame(0x200, {i,i/10,i/100,i%2,i%3,i%4,i%5,i*10});
        printf("Sending: %s...\n",frameToSend.to_string().c_str());
        bus->send(frameToSend);

        printf("Waiting for frame...\n");
        Frame frameReceived = bus->receive();
        printf("Received: %s\n", frameReceived.to_string().c_str());
    }

    return 0;
}

Lots more examples can be found in the examples folder!

Quirks / Known Bugs

  • A dedicated scripts-postbuild crate is used to move all the build-artifacts (libjcan.a, jcan.h, etc...) into /out/<profile>/<target>/jcan
  • Workspace-level cargo build is broken, use crossbuild.sh instead (as detailed below)
  • C++ examples can be built with the build.sh script found in each directory

Development

# Get code
git clone https://github.com/leighleighleigh/JCAN

# Setup the build environment, which
# - Installs rust 
# - Installs cross-rs
# - Installs podman
# - Sets up a python virtual environment in the repo, under .venv
./devsetup.sh

## Run the build scripts!
# (This will automatically source .venv/bin/activate if needed)

./clean.sh
./crossbuild.sh
./release.sh

# Build outputs, including python wheels, can then be found in the ./release folder!
You might also like...
A simple, fast, and easy to use Solidity test generator based on the Branching Tree Technique.

bulloak A simple, fast, and easy to use Solidity test generator based on the Branching Tree Technique. Installing cargo install bulloak Usage Basic Us

A simple, fast, and easy to use static file server

Warning This is still in early development, I would not recommend for production use.. yet. See the issues for things that are on the "roadmap" or mis

The dead easy way to use config files in your rust project

Configr The dead easy way to use config files in your project This will load a config.toml file if it exists, otherwise it will create the needed fold

An easy-to-use TUI crate for Rust, based off of the Elm architecture.

Rustea An easy-to-use TUI crate for Rust, based off of the Elm architecture. This is a re-implementation of Go's Tea, created by TJ Holowaychuk. Featu

easy-to-use immediate mode client side Rust web framework
easy-to-use immediate mode client side Rust web framework

An immediate mode web frontend library written in Rust. It builds up VDOM for not having to run too many DOM operations, but as it runs every time any

Call is an easy-to-use command tools for remote development.
Call is an easy-to-use command tools for remote development.

Call is an easy-to-use command tools for remote development. It helps you to build remote development easily and elegant. It can work with makefile and justfile.

Bartib is an easy to use time tracking tool for the command line.

Bartib is an easy to use time tracking tool for the command line. It saves a log of all tracked activities as a plaintext file and allows you to create flexible reports.

Requestty - An easy-to-use collection of interactive cli prompts inspired by Inquirer.js.
Requestty - An easy-to-use collection of interactive cli prompts inspired by Inquirer.js.

Requestty requestty (request-tty) is an easy-to-use collection of interactive cli prompts inspired by Inquirer.js. Easy-to-use - The builder API and m

Koi is a simple tool built to let you use ChatGPT through the command line

Koi is a simple tool built to let you use ChatGPT through the command line. It adds the ability to let ChatGPT run commands on your computer in order to help you out, or to help you out with complicated tasks.

Comments
  • Background thread, callback system

    Background thread, callback system

    This PR attempts to implement a "callback system" on top of JCAN, to allow for better integration into other callback-based application structures (such as ROS nodes). This feature necessitates the ability to manage socket IO in a background thread, so as not to block the main thread with the task of receiving CAN Frames - and to ensure no frames are dropped.

    The callback system allows application code (written in either Python or C++) to "register" a function to be called for a specific CAN Frame ID. These functions must take a single argument of type Frame, which contains the message data that was received. Both free functions and member functions can be registered as callbacks, provided the appropriate arguments are given to the bus.add_callback method - such that binding to a class instance can be performed if needed.

    When the application code makes a periodic call to the JCAN bus.spin() method, the buffered Frames collected by the background thread are iterated. If a callback is registered for the ID of a given Frame, the callback is then executed.

    Significant breaking changes had to be made to the JCAN C++ interface in order to implement the callback system, which demands changes be made to application code using JCAN. A partial example of the new JCAN interfaces can be found here.

    opened by leighleighleigh 1
Releases(v0.1.6)
Owner
Leigh Oliver
Embedded systems engineer at @AmbitRobotics and team member of @MonashNovaRover
Leigh Oliver
Nodium is an easy-to-use data analysis and automation platform built using Rust, designed to be versatile and modular.

Nodium is an easy-to-use data analysis and automation platform built using Rust, designed to be versatile and modular. Nodium aims to provide a user-friendly visual node-based interface for various tasks.

roggen 19 May 2, 2023
An easy to use library for pretty print tables of Rust structs and enums.

tabled An easy to use library for pretty printing tables of Rust structs and enums. Table of Contents Usage Settings Style Themes ASCII Psql Github Ma

Maxim Zhiburt 1.3k Jan 9, 2023
💫 Easy to use, robust Rust library for displaying spinners in the terminal

spinoff an easy to use, robust library for displaying spinners in the terminal ?? Install Add as a dependency to your Cargo.toml: [dependencies] spino

ad4m 401 Jun 24, 2023
Over-simplified, featherweight, open-source and easy-to-use authentication and authorization server.

concess ⚠️ Early Development: This is not production ready, yet. Do not use it for anything important. Introduction concess is a over-simplified, feat

Dustin Frisch 3 Nov 25, 2022
82 fun and easy to use, lightweight, spinners for Rust, with minimal overhead.

Spinners for Rust 82 fun and easy to use, lightweight, spinners for Rust, with minimal overhead, all the way from simple dots, to fun emoji based "spi

Juliette Cordor 2 May 17, 2022
🚀 A blazingly fast easy to use dotfile and global theme manager written in Rust

GTHEME A blazingly fast easy to use dotfile and global theme manager for *NIX systems written in Rust ?? Demo using wip desktop. To check out more des

David Rodriguez 19 Nov 28, 2022
A blazing fast and easy to use TRPC-like server for Rust.

rspc ?? Work in progress ?? A blazing fast and easy to use TRPC-like server for Rust. Website Example You define a trpc router and attach resolvers to

Oscar Beaumont 344 Dec 31, 2022
A robust, customizable, blazingly-fast, efficient and easy-to-use command line application to uwu'ify your text!

uwuifyy A robust, customizable, blazingly-fast, efficient and easy-to-use command line application to uwu'ify your text! Logo Credits: Jade Nelson Tab

Hamothy 43 Dec 12, 2022
Yet another lightweight and easy to use HTTP(S) server

Raptor Web server Raptor is a HTTP server written in Rust with aims to use as little memory as possible and an easy configuration. It is built on top

Volham 5 Oct 15, 2022
A simple cross-platform easy to use STL Viewer with GUI and CLI options

Stlvi STL viewer written in Rust. This project is still in development. It is available in both CLI and GUI mode. Supported OS Linux Windows Mac Scree

Mantresh Khurana 4 Mar 2, 2023