Indigresso Wiki

Open Source Stuff for DASH7

User Tools

Site Tools


CRC Module (OTlib)

DASH7 Mode 2 and most other communication standards use some version of CRC. OpenTag implements the DASH7 CRC spec via this CRC Module in OTlib, and it provides both software CRC and support for hardware CRC. In practice, the CRC Module is coupled tightly to the Encode Module, and the user does not really need to call the CRC Module directly.

Design Features

OpenTag's CRC Module is designed to be used in a byte-by-byte, streaming manner. Therefore, the CRC Module is initialized, and then each time a byte needs to be CRC'ed, a CRC Module function is called. The CRC Module will automatically manage the length of the stream, and it will automatically append the CRC value to the end of the stream.

Module Re-Use

In a typical object-oriented workflow, the CRC Module would be implemented as an object that gets malloc-ed when initialized and free-ed when the process is done. You could have as many simultaneous CRC processes in progress as you have memory to malloc as CRC objects.

But, OpenTag assumes no malloc, nor is it designed to be object-oriented.

Therefore, the CRC Module has some object-like properties, but it is really a module and not an object because it cannot be reused. The CRC Module is intended to work with DASH7 communication, and that's about it. The impact of making it an object – even a statically allocated one – is a bunch of pointer overhead that just isn't necessary in OpenTag.

Streaming Computation

As mentioned, the CRC module does most things automatically. It is always used with Queues in OpenTag, although it is implemented to work with more generic data (any kind of byte stream). The streaming CRC process will track the number of bytes remaining to compute, and when you start inputting bytes beyond this amount, the CRC Module will dump the computed CRC value to this location in the stream. If you continue to input bytes after the amount in the stream is over, and after the CRC value has been completely dumped onto the end of the stream, the CRC Module will do nothing.

Example Usage

  1. Call the initializer: crc_init_stream(ot_int stream_size, ot_u8* stream_addr)
  2. Call the calculation function: crc_calc_stream()
  3. Continue calling the calculation function for as many bytes in stream_size
  4. If TX'ing, the process is done.
  5. If RX'ing, call crc_check() to see if the CRC passed (returns True/False)

You may also use the function crc_calc_block(ot_int block_size, ot_u8 *block_addr) to perform a non-streaming CRC computation. This function will run all at once, and it will return the CRC value (which you must append yourself).


The code from crc16.h is pasted below, although you can also check the doxygen code documentation.

#include "OT_config.h"
#include "OT_types.h"

/** @typedef crc_struct
  * @ingroup CRC16
  * Iterative storage of CRC16 value and cursor
typedef struct {
    ot_u8*      cursor;
    ot_u8*      end;
    ot_u16      val;
    void        (*stream)();
} crc_struct;

extern crc_struct crc;

extern const ot_u16 crc_table[256];

/** @brief Calculates the CRC16 for a complete data block
  * @param block_size : (ot_int) number of bytes in the data block
  * @param block_addr : (ot_u8*) address of the data block
  * @retval ot_u16 : CRC16 value
  * @ingroup CRC16
ot_u16 crc_calc_block(ot_int block_size, ot_u8 *block_addr);

/** @brief Initializes streaming CRC16 engine
  * @param stream_size  (ot_int) length of datastream
  * @param stream_addr  (ot_u8*) pointer to start of datastream
  * @retval None
  * @ingroup CRC16
  * This must be run prior to engaging a streaming CRC calculation.  Only one
  * streaming CRC object may exist, so right now it's impossible to do streaming
  * CRC on parallel/concurrent data-streams.  init_crc_stream will zero the
  * crc_partial global variable before operating.
  * @note Make sure to set stream_size to 255 (or whatever is your max stream)
  *       if you are using a type of datastream that has variable length.  Use
  *       crc_update_stream() to change to the correct stream length once you
  *       find out what it is.
void crc_init_stream(ot_int stream_size, ot_u8* stream_addr);

/** @brief Calculates the CRC from the stream, and eventually writes it.
  * @param None
  * @retval None
  * @ingroup CRC16
  * This is state-based.  When the stream is done, the value of the CRC 
  * calculated from the stream data will be inserted onto the end of the stream
  * automatically.  If you keep calling it forever, it will keep writing the
  * CRC to the end of the stream.  It will not go off and start doing weird
  * shit to nearby data.
void crc_calc_stream();

/** @brief Updates the end of the CRC stream
  * @param new_end      (ot_u8*) new end pointer for crc stream
  * @retval None
  * @ingroup CRC16
  * Useful for receiving datastreams where the stream length is not known ahead 
  * of decoding.  Use this function to tell the CRC streamer where the end of
  * the stream is, once you know where it is.
void crc_update_stream(ot_u8* new_end);

/** @brief Checks the CRC in the stream against the known, good value.
  * @param None
  * @retval ot_bool : TRUE if CRC passes check. 
  * @ingroup CRC16
ot_bool crc_check();

/** @brief Gets the CRC value, as calculated by the most recent CRC operation
  * @param none
  * @retval ot_u16      The CRC value
  * @ingroup CRC16
ot_u16 crc_get();
opentag/otlib/crc.txt · Last modified: 2012/03/09 18:04 by jpnorair