Indigresso Wiki

Open Source Stuff for DASH7

User Tools

Site Tools


opentag:otlib:encode

Encode Module (OTlib)

OpenTag uses the Encode Module to encode/decode binary, byte-wise data to/from DASH7 Mode 2 PHY data. Functions from the Encode Module are typically called from within the Radio Module implementation (i.e. the radio driver) when data is being paged-in or paged-out from the radio core. So, the kernel and user applications never really need to interface with the Encode Module at all.

Module Design & Features

The Encode Module is designed to implement all of the features of the DASH7 Mode 2 PHY. In summary, these are a method of PN9 encoding and a method of FEC encoding. The Encode Module also manages CRC calculation transparently, via the CRC Module, so the kernel and user application never need to call the CRC module, either (unless they are using it for different purposes than radio communication).

Software and Hardware Codecs

The Encode Module is implemented with a lot of preprocessor directives, so that only the parts that need to get compiled are actually compiled. For example, if you are using a Radio core that has PN9 and FEC built in (such as TI CC1101) the PN9 and FEC codecs will not get compiled, and the radio core will do these processes in hardware. Thus, it is important to make sure that you configure your radio driver appropriately (all officially supported radio drivers already have optimized configuration files). If your radio core does not have the ability to do the encoding in HW, then the Encode Module software codecs will get compiled, and they will be used.

Data Elements

The Encode Module keeps a local struct called “em2.” So far there is nothing outside OTlib/encode_M2.c that uses it, but it is exposed anyway. There are several functions available in the Encode Module, em2_remaining_frames(), em2_remaining_bytes(), and em2_complete(), which are intended to be convenient interfaces with the em2 struct. The Radio Module uses these functions in place of accessing the actual struct. The functions themselves are typically inlined by the compiler.

Using the Encoder/Decoder

One good reference is a radio driver C file, such as OTradio/CC430/radio_CC430.c. The basic way the Encode Module is used is described below.

1. Prepare Encoder/Decoder

The Encoder/Decoder needs to be prepared, so that it initializes its em2 struct properly and selects the type of codec that needs to be used. Basically, you will just call these two functions together to prepare the Encoder (same for decoder)

em2_encode_newpacket();    //em2_decode_newpacket() for decode
em2_encode_newframe();     //em2_decode_newframe() for decode

2. Encode/Decode New Data

If you are encoding, you need to encode the data before TX'ing it on the radio. If you are decoding, you need to RX it on the radio before there is any data to decode. The methods for managing the data transfer from the radio core are not part of the Encode Module (they are part of the radio driver). However, the Encode Module will access the radio core once the radio driver tells it that the radio core is ready to have encoded data paged-in or encoded data paged-out (which needs decoding). The Encode Module uses the radio interface's radio_rxopen() and radio_txopen() functions to judge when the page is done. Here is a typical implementation of encoding:

em2_encode_data();

Note that the encoder must be initialized with step 1, before em2_encode_data() can be used. em2_encode_data() is actually a function pointer that gets linked to the encode function it needs to use. This design allows many different combinations of HW and SW encoding to be used, while the implementation on the radio driver stays simple. em2_encode_data() will automatically fill the radio core FIFO and then stop. Also note that some radio cores need to load the FIFO before starting TX, and others need to load the FIFO after starting TX.

3. Controlling Subsequent Paging

Every packet has at least one page of data. The size of a page depends on the encoding type used and the size of the radio core's FIFO. Sometimes, there needs to be more than one page. The radio driver needs to manage the paging of data to/from the Encode Module and the radio core. Below is an example from OTradio/CC430/radio_CC430.c that shows the TX data process using the Encode Module functions.

