Difference between revisions of "Technical topic: ASN.1 and ACN - How to add a CRC value to an encoded packet"
(→Solution using ASN.1 and ACN) |
|||
(One intermediate revision by one other user not shown) | |||
Line 14: | Line 14: | ||
== Solution using ASN.1 and ACN == | == Solution using ASN.1 and ACN == | ||
+ | |||
+ | '''EDIT''' A solution better than the one explained on this page is documented in the ASN.1/ACN user manual. Please check this link and ignore the rest of this page: | ||
+ | |||
+ | http://taste.tuxfamily.org/wiki/index.php?title=Technical_topic:_ASN.1_-_An_introduction_to_ACN#Encoding_fields_that_depend_on_the_encoding_binary_stream | ||
+ | |||
+ | == DEPRECATED PART == | ||
+ | |||
We need two things: | We need two things: |
Latest revision as of 13:11, 17 February 2022
The need
If you are using ASN.1 to encode the messages you send over a network (as you should!) you may face the situation where ASN.1 cannot know the value of a field before the whole packet is encoded. In space-ground links there are two fields of the standard telecommand packets that enter this category:
- a Length field in the packet header (used to know the number of bytes to wait for on the network interface)
- a CRC/Checksum field at the end of the packet
In the ASN.1 model you may add a placeholder for these fields but the encoder is of course not able to set the value, as it may require to compute it with a user-defined algorithm.
Adding manually the fields to the buffer after the encoding phase is possible but not trivial, as you need to take care of endianness and possibly shift bits here and there. In other words, you loose some benefits of ASN.1 by doing things manually again.
Luckily ASN1SCC provides help using a simple API to fill a value in the packet after it is encoded. You only need to know where to put the value.
Solution using ASN.1 and ACN
EDIT A solution better than the one explained on this page is documented in the ASN.1/ACN user manual. Please check this link and ignore the rest of this page:
DEPRECATED PART
We need two things:
- to specify the placeholder for the values
- to fill in the value after the packet is encoded
The placeholder can be present in the ASN.1 type itself, but since it is not a field that is of any relevance to the end user (not application semantics) we will rather use ACN to add it.
Assuming a top-level structure in ASN.1 that mimicks a space-to-ground telemetry packet (TM):
TM-PACKET ::= SEQUENCE { header TM-HEADER, data TM-DATA OPTIONAL } with TM-HEADER ::= SEQUENCE { applicationProcessID INTEGER(0..2047), grouping-flags TC-HEADER-SEQUENCE-FLAGS, sequence-count INTEGER(0..16383) }
One of the fields we want to add is at the level of the packet itself: we want to add a packet error control (CRC). Additionally we want to add at the end of the TM-HEADER structure a field that contains the total size of the TM-PACKET record.
We can create a corresponding ACN encoding structure that "adds" the missing fields (in bold):
TM-PACKET [] { header [], data [present-when header.data-field-header-flag], packet-error-control NULL [pattern '0000000000000000'B, align-to-next byte] } TM-HEADER [] { data-field-header-flag BOOLEAN [], applicationProcessID [], grouping-flags [], sequence-count [], packet-length NULL [pattern '0000000000000000'B] }
In your code, you may create the functions that compute the CRC and size after the packet is encoded.
Here is the code you can use:
// A buffer to encode your TM static byte encBuff[TM_PACKET_REQUIRED_BYTES_FOR_ACN_ENCODING]; BitStream bitStrm; BitStream bitStrm_aux; flag ret; int errCode; int i; //telemetry packet to be encoded static TM_PACKET tm_packet = .... // initialize bit stream BitStream_Init(&bitStrm, encBuff, TM_PACKET_REQUIRED_BYTES_FOR_ACN_ENCODING); // Encode value using ACN ret = TM_PACKET_ACN_Encode(&tm_packet, &bitStrm, &errCode, TRUE); // First field to add: get the length of the full packet asn1SccSint encoded_data_length = BitStream_GetLength(&bitStrm); // Encode length field bitStrm_aux.buf = bitStrm.buf; bitStrm_aux.count = bitStrm.count; bitStrm_aux.currentByte = 4; bitStrm_aux.currentBit = 0; BitStream_EncodeConstraintWholeNumber(&bitStrm_aux, encoded_data_length - 6, 0, 0xFFFF); //encode crc field; bitStrm_aux.buf = bitStrm.buf; bitStrm_aux.count = bitStrm.count; bitStrm_aux.currentByte = bitStrm.currentByte - 2; bitStrm_aux.currentBit = 0; uint16_t crc = gen_crc16(encBuff, bitStrm.currentByte); // User-defined CRC computation BitStream_EncodeConstraintWholeNumber(&bitStrm_aux, crc, 0, 0xFFFF);
That's it!