Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
.vscode/
dist/
someipy.egg-info/
__pycache__
__pycache__

test_apps/build
test_apps/install
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ The library is still under development. The current major limitations and deviat
### SOME/IP

- Events (and field notifiers) are supported.
- Methods are only supported on server side (offering methods). Calling methods (clients) are not supported yet.
- Only UDP services are supported.
- Methods are only supported on server side (offering methods). Calling methods (clients) is not supported yet.
- Only unicast services are supported.
- SOME/IP-TP is not supported.
- IPv6 endpoints are not supported.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import ipaddress
import logging

from someipy import ServiceBuilder, EventGroup, TransportLayerProtocol, SomeIpMessage
from someipy.service_discovery import construct_service_discovery
from someipy.client_service_instance import construct_client_service_instance
from someipy.logging import set_someipy_log_level
Expand All @@ -11,12 +12,15 @@
SD_PORT = 30490
INTERFACE_IP = "127.0.0.1"

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


def temperature_callback(payload: bytes) -> None:
print(f"Received {len(payload)} bytes.")
temperature_msg = TemparatureMsg().deserialize(payload)
def temperature_callback(someip_message: SomeIpMessage) -> None:
print(f"Received {len(someip_message.payload)} bytes.")
temperature_msg = TemparatureMsg().deserialize(someip_message.payload)
print(temperature_msg)


Expand All @@ -37,14 +41,24 @@ async def main():
# and port to which the events are sent to and the client will listen to
# 3. The ServiceDiscoveryProtocol object has to be passed as well, so the ClientServiceInstance can offer his service to
# other ECUs
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()
)

service_instance_temperature = await construct_client_service_instance(
service_id=1,
instance_id=1000,
major_version=1,
minor_version=0,
service=temperature_service,
instance_id=SAMPLE_INSTANCE_ID,
endpoint=(ipaddress.IPv4Address(INTERFACE_IP), 3002),
ttl=5,
sd_sender=service_discovery,
protocol=TransportLayerProtocol.UDP
)

# It's possible to optionally register a callback function which will be called when an event from the
Expand Down
85 changes: 43 additions & 42 deletions example_apps/send_events.py → example_apps/send_events_tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import ipaddress
import logging

from someipy import TransportLayerProtocol, ServiceBuilder, EventGroup, construct_server_service_instance
from someipy.service_discovery import construct_service_discovery
from someipy.server_service_instance import construct_server_service_instance
from someipy.logging import set_someipy_log_level
from someipy.serialization import Uint8, Uint64, Float32
from temperature_msg import TemparatureMsg
Expand All @@ -12,67 +12,67 @@
SD_PORT = 30490
INTERFACE_IP = "127.0.0.1"

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

async def main():

async def main():
# It's possible to configure the logging level of the someipy library, e.g. logging.INFO, logging.DEBUG, logging.WARN, ..
set_someipy_log_level(logging.DEBUG)

# Since the construction of the class ServiceDiscoveryProtocol is not trivial and would require an async __init__ function
# use the construct_service_discovery function
# The local interface IP address needs to be passed so that the src-address of all SD UDP packets is correctly set
service_discovery = await construct_service_discovery(SD_MULTICAST_GROUP, SD_PORT, INTERFACE_IP)

# 1. For sending events use a ServerServiceInstance
# 2. Pass the service and instance ID, version and endpoint and TTL. The endpoint is needed again as the src-address
# and port of all sent events
# 3. The ServiceDiscoveryProtocol object has to be passed as well, so the ServerServiceInstance can offer his service to
# other ECUs
# 4. cyclic_offer_delay_ms is the period of sending cyclic SD Offer service entries
service_discovery = await construct_service_discovery(
SD_MULTICAST_GROUP, SD_PORT, INTERFACE_IP
)

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()
)

# For sending events use a ServerServiceInstance
service_instance_temperature = await construct_server_service_instance(
service_id=1,
instance_id=1000,
major_version=1,
minor_version=0,
endpoint=(ipaddress.IPv4Address(INTERFACE_IP), 3000), # src IP and port of the service
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
cyclic_offer_delay_ms=2000,
protocol=TransportLayerProtocol.TCP
)

# The service instance has to be attached always to the ServiceDiscoveryProtocol object, so that the service instance
# is notified by the ServiceDiscoveryProtocol about e.g. subscriptions from other ECUs
service_discovery.attach(service_instance_temperature)

# For demonstration purposes we will construct a second ServerServiceInstance
service_instance_2 = await construct_server_service_instance(
service_id=2,
instance_id=2000,
major_version=1,
minor_version=0,
endpoint=(ipaddress.IPv4Address(INTERFACE_IP), 3001), # src IP and port of the service
ttl=5,
sd_sender=service_discovery,
cyclic_offer_delay_ms=2000
)
service_discovery.attach(service_instance_2)
# ..it's also possible to construct another ServerServiceInstance and attach it to service_discovery as well

# After constructing and attaching ServerServiceInstances to the ServiceDiscoveryProtocol objects the
# After constructing and attaching ServerServiceInstances to the ServiceDiscoveryProtocol object the
# start_offer method has to be called. This will start an internal timer, which will periodically send
# Offer service entries with a period of "cyclic_offer_delay_ms" which has been passed above
print("Start offering services..")
print("Start offering service..")
service_instance_temperature.start_offer()
service_instance_2.start_offer()

tmp_msg = TemparatureMsg()

