Offering SOME/IP Events

SOME/IP Events

SOME/IP events implement the publish-subscribe concept in SOME/IP. A server offers a service to which one or more clients can subscribe. In case the server sends an event, all subscribed clients will receive the event.

A SOME/IP event is identified through an event ID which is packed into the header of a SOME/IP message. The event ID can be used by multiple services and does not have to be globally unique. The unique identification of an event comes through the combination of service ID, instance ID and event ID.

A SOME/IP event usually carries a serialized payload. For defining the service interface data types and serializing structured data into bytes follow the article on SOME/IP Service Interface Data Types.

SOME/IP SD Eventgroups vs. SOME/IP Events

In SOME/IP there is also the term of Eventgroups. It’s important to understand the difference for setting up a proper SOME/IP communication. If eventgroup and event IDs are mixed up, the service discovery will not be able to create the subscription properly.

Eventgroups are only used in service discovery of SOME/IP and group events together for logically subscription. Eventgroups only exist at the service discovery level, but never appear in the actual data sent for an event. Once a client subscribed to a service, eventgroups are obsolete.

Grouping events in eventgroups allows clients to subscribe to multiple events at once reducing the bandwidth used for service discovery. For that purpose you could put all your events into a single eventgroup. Then a client can subscribe to a single eventgroup and will receive notifications for all events. This has the advantage of reduced traffic for service discovery. However, since all events are sent to the client even if he may not need all events for operation, more bandwidth is used for sending the actual data.

If you want to enable clients to subscribe to single events more granularly create multiple eventgroups or even one eventgroup for each event. This will require more service discovery traffic, however it may lead to sending only events that are actually needed by a particular client.

Step 1: Define a Service

In order to offer a service containing a SOME/IP event, we will define a Service first, which is used afterwards to instantiate a ServerServiceInstance. The Service will contain a single event with ID 0x0123 in the eventgroup with ID 0x0321. The ServiceBuilder class is used to build the Service object.

SAMPLE_SERVICE_ID = 0x1234
SAMPLE_INSTANCE_ID = 0x5678
SAMPLE_EVENTGROUP_ID = 0x0321
SAMPLE_EVENT_ID = 0x0123

temperature_eventgroup = EventGroup(
        id=SAMPLE_EVENTGROUP_ID, event_ids=[SAMPLE_EVENT_ID]
    )
temperature_service = (
        ServiceBuilder()
        .with_service_id(SAMPLE_SERVICE_ID)
        .with_major_version(1)
        .with_eventgroup(temperature_eventgroup)
        .build()
    )

Step 2: Instantiate the Service

The previously defined Service can be instantiated as one or multiple service instances. Since we are offering events as a server, a ServerServiceInstance object is created using the construct_server_service_instance function. The construct_server_service_instance is a coroutine and therefore has to be awaited.

You can choose to either use UDP or TCP as the transport protocol. Make sure, that the configuration matches with the client subscribing to the service.

# For sending events use a ServerServiceInstance
service_instance_temperature = await construct_server_service_instance(
    temperature_service,
    instance_id=SAMPLE_INSTANCE_ID,
    endpoint=(
        ipaddress.IPv4Address(INTERFACE_IP),
        3000,
    ),  # src IP and port of the service
    ttl=5,
    sd_sender=service_discovery,
    cyclic_offer_delay_ms=2000,
    protocol=TransportLayerProtocol.UDP,
)

The parameters ttl and cyclic_offer_delay_ms are described in Service Discovery Configuration Parameters

Multiple service instances: If you want to offer multiple service instances in the same application, you would simply construct another service instance here. Read the example application offer_multiple_services.py for more details.

Step 3: Announce the Service via Service Discovery

At this point, clients are not able to subscribe to the ServerServiceInstance and to its eventgroup with ID 0x0321. First, we need to attach the ServerServiceInstance to service discovery. This will enable the ServerServiceInstance to be notified about new subscriptions from clients. An observer pattern is implemented in which the ServerServiceInstance is the observer.

It is assumed that the service_discovery object was instantiated beforehand. For more information on that topic, read Service Discovery Configuration Parameters.

service_discovery.attach(service_instance_temperature)

The next step is to use start_offer to announce the service instance to potential clients. The start_offer function will start an internal timer with a cycle of cyclic_offer_delay_ms sending service discovery messages with offer entries.

service_instance_temperature.start_offer()

Step 4: Sending Event Notifications to Clients

Now that the service is offered, clients can subscribe to the eventgroup with ID 0x0321 and the server can send events to the clients. The send_event function expects a bytes-object which is typically created by serialized structured data:

payload = tmp_msg.serialize()
service_instance_temperature.send_event(
    SAMPLE_EVENTGROUP_ID, SAMPLE_EVENT_ID, payload
)

Typical sending strategies for SOME/IP events are cyclic updates or update on change. Update on change means that an event is sent whenever the contained value changes. In a cyclic update the event would be sent even if the contained data has not changed since the last publish.