Skip to content

Basic Usage

This guide demonstrates the fundamental steps to set up a CAN bus connection, send messages, and receive messages using Sockcan.

Two Usage Modes

Sockcan can be used in two main ways, as a 0-dependency library, or as an extension of python-can:

Mode Description Best For
Standalone Direct use of Sockcan's API Maximum performance, Linux native
python-can Drop-in Replaces python-can's socketcan backend Existing python-can applications, cross-platform, applications that must work over a variety of CAN drivers.

Usage below documents the basic API for both use cases.

1. Connecting to the CAN Bus

Standalone

Connect directly to a CAN interface using Sockcan's API:

from sockcan import SocketcanConfig, connect_to_socketcan

# Configure the CAN channel and loopback mode
config = SocketcanConfig(channel="vcan0")

# Connect to the SocketCAN interface
sock = connect_to_socketcan(config)
print(f"Connected to CAN bus on channel: {config.channel}")

# Remember to close the socket when you're done
sock.close()

With python-can

Replace python-can's socketcan implementation with Sockcan's optimized version:

import can
from sockcan.interop import hijack_python_can

# Replace python-can's socketcan backend
hijack_python_can()

# Now uses Sockcan internally
bus = can.Bus(interface="socketcan", channel="vcan0")
print(f"Connected to: {bus.channel_info}")

bus.shutdown()

2. Sending a CAN Message

Standalone

Build a send function to transmit CAN messages:

from sockcan import SocketcanConfig, connect_to_socketcan
from sockcan._protocol import build_send_func

config = SocketcanConfig(channel="vcan0")
sock = connect_to_socketcan(config)

try:
    send_func = build_send_func(sock, expects_msg_cls=False)

    # Example CAN message data
    arbitration_id = 0x123
    data = b'\x01\x02\x03\x04'
    is_extended = False

    # Send the message
    send_func(arbitration_id, data, is_extended)
    print(f"Sent message: ID={arbitration_id:#x}, Data={data.hex()}")

finally:
    sock.close()

With python-can

Use python-can's familiar API:

import can
from sockcan.interop import hijack_python_can

hijack_python_can()

bus = can.Bus(interface="socketcan", channel="vcan0")

try:
    message = can.Message(
        arbitration_id=0x456,
        data=[0x05, 0x06, 0x07, 0x08],
        is_extended_id=False,
    )
    bus.send(message)
    print(f"Sent message: ID={message.arbitration_id:#x}")

finally:
    bus.shutdown()

3. Receiving a CAN Message

Standalone

Build a receive function that blocks until a message arrives:

from sockcan import SocketcanConfig, connect_to_socketcan
from sockcan._protocol import build_recv_func

config = SocketcanConfig(channel="vcan0")
sock = connect_to_socketcan(config)

try:
    recv_func = build_recv_func(sock)

    print("Waiting for a CAN message...")
    received_message = recv_func()

    print("Received Message:")
    print(f"  Arbitration ID: {received_message.arbitration_id:#x}")
    print(f"  Data: {received_message.data.hex()}")
    print(f"  Is Extended ID: {received_message.is_extended_id}")
    print(f"  Timestamp: {received_message.timestamp}")

finally:
    sock.close()

WIth python-can

Use python-can's recv() method:

import can
from sockcan.interop import hijack_python_can

hijack_python_can()

bus = can.Bus(interface="socketcan", channel="vcan0")

try:
    print("Waiting for a CAN message...")
    message = bus.recv(timeout=5.0)  # 5 second timeout

    if message:
        print("Received Message:")
        print(f"  Arbitration ID: {message.arbitration_id:#x}")
        print(f"  Data: {message.data.hex()}")
        print(f"  Is Extended ID: {message.is_extended_id}")
    else:
        print("Timeout - no message received")

finally:
    bus.shutdown()


Setting Up the CAN Interface

Linux: Virtual CAN (vcan0)

sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set up vcan0

Linux: Real CAN Hardware

# List available interfaces
ip link show

# Bring up your CAN interface
sudo ip link set up can0

Windows

Windows requires the userspace daemon mode. See Windows Setup for details.


Complete Examples

Standalone: TX/RX Application

from sockcan import SocketcanConfig, connect_to_socketcan, build_send_func, build_recv_func
import time

def can_app(channel="vcan0"):
    config = SocketcanConfig(channel=channel)
    sock = connect_to_socketcan(config)
    send = build_send_func(sock, expects_msg_cls=False)
    recv = build_recv_func(sock)

    try:
        counter = 0
        while True:
            # Send periodic messages
            data = bytes([counter % 256])
            send(0x100, data, False)
            print(f"TX: ID=0x100, Data={data.hex()}")

            # Check for incoming messages
            try:
                msg = recv()
                print(f"RX: ID={msg.arbitration_id:#x}, Data={msg.data.hex()}")
            except BlockingIOError:
                pass

            counter += 1
            time.sleep(0.1)
    finally:
        sock.close()

python-can: TX/RX Application

import can
from sockcan.interop import hijack_python_can

def can_app(channel="vcan0"):
    hijack_python_can()
    bus = can.Bus(interface="socketcan", channel=channel)

    try:
        counter = 0
        while True:
            # Send periodic messages
            msg = can.Message(
                arbitration_id=0x100,
                data=[counter % 256],
                is_extended_id=False,
            )
            bus.send(msg)
            print(f"TX: ID=0x{msg.arbitration_id:x}, Data={msg.data.hex()}")

            # Check for incoming messages
            received = bus.recv(timeout=0.01)
            if received:
                print(f"RX: ID={received.arbitration_id:#x}, Data={received.data.hex()}")

            counter += 1
    finally:
        bus.shutdown()