This sample is provided as part of the OSS ASN.1 Tools trial and commercial shipments. The source code and related files are listed below for reference.
The sample demonstrates how to use the OSS ASN.1 Tools to work with messages for the CAM and DENM standards (ETSI EN 302 637-2 and ETSI EN 302 637-3).
It runs on Linux on x86-64 as an example and illustrates how to create, encode, decode, and print CAM and DENM messages using the OSS ASN.1 Tools API.
A makefile is included for building and running the test program using the OSS ASN.1/C runtime.
To explore more samples (LTE RRC, 5G RRC, S1AP, X2AP), visit the main Sample Code page.
This sample shows how to:
The files listed below are included in the OSS ASN.1 Tools trial and commercial shipments and are used by this sample program:
| File | Description |
|---|---|
| README.TXT | Instructions and sample overview. |
| CAM.asn | ASN.1 specification from ETSI EN 302 637-2 V1.4.1 (2019-04). |
| DENM.asn | ASN.1 specification from ETSI EN 302 637-3 V1.3.1 (2019-04). |
| ITS-Container.asn | ASN.1 specification from ETSI TS 102 894-2 V1.3.1 (2018-08). |
| camdenm-directives.asn | Additional ASN.1 compiler directives. |
| camdenm_h.c | Simple C program that demonstrates creating, encoding, decoding, and printing CAM and DENM messages. |
| makefile | Makefile that builds and runs the sample test. |
| makefile.rtoed | Makefile that builds and runs the sample test using RTOED. |
| gui/ | ASN.1 Studio project for viewing/compiling schema and generating sample data. |
(Installation instructions for the OSS ASN.1 Tools are included in all trial and commercial shipments.)
To build and run this sample, install a trial or licensed version of the OSS ASN.1 Tools for C.
If your shipment is runtime-only, generate the .c and .h files by running:
make cross
This creates a samples/cross directory with:
make
This command compiles the sample C source, links it with the OSS ASN.1 static library, and executes the test. To use another type of library in the shipment (such as a shared library), set the A makefile variable, for example:
make A=so
make clean
Note: The C source code in this sample is platform-independent. Linux commands are shown as an example, but equivalent samples and build instructions are available for Windows, macOS, and other platforms. For help with platform-specific instructions, please contact OSS Support.
The following listing shows the main C source file for this sample test program, camdenm_h.c. It demonstrates how to create, encode, decode, and print CAM and DENM messages using the OSS ASN.1 Tools API.
/*****************************************************************************/
/* Copyright (C) ###RELEASE_YEAR### OSS Nokalva, Inc. All rights reserved. */
/*****************************************************************************/
/* THIS FILE IS PROPRIETARY MATERIAL OF OSS NOKALVA, INC. */
/* AND MAY BE USED ONLY BY DIRECT LICENSEES OF OSS NOKALVA, INC. */
/* THIS FILE MAY NOT BE DISTRIBUTED. */
/* THIS COPYRIGHT STATEMENT MAY NOT BE REMOVED. */
/* THIS SAMPLE PROGRAM IS PROVIDED AS IS. THE SAMPLE PROGRAM AND ANY RESULTS */
/* OBTAINED FROM IT ARE PROVIDED WITHOUT ANY WARRANTIES OR REPRESENTATIONS, */
/* EXPRESS, IMPLIED OR STATUTORY. */
/*****************************************************************************/
/*
* Demonstrates CAM and DENM PDUs creating, encoding, decoding
* and further processing.
*/
#include <string.h>
#include "camdenm.h" /* Compiler-generated header file */
#ifdef DLL_LINKAGE
#define OSSTERM ossWterm
#else
#define OSSTERM ossterm
#endif
#define currentVersion 1
#define CTLTBL camdenm /* control table name located at the
* bottom of the generated header file */
#define ENCODING_RULES OSS_PER_UNALIGNED /* encoding rules */
/* Declaration of value creating functions for PDU types */
static CAM *create_CAM_value(OssGlobal *world);
static DENM *create_DENM_value(OssGlobal *world);
/* Declaration of functions that print some CAM/DENM fields */
static void print_some_CAM_fields(OssGlobal *world, CAM *value);
static void print_some_DENM_fields(OssGlobal *world, DENM *value);
/* Helper macro to allocate memory and set "length" and "value" fields of
* an UNBOUNDED string to initialize it by a string literal. It is assumed
* that "world" OssGlobal variable is available.
*/
#define SET_UNBOUNDED_BY_LITERAL(s, literal) {(s).length = sizeof(literal)-1;\
(s).value = memcpy(ossGetMemory(world, sizeof(literal)-1), literal, \
sizeof(literal)-1);}
int main(void)
{
struct ossGlobal w, *world = &w; /* OSS global structure */
OssBuf msgbuf = { 0, NULL }; /* encoded PDU */
CAM *CAM_msg = NULL, /* unencoded CAM_PDU */
*CAM_dec = NULL; /* decoded CAM_PDU */
DENM *DENM_msg = NULL, /* unencoded DENM_PDU */
*DENM_dec = NULL; /* decoded DENM_PDU */
int pdunum; /* PDU number */
int retcode; /* return code */
/*
* Initialize the OSS runtime first.
*/
if ((retcode = ossinit(world, CTLTBL))) {
ossPrint(NULL, "Ossinit() returned %d.\n", retcode);
return retcode;
}
#ifdef RELAXED_MODE
/*
* Set relaxed mode.
*/
ossSetFlags(world, ossGetFlags(world) | NOCONSTRAIN | OSS_RELAXED);
#endif
/*
* Set encoding rules. Not required unless more than one encoding rule
* was specified by ASN.1 compiler command line options
*/
/* ossSetEncodingRules(world, ENCODING_RULES); */
/* ==== Part 1. Create, encode and decode CAM message ==== */
/* This is a fake loop statement to simplify the error handling. */
do {
pdunum = CAM_PDU;
ossPrint(world,
"\nCreating a CAM PDU value... ");
CAM_msg = create_CAM_value(world);
ossPrint(world, "Done\n");
ossPrint(world,
"\nPrinting the created value with ossPrintPDU() API function...\n");
ossPrintPDU(world, pdunum, CAM_msg);
/*
* Set the output buffer. Let the encoder allocate memory.
*/
msgbuf.value = NULL;
msgbuf.length = 0;
ossPrint(world,
"\nEncoding the created CAM value... ");
if ((retcode = ossEncode(world, /* pointer to the OSS global structure */
pdunum, /* PDU identifier */
CAM_msg, /* Unencoded PDU to encode */
&msgbuf /* encoded PDU */
))) {
break;
}
ossPrint(world, "Done\n");
ossPrint(world, "\nEncoded CAM message:\n");
ossPrintHex(world, (char *) msgbuf.value, msgbuf.length);
/*
* Let the decoder allocate memory. It is also possible to provide
* a buffer to place the decoded value.
*/
CAM_dec = NULL;
ossPrint(world,
"\nDecoding the encoded CAM message... ");
if ((retcode = ossDecode(world, /* pointer to the OSS global structure */
&pdunum, /* PDU identifier */
&msgbuf, /* encoded PDU to decode */
(void **)&CAM_dec /* decoded PDU */
))) {
break;
}
ossPrint(world, "Done\n");
ossPrint(world,
"\nComparing the decoded message with the original PDU value... ");
ossPrint(world, ossCmpValue(world, pdunum, CAM_msg, CAM_dec)
? "Failed\n" : "Succeeded\n");
ossPrint(world, "\nPartial custom printing of the decoded CAM PDU:\n\n");
print_some_CAM_fields(world, CAM_dec);
} while (0);
if(retcode)
ossPrint(world, "Failed with return code %d\n%s\n", retcode, ossGetErrMsg(world));
/*
* Free the memory allocated by decoder and encoder.
*/
if (CAM_dec)
ossFreePDU(world, pdunum, CAM_dec);
if (msgbuf.value)
ossFreeBuf(world, msgbuf.value);
if (CAM_msg)
ossFreePDU(world, CAM_PDU, CAM_msg);
/* ==== Part 2. Create, encode and decode DENM message ==== */
/* This is a fake loop statement to simplify the error handling. */
do {
pdunum = DENM_PDU;
ossPrint(world,
"\nCreating a DENM PDU value... ");
DENM_msg = create_DENM_value(world);
ossPrint(world, "Done\n");
ossPrint(world,
"\nPrinting the created value with ossPrintPDU() API function...\n");
ossPrintPDU(world, pdunum, DENM_msg);
/*
* Set the output buffer. Let the encoder allocate memory.
*/
msgbuf.value = NULL;
msgbuf.length = 0;
/*
* Encode the PDU.
*/
ossPrint(world,
"\nEncoding the created DENM value... ");
if ((retcode = ossEncode(world, /* pointer to the OSS global structure */
pdunum, /* PDU identifier */
DENM_msg, /* Unencoded PDU to encode */
&msgbuf /* encoded PDU */
))) {
break;
}
ossPrint(world, "Done\n");
ossPrint(world, "\nEncoded DENM message:\n");
ossPrintHex(world, (char *) msgbuf.value, msgbuf.length);
/*
* Let the decoder allocate memory. It is also possible to provide
* a buffer to place the decoded value.
*/
DENM_dec = NULL;
ossPrint(world,
"\nDecoding the encoded DENM message... ");
if ((retcode = ossDecode(world, /* pointer to the OSS global structure */
&pdunum, /* PDU identifier */
&msgbuf, /* encoded PDU to decode */
(void **)&DENM_dec /* decoded PDU */
))) {
break;
}
ossPrint(world, "Done\n");
ossPrint(world,
"\nComparing the decoded message with the original PDU value... ");
ossPrint(world, ossCmpValue(world, pdunum, DENM_msg, DENM_dec)
? "Failed\n" : "Succeeded\n");
ossPrint(world,
"\nPartial custom printing of the decoded DENM PDU:\n\n");
print_some_DENM_fields(world, DENM_dec);
} while (0);
if(retcode)
ossPrint(world, "Failed with return code %d\n%s\n", retcode, ossGetErrMsg(world));
/*
* Free the memory allocated by decoder and encoder.
*/
if (DENM_dec)
ossFreePDU(world, pdunum, DENM_dec);
if (msgbuf.value)
ossFreeBuf(world, msgbuf.value);
if (DENM_msg)
ossFreePDU(world, DENM_PDU, DENM_msg);
/*
* Do final cleanup.
*/
OSSTERM(world);
return retcode;
}
/* Creation of sample value for the type 'CAM' */
/* ========================================== */
static const unsigned char _static_value6[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55
};
static CAM * create_CAM_value(OssGlobal *world)
{
CAM *_CAM_msg = (CAM *)ossGetMemory(world, sizeof(struct CAM));
_CAM_msg->header.protocolVersion = currentVersion;
_CAM_msg->header.messageID = messageID_cam;
_CAM_msg->header.stationID = 1234567;
_CAM_msg->cam.generationDeltaTime = 11409;
_CAM_msg->cam.camParameters.bit_mask = 0;
{
BasicContainer *b_container = &_CAM_msg->cam.camParameters.basicContainer;
b_container->stationType = passengerCar;
b_container->referencePosition.latitude = 40487111;
b_container->referencePosition.longitude = 79494789;
b_container->referencePosition.positionConfidenceEllipse.semiMajorConfidence = 500;
b_container->referencePosition.positionConfidenceEllipse.semiMinorConfidence = 400;
b_container->referencePosition.positionConfidenceEllipse.semiMajorOrientation = wgs84North;
b_container->referencePosition.altitude.altitudeValue = 2000;
b_container->referencePosition.altitude.altitudeConfidence = alt_000_02;
}
_CAM_msg->cam.camParameters.highFrequencyContainer.choice = basicVehicleContainerHighFrequency_chosen;
{
BasicVehicleContainerHighFrequency *b_frequency = &_CAM_msg->cam.camParameters.highFrequencyContainer.u.basicVehicleContainerHighFrequency;
b_frequency->bit_mask = 0;
b_frequency->heading.headingValue = wgs84North;
b_frequency->heading.headingConfidence = equalOrWithinZeroPointOneDegree;
b_frequency->speed.speedValue = 2000;
b_frequency->speed.speedConfidence = equalOrWithinOneCentimeterPerSec;
b_frequency->driveDirection = forward;
b_frequency->vehicleLength.vehicleLengthValue = 35;
b_frequency->vehicleLength.vehicleLengthConfidenceIndication = noTrailerPresent;
b_frequency->vehicleWidth = 20;
b_frequency->longitudinalAcceleration.longitudinalAccelerationValue = 10;
b_frequency->longitudinalAcceleration.longitudinalAccelerationConfidence = pointOneMeterPerSecSquared;
b_frequency->curvature.curvatureValue = CurvatureValue_straight;
b_frequency->curvature.curvatureConfidence = onePerMeter_0_00002;
b_frequency->curvatureCalculationMode = yawRateUsed;
b_frequency->yawRate.yawRateValue = YawRateValue_straight;
b_frequency->yawRate.yawRateConfidence = degSec_000_01;
b_frequency->bit_mask |= accelerationControl_present;
b_frequency->accelerationControl.length = 7;
b_frequency->accelerationControl.value = (unsigned char *)ossGetMemory(world, 1);
b_frequency->accelerationControl.value[gasPedalEngaged_byte] = gasPedalEngaged;
b_frequency->bit_mask |= steeringWheelAngle_present;
b_frequency->steeringWheelAngle.steeringWheelAngleValue = 30;
b_frequency->steeringWheelAngle.steeringWheelAngleConfidence = equalOrWithinOnePointFiveDegree;
b_frequency->bit_mask |= lateralAcceleration_present;
b_frequency->lateralAcceleration.lateralAccelerationValue = -2;
b_frequency->lateralAcceleration.lateralAccelerationConfidence = pointOneMeterPerSecSquared;
b_frequency->bit_mask |= verticalAcceleration_present;
b_frequency->verticalAcceleration.verticalAccelerationValue = pointOneMeterPerSecSquaredUp;
b_frequency->verticalAcceleration.verticalAccelerationConfidence = pointOneMeterPerSecSquared;
}
_CAM_msg->cam.camParameters.bit_mask |= lowFrequencyContainer_present;
{
LowFrequencyContainer *l_container = &_CAM_msg->cam.camParameters.lowFrequencyContainer;
l_container->choice = basicVehicleContainerLowFrequency_chosen;
l_container->u.basicVehicleContainerLowFrequency.vehicleRole = VehicleRole_default;
l_container->u.basicVehicleContainerLowFrequency.exteriorLights.length = 8;
l_container->u.basicVehicleContainerLowFrequency.exteriorLights.value = (unsigned char *)ossGetMemory(world, 1);
l_container->u.basicVehicleContainerLowFrequency.exteriorLights.value[lowBeamHeadlightsOn_byte] =
lowBeamHeadlightsOn | leftTurnSignalOn | daytimeRunningLightsOn;
/* Create a PathHistory list of one element */
{
PathHistory _pathHistory;
l_container->u.basicVehicleContainerLowFrequency.pathHistory =
_pathHistory = (PathHistory)ossGetMemory(world, sizeof(struct PathHistory));
_pathHistory->value.bit_mask = 0;
_pathHistory->value.pathPosition.deltaLatitude = 10000;
_pathHistory->value.pathPosition.deltaLongitude = 5000;
_pathHistory->value.pathPosition.deltaAltitude = DeltaAltitude_unavailable;
_pathHistory->value.bit_mask |= pathDeltaTime_present;
_pathHistory->value.pathDeltaTime = 1000;
_pathHistory->next = NULL;
}
}
_CAM_msg->cam.camParameters.bit_mask |= specialVehicleContainer_present;
_CAM_msg->cam.camParameters.specialVehicleContainer.choice = publicTransportContainer_chosen;
_CAM_msg->cam.camParameters.bit_mask |= specialVehicleContainer_present;
{
PublicTransportContainer *p_container = &_CAM_msg->cam.camParameters.specialVehicleContainer.u.publicTransportContainer;
p_container->bit_mask = 0;
p_container->embarkationStatus = FALSE;
p_container->bit_mask |= ptActivation_present;
p_container->ptActivation.ptActivationType = undefinedCodingType;
p_container->ptActivation.ptActivationData.length = 6;
#ifdef LED
p_container->ptActivation.ptActivationData.value =
(unsigned char*) ossGetInitializedMemory(world, 6);
#endif
memcpy(p_container->ptActivation.ptActivationData.value, _static_value6, 6);
}
return _CAM_msg;
}
/* Creation of sample value for the type 'DENM' */
/* =========================================== */
static DENM *create_DENM_value(OssGlobal *world)
{
DENM *_DENM_msg = (DENM *)ossGetMemory(world, sizeof(struct DENM));
_DENM_msg->header.protocolVersion = currentVersion;
_DENM_msg->header.messageID = messageID_denm;
_DENM_msg->header.stationID = 1234567;
_DENM_msg->denm.bit_mask = 0;
{
ManagementContainer *_management = &_DENM_msg->denm.management;
ReferencePosition *_eventPosition = &_management->eventPosition;
_management->bit_mask = 0;
_management->actionID.originatingStationID = 20;
_management->actionID.sequenceNumber = 30;
_management->detectionTime = 45000000000ULL;
_management->referenceTime = oneMillisecAfterUTCStartOf2004;
_eventPosition->latitude = 40487111;
_eventPosition->longitude = -79494789;
_eventPosition->positionConfidenceEllipse.semiMajorConfidence = 500;
_eventPosition->positionConfidenceEllipse.semiMinorConfidence = 400;
_eventPosition->positionConfidenceEllipse.semiMajorOrientation = 10;
_eventPosition->altitude.altitudeValue = 2000;
_eventPosition->altitude.altitudeConfidence = alt_000_02;
_management->relevanceDistance = lessThan100m;
_management->relevanceTrafficDirection = upstreamTraffic;
_management->bit_mask |= validityDuration_present;
_management->validityDuration = 600;
_management->bit_mask |= transmissionInterval_present;
_management->transmissionInterval = oneMilliSecond;
_management->stationType = unknown;
}
{
SituationContainer *_situation = &_DENM_msg->denm.situation;
_DENM_msg->denm.bit_mask |= situation_present;
_situation->bit_mask = 0;
_situation->informationQuality = lowest;
_situation->eventType.causeCode = roadworks;
_situation->eventType.subCauseCode = 0;
}
{
LocationContainer *_location = &_DENM_msg->denm.location;
_DENM_msg->denm.bit_mask |= location_present;
_location->bit_mask = 0;
_location->bit_mask |= eventSpeed_present;
_location->eventSpeed.speedValue = standstill;
_location->eventSpeed.speedConfidence = equalOrWithinOneCentimeterPerSec;
_location->bit_mask |= eventPositionHeading_present;
_location->eventPositionHeading.headingValue = wgs84North;
_location->eventPositionHeading.headingConfidence = equalOrWithinOneDegree;
/* Create a Traces list of one element */
{
Traces _traces;
_location->traces =
_traces = (Traces)ossGetMemory(world, sizeof(struct Traces));
/* Create a PathHistory list of two elements */
{
PathHistory _pathHistory;
/* Fill the element #1 */
_traces->value =
_pathHistory = (PathHistory)ossGetMemory(world, sizeof(struct PathHistory));
_pathHistory->value.bit_mask = 0;
_pathHistory->value.pathPosition.deltaLatitude = 20;
_pathHistory->value.pathPosition.deltaLongitude = 20;
_pathHistory->value.pathPosition.deltaAltitude = DeltaAltitude_unavailable;
_pathHistory->value.bit_mask |= pathDeltaTime_present;
_pathHistory->value.pathDeltaTime = tenMilliSecondsInPast;
/* Fill the element #2 */
_pathHistory->next = (PathHistory)ossGetMemory(world, sizeof(struct PathHistory));
_pathHistory = _pathHistory->next;
_pathHistory->value.bit_mask = 0;
_pathHistory->value.pathPosition.deltaLatitude = 22;
_pathHistory->value.pathPosition.deltaLongitude = 22;
_pathHistory->value.pathPosition.deltaAltitude = DeltaAltitude_unavailable;
_pathHistory->next = NULL;
}
_traces->next = NULL;
}
_location->bit_mask |= roadType_present;
_location->roadType = urban_NoStructuralSeparationToOppositeLanes;
}
{
AlacarteContainer *_alacarte = &_DENM_msg->denm.alacarte;
ImpactReductionContainer *_impactReduction = &_alacarte->impactReduction;
RoadWorksContainerExtended *_roadWorks = &_alacarte->roadWorks;
StationaryVehicleContainer *_stationaryVehicle = &_alacarte->stationaryVehicle;
_DENM_msg->denm.bit_mask |= alacarte_present;
_alacarte->bit_mask = 0;
_alacarte->bit_mask |= impactReduction_present;
_impactReduction->heightLonCarrLeft = HeightLonCarr_oneCentimeter;
_impactReduction->heightLonCarrRight = HeightLonCarr_oneCentimeter;
_impactReduction->posLonCarrLeft = PosLonCarr_oneCentimeter;
_impactReduction->posLonCarrRight = PosLonCarr_oneCentimeter;
/* Create a PositionOfPillars list of one element */
{
PositionOfPillars _posOfPillars;
_impactReduction->positionOfPillars =
_posOfPillars = (PositionOfPillars)ossGetMemory(world, sizeof(struct PositionOfPillars));
_posOfPillars->value = PosPillar_tenCentimeters;
_posOfPillars->next = NULL;
}
_impactReduction->posCentMass = PosCentMass_unavailable;
_impactReduction->wheelBaseVehicle = WheelBaseVehicle_tenCentimeters;
_impactReduction->turningRadius = point4Meters;
_impactReduction->posFrontAx = PosFrontAx_tenCentimeters;
_impactReduction->positionOfOccupants.length = 20;
_impactReduction->positionOfOccupants.value = (unsigned char *)ossGetMemory(world, 3);
_impactReduction->positionOfOccupants.value[row1LeftOccupied_byte] =
row1LeftOccupied | row1RightOccupied | row1MidOccupied | row1NotDetectable
| row1NotPresent | row2LeftOccupied | row2RightOccupied;
_impactReduction->positionOfOccupants.value[row3NotPresent_byte] = row3NotPresent;
_impactReduction->positionOfOccupants.value[row4NotPresent_byte] = row4NotPresent;
_impactReduction->vehicleMass = 20;
_impactReduction->requestResponseIndication = response;
_alacarte->bit_mask |= externalTemperature_present;
_alacarte->externalTemperature = oneDegreeCelsius;
_alacarte->bit_mask |= roadWorks_present;
_roadWorks->bit_mask = 0;
_roadWorks->bit_mask |= lightBarSirenInUse_present;
_roadWorks->lightBarSirenInUse.length = 2;
_roadWorks->lightBarSirenInUse.value = (unsigned char *)ossGetMemory(world, 1);
_roadWorks->lightBarSirenInUse.value[lightBarActivated_byte] = lightBarActivated | sirenActivated;
_roadWorks->bit_mask |= RoadWorksContainerExtended_closedLanes_present;
_roadWorks->closedLanes.bit_mask = 0;
_roadWorks->closedLanes.bit_mask |= outerhardShoulderStatus_present;
_roadWorks->closedLanes.outerhardShoulderStatus = availableForStopping;
_roadWorks->closedLanes.bit_mask = drivingLaneStatus_present;
_roadWorks->closedLanes.drivingLaneStatus.length = 3;
_roadWorks->closedLanes.drivingLaneStatus.value = (unsigned char *)ossGetMemory(world, 1);
_roadWorks->closedLanes.drivingLaneStatus.value[0] = 0x20 | 0x40;
_roadWorks->bit_mask |= restriction_present;
/* Create a RestrictedTypes list of one element */
{
RestrictedTypes _restrictedTypes;
_roadWorks->restriction =
_restrictedTypes = (RestrictedTypes)ossGetMemory(world, sizeof(struct RestrictedTypes));
_restrictedTypes->value = unknown;
_restrictedTypes->next = NULL;
}
_roadWorks->bit_mask |= RoadWorksContainerExtended_speedLimit_present;
_roadWorks->speedLimit = 20;
_roadWorks->bit_mask |= RoadWorksContainerExtended_incidentIndication_present;
_roadWorks->incidentIndication.causeCode = reserved;
_roadWorks->incidentIndication.subCauseCode = 0;
_roadWorks->bit_mask |= recommendedPath_present;
/* Create a ItineraryPath list of one element */
{
ItineraryPath _itineraryPath;
_roadWorks->recommendedPath =
_itineraryPath = (ItineraryPath)ossGetMemory(world, sizeof(struct ItineraryPath));
_itineraryPath->value.latitude = 20;
_itineraryPath->value.longitude = 20;
_itineraryPath->value.positionConfidenceEllipse.semiMajorConfidence = SemiAxisLength_oneCentimeter;
_itineraryPath->value.positionConfidenceEllipse.semiMinorConfidence = SemiAxisLength_oneCentimeter;
_itineraryPath->value.positionConfidenceEllipse.semiMajorOrientation = wgs84North;
_itineraryPath->value.altitude.altitudeValue = 200;
_itineraryPath->value.altitude.altitudeConfidence = alt_000_02;
_itineraryPath->next = NULL;
}
_alacarte->bit_mask |= positioningSolution_present;
_alacarte->positioningSolution = noPositioningSolution;
_alacarte->bit_mask |= stationaryVehicle_present;
_stationaryVehicle->bit_mask = 0;
_stationaryVehicle->bit_mask |= stationarySince_present;
_stationaryVehicle->stationarySince = equalOrGreater15Minutes;
_stationaryVehicle->bit_mask |= stationaryCause_present;
_stationaryVehicle->stationaryCause.causeCode = roadworks;
_stationaryVehicle->stationaryCause.subCauseCode = 0;
_stationaryVehicle->bit_mask |= numberOfOccupants_present;
_stationaryVehicle->numberOfOccupants = 30;
_stationaryVehicle->bit_mask |= vehicleIdentification_present;
_stationaryVehicle->vehicleIdentification.bit_mask |=
wMInumber_present | vDS_present;
#ifdef LED
SET_UNBOUNDED_BY_LITERAL(_stationaryVehicle->vehicleIdentification.wMInumber,"WVW");
SET_UNBOUNDED_BY_LITERAL(_stationaryVehicle->vehicleIdentification.vDS, "ZZZ1JZ");
#else
strcpy(_stationaryVehicle->vehicleIdentification.wMInumber, "WVW");
strcpy(_stationaryVehicle->vehicleIdentification.vDS, "ZZZ1JZ");
#endif
_stationaryVehicle->bit_mask |= energyStorageType_present;
_stationaryVehicle->energyStorageType.length = 6;
_stationaryVehicle->energyStorageType.value = (unsigned char *)ossGetMemory(world, 1);
_stationaryVehicle->energyStorageType.value[gasoline_byte] = gasoline;
}
return _DENM_msg;
}
static char *get_messageID(unsigned short id)
{
static char value[16];
switch (id) {
case messageID_denm: return "denm";
case messageID_cam: return "cam";
case poi: return "poi";
case spatem: return "spatem";
case mapem: return "mapem";
case ivim: return "ivim";
case ev_rsr: return "ev-rsr";
case tistpgtransaction: return "tistpgtransaction";
case srem: return "srem";
case ssem: return "ssem";
case evcsn: return "evcsn";
case saem: return "saem";
case rtcmem: return "rtcmem";
default:
sprintf(value, "%d???", id);
}
return value;
}
static char *get_stationType(StationType stype)
{
static char value[16];
switch (stype) {
case unknown: return "unknown";
case pedestrian: return "pedestrian";
case cyclist: return "cyclist";
case moped: return "moped";
case motorcycle: return "motorcycle";
case passengerCar: return "passengerCar";
case bus: return "bus";
case lightTruck: return "lightTruck";
case heavyTruck: return "heavyTruck";
case trailer: return "trailer";
case specialVehicles: return "specialVehicles";
case tram: return "tram";
case roadSideUnit: return "roadSideUnit";
default:
sprintf(value, "%d", stype);
}
return value;
}
static char *get_SpeedValue(SpeedValue val)
{
static char value[16];
switch (val) {
case standstill: return "standstill";
case oneCentimeterPerSec: return "oneCentimeterPerSec";
case SpeedValue_unavailable: return "unavailable";
default:
sprintf(value, "%d", val);
}
return value;
}
static void print_Position(OssGlobal *world,
Latitude latitude, Longitude longitude,
AltitudeValue altitudeValue)
{
char *_valueName = NULL;
ossPrint(world, "(");
switch (latitude) {
case Latitude_oneMicrodegreeNorth:
_valueName = "oneMicrodegreeNorth";
break;
case Latitude_oneMicrodegreeSouth:
_valueName = "oneMicrodegreeSouth";
break;
case Latitude_unavailable:
_valueName = "unavailable";
break;
default:
ossPrint(world, "%d.%06d", latitude / 1000000, abs(latitude % 1000000));
}
if (_valueName)
ossPrint(world, "%s", _valueName);
_valueName = NULL;
ossPrint(world, ", ");
switch (longitude) {
case Longitude_oneMicrodegreeEast:
_valueName = "oneMicrodegreeEast";
break;
case Longitude_oneMicrodegreeWest:
_valueName = "oneMicrodegreeWest";
break;
case Longitude_unavailable:
_valueName = "unavailable";
break;
default:
ossPrint(world, "%d.%06d", longitude / 1000000, abs(longitude % 1000000));
}
if (_valueName)
ossPrint(world, "%s", _valueName);
_valueName = NULL;
ossPrint(world, "), alt ");
switch (altitudeValue) {
case referenceEllipsoidSurface:
_valueName = "referenceEllipsoidSurface";
break;
case AltitudeValue_oneCentimeter:
_valueName = "oneCentimeter";
break;
case AltitudeValue_unavailable:
_valueName = "unavailable";
break;
default:
ossPrint(world, "%d.%02d m", altitudeValue / 100, abs(altitudeValue % 100));
}
if (_valueName)
ossPrint(world, "%s", _valueName);
ossPrint(world, "\n");
}
static char *get_CauseCode(CauseCodeType _causeCode)
{
static char str[16];
switch (_causeCode) {
case reserved: return "reserved";
case trafficCondition: return "trafficCondition";
case accident: return "accident";
case roadworks: return "roadworks";
case adverseWeatherCondition_Adhesion: return "adverseWeatherCondition-Adhesion";
case hazardousLocation_SurfaceCondition: return "hazardousLocation-SurfaceCondition";
case hazardousLocation_ObstacleOnTheRoad: return "hazardousLocation-ObstacleOnTheRoad";
case hazardousLocation_AnimalOnTheRoad: return "hazardousLocation-AnimalOnTheRoad";
case humanPresenceOnTheRoad: return "humanPresenceOnTheRoad";
case wrongWayDriving: return "wrongWayDriving";
case rescueAndRecoveryWorkInProgress: return "rescueAndRecoveryWorkInProgress";
case adverseWeatherCondition_ExtremeWeatherCondition: return "adverseWeatherCondition-ExtremeWeatherCondition";
case adverseWeatherCondition_Visibility: return "adverseWeatherCondition-Visibility";
case adverseWeatherCondition_Precipitation: return "adverseWeatherCondition-Precipitation";
case slowVehicle: return "slowVehicle";
case dangerousEndOfQueue: return "dangerousEndOfQueue";
case vehicleBreakdown: return "vehicleBreakdown";
case postCrash: return "postCrash";
case humanProblem: return "humanProblem";
case CauseCodeType_stationaryVehicle: return "stationaryVehicle";
case emergencyVehicleApproaching: return "emergencyVehicleApproaching";
case hazardousLocation_DangerousCurve: return "hazardousLocation-DangerousCurve";
case collisionRisk: return "collisionRisk";
case signalViolation: return "signalViolation";
case dangerousSituation: return "dangerousSituation";
default:
sprintf(str, "%u", _causeCode);
}
return str;
}
static void print_some_CAM_fields(OssGlobal *world, CAM *value)
{
BasicContainer *b_container;
HighFrequencyContainer *h_container;
ossPrint(world, "messageID: %s\n", get_messageID(value->header.messageID));
ossPrint(world, "stationID: %u\n", value->header.stationID);
ossPrint(world, "generationDeltaTime: ");
if (value->cam.generationDeltaTime == oneMilliSec)
ossPrint(world, "oneMilliSec\n");
else
ossPrint(world, "%d\n", value->cam.generationDeltaTime);
b_container = &value->cam.camParameters.basicContainer;
ossPrint(world, "stationType: %s\n",
get_stationType(b_container->stationType));
{
ReferencePosition *_refPos = &b_container->referencePosition;
ossPrint(world, "referencePosition: ");
print_Position(world, _refPos->latitude, _refPos->longitude,
_refPos->altitude.altitudeValue);
}
h_container = &value->cam.camParameters.highFrequencyContainer;
if (h_container->choice == basicVehicleContainerHighFrequency_chosen)
ossPrint(world, "speedValue: %s\n",
get_SpeedValue(h_container->u.basicVehicleContainerHighFrequency.speed.speedValue));
else
ossPrint(world, "printing of emptyRSUContainerHighFrequency is not supported\n");
}
static void print_some_DENM_fields(OssGlobal *world, DENM *value)
{
ossPrint(world, "messageID: %s\n", get_messageID(value->header.messageID));
ossPrint(world, "stationID: %u\n", value->header.stationID);
{
ReferencePosition *_refPos = &value->denm.management.eventPosition;
ossPrint(world, "eventPosition: ");
print_Position(world, _refPos->latitude, _refPos->longitude,
_refPos->altitude.altitudeValue);
}
if (value->denm.bit_mask & situation_present)
ossPrint(world, "causeCode: %s\n",
get_CauseCode(value->denm.situation.eventType.causeCode));
else
ossPrint(world, "causeCode omitted.\n");
}
This is the expected output when running the sample:
Created CAM message Encoding successful Decoding successful ... printed CAM message ... Created DENM message Encoding successful Decoding successful ... printed DENM message ...
-- Excerpt from ETSI EN 302 637-2 V1.4.1 (2019-04)
CAM-PDU-Descriptions {itu-t (0) identified-organization (4) etsi (0) itsDomain (5)
wg1 (1) en (302637) cam (2) version (2)}
DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
IMPORTS
ItsPduHeader, CauseCode, ReferencePosition, AccelerationControl, Curvature,
CurvatureCalculationMode, Heading, LanePosition, EmergencyPriority, EmbarkationStatus, Speed,
DriveDirection, LongitudinalAcceleration, LateralAcceleration, VerticalAcceleration, StationType,
ExteriorLights, DangerousGoodsBasic, SpecialTransportType, LightBarSirenInUse, VehicleRole,
VehicleLength, VehicleWidth, PathHistory, RoadworksSubCauseCode, ClosedLanes, TrafficRule,
SpeedLimit, SteeringWheelAngle, PerformanceClass, YawRate, ProtectedCommunicationZone, PtActivation,
Latitude, Longitude, ProtectedCommunicationZonesRSU, CenDsrcTollingZone
FROM ITS-Container {itu-t (0) identified-organization (4) etsi (0)
itsDomain (5) wg1 (1) ts (102894) cdd (2) version (2)};
-- The root data frame for cooperative awareness messages
CAM ::= SEQUENCE {
header ItsPduHeader,
cam CoopAwareness
}
CoopAwareness ::= SEQUENCE {
generationDeltaTime GenerationDeltaTime,
camParameters CamParameters
}
CamParameters ::= SEQUENCE {
basicContainer BasicContainer,
highFrequencyContainer HighFrequencyContainer,
lowFrequencyContainer LowFrequencyContainer OPTIONAL,
specialVehicleContainer SpecialVehicleContainer OPTIONAL,
...
}
HighFrequencyContainer ::= CHOICE {
basicVehicleContainerHighFrequency BasicVehicleContainerHighFrequency,
rsuContainerHighFrequency RSUContainerHighFrequency,
...
}
LowFrequencyContainer ::= CHOICE {
basicVehicleContainerLowFrequency BasicVehicleContainerLowFrequency,
...
}
SpecialVehicleContainer ::= CHOICE {
publicTransportContainer PublicTransportContainer,
specialTransportContainer SpecialTransportContainer,
dangerousGoodsContainer DangerousGoodsContainer,
roadWorksContainerBasic RoadWorksContainerBasic,
rescueContainer RescueContainer,
emergencyContainer EmergencyContainer,
safetyCarContainer SafetyCarContainer,
...
}
BasicContainer ::= SEQUENCE {
stationType StationType,
referencePosition ReferencePosition,
...
}
BasicVehicleContainerHighFrequency ::= SEQUENCE {
heading Heading,
speed Speed,
driveDirection DriveDirection,
vehicleLength VehicleLength,
vehicleWidth VehicleWidth,
longitudinalAcceleration LongitudinalAcceleration,
curvature Curvature,
curvatureCalculationMode CurvatureCalculationMode,
yawRate YawRate,
accelerationControl AccelerationControl OPTIONAL,
lanePosition LanePosition OPTIONAL,
steeringWheelAngle SteeringWheelAngle OPTIONAL,
lateralAcceleration LateralAcceleration OPTIONAL,
verticalAcceleration VerticalAcceleration OPTIONAL,
performanceClass PerformanceClass OPTIONAL,
cenDsrcTollingZone CenDsrcTollingZone OPTIONAL
}
The gui/ subdirectory contains an ASN.1 Studio project for this sample. With ASN.1 Studio you can:
This sample is provided solely for illustration purposes, for example to demonstrate usage of the OSS ASN.1 Tools API with CAM and DENM messages. It does not represent a complete application. To build and run this sample, you must use a trial or licensed version of the appropriate OSS ASN.1 Tools. The copyright and license statements included in each source file remain fully applicable.
If you have questions about using this sample, contact OSS Nokalva Support.