# Reminder: Do NOT write "tmp_msg.version.major = 1". Always use the provided classes in someipy like Uint8,
# Reminder: Do NOT use "tmp_msg.version.major = 1". Always use the provided classes in someipy like Uint8,
# so that the data can be propery serialized. Python literals won't be serialized properly
tmp_msg.version.major = Uint8(1)
tmp_msg.version.minor = Uint8(0)

tmp_msg.measurements.data[0] = Float32(20.0)
tmp_msg.measurements.data[1] = Float32(21.0)
tmp_msg.measurements.data[2] = Float32(22.0)
Expand All @@ -81,18 +81,19 @@ async def main():
try:
# Either cyclically send events in an endless loop..
while True:
await asyncio.sleep(5)
await asyncio.sleep(1)
tmp_msg.timestamp = Uint64(tmp_msg.timestamp.value + 1)
payload = tmp_msg.serialize()
service_instance_temperature.send_event(SAMPLE_EVENTGROUP_ID, SAMPLE_EVENT_ID, payload)
service_instance_temperature.send_event(
SAMPLE_EVENTGROUP_ID, SAMPLE_EVENT_ID, payload
)

# .. or in case your app is waiting for external events, using await asyncio.Future() to
# .. or in case your app is waiting for external events, use await asyncio.Future() to
# keep the task alive
# await asyncio.Future()
except asyncio.CancelledError as e:
print("Stop offering services..")
except asyncio.CancelledError:
print("Stop offering service..")
await service_instance_temperature.stop_offer()
await service_instance_2.stop_offer()
finally:
print("Service Discovery close..")
service_discovery.close()
Expand All @@ -103,5 +104,5 @@ async def main():
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt as e:
except KeyboardInterrupt:
pass
108 changes: 108 additions & 0 deletions example_apps/send_events_udp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import asyncio
import ipaddress
import logging

from someipy import TransportLayerProtocol, ServiceBuilder, EventGroup, construct_server_service_instance
from someipy.service_discovery import construct_service_discovery
from someipy.logging import set_someipy_log_level
from someipy.serialization import Uint8, Uint64, Float32
from temperature_msg import TemparatureMsg

SD_MULTICAST_GROUP = "224.224.224.245"
SD_PORT = 30490
INTERFACE_IP = "127.0.0.1"

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


async def main():
# It's possible to configure the logging level of the someipy library, e.g. logging.INFO, logging.DEBUG, logging.WARN, ..
set_someipy_log_level(logging.DEBUG)

# Since the construction of the class ServiceDiscoveryProtocol is not trivial and would require an async __init__ function
# use the construct_service_discovery function
# The local interface IP address needs to be passed so that the src-address of all SD UDP packets is correctly set
service_discovery = await construct_service_discovery(
SD_MULTICAST_GROUP, SD_PORT, INTERFACE_IP
)

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()
)

# 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 service instance has to be attached always to the ServiceDiscoveryProtocol object, so that the service instance
# is notified by the ServiceDiscoveryProtocol about e.g. subscriptions from other ECUs
service_discovery.attach(service_instance_temperature)

# ..it's also possible to construct another ServerServiceInstance and attach it to service_discovery as well

# After constructing and attaching ServerServiceInstances to the ServiceDiscoveryProtocol object the
# start_offer method has to be called. This will start an internal timer, which will periodically send
# Offer service entries with a period of "cyclic_offer_delay_ms" which has been passed above
print("Start offering service..")
service_instance_temperature.start_offer()

tmp_msg = TemparatureMsg()

# Reminder: Do NOT use "tmp_msg.version.major = 1". Always use the provided classes in someipy like Uint8,
# so that the data can be propery serialized. Python literals won't be serialized properly
tmp_msg.version.major = Uint8(1)
tmp_msg.version.minor = Uint8(0)

tmp_msg.measurements.data[0] = Float32(20.0)
tmp_msg.measurements.data[1] = Float32(21.0)
tmp_msg.measurements.data[2] = Float32(22.0)
tmp_msg.measurements.data[3] = Float32(23.0)

try:
# Either cyclically send events in an endless loop..
while True:
await asyncio.sleep(1)
tmp_msg.timestamp = Uint64(tmp_msg.timestamp.value + 1)
payload = tmp_msg.serialize()
service_instance_temperature.send_event(
SAMPLE_EVENTGROUP_ID, SAMPLE_EVENT_ID, payload
)

# .. or in case your app is waiting for external events, use await asyncio.Future() to
# keep the task alive
# await asyncio.Future()
except asyncio.CancelledError:
print("Stop offering service..")
await service_instance_temperature.stop_offer()
finally:
print("Service Discovery close..")
service_discovery.close()

print("End main task..")


if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
pass
4 changes: 4 additions & 0 deletions src/someipy/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from ._internal.someip_sd_header import TransportLayerProtocol
from .server_service_instance import ServerServiceInstance, construct_server_service_instance
from .service import Service, ServiceBuilder, EventGroup
from ._internal.someip_message import SomeIpMessage
3 changes: 2 additions & 1 deletion src/someipy/_internal/service_discovery_abcs.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import ipaddress
from abc import ABC, abstractmethod
from someipy._internal.someip_sd_header import *
from someipy._internal.someip_sd_header import SdService, SdEventGroupEntry, SdIPV4EndpointOption
from someipy._internal.session_handler import SessionHandler


Expand Down
Loading