Decode and Encode NG-RAN E1AP PER Messages in Rust Using the ASN.1/Rust Web Compiler


The generated source code and related project files are described below.

The sample demonstrates how to decode and encode messages for the 3GPP NG-RAN E1AP standard (TS 37.483 V18.2.0) using Rust code generated by the ASN.1/Rust Web Compiler.

The ASN.1/Rust Web Compiler generates a Rust codec and sample application from the E1AP ASN.1 schema. The generated sample decodes a PER-encoded E1AP-PDU, converts and prints the decoded value, and encodes the value back to PER.

To explore more samples (LTE RRC, 5G RRC, S1AP, X2AP), visit the main Sample Code page.

Overview

This sample shows how to:

  • Generate a Rust codec and sample application from the NG-RAN E1AP ASN.1 schema.
  • Decode a PER-encoded E1AP-PDU.
  • Convert the decoded value to a formatted string and print it.
  • Encode the decoded E1AP-PDU back to PER.
  • Print the encoded data in hexadecimal format.
  • Handle decoding, formatting, and encoding errors.
  • Build and run the generated Rust sample using Cargo.

Schema and Compiler Information

  • Standard: 3GPP TS 37.483
  • Version: V18.2.0 (2024-07)
  • Protocol: NG-RAN E1AP
  • Language: Rust
  • Encoding rule: PER
  • ASN.1 compiler version: 1.1.9

Files in This Sample

The ASN.1/Rust Web Compiler generates the Rust codec, sample application, and Cargo configuration files required to build the project.

File Description
sample/src/main.rs Generated Rust sample application that demonstrates how to decode, print, and re-encode an E1AP PDU.
sample/Cargo.toml Cargo configuration for the sample application.
codec/src/ Rust codec source generated from the NG-RAN E1AP ASN.1 schema.
codec/Cargo.toml Cargo configuration for the generated codec.
Cargo.toml Cargo workspace configuration for the generated project.
compiler_*.json Compiler configuration associated with the generated project.

Generated Codec and Sample Application

The codec/ directory contains the Rust codec generated from the NG-RAN E1AP ASN.1 schema. The sample/src/main.rs file contains the generated sample application that demonstrates how to use the codec.

Generate the Rust Codec and Sample

To generate the Rust codec and sample application using the ASN.1/Rust Web Compiler:

  1. Select the NG-RAN E1AP ASN.1 schema.
  2. Specify the ASN.1 types to encode or decode.
  3. Select the target platform and code generation options.
  4. Generate the Rust codec.
  5. Download the generated codec and sample code.

For this sample, the E1AP-PDU type is used to demonstrate PER encoding and decoding.

Message Processing Workflow

The generated sample application:

  1. Defines a sample PER-encoded E1AP-PDU as a byte vector.
  2. Selects PER as the encoding rule.
  3. Decodes the encoded bytes into an E1AP-PDU value.
  4. Converts the decoded value to a formatted string and prints it.
  5. Encodes the decoded E1AP-PDU back to PER.
  6. Prints the encoded data in hexadecimal format.
  7. Reports an error if decoding, string conversion, or encoding fails.

Build and Run Instructions

Before building the generated Rust project, install Cargo and the Rust compiler (rustc). The recommended way to install both is with rustup. See the Rust installation instructions.

1. Extract the generated project

Download and extract the archive generated by the ASN.1/Rust Web Compiler. The generated project contains the codec and sample subdirectories and a top-level Cargo.toml file.

2. Build the codec and sample

Open a terminal in the root directory of the extracted project, where the top-level Cargo.toml file is located, and run:

cargo build

This command builds the generated Rust codec and sample application.

3. Run the sample

From the same directory, run:

cargo run sample

This command runs the generated sample application.

Code Listing: main.rs

The following listing shows the generated Rust sample application, sample/src/main.rs. It demonstrates how to decode a PER-encoded E1AP PDU, convert and print the decoded value, encode the value back to PER, and handle errors using the generated Rust codec.

