Skip to content

Commit 4b651b4

Browse files
VERSION 0.10.6
1 parent 935da03 commit 4b651b4

File tree

16 files changed

+254
-209
lines changed

16 files changed

+254
-209
lines changed

examples/all_sender_and_receiver.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1+
from __future__ import annotations
2+
import os
3+
import sys
4+
# Ensure ../src (relative to this file) is on PYTHONPATH so local modules can be imported
5+
_this_dir = os.path.dirname(os.path.abspath(__file__))
6+
_src_dir = os.path.normpath(os.path.join(_this_dir, "..", "src"))
7+
if _src_dir not in sys.path:
8+
sys.path.insert(0, _src_dir)
9+
110
import logging
11+
import time
212
from flexstack.linklayer.raw_link_layer import RawLinkLayer
313
from flexstack.geonet.router import Router as GNRouter
414
from flexstack.geonet.mib import MIB
515
from flexstack.geonet.gn_address import GNAddress, M, ST, MID
616
from flexstack.btp.router import Router as BTPRouter
717
from flexstack.utils.static_location_service import ThreadStaticLocationService, generate_tpv_dict_with_current_timestamp
8-
from flexstack.facilities.local_dynamic_map.factory import ldm_factory
18+
from flexstack.facilities.local_dynamic_map.factory import LDMFactory
919
from flexstack.facilities.local_dynamic_map.ldm_classes import (
1020
AccessPermission,
1121
Circle,
@@ -42,13 +52,6 @@
4252
)
4353
from flexstack.facilities.local_dynamic_map.ldm_classes import ComparisonOperators
4454
import random
45-
import os
46-
import sys
47-
# Ensure ../src (relative to this file) is on PYTHONPATH so local modules can be imported
48-
_this_dir = os.path.dirname(os.path.abspath(__file__))
49-
_src_dir = os.path.normpath(os.path.join(_this_dir, "..", "src"))
50-
if _src_dir not in sys.path:
51-
sys.path.insert(0, _src_dir)
5255

5356

