Decentralized Environmental Notification (DEN) Service
The DEN Service broadcasts hazard warnings to nearby vehicles using Decentralized Environmental Notification Messages (DENMs). While CAMs say “I’m here,” DENMs say “Watch out for this!”
Note
The DEN Service implements ETSI TS 103 831 V2.2.1 (2024-04). DENMs are event-driven messages that warn about road hazards, accidents, emergency vehicles, and other dangerous situations.
What DENMs Are For
DENMs alert drivers to hazardous situations:
Use Case |
Description |
|---|---|
🚑 Emergency Vehicle |
Ambulance, fire truck, or police approaching |
🚧 Road Hazard |
Obstacle on road, slippery conditions, road works |
💥 Accident |
Collision ahead, stationary vehicle |
⚠️ Dangerous Situation |
Wrong-way driver, traffic jam end warning |
🌧️ Weather |
Fog, heavy rain, ice on road |
CAM vs DENM
Aspect |
CAM |
DENM |
|---|---|---|
Purpose |
“I am here” |
“Watch out for this” |
Trigger |
Periodic (time/position based) |
Event-driven (hazard detected) |
Lifetime |
Single transmission |
Persists until terminated |
BTP Port |
2001 |
2002 |
Architecture
The DEN Service consists of three components:
flowchart TB
subgraph "Application Layer"
EVA[Emergency Vehicle<br/>Approaching Service]
LCRW[Longitudinal Collision<br/>Risk Warning]
APP[Other Applications]
end
subgraph "DEN Service"
DEN[DEN Service]
TM[Transmission<br/>Management]
RM[Reception<br/>Management]
COD[DEN Coder]
end
subgraph "Transport"
BTP[BTP Router<br/>Port 2002]
end
subgraph "Optional"
LDM[(Local Dynamic Map)]
end
EVA --> DEN
LCRW --> DEN
APP --> DEN
DEN <--> TM
DEN <--> RM
DEN <--> COD
DEN <-->|"Send/Receive"| BTP
RM -.->|"Store"| LDM
style DEN fill:#ffebee,stroke:#c62828
style EVA fill:#fff3e0
style LCRW fill:#fff3e0
Components:
Component |
Description |
|---|---|
DEN Service |
Main service handling DENM creation, management, and lifecycle |
Transmission Management |
Handles message triggering, updates, and termination |
Reception Management |
Processes incoming DENMs (automatic, no setup needed) |
DEN Coder |
Encodes/decodes DENM ASN.1 format |
Getting Started
Prerequisites
The DEN Service requires:
BTP Router — for transport (port 2002)
Vehicle Data — your station’s information
Location Service — for position updates (recommended)
Optional but recommended:
Local Dynamic Map — for storing received DENMs
Step 1: Create DEN Service
from flexstack.facilities.decentralized_environmental_notification_service.den_service import (
DecentralizedEnvironmentalNotificationService,
)
from flexstack.facilities.ca_basic_service.cam_transmission_management import VehicleData
# Configure vehicle data
vehicle_data = VehicleData(
station_id=12345,
station_type=5, # Passenger car
drive_direction="forward",
vehicle_length={"vehicleLengthValue": 42, "vehicleLengthConfidenceIndication": "unavailable"},
vehicle_width=18,
)
# Create DEN Service
den_service = DecentralizedEnvironmentalNotificationService(
btp_router=btp_router,
vehicle_data=vehicle_data,
)
That’s it! The DEN Service is now ready. Reception management is automatic — incoming DENMs will be processed without any additional setup.
Step 2: Use an Application Service
The DEN Service is typically used through application layer services that implement specific use cases. FlexStack provides two built-in applications:
Emergency Vehicle Approaching Service — alerts about approaching emergency vehicles
Longitudinal Collision Risk Warning — warns about collision risks ahead
Emergency Vehicle Approaching Service
This service broadcasts DENMs when an emergency vehicle (ambulance, fire truck, police) needs to alert nearby traffic.
from flexstack.applications.road_hazard_signalling_service.emergency_vehicle_approaching_service import (
EmergencyVehicleApproachingService,
)
from flexstack.utils.static_location_service import generate_tpv_dict_with_current_timestamp
# Create the application service
emergency_service = EmergencyVehicleApproachingService(
den_service=den_service,
duration=10000, # DENM validity duration in ms
)
# Trigger a DENM (e.g., when emergency lights are activated)
position = generate_tpv_dict_with_current_timestamp(
latitude=41.386931,
longitude=2.112104,
)
emergency_service.trigger_denm_sending(position)
Parameters:
Parameter |
Type |
Description |
|---|---|---|
|
|
The DEN Service instance |
|
|
How long the DENM remains valid (milliseconds) |
DENM Lifecycle
Unlike CAMs (which are fire-and-forget), DENMs have a lifecycle:
stateDiagram-v2
[*] --> Active: Trigger
Active --> Active: Update
Active --> Terminated: Cancel/Expire
Terminated --> [*]
note right of Active: DENM is valid and<br/>being rebroadcast
note right of Terminated: Event is over,<br/>DENM cancelled
DENM Actions:
Action |
Description |
|---|---|
Trigger |
Start a new DENM (hazard detected) |
Update |
Modify an existing DENM (situation changed) |
Terminate |
Cancel the DENM (hazard cleared) |
Each DENM is identified by an ActionID (station ID + sequence number), allowing receivers to track updates and terminations.
DENM Message Structure
A DENM contains four containers:
flowchart LR
subgraph DENM[DENM Message]
H[ITS PDU Header]
MC[Management Container]
SC[Situation Container]
LC[Location Container]
AC[À la Carte Container]
end
H --> MC --> SC --> LC --> AC
Container |
Contents |
|---|---|
Management |
Action ID, detection time, reference time, event position, validity duration |
Situation |
Cause code, sub-cause code, severity, linked cause (optional) |
Location |
Event area, road type, lane position, traces |
À la Carte |
Additional optional data (road works, stationary vehicle, etc.) |
Complete Example
Here’s a complete script demonstrating the Emergency Vehicle Approaching Service:
1#!/usr/bin/env python3
2"""
3Emergency Vehicle Approaching Service Example
4
5Broadcasts DENMs to alert nearby vehicles about an approaching emergency vehicle.
6Run with: sudo python emergency_vehicle_example.py
7"""
8
9import logging
10import random
11import time
12
13from flexstack.linklayer.raw_link_layer import RawLinkLayer
14from flexstack.geonet.router import Router as GNRouter
15from flexstack.geonet.mib import MIB
16from flexstack.geonet.gn_address import GNAddress, M, ST, MID
17from flexstack.btp.router import Router as BTPRouter
18from flexstack.utils.static_location_service import (
19 ThreadStaticLocationService,
20 generate_tpv_dict_with_current_timestamp,
21)
22from flexstack.facilities.ca_basic_service.cam_transmission_management import VehicleData
23from flexstack.facilities.decentralized_environmental_notification_service.den_service import (
24 DecentralizedEnvironmentalNotificationService,
25)
26from flexstack.applications.road_hazard_signalling_service.emergency_vehicle_approaching_service import (
27 EmergencyVehicleApproachingService,
28)
29
30logging.basicConfig(level=logging.INFO)
31
32# Configuration
33POSITION = [41.386931, 2.112104] # Barcelona
34MAC_ADDRESS = bytes([random.randint(0, 255) | 0x02 for _ in range(6)])
35STATION_ID = random.randint(1, 2147483647)
36
37
38def main():
39 # Location Service
40 location_service = ThreadStaticLocationService(
41 period=1,
42 latitude=POSITION[0],
43 longitude=POSITION[1],
44 )
45
46 # GeoNetworking
47 mib = MIB(
48 itsGnLocalGnAddr=GNAddress(
49 m=M.GN_MULTICAST,
50 st=ST.SPECIAL_VEHICLE, # Emergency vehicle
51 mid=MID(MAC_ADDRESS),
52 ),
53 )
54 gn_router = GNRouter(mib=mib, sign_service=None)
55 location_service.add_callback(gn_router.refresh_ego_position_vector)
56
57 # BTP
58 btp_router = BTPRouter(gn_router)
59 gn_router.register_indication_callback(btp_router.btp_data_indication)
60
61 # Vehicle Data (emergency vehicle)
62 vehicle_data = VehicleData(
63 station_id=STATION_ID,
64 station_type=10, # Special vehicle (emergency)
65 drive_direction="forward",
66 vehicle_length={"vehicleLengthValue": 70, "vehicleLengthConfidenceIndication": "unavailable"},
67 vehicle_width=25,
68 )
69
70 # DEN Service
71 den_service = DecentralizedEnvironmentalNotificationService(
72 btp_router=btp_router,
73 vehicle_data=vehicle_data,
74 )
75
76 # Emergency Vehicle Approaching Service
77 emergency_service = EmergencyVehicleApproachingService(
78 den_service=den_service,
79 duration=10000, # 10 second validity
80 )
81
82 # Trigger DENM (simulating emergency lights activation)
83 print("🚨 Triggering Emergency Vehicle DENM...")
84 emergency_service.trigger_denm_sending(
85 generate_tpv_dict_with_current_timestamp(POSITION[0], POSITION[1])
86 )
87
88 # Link Layer
89 btp_router.freeze_callbacks()
90 link_layer = RawLinkLayer(
91 "lo",
92 MAC_ADDRESS,
93 receive_callback=gn_router.gn_data_indicate,
94 )
95 gn_router.link_layer = link_layer
96
97 print("✅ Emergency Vehicle Service running!")
98 print("📡 Broadcasting DENMs...")
99 print("Press Ctrl+C to exit\n")
100
101 try:
102 while True:
103 time.sleep(1)
104 except KeyboardInterrupt:
105 print("\n👋 Shutting down...")
106
107 location_service.stop_event.set()
108 location_service.location_service_thread.join()
109 link_layer.sock.close()
110
111
112if __name__ == "__main__":
113 main()
Cause Codes
DENMs use standardized cause codes (defined in ETSI TS 102 894-2):
Code |
Cause |
Example Sub-causes |
|---|---|---|
1 |
Traffic Condition |
Traffic jam, slow traffic |
2 |
Accident |
Multi-vehicle, heavy accident |
3 |
Road Works |
Construction, maintenance |
6 |
Adverse Weather |
Fog, rain, ice, wind |
9 |
Hazardous Location |
Obstacle, animal on road |
12 |
Wrong Way Driver |
Vehicle going wrong direction |
14 |
Rescue/Recovery |
Emergency vehicle, recovery in progress |
15 |
Emergency Vehicle |
Approaching ambulance/fire/police |
91 |
Vehicle Breakdown |
Stationary disabled vehicle |
94 |
Stationary Vehicle |
Stopped vehicle (various reasons) |
See Also
Getting Started — Complete V2X tutorial
Cooperative Awareness (CA) Basic Service — Cooperative Awareness Messages
Local Dynamic Map — Store and query received DENMs
Basic Transport Protocol (BTP) — Transport layer (BTP port 2002)