Show main.rs source code
/*

******************************************************************
* Copyright (C) 2026 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.

* Generated Codec Name: my_codec 
* ASN.1 Compiler Version: 1.1.9
*/

#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(unused_parens)]
#![allow(unused_mut)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_assignments)]


use std::ptr;
use std::cell::LazyCell;

pub fn E1AP_PDU_sample(){
	oss_print_string_literal("================================================================\x0a\x0a");
	oss_print_string_literal("Encoding/Decoding value of type 'E1AP-PDU-Descriptions.E1AP-PDU':\x0a\x0a");
	let  sample_bytes : mut_oss_Vector_of_uint8 = vec![(((i64_to_u8(((0) as i64))) as u32)) as u8, (((i64_to_u8(((0) as i64))) as u32)) as u8, (((i64_to_u8(((0) as i64))) as u32)) as u8, (((i64_to_u8(((9) as i64))) as u32)) as u8, (((i64_to_u8(((0) as i64))) as u32)) as u8, (((i64_to_u8(((0) as i64))) as u32)) as u8, (((i64_to_u8(((1) as i64))) as u32)) as u8, (((i64_to_u8(((0) as i64))) as u32)) as u8, (((i64_to_u8(((0) as i64))) as u32)) as u8, (((i64_to_u8(((0) as i64))) as u32)) as u8, (((i64_to_u8(((2) as i64))) as u32)) as u8, (((i64_to_u8(((0) as i64))) as u32)) as u8, (((i64_to_u8(((0) as i64))) as u32)) as u8];
	let encoding_rule : oss_EncodingRules = oss_EncodingRules_per;
	let mut decode_ok : bool = false;
	let mut decoded_value : *mut E1AP_PDU = (ptr::null_mut() as *mut E1AP_PDU);
	let mut error_messages : oss_String = oss_String_init();
	(decode_ok, decoded_value, error_messages) = E1AP_PDU_Decode((& encoding_rule as *const oss_EncodingRules), (& sample_bytes));
	if !decode_ok {
		oss_print_string_literal("The 'Decode' call failed!\x0a");
		oss_print_string((& error_messages as *const oss_String));
		oss_print_string_literal("");
		oss_exit(1);
	}
	let mut to_json_ok : bool = false;
	let mut json_value : *mut oss_String = (ptr::null_mut() as *mut oss_String);
	oss_String_Clear((&mut error_messages as *mut oss_String));
	(to_json_ok, json_value, error_messages) = E1AP_PDU_ToString(decoded_value);
	if !to_json_ok {
		oss_print_string_literal("The 'ToString' call failed!\x0a");
		oss_print_string((& error_messages as *const oss_String));
		oss_print_string_literal("");
		oss_exit(1);
	}
	oss_print_string_literal("Decoded value (formatted string): ");
	oss_print_string(json_value);
	oss_print_string_literal("\x0a\x0a");
	let mut encode_ok : bool = false;
	let mut encoded_value : *const mut_oss_Vector_of_uint8 = (ptr::null() as *const mut_oss_Vector_of_uint8);
	oss_String_Clear((&mut error_messages as *mut oss_String));
	(encode_ok, encoded_value, error_messages) = E1AP_PDU_Encode((& encoding_rule as *const oss_EncodingRules), decoded_value);
	if !encode_ok {
		oss_print_string_literal("The 'Encode' call failed!\x0a");
		oss_print_string((& error_messages as *const oss_String));
		oss_print_string_literal("");
		oss_exit(1);
	}
	oss_print_hex(encoded_value);
	oss_print_string_literal("\x0a");
	if !(json_value == (ptr::null_mut() as *mut oss_String)) {
		let mut tmp_value_1083217 : *mut oss_String = json_value;
		if !(tmp_value_1083217 == (ptr::null_mut() as *mut oss_String)) {
			oss_String_Dtr(tmp_value_1083217);
		}
		(_) = delete_oss_String(tmp_value_1083217);
	}
	(_) = delete_oss_Vector_of_uint8(encoded_value);
	prune_E1AP_PDU(decoded_value);
	(_) = delete_E1AP_PDU(decoded_value);
	oss_String_Dtr((&mut error_messages as *mut oss_String));
}
/*
prints a native string literal to the console
	a_str: a native reference to the string to be printed

*/
pub fn oss_print_string_literal(a_str: &str) {
	print!("{}", a_str);
}
/*
prints raw bytes to the console
	v: a reference to the constant vector of uint8 bytes to be printed

*/
pub fn oss_print_hex(v: *const mut_oss_Vector_of_uint8) {
	if v.is_null() {
		println!("Null pointer passed to print_oss_vector_hex.");
		return;
	}
	let vec = unsafe { &*v };

	print!("Encoding HEX (len={}): ", vec.len());
	for byte in vec {
		print!("{:02X} ", byte);
	}
	println!();
}

