# Broadcast Manager

The broadcast manager allows the user to setup periodic message jobs. For example sending a particular message at a given period. The broadcast manager supported natively by several interfaces and a software thread based scheduler is used as a fallback.

This example shows the socketcan backend using the broadcast manager:

      1#!/usr/bin/env python
      2# coding: utf-8
      3
      4"""
      5This example exercises the periodic sending capabilities.
      6
      7Expects a vcan0 interface:
      8
      9    python3 -m examples.cyclic
     10
     11"""
     12
     13from __future__ import print_function
     14
     15import logging
     16import time
     17
     18import can
     19
     20logging.basicConfig(level=logging.INFO)
     21
     22
     23def simple_periodic_send(bus):
     24    """
     25    Sends a message every 20ms with no explicit timeout
     26    Sleeps for 2 seconds then stops the task.
     27    """
     28    print("Starting to send a message every 200ms for 2s")
     29    msg = can.Message(arbitration_id=0x123, data=[1, 2, 3, 4, 5, 6], is_extended_id=False)
     30    task = bus.send_periodic(msg, 0.20)
     31    assert isinstance(task, can.CyclicSendTaskABC)
     32    time.sleep(2)
     33    task.stop()
     34    print("stopped cyclic send")
     35
     36
     37def limited_periodic_send(bus):
     38    print("Starting to send a message every 200ms for 1s")
     39    msg = can.Message(arbitration_id=0x12345678, data=[0, 0, 0, 0, 0, 0], is_extended_id=True)
     40    task = bus.send_periodic(msg, 0.20, 1, store_task=False)
     41    if not isinstance(task, can.LimitedDurationCyclicSendTaskABC):
     42        print("This interface doesn't seem to support a ")
     43        task.stop()
     44        return
     45
     46    time.sleep(2)
     47    print("Cyclic send should have stopped as duration expired")
     48    # Note the (finished) task will still be tracked by the Bus
     49    # unless we pass `store_task=False` to bus.send_periodic
     50    # alternatively calling stop removes the task from the bus
     51    #task.stop()
     52
     53
     54def test_periodic_send_with_modifying_data(bus):
     55    print("Starting to send a message every 200ms. Initial data is ones")
     56    msg = can.Message(arbitration_id=0x0cf02200, data=[1, 1, 1, 1])
     57    task = bus.send_periodic(msg, 0.20)
     58    if not isinstance(task, can.ModifiableCyclicTaskABC):
     59        print("This interface doesn't seem to support modification")
     60        task.stop()
     61        return
     62    time.sleep(2)
     63    print("Changing data of running task to begin with 99")
     64    msg.data[0] = 0x99
     65    task.modify_data(msg)
     66    time.sleep(2)
     67
     68    task.stop()
     69    print("stopped cyclic send")
     70    print("Changing data of stopped task to single ff byte")
     71    msg.data = bytearray([0xff])
     72    msg.dlc = 1
     73    task.modify_data(msg)
     74    time.sleep(1)
     75    print("starting again")
     76    task.start()
     77    time.sleep(1)
     78    task.stop()
     79    print("done")
     80
     81
     82# Will have to consider how to expose items like this. The socketcan
     83# interfaces will continue to support it... but the top level api won't.
     84# def test_dual_rate_periodic_send():
     85#     """Send a message 10 times at 1ms intervals, then continue to send every 500ms"""
     86#     msg = can.Message(arbitration_id=0x123, data=[0, 1, 2, 3, 4, 5])
     87#     print("Creating cyclic task to send message 10 times at 1ms, then every 500ms")
     88#     task = can.interface.MultiRateCyclicSendTask('vcan0', msg, 10, 0.001, 0.50)
     89#     time.sleep(2)
     90#
     91#     print("Changing data[0] = 0x42")
     92#     msg.data[0] = 0x42
     93#     task.modify_data(msg)
     94#     time.sleep(2)
     95#
     96#     task.stop()
     97#     print("stopped cyclic send")
     98#
     99#     time.sleep(2)
    100#
    101#     task.start()
    102#     print("starting again")
    103#     time.sleep(2)
    104#     task.stop()
    105#     print("done")
    106
    107
    108if __name__ == "__main__":
    109
    110    reset_msg = can.Message(arbitration_id=0x00, data=[0, 0, 0, 0, 0, 0], is_extended_id=False)
    111
    112    for interface, channel in [
    113        ('socketcan', 'vcan0'),
    114        #('ixxat', 0)
    115    ]:
    116        print("Carrying out cyclic tests with {} interface".format(interface))
    117
    118        bus = can.Bus(interface=interface, channel=channel, bitrate=500000)
    119        bus.send(reset_msg)
    120
    121        simple_periodic_send(bus)
    122
    123        bus.send(reset_msg)
    124
    125        limited_periodic_send(bus)
    126
    127        test_periodic_send_with_modifying_data(bus)
    128
    129        #print("Carrying out multirate cyclic test for {} interface".format(interface))
    130        #can.rc['interface'] = interface
    131        #test_dual_rate_periodic_send()
    132
    133        bus.shutdown()
    134
    135    time.sleep(2)

## Message Sending Tasks

The class based api for the broadcast manager uses a series of mixin classes. All mixins inherit from `CyclicSendTaskABC` which inherits from `CyclicTask`.

class can.broadcastmanager.CyclicTask

  Abstract Base for all cyclic tasks.

  abstract stop()

    Cancel this periodic task.

    Raises

      can.CanError – If stop is called on an already stopped task.

class can.broadcastmanager.CyclicSendTaskABC(message, period)

  Message send task with defined period

  Parameters

    - message (can.Message) – The message to be sent periodically.

    - period (float) – The rate in seconds at which to send the message.

class can.broadcastmanager.LimitedDurationCyclicSendTaskABC(message, period, duration)

  Message send task with a defined duration and period.

  Parameters

    - message (can.Message) – The message to be sent periodically.

    - period (float) – The rate in seconds at which to send the message.

    - duration (float) – The duration to keep sending this message at given rate.

class can.broadcastmanager.MultiRateCyclicSendTaskABC(channel, message, count, initial_period, subsequent_period)

  A Cyclic send task that supports switches send frequency after a set time.

  Transmits a message count times at initial_period then continues to transmit message at subsequent_period.

  Parameters

    - channel – See interface specific documentation.

    - message (can.Message) –

    - count (int) –

    - initial_period (float) –

    - subsequent_period (float) –

class can.ModifiableCyclicTaskABC(message, period)

  Adds support for modifying a periodic message

  Parameters

    - message (can.Message) – The message to be sent periodically.

    - period (float) – The rate in seconds at which to send the message.

  modify_data(message)

    Update the contents of this periodically sent message without altering the timing.

    Parameters

      message (can.Message) – The message with the new `can.Message.data`. Note: The arbitration ID cannot be changed.

class can.RestartableCyclicTaskABC(message, period)

  Adds support for restarting a stopped cyclic task

  Parameters

    - message (can.Message) – The message to be sent periodically.

    - period (float) – The rate in seconds at which to send the message.

  abstract start()

    Restart a stopped periodic task.

### Functional API

Warning

The functional API in `can.broadcastmanager.send_periodic()` is now deprecated and will be removed in version 4.0. Use the object oriented API via `can.BusABC.send_periodic()` instead.

can.broadcastmanager.send_periodic(bus, message, period, *args, **kwargs)

  Send a `Message` every period seconds on the given bus.

  Parameters

    - bus (can.BusABC) – A CAN bus which supports sending.

    - message (can.Message) – Message to send periodically.

    - period (float) – The minimum time between sending messages.

  Returns

    A started task instance