void rm2_txdata_isr() {
    /// Continues where rm2_txcsma() leaves off.
    switch ( (radio.state >> RADIO_STATE_TXSHIFT) & (RADIO_STATE_TXMASK >> RADIO_STATE_TXSHIFT) ) {

        /// 4. Continuous TX'ing of a single packet data
        case (RADIO_STATE_TXDATA >> RADIO_STATE_TXSHIFT): {
        rm2_txpkt_TXDATA:
            /// Buffer needs filling, frame is not done
            if (em2_remaining_bytes() != 0) {
                em2_encode_data();
                break;
            }

            /// Packet flooding.  Only needed on devices that can send M2AdvP
#           if (SYS_FLOOD == ENABLED)
            if (radio.flags & RADIO_FLAG_FLOOD) {
                radio.evtdone(2, 0);
                txq.getcursor = txq.front;
                em2_encode_newframe();
                goto rm2_txpkt_TXDATA;
            }
#           endif

            /// If the frame is done (em2_remaining_bytes() == 0) and there are
            /// no more frames to transmit, then this interrupt is due to a low
            /// threshold, and we just need to turn-off the threshold interrupt
            /// and wait for the last bit of data to get sent.
            if (em2_remaining_frames() == 0) {
                radio.state = RADIO_STATE_TXDONE;
                RFCONFIG_TXFIFOLOW_INTOFF();
                break;
            }

            /// If the frame is done, but more need to be sent (e.g. MFP's)
            /// queue it up.  The additional encode stage is there to fill up
            /// what's left of the buffer.
#           if (M2_FEATURE(MULTIFRAME) == ENABLED)
            if (radio.flags & RADIO_FLAG_FRCONT) {
                q_rebase(&txq, txq.getcursor);
                radio.evtdone(1, 0);        //callback action for next frame
                em2_encode_newframe();
                txq.front[1] = phymac[0].tx_eirp;
                em2_encode_data();
                goto rm2_txpkt_TXDATA;
            }
#           endif
        }

        /// 5. Conclude the TX process, and wipe the radio state
        //     turn off any remaining TX interrupts
        case (RADIO_STATE_TXDONE >> RADIO_STATE_TXSHIFT):
            sub_kill(0, 0);
            break;

        /// Bug trap
        default:
            sub_kill(RM2_ERR_GENERIC, 0);
            break;
    }
}

OTlib/encode.h

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

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


typedef struct {
    ot_u8*  fr_info;
    ot_int  bytes;
    ot_int  state;              // could be changed to ot_s8

#   if ( (RF_FEATURE(PN9) != ENABLED) || \
         ((M2_FEATURE(FEC) == ENABLED) && (RF_FEATURE(FEC) != ENABLED)) )
        Twobytes PN9_lfsr;
#   endif

#   if ((M2_FEATURE(FEC) == ENABLED) && (RF_FEATURE(FEC) != ENABLED))
        ot_int  databytes;
        ot_int  path_bits;
        ot_u8   last_buffer;
        ot_u8   current_buffer;
        ot_u8   cost_matrix[2][8];
#   endif

} em2_struct;

extern em2_struct   em2;




/** @brief  Initializes the encoder for a new Mode 2 packet
  * @param  None
  * @retval None
  * @ingroup Encode
  */
void em2_encode_newpacket();


/** @brief  Initializes the decoder for a new Mode 2 packet
  * @param  None
  * @retval None
  * @ingroup Encode
  *
  * The decoding engine needs to be initialized at the packet level.  It is
  * conceivable that a packet may consist of multiple frames.
  */
void em2_decode_newpacket();


/** @brief  Initializes the encoder for encoding a Mode 2 Frame
  * @param  None
  * @retval None
  * @ingroup Encode
  */
void em2_encode_newframe();
//ot_int em1_encode_newframe( );


/** @brief  Initialize the frame manager for decoding a Mode 2 Frame
  * @param  None
  * @retval None
  * @ingroup Encode
  *
  * The decoding engine is at the packet level, but the calculation of CRC and
  * management of the data queue are done at the frame level.  So to manage
  * the frame, this function needs to be run before a frame comes in.
  */
void em2_decode_newframe();
//void em1_decode_newframe(ot_u32 header); 


/** @brief  Returns the number of frames following the current one
  * @param none
  * @retval ot_int      value from em2.frames
  * @ingroup Encode
  */
ot_int em2_remaining_frames();


/** @brief  Returns bytes remaining to encode or decode
  * @param none
  * @retval ot_int      value from em2.bytes
  * @ingroup Encode
  *
  * For encoding, the value returned is the number of unencoded bytes that are
  * remaining to be encoded.  For decoding, the value is the number of encoded
  * bytes that are remaining to be decoded.
  */
ot_int em2_remaining_bytes();


/** @brief  Returns True when the encoding/decoding is complete
  * @param none
  * @retval ot_bool     true on (em2.bytes == 0) && (em2.frames == 0)
  * @ingroup Encode
  */
ot_bool em2_complete();


/** @par Mode 2 Encode Data function pointer
  * The function @c em2_encode_newframe() sets this function pointer to the 
  * appropriate encode function, based on the queue options field and compiled
  * in feature settings.
  * 
  * @fn     em2_encode_data
  * @brief  None
  * @param  q           (Queue*) queue to load data for encoding
  * @retval None
  * @ingroup Encode
  */
extern void (*em2_encode_data)();


/** @par Decode function pointer
  * The function @c decode_newpacket sets this function pointer to the 
  * appropriate decode function, based on input to @c decode_newpacket
  *
  * @fn     decode_data
  * @brief  Decodes comm data into byte-wise data
  * @param  None
  * @retval None
  * @ingroup Encode
  */
extern void (*em2_decode_data)();
opentag/otlib/encode.txt · Last modified: 2012/03/09 17:09 by jpnorair