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)
Linux: Real CAN Hardware
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()