5457
logging.basicConfig(level=logging.INFO)
@@ -82,9 +85,9 @@ def generate_random_mac_address(locally_administered: bool = True, multicast: bo
8285
POSITION_COORDINATES = [41.386931, 2.112104]
8386
MAC_ADDRESS = generate_random_mac_address()
8487
STATION_ID = random.randint(1, 2147483647)
85-
SEND_CAMS = False
86-
SEND_VAMS = False
87-
SEND_DENMS = False
88+
SEND_CAMS = True
89+
SEND_VAMS = True
90+
SEND_DENMS = True
8891

8992

9093
def main():
@@ -121,7 +124,8 @@ def main():
121124
rectangle=None,
122125
ellipse=None,
123126
)
124-
ldm = ldm_factory(
127+
ldm = LDMFactory()
128+
ldm = ldm.create_ldm(
125129
ldm_location,
126130
ldm_maintenance_type="Reactive",
127131
ldm_service_type="Reactive",
@@ -146,7 +150,6 @@ def main():
146150
def cam_ldm_subscription_callback(data: RequestDataObjectsResp) -> None:
147151
print(
148152
f'Notified CAM from : {data.data_objects[0]["dataObject"]["header"]["stationId"]}')
149-
print(len(data.data_objects))
150153

151154
subscribe_data_consumer_response: SubscribeDataObjectsResp = (
152155
ldm.if_ldm_4.subscribe_data_consumer(
@@ -159,7 +162,7 @@ def cam_ldm_subscription_callback(data: RequestDataObjectsResp) -> None:
159162
STATION_ID)),
160163
notify_time=TimestampIts(0),
161164
multiplicity=1,
162-
order=(OrderTupleValue(attribute="cam.generationDeltaTime",
165+
order=(OrderTupleValue(attribute="utc_timestamp",
163166
ordering_direction=OrderingDirection.DESCENDING),),
164167
),
165168
cam_ldm_subscription_callback,
@@ -172,7 +175,6 @@ def cam_ldm_subscription_callback(data: RequestDataObjectsResp) -> None:
172175
def vam_ldm_subscription_callback(data: RequestDataObjectsResp) -> None:
173176
print(
174177
f'Notified VAM from : {data.data_objects[0]["dataObject"]["header"]["stationId"]}')
175-
print(len(data.data_objects))
176178

177179
subscribe_data_consumer_response: SubscribeDataObjectsResp = (
178180
ldm.if_ldm_4.subscribe_data_consumer(
@@ -185,7 +187,7 @@ def vam_ldm_subscription_callback(data: RequestDataObjectsResp) -> None:
185187
STATION_ID)),
186188
notify_time=TimestampIts(0),
187189
multiplicity=1,
188-
order=(OrderTupleValue(attribute="vam.generationDeltaTime",
190+
order=(OrderTupleValue(attribute="utc_timestamp",
189191
ordering_direction=OrderingDirection.DESCENDING),),
190192
),
191193
vam_ldm_subscription_callback,
@@ -273,8 +275,15 @@ def denm_ldm_subscription_callback(data: RequestDataObjectsResp) -> None:
273275

274276
gn_router.link_layer = link_layer
275277
print("Press Ctrl+C to stop the program.")
278+
try:
279+
while True:
280+
time.sleep(1)
281+
except KeyboardInterrupt:
282+
print("Exiting...")
283+
284+
location_service.stop_event.set()
276285
location_service.location_service_thread.join()
277-
286+
link_layer.sock.close()
278287

279288
if __name__ == "__main__":
280289
main()

examples/cam_sender_and_receiver.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
# Configure logging
1010
import random
11+
import time
1112
from flexstack.facilities.local_dynamic_map.ldm_classes import ComparisonOperators
1213
from flexstack.facilities.ca_basic_service.cam_transmission_management import (
1314
VehicleData,
@@ -33,7 +34,7 @@
3334
SubscribeDataobjectsResult,
3435
TimestampIts,
3536
)
36-
from flexstack.facilities.local_dynamic_map.factory import ldm_factory
37+
from flexstack.facilities.local_dynamic_map.factory import LDMFactory
3738
from flexstack.utils.static_location_service import ThreadStaticLocationService
3839
from flexstack.btp.router import Router as BTPRouter
3940
from flexstack.geonet.gn_address import GNAddress, M, ST, MID
@@ -106,7 +107,8 @@ def main():
106107
rectangle=None,
107108
ellipse=None,
108109
)
109-
ldm = ldm_factory(
110+
ldm_factory = LDMFactory()
111+
ldm = ldm_factory.create_ldm(
110112
ldm_location,
111113
ldm_maintenance_type="Reactive",
112114
ldm_service_type="Reactive",
@@ -180,9 +182,15 @@ def ldm_subscription_callback(data: RequestDataObjectsResp) -> None:
180182
)
181183

182184
gn_router.link_layer = link_layer
183-
print("Press Ctrl+C to stop the program.")
185+
try:
186+
while True:
187+
time.sleep(1)
188+
except KeyboardInterrupt:
189+
print("Exiting...")
190+
191+
location_service.stop_event.set()
184192
location_service.location_service_thread.join()
185-
193+
link_layer.sock.close()
186194

187195
if __name__ == "__main__":
188196
main()

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "v2xflexstack"
7-
version = "0.10.5"
7+
version = "0.10.6"
88
authors = [
99
{ name = "Jordi Marias-i-Parella", email = "[email protected]" },
1010
{ name = "Daniel Ulied Guevara", email = "[email protected]" },

src/flexstack/applications/road_hazard_signalling_service/emergency_vehicle_approaching_service.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ def trigger_denm_sending(self, tpv: dict) -> None:
7676
- "lon" : Longitude in decimal degrees.
7777
- "altHAE" : Altitude in meters above the WGS-84 ellipsoid.
7878
"""
79-
request = DENRequest()
8079
if "lat" in tpv.keys():
8180
self.event_position["latitude"] = int(tpv["lat"] * 10000000)
8281
if "lon" in tpv.keys():
@@ -92,6 +91,6 @@ def trigger_denm_sending(self, tpv: dict) -> None:
9291
tpv["altHAE"] * 100
9392
)
9493

95-
request.with_emergency_vehicle_approaching(self)
94+
request = DENRequest.with_emergency_vehicle_approaching(self)
9695
self.den_service.denm_transmission_management.request_denm_sending(
9796
request)
Lines changed: 60 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
from __future__ import annotations
2-
from enum import Enum
32
from typing import TYPE_CHECKING
3+
from dataclasses import dataclass, field
4+
from enum import Enum
45
from ...facilities.local_dynamic_map.ldm_classes import ReferencePosition, TimestampIts
5-
66
if TYPE_CHECKING:
77
from .emergency_vehicle_approaching_service import (
88
EmergencyVehicleApproachingService,
99
)
1010

1111

12+
@dataclass(frozen=True)
1213
class RelevanceArea:
1314
"""
1415
Class to define the relevance area of the DENM.
@@ -22,22 +23,8 @@ class RelevanceArea:
2223
Relevance direction from the vehicle to a traffic hazard
2324
or to its future position.
2425
"""
25-
26-
def __init__(self, r_distance: int, r_direction: int) -> None:
27-
"""
28-
Initialize the relevance area of the DENM.
29-
30-
Parameters
31-
----------
32-
r_distance : int
33-
Relevance distance from the vehicle to a traffic hazard
34-
or to its future position.
35-
r_direction : int
36-
Relevance direction from the vehicle to a traffic hazard
37-
or to its future position.
38-
"""
39-
self.relevance_distance = r_distance
40-
self.relevance_direction = r_direction
26+
relevance_distance: int
27+
relevance_direction: int
4128

4229

4330
class PriorityLevel(Enum):
@@ -56,6 +43,7 @@ class PriorityLevel(Enum):
5643
PRECRASH = 0
5744

5845

46+
@dataclass(frozen=True)
5947
class DENRequest:
6048
"""
6149
Class for storing the data of the DENM.
@@ -106,37 +94,32 @@ class DENRequest:
10694
Relevance area for the emergency vehicle approaching use case.
10795
Defines the farthest future position of the emergency vehicle.
10896
"""
109-
110-
def __init__(self) -> None:
111-
"""
112-
Initialize the specific data of the DENM.
113-
"""
114-
115-
self.denm_interval = 100
116-
self.priority_level = 1
117-
# Data elements values
118-
self.detection_time = 0
119-
self.time_period = 0
120-
self.quality = 7
121-
self.event_position = {}
122-
self.heading = 0 # or N/A
123-
self.confidence = 2 # or N/A
124-
# self.traceID = N/A
125-
# self.waypoints = N/A
126-
# Emergency Vehicle Approaching specific data elements
127-
self.relevance_distance: str = None
128-
self.relevance_traffic_direction: str = None
129-
self.rhs_cause_code: str = None
130-
self.rhs_subcause_code: int = None
131-
self.rhs_event_speed: int = None
132-
self.rhs_vehicle_type: int = None
133-
# Longitudinal Collision Risk Warning specific data elements
134-
self.lcrw_cause_code: str = None
135-
self.lcrw_subcause_code: int = None
136-
97+
denm_interval: int = 100
98+
priority_level: PriorityLevel = PriorityLevel.WARNING
99+
# Data elements values
100+
detection_time: int = 0
101+
time_period: int = 0
102+
quality: int = 7
103+
event_position: dict = field(default_factory=dict)
104+
heading: int = 0 # or N/A
105+
confidence: int = 2 # or N/A
106+
# traceID = N/A
107+
# waypoints = N/A
108+
# Emergency Vehicle Approaching specific data elements
109+
relevance_distance: str | None = None
110+
relevance_traffic_direction: str | None = None
111+
rhs_cause_code: str | None = None
112+
rhs_subcause_code: int | None = None
113+
rhs_event_speed: int | None = None
114+
rhs_vehicle_type: int | None = None
115+
# Longitudinal Collision Risk Warning specific data elements
116+
lcrw_cause_code: str | None = None
117+
lcrw_subcause_code: int | None = None
118+
119+
@staticmethod
137120
def with_emergency_vehicle_approaching(
138-
self, service: "EmergencyVehicleApproachingService"
139-
) -> None:
121+
service: "EmergencyVehicleApproachingService"
122+
) -> DENRequest:
140123
"""
141124
Fulfills the DENM Request for Emergency Vehicle Approaching Service
142125
@@ -145,29 +128,29 @@ def with_emergency_vehicle_approaching(
145128
service : EmergencyVehicleApproachingService
146129
Emergency Vehicle Approaching Service object
147130
"""
148-
self.denm_interval = service.denm_interval
149-
self.priority_level = service.priority_level
150-
151-
# Relevance area parameters
152-
self.relevance_distance = "lessThan200m"
153-
self.relevance_traffic_direction = "upstreamTraffic"
154-
# self.DENMTermination = "isCancellation"
155-
156-
# Data elements values
157-
self.detection_time = service.detection_time
158-
self.time_period = service.denm_duration
159-
self.event_position = service.event_position
160-
161-
# Specific use cases data elemenets
162-
self.rhs_cause_code = "emergencyVehicleApproaching95"
163-
self.rhs_subcause_code = 1 # [OPTIONAL]
164-
self.rhs_event_speed = 30 # 108 km/h
165-
self.rhs_vehicle_type = 0
166-
# self.rhs_relevance_area = RelevanceArea(4, 0)
167-
131+
return DENRequest(
132+
denm_interval=service.denm_interval,
133+
priority_level=service.priority_level,
134+
# Relevance area parameters
135+
relevance_distance="lessThan200m",
136+
relevance_traffic_direction="upstreamTraffic",
137+
# DENMTermination = "isCancellation"
138+
# Data elements values
139+
detection_time=service.detection_time,
140+
time_period=service.denm_duration,
141+
event_position=service.event_position,
142+
# Specific use cases data elemenets
143+
rhs_cause_code="emergencyVehicleApproaching95",
144+
rhs_subcause_code=1, # [OPTIONAL]
145+
rhs_event_speed=30, # 108 km/h
146+
rhs_vehicle_type=0,
147+
# rhs_relevance_area=RelevanceArea(4, 0),
148+
)
149+
150+
@staticmethod
168151
def with_collision_risk_warning(
169-
self, detection_time: TimestampIts, event_position: ReferencePosition
170-
) -> None:
152+
detection_time: TimestampIts, event_position: ReferencePosition
153+
) -> DENRequest:
171154
"""
172155
Fulfills the DENM Request for Longitudinal Collision Risk Warnings
173156
@@ -178,8 +161,10 @@ def with_collision_risk_warning(
178161
event_position : ReferencePosition
179162
Position of the hazard.
180163
"""
181-
self.priority_level = 1
182-
self.detection_time = detection_time.timestamp_its
183-
self.event_position = event_position.to_dict()
184-
self.lcrw_cause_code = "collisionRisk97" # Collision risk
185-
self.lcrw_subcause_code = 4 # Collision risk involving VRU
164+
return DENRequest(
165+
priority_level=PriorityLevel.WARNING,
166+
detection_time=detection_time.timestamp_its,
167+
event_position=event_position.to_dict(),
168+
lcrw_cause_code="collisionRisk97", # Collision risk
169+
lcrw_subcause_code=4 # Collision risk involving VRU
170+
)

src/flexstack/facilities/local_dynamic_map/factory.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44

55
from .ldm_classes import (
6+
GeometricArea,
67
Location,
78
SubscribeDataobjectsReq,
89
SubscribeDataObjectsResp,
@@ -78,7 +79,7 @@ def create_ldm(
7879
ldm_maintenance = LDMMaintenanceReactive(ldm_location, ldm_database)
7980
logs.info('LDM Maintenance "Reactive" configured.')
8081
elif ldm_maintenance_type == "Thread":
81-
ldm_maintenance = LDMMaintenanceThread(ldm_location, ldm_database, None)
82+
ldm_maintenance = LDMMaintenanceThread(ldm_location, ldm_database)
8283
logs.info('LDM Maintenance "Thread" configured.')
8384
else:
8485
logs.error(
@@ -117,7 +118,7 @@ def create_ldm(
117118
def subscribe_to_ldm(
118119
self,
119120
own_station_id: int,
120-
ldm_location: Location,
121+
area_of_interest: GeometricArea,
121122
callback_function: Callable[[RequestDataObjectsResp], None],
122123
) -> None:
123124
"""
@@ -142,7 +143,7 @@ def subscribe_to_ldm(
142143
RegisterDataConsumerReq(
143144
application_id=AccessPermission.CAM,
144145
access_permisions=(AccessPermission.CAM, AccessPermission.VAM),
145-
area_of_interest=ldm_location,
146+
area_of_interest=area_of_interest,
146147
)
147148
)
148149
if register_data_consumer_reponse.result == 2:

0 commit comments

Comments
 (0)