The 3GPP family of PER protocols RANAP, RNSAP, NBAP, etc. are all very similar as to internal logic and general pattern. They use heavily such recent features of ASN.1 as parameterization, CLASSes, information object sets and component relation constraints. This makes them difficult to understand for beginners. Let's consider in more detail how we build a RANAP PDU. No matter how diffucult they seem, all these protocols have much in common. The upper level or interface enclosing PDU type RANAP-PDU ::= CHOICE { initiatingMessage InitiatingMessage, successfulOutcome SuccessfulOutcome, unsuccessfulOutcome UnsuccessfulOutcome, outcome Outcome, ... } can theoretically generate a great number of different PDU values with deep nesting. We'll use here ASN.1 value notation which is useful not only for general testing but for understanding the internals of the protocols. We start with the upper level PDU: rANAP-PDU1 RANAP-PDU ::= initiatingMessage: { procedureCode id-privateMessage-ranap, criticality ignore, value PrivateMessage-ranap: ??? } Above we chose initiatingMessage in the 4 choices presented by the RANAP basic PDU type. We see that InitiatingMessage is in fact: InitiatingMessage ::= SEQUENCE { procedureCode RANAP-ELEMENTARY-PROCEDURE.&procedureCode ({RANAP-ELEMENTARY-PROCEDURES}), criticality RANAP-ELEMENTARY-PROCEDURE.&criticality ({RANAP-ELEMENTARY-PROCEDURES}{@procedureCode}), value RANAP-ELEMENTARY-PROCEDURE.&InitiatingMessage ({RANAP-ELEMENTARY-PROCEDURES}{@procedureCode}) } As you can see, each of the 3 fields above is constrained by the information object set RANAP-ELEMENTARY-PROCEDURES defined as: RANAP-ELEMENTARY-PROCEDURES RANAP-ELEMENTARY-PROCEDURE ::= { RANAP-ELEMENTARY-PROCEDURES-CLASS-1 | RANAP-ELEMENTARY-PROCEDURES-CLASS-2 | RANAP-ELEMENTARY-PROCEDURES-CLASS-3, ... } and followed by a long list of other 3 information object sets like: RANAP-ELEMENTARY-PROCEDURES-CLASS-1 RANAP-ELEMENTARY-PROCEDURE ::= { ... } etc. We do not show all of them above. Since the 3 flelds of InitiatingMessage are constrained you are not free to set their values arbitrarily. Instead you should follow the rule given in the information object set or the table with rows and columns. So, if you want to go with PrivateMessage, then you should look up through all the possible information object sets and find that the following information object set contains PrivateMessage: privateMessage-ranap RANAP-ELEMENTARY-PROCEDURE ::= { INITIATING MESSAGE PrivateMessage-ranap PROCEDURE CODE id-privateMessage-ranap CRITICALITY ignore } The above information object set explicitly identifies the 3 fields of InitiatingMessage, i.e. procedureCode, criticality and value. Se we can now write: rANAP-PDU1 RANAP-PDU ::= initiatingMessage: { procedureCode id-privateMessage-ranap, criticality ignore, value PrivateMessage-ranap: ??? } The next step is to find out what the OpenType PrivateMessage is about. We find that it is defined as: PrivateMessage-ranap ::= SEQUENCE { privateIEs PrivateIE-Container {{PrivateMessage-IEs}}, ... } We see that PrivateIE-Container is a parameterized type defined as: PrivateIE-Container {RANAP-PRIVATE-IES: IEsSetParam} ::= SEQUENCE (SIZE (1..maxPrivateIEs-ranap)) OF PrivateIE-Field {{IEsSetParam}} PrivateIE-Field {RANAP-PRIVATE-IES : IEsSetParam} ::= SEQUENCE { id RANAP-PRIVATE-IES.&id ({IEsSetParam}), criticality RANAP-PRIVATE-IES.&criticality ({IEsSetParam}{@id}), value RANAP-PRIVATE-IES.&Value ({IEsSetParam}{@id}) } The above type PrivateIE-Container simply means a template, a parameterized type that takes an information object set of CLASS RANAP-PRIVATE-IES as a parameter. And that particular information object set in our case is PrivateMessage-IEs: PrivateMessage-IEs RANAP-PRIVATE-IES ::= { {ID global : { 0 2 440 200043 2 0 } CRITICALITY ignore TYPE HealthCheck PRESENCE optional} | {ID global : { 0 2 440 200043 2 1 } CRITICALITY ignore TYPE TrafficDataReportRequest PRESENCE optional} | {ID global : { 0 2 440 200043 2 2 } CRITICALITY ignore TYPE TrafficDataReport PRESENCE optional} | {ID global : { 0 2 440 200043 2 3 } CRITICALITY ignore TYPE OAM-InformationReport PRESENCE optional} | {ID global : { 0 2 440 200043 2 4 } CRITICALITY ignore TYPE OAM-InformationReportAcknowledgePRESENCE optional} | {ID global : { 0 2 440 200043 2 5 } CRITICALITY ignore TYPE SCCP-ConnectionSetupRequest PRESENCE optional} | {ID global : { 0 2 440 200043 2 6 } CRITICALITY ignore TYPE SCCP-ConnectionSetupResponse PRESENCE optional} | {ID global : { 0 2 440 200043 2 7 } CRITICALITY ignore TYPE InitializationRequest PRESENCE optional} | {ID global : { 0 2 440 200043 2 8 } CRITICALITY ignore TYPE InitializationResponse PRESENCE optional} , ... } The above table means that PrivateMessage-ranap cannot be chosen arbitrarily but instead it must be one of the above types identified by TYPE. So we have a choice here. Let's pick TrafficDataReport uniquely identified by the OBJECT IDENTIFIER value: ID global: {0 2 440 200043 2 2} because according to the CLASS RANAP-PRIVATE-IES: RANAP-PRIVATE-IES ::= CLASS { &id PrivateIE-ID, &criticality Criticality, &Value, &presence Presence } WITH SYNTAX { ID &id CRITICALITY &criticality TYPE &Value PRESENCE &presence } ID above is a type PrivateIE-ID: PrivateIE-ID ::= CHOICE { local INTEGER (0..65535), global OBJECT IDENTIFIER } So now we can continue building our PDU as follows: rANAP-PDU1 RANAP-PDU ::= initiatingMessage: { procedureCode id-privateMessage-ranap, criticality ignore, value PrivateMessage-ranap: { privateIEs { { id global: { 0 2 440 200043 2 2 }, criticality ignore, value TrafficDataReport: ??? } } } } Now we have a new inner OpenType TrafficDataReport. Let's see what it is: TrafficDataReport ::= SEQUENCE { rAB-TrafficDataReportList RAB-TrafficDataReportList, criticalityDiagnostics CriticalityDiagnostics OPTIONAL, ... } We see that it is a SEQUENCE with one OPTIONAL field which we will drop for simplicity here. So we are left with: RAB-TrafficDataReportList ::= SEQUENCE (SIZE(1..maxNrOfRABs)) OF RAB-TrafficDataReportItem RAB-TrafficDataReportItem ::= SEQUENCE { rAB-ID RAB-ID, cause Cause OPTIONAL dl-SuccessfullyTransmittedDataVolume TrafficDataList OPTIONAL ... } If we drop OPTIONAL fields for simplicity sake, then we end up with the following complete PDU that can be automatically encoded and decoded: rANAP-PDU1 RANAP-PDU ::= initiatingMessage: { procedureCode id-privateMessage-ranap, criticality ignore, value PrivateMessage-ranap: { privateIEs { { id global: { 0 2 440 200043 2 2 }, criticality ignore, value TrafficDataReport: { rAB-TrafficDataReportList { { rAB-ID 1 } } } } } } } The same logic can be applied to any other PDU of RANAP, NBAP and RNSAP, and other similar 3GPP protocols.