Two-phase Encoding

We demonstrate an example of two-phase encoding using communication with an electrocardiogram. This code is based on the ASN.1 specification provided in IEEE 11073-20601-2008 and submitted drafts for an application of this type.

Two-phase encoding requires the use of multiple encoding contexts to encode both the header and payload. They must therefore be declared with the rest of the pertinent variables:

   ApduType   apdu;
   AarqApdu   aarq;
   DataProto* pDataProto;
   PhdAssociationInformation phdAssocInfo;

   OSCTXT     ctxt, ctxt2;
   OSOCTET*   msgptr;
   int        len;
   const char* filename = "message.dat";

We first populate and encode the payload; specific details will vary depending on the application:

   /* Populate and encode PhdAssociationInformation */
   OSCRTLMEMSET (&phdAssocInfo, 0, sizeof(phdAssocInfo));

   phdAssocInfo.protocol_version.numbits = 32;
   phdAssocInfo.protocol_version.data[0] = 0x40;

   phdAssocInfo.encoding_rules.numbits = 16;
   rtxSetBit (phdAssocInfo.encoding_rules.data, 16, EncodingRules_mder);

   phdAssocInfo.nomenclature_version.numbits = 32;
   rtxSetBit (phdAssocInfo.nomenclature_version.data, 32, 
              NomenclatureVersion_nom_version1);

   phdAssocInfo.functional_units.numbits = 32;

   phdAssocInfo.system_type.numbits = 32;
   rtxSetBit (phdAssocInfo.system_type.data, 32, SystemType_sys_type_agent);
   {
   static const OSOCTET sysId[] = {
      0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38
   } ;
   phdAssocInfo.system_id.numocts = (OSUINT32) 8;
   phdAssocInfo.system_id.data = (OSOCTET*) sysId;
   }
   phdAssocInfo.dev_config_id = extended_config_start;

   phdAssocInfo.data_req_mode_capab.data_req_mode_flags.numbits = 16;
   phdAssocInfo.data_req_mode_capab.data_req_init_agent_count = 1;
   phdAssocInfo.data_req_mode_capab.data_req_init_manager_count = 0;

   /* Create memory output stream */
   stat = rtxStreamMemoryCreateWriter (&ctxt, 0, 0);
   if (stat < 0) {
      printf ("Create memory output stream failed\n");
      rtxErrPrint (&ctxt);
      rtFreeContext (&ctxt);
      return stat;
   }

   /* Encode */
   stat = MDEREnc_PhdAssociationInformation (&ctxt, &phdAssocInfo);
   
   msgptr = rtxStreamMemoryGetBuffer (&ctxt, &len);

In brief, the data structures used for the payload are initialized to zero using the OSCRTLMEMSET macro, which here acts just like the C runtime library memset function. The data used for populating this example are taken from a draft specification.

After filling in the necessary fields, the rtxStreamMemoryCreateWriter function is used to create a memory stream for encoding the payload. More information on this function can be found in the C/C++ Common Run Time Library manual. In case of failure, errors are trapped and reported.

Finally, the proper MDEREnc function is called to encode the data. A pointer to the message content is retrieved using the rtxStreamMemoryGetBuffer function. This pointer is used later to fill in the contents of the payload.

After encoding the payload, the rest of the message content must be populated and encoded:

   /* Initialize 2nd context structure */
   stat = rtInitContext (&ctxt2);

   /* Populate apdu with test data */
   OSCRTLMEMSET (&aarq, 0, sizeof(AarqApdu));
   aarq.assoc_version.numbits = 32;
   rtxSetBit (aarq.assoc_version.data, 32, AssociationVersion_assoc_version1);

   pDataProto = rtxMemAllocType (&ctxt2, DataProto);
   pDataProto->data_proto_id = data_proto_id_20601;
   pDataProto->data_proto_info.numocts = len;
   pDataProto->data_proto_info.data = msgptr;

   rtxDListAppend (&ctxt2, &aarq.data_proto_list, pDataProto);

The msgptr variable is used here to fill in the contents of the data_proto_info structure. The rest of the contents are initialized and then encoded:

   apdu.t = T_ApduType_aarq;
   apdu.u.aarq = &aarq;

   /* Create memory output stream */
   stat = rtxStreamMemoryCreateWriter (&ctxt2, 0, 0);
   if (stat < 0) {
      printf ("Create memory output stream failed\n");
      rtxErrPrint (&ctxt);
      rtFreeContext (&ctxt);
   }

   /* Encode */
   stat = MDEREnc_ApduType (&ctxt2, &apdu);

Again, a memory stream writer is used here for encoding, but other options exist to write to a file or a socket.