|
|
# Technical topic: ASN.1 and ACN - How to add a CRC value to an encoded packet
|
|
|
|
|
|
## <span id="The_need" class="mw-headline">The need</span>
|
|
|
|
|
|
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.
|
|
|
|
|
|
## <span id="Solution_using_ASN.1_and_ACN" class="mw-headline">Solution using ASN.1 and ACN</span>
|
|
|
|
|
|
**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>
|
|
|
|
|
|
## <span id="DEPRECATED_PART" class="mw-headline">DEPRECATED PART</span>
|
|
|
|
|
|
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\! |