pub fn main(){
	E1AP_PDU_sample();
}
use codec::bindings::*;
use codec::api::*;

Expected Output (Excerpt)

This is an excerpt of the output produced when running the generated sample:

Encoding/Decoding value of type 'E1AP-PDU-Descriptions.E1AP-PDU':

Decoded value (formatted string):
{
    ...
    "procedureCode": 0,
    "criticality": "reject",
    "value": {
        ...
    }
}

Encoding HEX (len=13): 00 00 00 09 ... 00 02 00 00

ASN.1 Schema Excerpt (E1AP-PDU)

The following excerpt shows the E1AP-PDU definition from the 3GPP TS 37.483 V18.2.0 ASN.1 schema used to generate this sample.

Show excerpt
-- Excerpt from 3GPP TS 37.483 V18.2.0 (2024-07) 
-- **************************************************************
--
-- Elementary Procedure definitions
--
-- **************************************************************

E1AP-PDU-Descriptions {
itu-t (0) identified-organization (4) etsi (0) mobileDomain (0)
ngran-access (22) modules (3) e1ap (5) version1 (1) e1ap-PDU-Descriptions (0) }

DEFINITIONS AUTOMATIC TAGS ::= 

BEGIN

-- **************************************************************
--
-- IE parameter types from other modules
--
-- **************************************************************

IMPORTS
	Criticality,
	ProcedureCode

FROM E1AP-CommonDataTypes
	Reset,
	ResetAcknowledge,
	ErrorIndication,
	GNB-CU-UP-E1SetupRequest,
	GNB-CU-UP-E1SetupResponse,
	GNB-CU-UP-E1SetupFailure, 
	GNB-CU-CP-E1SetupRequest,
	GNB-CU-CP-E1SetupResponse,
	GNB-CU-CP-E1SetupFailure, 
	GNB-CU-UP-ConfigurationUpdate,
	GNB-CU-UP-ConfigurationUpdateAcknowledge,
	GNB-CU-UP-ConfigurationUpdateFailure,
	GNB-CU-CP-ConfigurationUpdate,
	GNB-CU-CP-ConfigurationUpdateAcknowledge,
	GNB-CU-CP-ConfigurationUpdateFailure,
	BCBearerContextSetupRequest,
	BCBearerContextSetupResponse,
	BCBearerContextSetupFailure,
	BCBearerContextModificationRequest,
	BCBearerContextModificationResponse,
	BCBearerContextModificationFailure,
	BCBearerContextModificationRequired,
	BCBearerContextModificationConfirm,
	BCBearerContextReleaseCommand,
	BCBearerContextReleaseComplete,
	BCBearerContextReleaseRequest,
	BearerContextSetupRequest,
	BearerContextSetupResponse,
	BearerContextSetupFailure,
	BearerContextModificationRequest,
	BearerContextModificationResponse,
	BearerContextModificationFailure,
	BearerContextModificationRequired,
	BearerContextModificationConfirm,
	BearerContextReleaseCommand,
	BearerContextReleaseComplete,
	BearerContextReleaseRequest,
	BearerContextInactivityNotification,
	DLDataNotification,
	ULDataNotification,
	DataUsageReport,
	E1ReleaseRequest,
	E1ReleaseResponse,
	GNB-CU-UP-CounterCheckRequest,
	GNB-CU-UP-StatusIndication,
	MCBearerContextSetupRequest,
	MCBearerContextSetupResponse,
	MCBearerContextSetupFailure,
	MCBearerContextModificationRequest,
	MCBearerContextModificationResponse,
	MCBearerContextModificationFailure,
	MCBearerContextModificationRequired,
	MCBearerContextModificationConfirm,
	MCBearerNotification,
	MCBearerContextReleaseCommand,
	MCBearerContextReleaseComplete,
	MCBearerContextReleaseRequest,
	MRDC-DataUsageReport,
	DeactivateTrace,
	TraceStart,
	PrivateMessage,
	ResourceStatusRequest,
	ResourceStatusResponse,
	ResourceStatusFailure,
	ResourceStatusUpdate,
	IAB-UPTNLAddressUpdate,
	IAB-UPTNLAddressUpdateAcknowledge,
	IAB-UPTNLAddressUpdateFailure,
	CellTrafficTrace,
	EarlyForwardingSNTransfer,
	GNB-CU-CPMeasurementResultsInformation,
	IABPSKNotification

