Bitbus Function Block
Features
The SIO07 has a Bitbus sniffer function block to capture Bitbus frames on the Bitbus and provide them as a stream of frames to the host application.
The Bitbus sniffer operates listen-only, i.e. can only read from the bus, it cannot send any data, simply because the hardware has no transmitter.
Features:
- Timestamping of received data with microsecond resolution
- Capturing of all SDLC frames on the Bitbus
- Filtering of Bitbus frames by address and minimal length
- 62.5 and 375 kBaud supported
Functional Description
The Bitbus sniffer firmware permanently captures all frames from both lines of the Bitbus.
The captured frames contain the SDLC frame data: Address, Control and Information field. The CRC field is not included in the frame data.
Whether frames with CRC error are captured or discarded can be configured by the host application.
Baudrate and filter settings are configured by the host application.
Multiple applications may be connected simultaneously to the same Bitbus sniffer.
Using the io4edge API to access the Bitbus Sniffer
Info
At the moment, only the Python API is supported.
First, install the io4edge client library.
Want to have a quick look to the examples? See our Github repository.
Connect to the Bitbus Sniffer Function
To access the Bitbus Sniffer Function, create a Client and save it to the variable bitbus_client. Pass as address either a service address or an ip address with port. Examples:
- As a service address:
SIO07-1-bitbus - As an IP/Port:
192.168.201.1:10001
We need this client variable for all further access methods.
import io4edge_client.bitbussniffer as bbsniffer
import io4edge_client.functionblock as fb
def main():
bb_client = bbsniffer.Client(address)
Configuring the Bitbus Sniffer
With the configuration upload function, the Bitbus Sniffer can be configured. The following example configures the Bitbus Sniffer to ignore CRC errors, use 375kBaud, and only pass frames with addresses 0, 1, and 2. Furthermore, frames with length 0 are discarded.
addr_filter = bytearray([0x00] * 32)
addr_filter[0] = 0x07 # only pass addresses 0,1,2, all others blocked
bb_client.upload_configuration(
bbsniffer.Pb.ConfigurationSet(
ignore_crc=True,
baud_62500=False,
address_filter=bytes(addr_filter),
min_frame_length=1, # Discard frames with 0 length
)
)
Receiving Bitbus Frames
Start a Stream
To receive frames from the Bitbus, the API provides functions to start a Stream. When starting the stream, you can specify a filter to receive only frames that match the filter criteria.
The following code shows a typical filter setting: Receive all frames with all FCodes, but no timed out frames.
bb_client.start_stream(
bbsniffer.Pb.StreamControlStart(),
fb.Pb.StreamControlStart(
bucketSamples=20,
keepaliveInterval=1000,
bufferedSamples=60, # Minimum frames with max. length to buffer. If frames are small, much more frames are buffered
),
)
Receive Telegrams
In the stream the firmware generates Buckets, where each Bucket contains a number of Frames. The frame contains the timestamp, the Bitbus frame data, and flags (e.g. CRC error). Within the bitbus frame data, the first byte is the Address, the second byte is the Control field, and the remaining bytes are the Information field.
To read samples from the stream:
while True:
try:
generic_stream_data, stream_data = bb_client.read_stream(timeout=3)
except TimeoutError:
print("Timeout while reading stream")
continue
print(
"Received %d samples, seq=%d, ts=%d"
% (
len(stream_data.samples),
generic_stream_data.sequence,
generic_stream_data.deliveryTimestampUs,
)
)
for sample in stream_data.samples:
print(sample_to_str(sample))
def sample_to_str(sample):
ret_val = "%10d us: " % sample.timestamp
if len(sample.bitbus_frame) >= 2:
ret_val += f"ADDR: 0x{sample.bitbus_frame[0]:02X} "
ret_val += f"CTRL: 0x{sample.bitbus_frame[1]:02X} "
ret_val += "INFO: "
for i in range(2, len(sample.bitbus_frame)):
ret_val += "%02X " % sample.bitbus_frame[i]
if sample.flags != bbsniffer.Pb.Sample.Flags.none:
if sample.flags & bbsniffer.Pb.Sample.Flags.bad_crc:
ret_val += " CRC_ERR"
if sample.flags & bbsniffer.Pb.Sample.Flags.frames_lost:
ret_val += " LOST"
if sample.flags & bbsniffer.Pb.Sample.Flags.buf_overrun:
ret_val += " BUF_OVERRUN"
return ret_val
Info
At the moment, timestamps are expressed in microseconds relative to the start of the SIO07. Future client libraries will map the time to the host's time domain.
Controlling the Stream
The stream behavior can be fine-tuned to the application needs:
-
The
bucketSamplesparameter defines the number of samples per bucket. If the bucket containsbucketSamples, it is sent to the client. -
The
keepAliveIntervalparameter defines the maximum time in ms between two buckets. If the bucket is not full, it is sent after the configured interval. -
The
bufferedSamplesparameter defines the number of samples that can be buffered in the device. If the buffer is full, the oldest samples are overwritten. As a rule of thumb,bufferedSamplesshould be at least two times thebucketSamples. Select a higher number if your reception process is slow to avoid buffer overruns.
bb_client.start_stream(
bbsniffer.Pb.StreamControlStart(),
fb.Pb.StreamControlStart(
bucketSamples=20,
keepaliveInterval=1000,
bufferedSamples=60,
),
)