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 Windows as an example and illustrates how to create, encode, decode, and print CAM and DENM messages using the OSS ASN.1 Tools API.
A Windows batch script (run.bat) is included for 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 | Additional ASN.1 compiler directives. |
| app.cs | Simple C# program that demonstrates creating, encoding, decoding, and printing CAM and DENM messages. | run.bat | Windows batch script that runs the test. |
| 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 you use the OSS command prompt window, you do not need to set environment variables to run this sample. Otherwise, ensure the following are defined:
If using Visual Studio, run the Microsoft vsvars32.bat script to set up the .NET command-line environment. If Visual Studio is not installed, ensure your PATH includes the required .NET directories. For details, see ossvars.bat installed with the product.
run
run clean
Note: The C# source code in this sample is platform-independent. Windows commands are shown as an example, but equivalent samples and run instructions may be available for 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, app.cs. 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 part of the CAM & DENM protocols.
//
// Classes generated from ASN.1 specification.
using Cam;
using Cam.CAMPDUDescriptions;
using Cam.ITSContainer;
using Cam.DENMPDUDescriptions;
// Classes from the OSS runtime library.
using Oss.Asn1;
// C# system classes.
using System;
using System.Collections.Generic;
using System.IO;
public class Program
{
public static int Main(string[] args)
{
try
{
Tcamdenm camdenm = new Tcamdenm();
Console.WriteLine("Creating a CAM PDU...");
CAMType unencoded_cam = camdenm.CreateCam();
byte[] encoded_cam = camdenm.Encode(unencoded_cam, null);
Console.WriteLine();
CAMType decoded_cam = camdenm.DecodeCAM(encoded_cam);
Console.WriteLine("\nComparing the decoded CAM PDU with the original one...");
if (decoded_cam.Equals(unencoded_cam))
Console.WriteLine("Comparison succeeded.");
else
Console.WriteLine("Comparison failed.");
Console.WriteLine("\nCreating a DEMN PDU...");
DENMContainer unencoded_denm = camdenm.CreateDenm();
byte[] encoded_denm = camdenm.Encode(null, unencoded_denm);
Console.WriteLine();
DENMContainer decoded_denm = camdenm.DecodeDENM(encoded_denm);
Console.WriteLine();
Console.WriteLine("Decoded & Encoded successfully.");
return 0;
}
catch (Exception e)
{
// Print complete exception information.
Console.WriteLine(e);
return 1;
}
}
}
/// <summary>
/// Creates a CAM message, prints it, then encodes and
/// decodes it.
/// </summary>
public class Tcamdenm
{
PerUnalignedCodec codec = new PerUnalignedCodec();
/// <summary>
/// UPER-decodes, prints and compares CAM messages.
/// </summary>
public CAMType DecodeCAM(byte[] encoded)
{
try
{
CAMType decoded = new CAMType();
codec.Decode(encoded, decoded);
Console.WriteLine("\nPrinting the UPER-Decoded PDU...\n");
ValueNotationFormatter.Print(decoded, Console.Out);
return decoded;
}
catch (Exception e)
{
Console.WriteLine("ERROR: " + e.Message + "\n");
return null;
}
}
/// <summary>
/// UPER-decodes, prints and compares CAM messages.
/// </summary>
public DENMContainer DecodeDENM(byte[] encoded)
{
try
{
DENMContainer decoded = new DENMContainer();
codec.Decode(encoded, decoded);
Console.WriteLine("\nPrinting the UPER-Decoded PDU...\n");
ValueNotationFormatter.Print(decoded, Console.Out);
return decoded;
}
catch (Exception e)
{
Console.WriteLine("ERROR: " + e.Message + "\n");
return null;
}
}
/// <summary>
/// Creates and then UPER-encodes a CAM PDU.
/// </summary>
public byte [] Encode(CAMType unencoded_cam, DENMContainer unencoded_denm)
{
string pdu = unencoded_cam == null? "DENM": "CAM";
byte[] encoded;
try
{
Console.WriteLine("Created successfully.\n");
Console.WriteLine("Printing the created " + pdu + " PDU...\n");
if (unencoded_denm == null)
ValueNotationFormatter.Print(unencoded_cam, Console.Out);
else
ValueNotationFormatter.Print(unencoded_denm, Console.Out);
Console.WriteLine("\nEncoding the " + pdu + " PDU...");
if (unencoded_denm == null)
encoded = codec.Encode(unencoded_cam);
else
encoded = codec.Encode(unencoded_denm);
Console.WriteLine("Encoded successfully.\n");
Console.WriteLine("Printing the UPER-Encoded " + pdu + " PDU...\n");
ValueNotationFormatter.Print(encoded, encoded.Length, Console.Out);
return encoded;
}
catch (Exception e)
{
throw new Exception("ERROR: " + e.Message + "\n");
}
}
/// <summary>
/// Creates a CAM PDU.
/// </summary>
public CAMType CreateCam()
{
CAMType cam = new CAMType() {
Header = new ItsPduHeader() {
ProtocolVersion = 1,
MessageID = 2,
StationID = 1234567
},
CamField = new CoopAwareness() {
GenerationDeltaTime = 11409,
CamParameters = new CamParameters() {
BasicContainer = new BasicContainer() {
StationType = 5,
ReferencePosition = new ReferencePosition() {
Latitude = 40487111,
Longitude = 79494789,
PositionConfidenceEllipse = new PosConfidenceEllipse() {
SemiMajorConfidence = 500,
SemiMinorConfidence = 400,
SemiMajorOrientation = 0
},
Altitude = new Altitude() {
AltitudeValue = 2000,
AltitudeConfidence = AltitudeConfidence.Alt00002
}
}
},
HighFrequencyContainer = new HighFrequencyContainer() {
BasicVehicleContainerHighFrequency = new BasicVehicleContainerHighFrequency() {
Heading = new Heading() {
HeadingValue = 0,
HeadingConfidence = 1
},
Speed = new Speed() {
SpeedValue = 2000,
SpeedConfidence = 1
},
DriveDirection = DriveDirection.Forward,
VehicleLength = new VehicleLength() {
VehicleLengthValue = 35,
VehicleLengthConfidenceIndication = VehicleLengthConfidenceIndication.NoTrailerPresent
},
VehicleWidth = 20,
LongitudinalAcceleration = new LongitudinalAcceleration() {
LongitudinalAccelerationValue = 10,
LongitudinalAccelerationConfidence = 1
},
Curvature = new Curvature() {
CurvatureValue = 0,
CurvatureConfidence = CurvatureConfidence.OnePerMeter000002
},
CurvatureCalculationMode = CurvatureCalculationMode.YawRateUsed,
YawRate = new YawRate() {
YawRateValue = 0,
YawRateConfidence = YawRateConfidence.DegSec00001
},
AccelerationControl = new Oss.Asn1.BitStringWithNamedBits (
new byte[] {
0x40
}, 2
),
SteeringWheelAngle = new SteeringWheelAngle() {
SteeringWheelAngleValue = 30,
SteeringWheelAngleConfidence = 1
},
LateralAcceleration = new LateralAcceleration() {
LateralAccelerationValue = -2,
LateralAccelerationConfidence = 1
},
VerticalAcceleration = new VerticalAcceleration() {
VerticalAccelerationValue = 1,
VerticalAccelerationConfidence = 1
}
}
},
LowFrequencyContainer = new LowFrequencyContainer() {
BasicVehicleContainerLowFrequency = new BasicVehicleContainerLowFrequency() {
VehicleRole = VehicleRole.Default,
ExteriorLights = new Oss.Asn1.BitStringWithNamedBits (
new byte[] {
0xA8
}, 5
),
PathHistory = new PathHistory() {
new PathPoint() {
PathPosition = new DeltaReferencePosition() {
DeltaLatitude = 10000,
DeltaLongitude = 5000,
DeltaAltitude = 12800
},
PathDeltaTime = 1000
}
}
}
},
SpecialVehicleContainer = new SpecialVehicleContainer() {
PublicTransportContainer = new PublicTransportContainer() {
EmbarkationStatus = false,
PtActivation = new PtActivation() {
PtActivationType = 0,
PtActivationData = new byte[] {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55
}
}
}
}
}
}
};
return cam;
}
/// <summary>
/// Creates a DENM PDU.
/// </summary>
public DENMContainer CreateDenm()
{
DENMContainer denm = new DENMContainer() {
Header = new ItsPduHeader() {
ProtocolVersion = 1,
MessageID = 1,
StationID = 1234567
},
Denm = new DecentralizedEnvironmentalNotificationMessage() {
Management = new ManagementContainer() {
ActionID = new ActionID() {
OriginatingStationID = 20,
SequenceNumber = 30
},
DetectionTime = 45000000000,
ReferenceTime = 1,
Termination = Termination.IsCancellation,
EventPosition = new ReferencePosition() {
Latitude = 40487111,
Longitude = -79494789,
PositionConfidenceEllipse = new PosConfidenceEllipse() {
SemiMajorConfidence = 500,
SemiMinorConfidence = 400,
SemiMajorOrientation = 10
},
Altitude = new Altitude() {
AltitudeValue = 2000,
AltitudeConfidence = AltitudeConfidence.Alt00002
}
},
RelevanceDistance = RelevanceDistance.LessThan100m,
RelevanceTrafficDirection = RelevanceTrafficDirection.UpstreamTraffic,
ValidityDuration = 600,
TransmissionInterval = 1,
StationType = 5
},
Situation = new SituationContainer() {
InformationQuality = 1,
EventType = new CauseCodeContainer() {
CauseCode = 3,
SubCauseCode = 0
}
},
Location = new LocationContainer() {
EventSpeed = new Speed() {
SpeedValue = 0,
SpeedConfidence = 1
},
EventPositionHeading = new Heading() {
HeadingValue = 0,
HeadingConfidence = 10
},
Traces = new Traces() {
new PathHistory() {
new PathPoint() {
PathPosition = new DeltaReferencePosition() {
DeltaLatitude = 20,
DeltaLongitude = 20,
DeltaAltitude = 12800
},
PathDeltaTime = 1
},
new PathPoint() {
PathPosition = new DeltaReferencePosition() {
DeltaLatitude = 22,
DeltaLongitude = 22,
DeltaAltitude = 12800
}
}
}
},
RoadType = RoadType.UrbanNoStructuralSeparationToOppositeLanes
},
Alacarte = new AlacarteContainer() {
ImpactReduction = new ImpactReductionContainer() {
HeightLonCarrLeft = 1,
HeightLonCarrRight = 1,
PosLonCarrLeft = 1,
PosLonCarrRight = 1,
PositionOfPillars = new PositionOfPillars() {
1
},
PosCentMass = 63,
WheelBaseVehicle = 1,
TurningRadius = 1,
PosFrontAx = 1,
PositionOfOccupants = new Oss.Asn1.BitStringWithNamedBits (
new byte[] {
0xFE ,0x02 ,0x10
}, 20
),
VehicleMass = 20,
RequestResponseIndication = RequestResponseIndication.Response
},
ExternalTemperature = 1,
RoadWorks = new RoadWorksContainerExtended() {
LightBarSirenInUse = new Oss.Asn1.BitStringWithNamedBits (
new byte[] {
0xC0
}, 2
),
ClosedLanes = new ClosedLanes() {
OuterhardShoulderStatus = HardShoulderStatus.AvailableForStopping,
DrivingLaneStatus = new Oss.Asn1.BitStringWithNamedBits (
new byte[] {
0x60
}, 3
)
},
Restriction = new RestrictedTypes() {
0
},
SpeedLimit = 20,
IncidentIndication = new CauseCodeContainer() {
CauseCode = 0,
SubCauseCode = 0
},
RecommendedPath = new ItineraryPath() {
new ReferencePosition() {
Latitude = 20,
Longitude = 20,
PositionConfidenceEllipse = new PosConfidenceEllipse() {
SemiMajorConfidence = 1,
SemiMinorConfidence = 1,
SemiMajorOrientation = 0
},
Altitude = new Altitude() {
AltitudeValue = 200,
AltitudeConfidence = AltitudeConfidence.Alt00002
}
}
}
},
PositioningSolution = PositioningSolutionType.NoPositioningSolution,
StationaryVehicle = new StationaryVehicleContainer() {
StationarySince = StationarySince.EqualOrGreater15Minutes,
StationaryCause = new CauseCodeContainer() {
CauseCode = 3,
SubCauseCode = 0
},
NumberOfOccupants = 30,
VehicleIdentification = new VehicleIdentification() {
WMInumber = "WVW",
VDS = "ZZZ1JZ"
},
EnergyStorageType = new Oss.Asn1.BitStringWithNamedBits (
new byte[] {
0x04
}, 6
)
}
}
}
};
return denm;
}
}
This is the expected output when running the sample:
Creating the CAM PDU value... Done Encoding the created CAM value... Done Decoding the encoded CAM message... Done Comparing the decoded message with the original PDU value... Succeeded Partial custom printing of the decoded CAM PDU: messageID: cam stationID: 1234567 generationDeltaTime: 11409 stationType: passengerCar referencePosition: (40.487111, 79.494789), alt 20.00 m speedValue: 2000 Creating the DENM PDU value... Done Encoding the created DENM value... Done Decoding the encoded DENM message... Done Comparing the decoded message with the original PDU value... Succeeded Partial custom printing of the decoded DENM PDU: messageID: denm stationID: 1234567 eventPosition: (40.487111, -79.494789), alt 20.00 m causeCode: roadworks
-- 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.