FROM E1AP-PDU-Contents
	id-reset,
	id-errorIndication,
	id-gNB-CU-UP-E1Setup,
	id-gNB-CU-CP-E1Setup,
	id-gNB-CU-UP-ConfigurationUpdate,
	id-gNB-CU-CP-ConfigurationUpdate,
	id-e1Release,
	id-bearerContextSetup,
	id-bearerContextModification,
	id-bearerContextModificationRequired,
	id-bearerContextRelease,
	id-bearerContextReleaseRequest,
	id-bearerContextInactivityNotification,
	id-dLDataNotification,
	id-uLDataNotification,
	id-dataUsageReport,
	id-gNB-CU-UP-CounterCheck,
	id-gNB-CU-UP-StatusIndication,
	id-mRDC-DataUsageReport,
	id-DeactivateTrace,
	id-TraceStart,
	id-privateMessage,
	id-resourceStatusReportingInitiation,
	id-resourceStatusReporting,
	id-iAB-UPTNLAddressUpdate,
	id-CellTrafficTrace,
	id-earlyForwardingSNTransfer,
	id-gNB-CU-CPMeasurementResultsInformation,
	id-iABPSKNotification,
	id-BCBearerContextSetup,
	id-BCBearerContextModification,
	id-BCBearerContextModificationRequired,
	id-BCBearerContextRelease,
	id-BCBearerContextReleaseRequest,
	id-MCBearerContextSetup,
	id-MCBearerContextModification,
	id-MCBearerContextModificationRequired,
	id-MCBearerNotification,
	id-MCBearerContextRelease,
	id-MCBearerContextReleaseRequest

FROM E1AP-Constants;

-- **************************************************************
--
-- Interface Elementary Procedure Class
--
-- **************************************************************

E1AP-ELEMENTARY-PROCEDURE ::= CLASS {
	&InitiatingMessage				,
	&SuccessfulOutcome							OPTIONAL,
	
&UnsuccessfulOutcome						OPTIONAL,
	&procedureCode				ProcedureCode 	UNIQUE,
	&criticality				Criticality 	DEFAULT ignore
}
WITH SYNTAX {
	INITIATING MESSAGE			&InitiatingMessage
	[SUCCESSFUL OUTCOME			&SuccessfulOutcome]
	[UNSUCCESSFUL OUTCOME		&UnsuccessfulOutcome]
	PROCEDURE CODE				&procedureCode
	[CRITICALITY				&criticality]
}

-- **************************************************************
--
-- Interface PDU Definition
--
-- **************************************************************

E1AP-PDU ::= CHOICE {
	initiatingMessage		InitiatingMessage,
	successfulOutcome		SuccessfulOutcome,
	unsuccessfulOutcome		UnsuccessfulOutcome,
	...
}

