Skip to content

Documentation

Using LIN from Python and C

Applications communicate with the HAT through a local Unix socket – no custom I²C driver required.

Using LIN from Python and C

Normal applications do not access I²C directly.

Python / C / custom application
          |
          | Unix SOCK_SEQPACKET
          v
      beiis-lind
          |
          | I²C
          v
        STM32

This ensures that only one process owns the I²C endpoint. Multiple applications do not need to know the hardware details.

Starting the daemon

For development:

source .venv/bin/activate

beiis-lind \
  --bus 1 \
  --address 0x42 \
  --socket /tmp/beiis-lin.sock \
  --lock-file /tmp/beiis-lind.lock

Check connectivity:

beiis-lin --socket /tmp/beiis-lin.sock info

On Raspberry Pi hardware, the daemon normally also uses the isolated GPIO6 interrupt as its wake-up signal.

Python

The simplest integration uses DaemonClient:

from beiis_lin.client import DaemonClient

c = DaemonClient("/run/beiis/lin-hat.sock")

c.set_active_instance(0)      # master_tx_query
c.data_send(0, b"\x00")     # Native PING

instance, channel, reply = c.data_recv(
    instance=1,              # master_rx_query
    channel=0,
    timeout=2.0,
)

print(reply.hex(" "))
c.close()

Expected response:

00 00

The first byte identifies the operation; the second is status 0 = OK.

Python: Send a LIN frame

from beiis_lin.client import DaemonClient

c = DaemonClient()

c.set_active_instance(0)

request = bytes.fromhex(
    "02 12 01 04 11 22 33 44"
)
c.data_send(0, request)

_, _, reply = c.data_recv(
    instance=1,
    channel=0,
    timeout=2.0,
)

assert reply == bytes.fromhex("02 00")
c.close()

C

The socket interface is a standard Unix-domain SOCK_SEQPACKET socket.

int fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);

Default path:

/run/beiis/lin-hat.sock

Each request is one UTF-8 JSON packet.

Select the active master query:

{"v":1,"id":1,"type":"request","op":"set_active_instance","args":{"instance":0}}

Send a native PING:

{"v":1,"id":2,"type":"request","op":"data_send","args":{"channel":0,"data":"00"}}

Read a reply from master_rx_query:

{"v":1,"id":3,"type":"request","op":"data_recv","args":{"instance":1,"channel":0,"timeout":2.0}}

A complete minimal C example is included at:

examples/runtime/c_basic.c

Compile and run:

cc -O2 -Wall -Wextra examples/runtime/c_basic.c -o /tmp/beiis-runtime-c
/tmp/beiis-runtime-c

Why a socket instead of direct I²C access?

The socket abstracts away:

  • I²C register details.
  • Access synchronization.
  • GPIO interrupt handling.
  • STM32 runtime framing.
  • Firmware recovery and mboot.

The same architecture is therefore accessible from Python, C or any other language supporting Unix sockets and JSON.

Important: One I²C owner

When beiis-lind is running, no second application should access the same I²C address concurrently using --direct.

For regular applications:

Use the socket. Reserve direct I²C access for bring-up, recovery and low-level debugging.