1#include <vanetza/asn1/cam.hpp>
2#include <vanetza/facilities/cam_functions.hpp>
3#include <vanetza/facilities/path_history.hpp>
4#include <vanetza/geonet/areas.hpp>
5#include <boost/algorithm/clamp.hpp>
6#include <boost/date_time/posix_time/posix_time.hpp>
7#include <boost/math/constants/constants.hpp>
8#include <boost/units/cmath.hpp>
9#include <boost/units/systems/si/prefixes.hpp>
10#include <boost/units/systems/angle/degrees.hpp>
20using vanetza::units::Angle;
22static const auto microdegree = units::degree * units::si::micro;
25void copy(
const facilities::PathHistory& ph, BasicVehicleContainerLowFrequency& container)
27 static const std::size_t scMaxPathPoints = 23;
28 static const boost::posix_time::time_duration scMaxDeltaTime = boost::posix_time::millisec(655350);
29 static const auto scMicrodegree = microdegree;
31 const auto& concise_points = ph.getConcisePoints();
32 const facilities::PathPoint& ref = ph.getReferencePoint();
33 std::size_t path_points = 0;
35 for (
const PathPoint& point : concise_points) {
36 auto delta_time = ref.time - point.time;
37 auto delta_latitude = point.latitude - ref.latitude;
38 auto delta_longitude = point.longitude - ref.longitude;
40 while (!delta_time.is_negative() && path_points < scMaxPathPoints) {
41 ::PathPoint* path_point = asn1::allocate<::PathPoint>();
42 path_point->pathDeltaTime = asn1::allocate<PathDeltaTime_t>();
43 *(path_point->pathDeltaTime) = std::min(delta_time, scMaxDeltaTime).total_milliseconds() /
44 10 * PathDeltaTime::PathDeltaTime_tenMilliSecondsInPast;
45 path_point->pathPosition.deltaLatitude = (delta_latitude / scMicrodegree).value() *
46 DeltaLatitude::DeltaLatitude_oneMicrodegreeNorth;
47 path_point->pathPosition.deltaLongitude = (delta_longitude / scMicrodegree).value() *
48 DeltaLongitude::DeltaLongitude_oneMicrodegreeEast;
49 path_point->pathPosition.deltaAltitude = DeltaAltitude::DeltaAltitude_unavailable;
51 ASN_SEQUENCE_ADD(&container.pathHistory, path_point);
53 delta_time -= scMaxDeltaTime;
59bool similar_heading(
const Heading& a,
const Heading& b, Angle limit)
62 static_assert(HeadingValue_wgs84East == 900,
"HeadingValue interpretation fails");
65 if (is_available(a) && is_available(b)) {
66 using vanetza::units::degree;
67 const Angle angle_a { a.headingValue / 10.0 * degree };
68 const Angle angle_b { b.headingValue / 10.0 * degree };
69 result = similar_heading(angle_a, angle_b, limit);
75bool similar_heading(
const Heading& a, Angle b, Angle limit)
78 if (is_available(a)) {
79 using vanetza::units::degree;
80 result = similar_heading(Angle { a.headingValue / 10.0 * degree}, b, limit);
85bool similar_heading(Angle a, Angle b, Angle limit)
87 using namespace boost::units;
88 using boost::math::double_constants::pi;
90 static const Angle full_circle = 2.0 * pi * si::radian;
91 const Angle abs_diff = fmod(abs(a - b), full_circle);
92 return abs_diff <= limit || abs_diff >= full_circle - limit;
95units::Length distance(
const ReferencePosition_t& a,
const ReferencePosition_t& b)
97 using geonet::GeodeticPosition;
98 using units::GeoAngle;
100 auto length = units::Length::from_value(std::numeric_limits<double>::quiet_NaN());
101 if (is_available(a) && is_available(b)) {
102 GeodeticPosition geo_a {
103 GeoAngle { a.latitude / Latitude_oneMicrodegreeNorth * microdegree },
104 GeoAngle { a.longitude / Longitude_oneMicrodegreeEast * microdegree }
106 GeodeticPosition geo_b {
107 GeoAngle { b.latitude / Latitude_oneMicrodegreeNorth * microdegree },
108 GeoAngle { b.longitude / Longitude_oneMicrodegreeEast * microdegree }
110 length = geonet::distance(geo_a, geo_b);
115units::Length distance(
const ReferencePosition_t& a, units::GeoAngle lat, units::GeoAngle lon)
117 using geonet::GeodeticPosition;
118 using units::GeoAngle;
120 auto length = units::Length::from_value(std::numeric_limits<double>::quiet_NaN());
121 if (is_available(a)) {
122 GeodeticPosition geo_a {
123 GeoAngle { a.latitude / Latitude_oneMicrodegreeNorth * microdegree },
124 GeoAngle { a.longitude / Longitude_oneMicrodegreeEast * microdegree }
126 GeodeticPosition geo_b { lat, lon };
127 length = geonet::distance(geo_a, geo_b);
132bool is_available(
const Heading& hd)
134 return hd.headingValue != HeadingValue_unavailable;
137bool is_available(
const ReferencePosition& pos)
139 return pos.latitude != Latitude_unavailable && pos.longitude != Longitude_unavailable;
143template<
typename T,
typename U>
144long round(
const boost::units::quantity<T>& q,
const U& u)
146 boost::units::quantity<U> v { q };
147 return std::round(v.value());
150void copy(
const PositionFix& position, ReferencePosition& reference_position) {
151 reference_position.longitude = round(position.longitude, microdegree) * Longitude_oneMicrodegreeEast;
152 reference_position.latitude = round(position.latitude, microdegree) * Latitude_oneMicrodegreeNorth;
153 reference_position.positionConfidenceEllipse.semiMajorOrientation = HeadingValue_unavailable;
154 reference_position.positionConfidenceEllipse.semiMajorConfidence = SemiAxisLength_unavailable;
155 reference_position.positionConfidenceEllipse.semiMinorConfidence = SemiAxisLength_unavailable;
156 if (position.altitude) {
157 reference_position.altitude.altitudeValue = to_altitude_value(position.altitude->value());
158 reference_position.altitude.altitudeConfidence = to_altitude_confidence(position.altitude->confidence());
160 reference_position.altitude.altitudeValue = AltitudeValue_unavailable;
161 reference_position.altitude.altitudeConfidence = AltitudeConfidence_unavailable;
165AltitudeConfidence_t to_altitude_confidence(units::Length confidence)
167 const double alt_con = confidence / units::si::meter;
169 if (alt_con < 0 || std::isnan(alt_con)) {
170 return AltitudeConfidence_unavailable;
171 }
else if (alt_con <= 0.01) {
172 return AltitudeConfidence_alt_000_01;
173 }
else if (alt_con <= 0.02) {
174 return AltitudeConfidence_alt_000_02;
175 }
else if (alt_con <= 0.05) {
176 return AltitudeConfidence_alt_000_05;
177 }
else if (alt_con <= 0.1) {
178 return AltitudeConfidence_alt_000_10;
179 }
else if (alt_con <= 0.2) {
180 return AltitudeConfidence_alt_000_20;
181 }
else if (alt_con <= 0.5) {
182 return AltitudeConfidence_alt_000_50;
183 }
else if (alt_con <= 1.0) {
184 return AltitudeConfidence_alt_001_00;
185 }
else if (alt_con <= 2.0) {
186 return AltitudeConfidence_alt_002_00;
187 }
else if (alt_con <= 5.0) {
188 return AltitudeConfidence_alt_005_00;
189 }
else if (alt_con <= 10.0) {
190 return AltitudeConfidence_alt_010_00;
191 }
else if (alt_con <= 20.0) {
192 return AltitudeConfidence_alt_020_00;
193 }
else if (alt_con <= 50.0) {
194 return AltitudeConfidence_alt_050_00;
195 }
else if (alt_con <= 100.0) {
196 return AltitudeConfidence_alt_100_00;
197 }
else if (alt_con <= 200.0) {
198 return AltitudeConfidence_alt_200_00;
200 return AltitudeConfidence_outOfRange;
204AltitudeValue_t to_altitude_value(units::Length alt)
206 using boost::units::isnan;
209 alt = boost::algorithm::clamp(alt, -1000.0 * units::si::meter, 8000.0 * units::si::meter);
210 return AltitudeValue_oneCentimeter * 100.0 * (alt / units::si::meter);
212 return AltitudeValue_unavailable;
216bool check_service_specific_permissions(
const asn1::Cam& cam, security::CamPermissions ssp)
218 using security::CamPermission;
219 using security::CamPermissions;
221 CamPermissions required_permissions;
222 const CamParameters_t& params = cam->cam.camParameters;
224 if (params.highFrequencyContainer.present == HighFrequencyContainer_PR_rsuContainerHighFrequency) {
225 const RSUContainerHighFrequency_t& rsu = params.highFrequencyContainer.choice.rsuContainerHighFrequency;
226 if (rsu.protectedCommunicationZonesRSU) {
227 required_permissions.add(CamPermission::CEN_DSRC_Tolling_Zone);
231 if (
const SpecialVehicleContainer_t* special = params.specialVehicleContainer) {
232 const EmergencyContainer_t* emergency =
nullptr;
233 const SafetyCarContainer_t* safety =
nullptr;
234 const RoadWorksContainerBasic_t* roadworks =
nullptr;
236 switch (special->present) {
237 case SpecialVehicleContainer_PR_publicTransportContainer:
238 required_permissions.add(CamPermission::Public_Transport);
240 case SpecialVehicleContainer_PR_specialTransportContainer:
241 required_permissions.add(CamPermission::Special_Transport);
243 case SpecialVehicleContainer_PR_dangerousGoodsContainer:
244 required_permissions.add(CamPermission::Dangerous_Goods);
246 case SpecialVehicleContainer_PR_roadWorksContainerBasic:
247 required_permissions.add(CamPermission::Roadwork);
248 roadworks = &special->choice.roadWorksContainerBasic;
250 case SpecialVehicleContainer_PR_rescueContainer:
251 required_permissions.add(CamPermission::Rescue);
253 case SpecialVehicleContainer_PR_emergencyContainer:
254 required_permissions.add(CamPermission::Emergency);
255 emergency = &special->choice.emergencyContainer;
257 case SpecialVehicleContainer_PR_safetyCarContainer:
258 required_permissions.add(CamPermission::Safety_Car);
259 safety = &special->choice.safetyCarContainer;
261 case SpecialVehicleContainer_PR_NOTHING:
266 if (emergency && emergency->emergencyPriority && emergency->emergencyPriority->size == 1) {
268 assert(emergency->emergencyPriority->buf);
269 uint8_t bits = *emergency->emergencyPriority->buf;
270 if (bits & (1 << (7 - EmergencyPriority_requestForRightOfWay))) {
271 required_permissions.add(CamPermission::Request_For_Right_Of_Way);
273 if (bits & (1 << (7 - EmergencyPriority_requestForFreeCrossingAtATrafficLight))) {
274 required_permissions.add(CamPermission::Request_For_Free_Crossing_At_Traffic_Light);
278 if (roadworks && roadworks->closedLanes) {
279 required_permissions.add(CamPermission::Closed_Lanes);
282 if (safety && safety->trafficRule) {
283 switch (*safety->trafficRule) {
284 case TrafficRule_noPassing:
285 required_permissions.add(CamPermission::No_Passing);
287 case TrafficRule_noPassingForTrucks:
288 required_permissions.add(CamPermission::No_Passing_For_Trucks);
295 if (safety && safety->speedLimit) {
296 required_permissions.add(CamPermission::Speed_Limit);
300 return ssp.has(required_permissions);
303void print_indented(std::ostream& os,
const asn1::Cam& message,
const std::string& indent,
unsigned level)
305 auto prefix = [&](
const char* field) -> std::ostream& {
306 for (
unsigned i = 0; i < level; ++i) {
313 const ItsPduHeader_t& header = message->header;
314 prefix(
"ITS PDU Header") <<
"\n";
316 prefix(
"Protocol Version") << header.protocolVersion <<
"\n";
317 prefix(
"Message ID") << header.messageID <<
"\n";
318 prefix(
"Station ID") << header.stationID <<
"\n";
321 const CoopAwareness_t& cam = message->cam;
322 prefix(
"CoopAwarensess") <<
"\n";
324 prefix(
"Generation Delta Time") << cam.generationDeltaTime <<
"\n";
326 prefix(
"Basic Container") <<
"\n";
328 const BasicContainer_t& basic = cam.camParameters.basicContainer;
329 prefix(
"Station Type") << basic.stationType <<
"\n";
330 prefix(
"Reference Position") <<
"\n";
332 prefix(
"Longitude") << basic.referencePosition.longitude <<
"\n";
333 prefix(
"Latitude") << basic.referencePosition.latitude <<
"\n";
334 prefix(
"Semi Major Orientation") << basic.referencePosition.positionConfidenceEllipse.semiMajorOrientation <<
"\n";
335 prefix(
"Semi Major Confidence") << basic.referencePosition.positionConfidenceEllipse.semiMajorConfidence <<
"\n";
336 prefix(
"Semi Minor Confidence") << basic.referencePosition.positionConfidenceEllipse.semiMinorConfidence <<
"\n";
337 prefix(
"Altitude [Confidence]") << basic.referencePosition.altitude.altitudeValue
338 <<
" [" << basic.referencePosition.altitude.altitudeConfidence <<
"]\n";
342 if (cam.camParameters.highFrequencyContainer.present == HighFrequencyContainer_PR_basicVehicleContainerHighFrequency) {
343 prefix(
"High Frequency Container [Basic Vehicle]") <<
"\n";
345 const BasicVehicleContainerHighFrequency& bvc =
346 cam.camParameters.highFrequencyContainer.choice.basicVehicleContainerHighFrequency;
347 prefix(
"Heading [Confidence]") << bvc.heading.headingValue
348 <<
" [" << bvc.heading.headingConfidence <<
"]\n";
349 prefix(
"Speed [Confidence]") << bvc.speed.speedValue
350 <<
" [" << bvc.speed.speedConfidence <<
"]\n";
351 prefix(
"Drive Direction") << bvc.driveDirection <<
"\n";
352 prefix(
"Longitudinal Acceleration [Confidence]") << bvc.longitudinalAcceleration.longitudinalAccelerationValue
353 <<
" [" << bvc.longitudinalAcceleration.longitudinalAccelerationConfidence <<
"]\n";
354 prefix(
"Vehicle Length [Confidence Indication]") << bvc.vehicleLength.vehicleLengthValue
355 <<
" [" << bvc.vehicleLength.vehicleLengthConfidenceIndication <<
"]\n";
356 prefix(
"Vehicle Width") << bvc.vehicleWidth <<
"\n";
357 prefix(
"Curvature [Confidence]") << bvc.curvature.curvatureValue
358 <<
" [" << bvc.curvature.curvatureConfidence <<
"]\n";
359 prefix(
"Curvature Calculation Mode") << bvc.curvatureCalculationMode <<
"\n";
360 prefix(
"Yaw Rate [Confidence]") << bvc.yawRate.yawRateValue
361 <<
" [" << bvc.yawRate.yawRateConfidence <<
"]\n";
363 }
else if (cam.camParameters.highFrequencyContainer.present == HighFrequencyContainer_PR_rsuContainerHighFrequency) {
364 prefix(
"High Frequency Container [RSU]") <<
"\n";
365 const RSUContainerHighFrequency_t& rsu = cam.camParameters.highFrequencyContainer.choice.rsuContainerHighFrequency;
366 if (
nullptr != rsu.protectedCommunicationZonesRSU &&
nullptr != rsu.protectedCommunicationZonesRSU->list.array) {
368 int size = rsu.protectedCommunicationZonesRSU->list.count;
369 for (
int i = 0; i < size; i++)
371 prefix(
"Protected Zone") <<
"\n";
373 prefix(
"Type") << rsu.protectedCommunicationZonesRSU->list.array[i]->protectedZoneType <<
"\n";
374 if (rsu.protectedCommunicationZonesRSU->list.array[i]->expiryTime
375 &&
nullptr != rsu.protectedCommunicationZonesRSU->list.array[i]->expiryTime->buf
376 && rsu.protectedCommunicationZonesRSU->list.array[i]->expiryTime->size > 0)
377 prefix(
"Expiry Time") << (unsigned) rsu.protectedCommunicationZonesRSU->list.array[i]->expiryTime->buf[0] <<
"\n";
378 prefix(
"Latitude") << rsu.protectedCommunicationZonesRSU->list.array[i]->protectedZoneLatitude <<
"\n";
379 prefix(
"Longitude") << rsu.protectedCommunicationZonesRSU->list.array[i]->protectedZoneLongitude <<
"\n";
380 if (
nullptr != rsu.protectedCommunicationZonesRSU->list.array[i]->protectedZoneRadius)
381 prefix(
"Radius") << *(rsu.protectedCommunicationZonesRSU->list.array[i]->protectedZoneRadius) <<
"\n";
382 if (
nullptr != rsu.protectedCommunicationZonesRSU->list.array[i]->protectedZoneRadius)
383 prefix(
"ID") << *(rsu.protectedCommunicationZonesRSU->list.array[i]->protectedZoneID) <<
"\n";
389 prefix(
"High Frequency Container") <<
"empty\n";
392 if (
nullptr != cam.camParameters.lowFrequencyContainer) {
393 if (cam.camParameters.lowFrequencyContainer->present == LowFrequencyContainer_PR_basicVehicleContainerLowFrequency) {
394 prefix(
"Low Frequency Container") <<
"\n";
395 const BasicVehicleContainerLowFrequency_t& lfc =
396 cam.camParameters.lowFrequencyContainer->choice.basicVehicleContainerLowFrequency;
398 prefix(
"Vehicle Role") << (lfc.vehicleRole) <<
"\n";
400 if (
nullptr != lfc.exteriorLights.buf && lfc.exteriorLights.size > 0)
401 prefix(
"Exterior Lights") << unsigned(*(lfc.exteriorLights.buf)) <<
"\n";
402 if (
nullptr != lfc.pathHistory.list.array) {
403 int size = lfc.pathHistory.list.count;
404 for (
int i = 0; i < size; i++)
406 prefix(
"Path history point") <<
"\n";
408 prefix(
"Latitude") << (lfc.pathHistory.list.array[i]->pathPosition.deltaLatitude) <<
"\n";
409 prefix(
"Longitude") << (lfc.pathHistory.list.array[i]->pathPosition.deltaLongitude) <<
"\n";
410 prefix(
"Altitude") << (lfc.pathHistory.list.array[i]->pathPosition.deltaAltitude) <<
"\n";
411 if (lfc.pathHistory.list.array[i]->pathDeltaTime)
412 prefix(
"Delta time") << *(lfc.pathHistory.list.array[i]->pathDeltaTime) <<
"\n";
419 prefix(
"Low Frequency Container") <<
"present but empty" <<
"\n";
422 prefix(
"Low Frequency Container") <<
"not present" <<
"\n";
424 if (
nullptr != cam.camParameters.specialVehicleContainer) {
425 if (cam.camParameters.specialVehicleContainer->present == SpecialVehicleContainer_PR_publicTransportContainer) {
426 prefix(
"Special Vehicle Container [Public Transport]") <<
"\n";
427 PublicTransportContainer_t& ptc = cam.camParameters.specialVehicleContainer->choice.publicTransportContainer;
429 prefix(
"Embarkation Status") << ptc.embarkationStatus <<
"\n";
430 if (ptc.ptActivation) {
431 prefix(
"PT Activation Type") << ptc.ptActivation->ptActivationType <<
"\n";
432 if (0 != ptc.ptActivation->ptActivationData.size) {
433 int size = ptc.ptActivation->ptActivationData.size;
434 for (
int i = 0; i < ptc.ptActivation->ptActivationData.size; i++)
435 prefix(
"PT Activation Data") << (unsigned) ptc.ptActivation->ptActivationData.buf[i] <<
"\n";
439 }
else if (cam.camParameters.specialVehicleContainer->present == SpecialVehicleContainer_PR_specialTransportContainer) {
440 prefix(
"Special Vehicle Container [Special Transport]") <<
"\n";
441 SpecialTransportContainer_t& stc = cam.camParameters.specialVehicleContainer->choice.specialTransportContainer;
443 if (
nullptr != stc.specialTransportType.buf && stc.specialTransportType.size > 0)
444 prefix(
"Type") << (unsigned) stc.specialTransportType.buf[0] <<
"\n";
445 if (
nullptr != stc.lightBarSirenInUse.buf && stc.lightBarSirenInUse.size > 0)
446 prefix(
"Light Bar Siren in Use") << (unsigned) stc.lightBarSirenInUse.buf[0] <<
"\n";
448 }
else if (cam.camParameters.specialVehicleContainer->present == SpecialVehicleContainer_PR_dangerousGoodsContainer) {
449 prefix(
"Special Vehicle Container [Dangerous Goods]") <<
"\n";
450 DangerousGoodsContainer_t& dgc = cam.camParameters.specialVehicleContainer->choice.dangerousGoodsContainer;
452 prefix(
"Dangerous Goods Basic Type") << (unsigned)dgc.dangerousGoodsBasic <<
"\n";
454 }
else if (cam.camParameters.specialVehicleContainer->present == SpecialVehicleContainer_PR_roadWorksContainerBasic) {
455 prefix(
"Special Vehicle Container [Road Works]") <<
"\n";
456 RoadWorksContainerBasic_t& rwc = cam.camParameters.specialVehicleContainer->choice.roadWorksContainerBasic;
458 if (
nullptr != rwc.roadworksSubCauseCode)
459 prefix(
"Sub Cause Code") << *(rwc.roadworksSubCauseCode) <<
"\n";
460 if (
nullptr != rwc.lightBarSirenInUse.buf && rwc.lightBarSirenInUse.size > 0)
461 prefix(
"Light Bar Siren in Use") << (unsigned) rwc.lightBarSirenInUse.buf[0] <<
"\n";
462 if (
nullptr != rwc.closedLanes) {
463 if (rwc.closedLanes->innerhardShoulderStatus)
464 prefix(
"Inner Hard Shoulder Status") << *(rwc.closedLanes->innerhardShoulderStatus) <<
"\n";
465 if (rwc.closedLanes->outerhardShoulderStatus)
466 prefix(
"Outer Hard Shoulder Status") << *(rwc.closedLanes->outerhardShoulderStatus) <<
"\n";
467 if (rwc.closedLanes->drivingLaneStatus &&
nullptr != rwc.closedLanes->drivingLaneStatus->buf
468 && rwc.closedLanes->drivingLaneStatus->size > 0)
469 prefix(
"Driving Lane Status") << (unsigned) rwc.closedLanes->drivingLaneStatus->buf[0] <<
"\n";
472 }
else if (cam.camParameters.specialVehicleContainer->present == SpecialVehicleContainer_PR_rescueContainer) {
473 prefix(
"Special Vehicle Container [Rescue]") <<
"\n";
474 RescueContainer_t& rc = cam.camParameters.specialVehicleContainer->choice.rescueContainer;
476 if (
nullptr != rc.lightBarSirenInUse.buf && rc.lightBarSirenInUse.size > 0)
477 prefix(
"Light Bar Siren in Use") << (unsigned) rc.lightBarSirenInUse.buf[0] <<
"\n";
479 }
else if (cam.camParameters.specialVehicleContainer->present == SpecialVehicleContainer_PR_emergencyContainer) {
480 prefix(
"Special Vehicle Container [Emergency]") <<
"\n";
481 EmergencyContainer_t& ec = cam.camParameters.specialVehicleContainer->choice.emergencyContainer;
483 if (
nullptr != ec.lightBarSirenInUse.buf && ec.lightBarSirenInUse.size > 0)
484 prefix(
"Light Bar Siren in Use") << (unsigned) ec.lightBarSirenInUse.buf[0] <<
"\n";
485 if (
nullptr != ec.incidentIndication) {
486 prefix(
"Incident Indication Cause Code") << ec.incidentIndication->causeCode <<
"\n";
487 prefix(
"Incident Indication Sub Cause Code") << ec.incidentIndication->subCauseCode <<
"\n";
489 if (
nullptr != ec.emergencyPriority &&
nullptr != ec.emergencyPriority->buf
490 && ec.emergencyPriority->size > 0) {
491 prefix(
"Emergency Priority") << (unsigned) ec.emergencyPriority->buf[0] <<
"\n";
494 }
else if (cam.camParameters.specialVehicleContainer->present == SpecialVehicleContainer_PR_safetyCarContainer) {
495 prefix(
"Special Vehicle Container [Safety Car]") <<
"\n";
496 SafetyCarContainer_t& sc = cam.camParameters.specialVehicleContainer->choice.safetyCarContainer;
498 if (
nullptr != sc.lightBarSirenInUse.buf && sc.lightBarSirenInUse.size > 0)
499 prefix(
"Light Bar Siren in Use") << (unsigned) sc.lightBarSirenInUse.buf[0] <<
"\n";
500 if (
nullptr != sc.incidentIndication) {
501 prefix(
"Incident Indication Cause Code") << sc.incidentIndication->causeCode <<
"\n";
502 prefix(
"Incident Indication Sub Cause Code") << sc.incidentIndication->subCauseCode <<
"\n";
504 if (
nullptr != sc.trafficRule) {
505 prefix(
"Traffic Rule") << *(sc.trafficRule) <<
"\n";
507 if (
nullptr != sc.speedLimit) {
508 prefix(
"Speed Limit") << *(sc.speedLimit) <<
"\n";
513 prefix(
"Special Vehicle Container") << (
"present but empty") <<
"\n";
516 prefix(
"Special Vehicle Container") <<
"not present" <<
"\n";