InitiatingMessage ::= SEQUENCE {
	procedureCode			E1AP-ELEMENTARY-PROCEDURE.&procedureCode		({E1AP-ELEMENTARY-PROCEDURES}),
	criticality				E1AP-ELEMENTARY-PROCEDURE.&criticality			({E1AP-ELEMENTARY-PROCEDURES}{@procedureCode}),
	value					E1AP-ELEMENTARY-PROCEDURE.&InitiatingMessage	({E1AP-ELEMENTARY-PROCEDURES}{@procedureCode})
}

SuccessfulOutcome ::= SEQUENCE {
	procedureCode			E1AP-ELEMENTARY-PROCEDURE.&procedureCode		({E1AP-ELEMENTARY-PROCEDURES}),
	criticality				E1AP-ELEMENTARY-PROCEDURE.&criticality			({E1AP-ELEMENTARY-PROCEDURES}{@procedureCode}),
	value					E1AP-ELEMENTARY-PROCEDURE.&SuccessfulOutcome	({E1AP-ELEMENTARY-PROCEDURES}{@procedureCode})
}

UnsuccessfulOutcome ::= SEQUENCE {
	procedureCode			E1AP-ELEMENTARY-PROCEDURE.&procedureCode		({E1AP-ELEMENTARY-PROCEDURES}),
	criticality				E1AP-ELEMENTARY-PROCEDURE.&criticality			({E1AP-ELEMENTARY-PROCEDURES}{@procedureCode}),
	value					E1AP-ELEMENTARY-PROCEDURE.&UnsuccessfulOutcome	({E1AP-ELEMENTARY-PROCEDURES}{@procedureCode})
}

-- **************************************************************
--
-- Interface Elementary Procedure List
--
-- **************************************************************

E1AP-ELEMENTARY-PROCEDURES E1AP-ELEMENTARY-PROCEDURE ::= {
	E1AP-ELEMENTARY-PROCEDURES-CLASS-1			|
	E1AP-ELEMENTARY-PROCEDURES-CLASS-2			,

	...
}

E1AP-ELEMENTARY-PROCEDURES-CLASS-1 E1AP-ELEMENTARY-PROCEDURE ::= {
	reset										|
	gNB-CU-UP-E1Setup							|
	gNB-CU-CP-E1Setup							|
	gNB-CU-UP-ConfigurationUpdate				|
	gNB-CU-CP-ConfigurationUpdate				|
	e1Release									|
	bearerContextSetup							|
	bearerContextModification					|
	bearerContextModificationRequired			|
	bearerContextRelease						|
	resourceStatusReportingInitiation			|
	iAB-UPTNLAddressUpdate						|
	bCBearerContextSetup						|
	bCBearerContextModification					|
	bCBearerContextModificationRequired			|
	bCBearerContextRelease						|
	mCBearerContextSetup						|
	mCBearerContextModification					|
	mCBearerContextModificationRequired			|
	mCBearerContextRelease						,
	...
}

E1AP-ELEMENTARY-PROCEDURES-CLASS-2 E1AP-ELEMENTARY-PROCEDURE ::= {
	errorIndication							|
	bearerContextReleaseRequest				|
	bearerContextInactivityNotification		|
	dLDataNotification						|
	uLDataNotification						|
	dataUsageReport							|
	gNB-CU-UP-CounterCheck					|
	gNB-CU-UP-StatusIndication				|
	mRDC-DataUsageReport					|
	deactivateTrace							|
	traceStart								|
	privateMessage							|
	cellTrafficTrace						|
	resourceStatusReporting					|
	earlyForwardingSNTransfer				|
	gNB-CU-CPMeasurementResultsInformation  |
	iABPSKNotification						|
	bCBearerContextReleaseRequest			|
	mCBearerContextReleaseRequest			|
	mCBearerNotification					,
	...
}

-- **************************************************************
--
-- Interface Elementary Procedures
--
-- **************************************************************

Related Samples

Disclaimer

This sample is provided solely for illustration purposes to demonstrate how to process 3GPP NG-RAN E1AP messages using Rust code generated by the ASN.1/Rust Web Compiler. It does not represent a complete application. The copyright and license statements included in the generated source files remain fully applicable.

Need Help?

If you have questions about using this sample, contact OSS Nokalva Support.

See Also