Indigresso Wiki

Open Source Stuff for DASH7

User Tools

Site Tools


opentag:otlib:radio_h

Radio Interface (OTlib)

The OpenTag radio interface provides a common set of data elements and functions that OTlib code can use with the OTradio drivers (each supported radio tends to have its own driver implementation).

Basic Features

The common radio interface includes functions for mode-control (such as power-up, power-down, etc), reading or writing data to the radio FIFO, and state-control (go into RX, go into TX, etc). As implemented, the Kernel works on mode-control and state-control, and the Encode Module uses the read and write features. User applications don't normally need to call any radio functions or access radio data elements, but OpenTag will never prevent users from doing interesting things. So, the radio interface exposes most features openly to the user, even though using them in the application layer could be dangerous.

phymac struct

The Radio interface stores some parameters in the “phymac” struct. These are momentarily buffered parameters, pulled from the channel configuration data element of the DASH7 filesystem when a radio front end is accessing a channel.

This struct is actually an array of structs, but in most radio implementations it is an array of size 1. Some radio components are double-ended (SX1282, MLX73290) and could potentially support a phymac struct array of size 2, allowing simultaneous usage of the two front ends, with different channels. For the most part, just assume that the phymac struct array is size 1 and that OpenTag can only access one channel at a time.

"radio_..." Functions

The Radio interface has several functions named as “radio_…()”. These are very generic functions that are important to any kind of communication, not just DASH7 Mode 2. Using previous descriptions (from above) these functions are the mode-control, read, and write features.

"rm2_..." Functions

The “rm2_…” functions are state-control features that are designed especially for Mode 2. “rm2…()” functions are typically called by the kernel, or internally within the radio module itself.

OTlib/radio.h

The only Radio file in OTlib is the Radio header file. It defines the common interface that all Radio Module implementations must abide. The code from radio.h is pasted below, although you can also check the doxygen code documentation.

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

#include "system.h"





/** Mode 2 PHY-MAC variables
  * These variables come from the Channel Configuration ISFS File, and are 
  * stored here (and possibly altered slightly) before the channel is used by
  * the PHY.  Some of these parameters measure RSSI or EIRP.  These assume a
  * perfectly matched, 100% efficient antenna.  You will have to offset them
  * to account for the losses of your platform's antenna and matching circuit.
  * You will probably have to figure those out by testing, but if you are just 
  * hacking around, 6 dB attenuation usually suits a compact 433 MHz antenna
  * system, 3 dB for a monopole whip, 1-2 dB for dipole.
  *
  * phymac_struct description
  * 
  * tg              (ot_int) channel guard time (in ti units) as determined by
  *                 the spec.  It is 2, 3, 5, or 10 ti depending on the channel.
  * 
  * channel         (ot_u8) channel id to use
  *
  * autoscale       (ot_u8) A code that specifies an algorithm used for adaptive
  *                 scaling of tx eirp and/or link budget filtering.
  *
  * tx_eirp         (ot_u8) A value for tx eirp (radiated power) that is applied
  *                 to transmitted packets. eirp dBm = (0x7F & tx_eirp)/2 + 40
  *
  * link_qual       (ot_u8) Used for link quality filtering of received packets.
  *                 Mode 2 packets report TX EIRP in the header.  Received EIRP
  *                 minus received RSSI yields the packet link quality (reverse
  *                 of link budget).  Lower number is better quality.  This
  *                 derived value must be less than the programmed value for the
  *                 packet to pass the link quality filter.
  *
  * cs_rssi         (ot_u8) the min RSSI value to validate carrier sense, for 
  *                 receiving packets.  It should be large enough so that the
  *                 data can be reliably decoded at an acceptable BER.
  *
  * cca_rssi        (ot_u8) the max RSSI value to validate clear chan assesment 
  *                 for CSMA-CA.  It is usually lower than the decodable min
  *                 RSSI, in order to prevent "hidden node problem" in CSMA.
  */
typedef struct {
    ot_int  tg;
    ot_u8   channel;
    ot_u8   autoscale;
    ot_u8   tx_eirp;
    ot_u8   link_qual;
    ot_u8   cs_thr;
    ot_u8   cca_thr;
} 
phymac_struct;



/** PHY-MAC Channel Data
  * The MAC/System level rx chanlist maps to this array.  Mode 2 only supports
  * single channel transmit, so transmit channel data is always phymac[0].  In
  * most systems, this array will only be length 1, because most systems are 
  * SISO hosts.
  */
#ifndef M2_PARAM_MI_CHANNELS
#   define M2_PARAM_MI_CHANNELS  1
#endif
  
extern phymac_struct   phymac[M2_PARAM_MI_CHANNELS];




/** Recasting of some radio attributes
  * Most radios we use have internal FIFO.  But the buffer could also be a DMA
  * on the MCU.  If you do not have a DMA on your micro, make sure you are using
  * a radio with a FIFO because you need to have one or the other.
  */
#if (RF_FEATURE(FIFO) == ENABLED)
#   define RADIO_BUFFER_TXMAX        RF_FEATURE(TXFIFO_BYTES)
#   define RADIO_BUFFER_RXMAX        RF_FEATURE(RXFIFO_BYTES)
#else
#   define RADIO_BUFFER_TXMAX        MCU_FEATURE(RADIODMA_TXBYTES)
#   define RADIO_BUFFER_RXMAX        MCU_FEATURE(RADIODMA_RXBYTES)
#endif


#define RADIO_ERROR_NDATA   
#define RADIO_ERROR_TDATA   


#if (PLATFORM_TYPE == SIMULATOR)
    /** Air buffer (simulator only)
      * For simulation, the TX puts information to the air buffer, and RX 
      * gets information from the air buffer.
      */
    extern ot_int air_i;
    extern ot_u8 air[520];
#endif




/** Basic Mode 2 Channel IDs
  * These may or may not be useful
  */

// Base Transport Channel
#define RM2_CHAN_BASE       0x00

// Legacy Transport Channel (Mode 1)
#define RM2_CHAN_LEGACY     0x01

// Normal Channels
#define RM2_CHAN_NORMAL_0   0x10
#define RM2_CHAN_NORMAL_2   0x12
#define RM2_CHAN_NORMAL_4   0x14
#define RM2_CHAN_NORMAL_6   0x16
#define RM2_CHAN_NORMAL_8   0x18
#define RM2_CHAN_NORMAL_A   0x1A
#define RM2_CHAN_NORMAL_C   0x1C
#define RM2_CHAN_NORMAL_E   0x1E

// Turbo Channels
#define RM2_CHAN_TURBO_1    0x21
#define RM2_CHAN_TURBO_3    0x23
#define RM2_CHAN_TURBO_5    0x25
#define RM2_CHAN_TURBO_7    0x27
#define RM2_CHAN_TURBO_9    0x29
#define RM2_CHAN_TURBO_B    0x2B
#define RM2_CHAN_TURBO_D    0x2D

// Blink Channels
#define RM2_CHAN_BLINK_2    0x32
#define RM2_CHAN_BLINK_C    0x3C

// Wildcard Channel
#define RM2_CHAN_WILDCARD   0x7F

// MAC configuration of PHY parameters via synchronizer packet
#define RM2_ENCODING_FEC    0x80

#define RM2_ERR_KILL        -1
#define RM2_ERR_CCAFAIL     -2
#define RM2_ERR_BADCHANNEL  -3
#define RM2_ERR_TIMEOUT     -4
#define RM2_ERR_LINK        -5
#define RM2_ERR_GENERIC     -6





/** Radio Module control    <BR>
  * ========================================================================<BR>
  * Used for module configuration and utility
  */

/** @brief Initializes Radio
  * @param None
  * @retval None
  * @ingroup Radio
  *
  * radio_init() turns-on, initializes, and enables the radio module by setting 
  * device-specific default values for the radio part and MCU facilities.
  *
  * A simple practice is to call init_radio() before looking for the wakeup
  * tone. By default, the Protocol module handles this automatically. Otherwise,
  * usage of init_radio() is somewhat device-dependent (see the device-specific
  * initialization function for more information).  Typically, it needs to be
  * done whenever:
  *  A. The radio is being turned-on
  *  B. the registers on the radio device need resetting to defaults
  *  C. the peripherals on the MCU need to be reconfigured for UHF usage
  */
void radio_init();



/** @brief  Returns the RSSI value of the most recent reception.
  * @param None
  * @retval ot_int      RSSI of last reception in units of 0.5 dBm
  * @ingroup Radio
  *
  * This function is callable outside the process of a dialog, because it 
  * returns the RSSI detected during the most recent receive operation, not the
  * instantaneous RSSI.  RSSI detection happens early in the course of each RX,
  * so in the case that this function is called during process of a dialog, it 
  * will return the RSSI of the current reception.
  *
  * On most hardware, the RSSI range of -100 to -40 dBm [-200 to -80 returned] 
  * is the area of interest.
  */
ot_int radio_rssi();



/** @brief Debug function for checking radio buffer
  * @param index        (ot_int) buffer index
  * @retval ot_u8       buffered value at index
  * @ingroup Radio
  *
  * This function is primarily for testing & hacking purposes.  On certain
  * platforms there may not be a radio buffer localized on the MCU, and on these
  * builds the functionality of radio_buffer() is not guaranteed.
  */
ot_u8 radio_buffer(ot_int index);








/** Radio Core control    <BR>
  * ========================================================================<BR>
  * - Basic radio control functions         <BR>
  * - called mostly by Encode module        <BR>
  */

/** @brief  Turns off the radio transceiver
  * @param None
  * @retval None
  * @ingroup Radio
  *
  * The transceiver is "off" when it is not retaining its registers.  This mode
  * usually is extremely low in power, because only leakage current is used.
  * 
  * The radio_init() function must be called to bring radio from the off state
  * into the sleep state.
  */
void radio_off();



/** @brief Disables all Events/Interrupts used by the radio module
  * @param None
  * @retval None
  * @ingroup Radio
  *
  * In certain cases, latent interrupt bits don't get cleared when they should
  * be (like if you manually reset a HW RF Core MAC).  This function can be 
  * called to make sure the radio doesn't keep sending interrupts when you want
  * it to just go idle and shut-up.
  */
void radio_gag();



/** @brief  Puts the transceiver core in the sleep mode.
  * @param  None
  * @retval None
  * @ingroup Radio
  *
  * Different radio HW may have different names for sleep mode.  In any case,
  * radio_sleep() will put the radio into the mode that is lowest power, where
  * register contents are retained.  On HW that I've studied, going from sleep 
  * to active RX or TX takes anywhere from 400 µs to 2000 µs.  Here are specs 
  * from the chips I like most:
  *
  * CC430:      ~400 µs      (CC430 calibrates after every fourth TX/RX usage)
  * ADµCRF101:  ~600 µs
  * SX1212:     ~1500 µs     (Integer PLL is slow but allows 2.5mA RX)
  */
void radio_sleep();



/** @brief  Puts the transceiver core in idle mode.
  * @param  None
  * @retval None
  * @ingroup Radio
  *
  * Different radio HW may have different names for idle mode.  On some chips it
  * may be called "FS on" (Frequency Synthesizer On).  Going from idle to active
  * RX or TX is usually quite fast.  Power used in idle mode varies, but it is
  * usually between 0.5mW and 5mW.
  */
void radio_idle();



/** @brief Flushes the TX buffer
  * @param None
  * @retval None
  * @ingroup Radio
  *
  * The radio buffer is either implemented in the radio core (HW) or via SW in
  * the radio driver module.  In both cases, this flushes the TX buffer, 
  * however, it may also flush the RX buffer if they are co-located.
  */
void radio_flush_tx();

/** @brief Flushes the RX buffer
  * @param None
  * @retval None
  * @ingroup Radio
  *
  * The radio buffer is either implemented in the radio core (HW) or via SW in
  * the radio driver module.  In both cases, this flushes the RX buffer, 
  * however, it may also flush the TX buffer if they are co-located.
  */
void radio_flush_rx();



/** @brief Puts a byte to the TX radio buffer
  * @param databyte     (ot_u8) Byte to put on TX
  * @retval None
  * @ingroup Radio
  */
void radio_putbyte(ot_u8 databyte);

/** @brief Puts four bytes to the TX radio buffer
  * @param databyte     (ot_u8*) byte array to the four bytes
  * @retval None
  * @ingroup Radio
  * 
  * This function exists primarily as a way to dump a 32 bit block that has
  * come from the FEC interleaver.  You can supply an ot_ulong (or ot_long) as
  * the argument by this method: (ot_u8*)&(ot_ulong).
  */
void radio_putfourbytes(ot_u8* data);



/** @brief Gets a byte from the RX radio buffer
  * @param none
  * @retval ot_u8       byte from radio RX
  * @ingroup Radio
  */
ot_u8 radio_getbyte();

/** @brief Gets 4 bytes from the RX radio buffer
  * @param data         (ot_u8*) pointer to an array to load into
  * @retval none
  * @ingroup Radio
  *
  * This function exists primarily as a way to grab a 32 bit block to put into
  * FEC deinterleaver.  You can supply an ot_ulong (or ot_long) as the argument
  * by this method: (ot_u8*)&(ot_ulong).
  */
void radio_getfourbytes(ot_u8* data);



/** @brief Checks the RX buffer to see if there is at least 1 more byte in it
  * @param none
  * @retval ot_bool     True if at least 1 more byte in buffer
  * @ingroup Radio
  */
ot_bool radio_rxopen();

/** @brief Checks the RX buffer to see if there are at least 4 more bytes in it
  * @param none
  * @retval ot_bool     True if at least 4 more bytes in buffer
  * @ingroup Radio
  */
ot_bool radio_rxopen_4();



/** @brief Checks the TX buffer to see if at least 1 more byte can fit in it
  * @param none
  * @retval ot_bool     True if at least 1 more byte can fit
  * @ingroup Radio
  */
ot_bool radio_txopen();

/** @brief Checks the TX buffer to see if at least 4 more bytes can fit in it
  * @param none
  * @retval ot_bool     True if at least 4 more bytes can fit
  * @ingroup Radio
  */
ot_bool radio_txopen_4();









/****************************************************************
  * Mode 2 Radio Functions                                      *
  * - radio I/O specific to the way DASH7 Mode 2 works          *
  * - called in system.c, probably nowhere else                 *
  ***************************************************************/

/** @brief  Returns default Tgd (guard period) for the specified channel
  * @param  chan_id     (ot_u8) Mode 2 channel ID
  * @retval ot_int      Tgd in ticks (units: 1/1024 seconds)
  * @ingroup Radio
  */
ot_int rm2_default_tgd(ot_u8 chan_id);



/** @brief  Returns estimated time until the packet is completed
  * @param  pkt_bytes   (ot_u8) number of bytes left in the packet
  * @retval ot_int      Duration of packet in ticks (units: 1/1024 seconds)
  * @ingroup Radio
  * @sa rm2_scale_codec()
  *
  * Basically identical to rm2_scale_codec(), except that some padding is added
  * to the output in order to account for FIFO lag of the radio.
  */
ot_int rm2_pkt_duration(ot_int pkt_bytes);



/** @brief  Returns estimated time until the buffered data is airborne
  * @param  pkt_bytes   (ot_u8) number of bytes (or bytes left) in the packet
  * @retval ot_int      Duration of packet in ticks (units: 1/1024 seconds)
  * @ingroup Radio
  * @sa rm2_pkt_duration()
  *
  * Basically identical to rm2_scale_codec(), except that some padding is added
  * to the output in order to account for FIFO lag of the radio.
  */
ot_int rm2_scale_codec(ot_int buf_bytes);



/** @brief  Initializes RX engine for "foreground" packet reception
  * @param  channel     (ot_u8) Mode 2 channel ID to look for packet
  * @param  netstate    (ot_u8) Mode 2 network session state (association)
  * @param  est_frames  (ot_int) Estimated number of frames in the next packet
  * @param  callback    (ot_sig2) callback for when RX is done, on error or complete
  * @retval None
  * @ingroup Radio
  * @sa rm2_rxinit_bf
  *
  * Call this to listen for a foreground packet.  A foreground packet contains
  * one or more foreground frames (usually 1), which have a certain format and
  * are subject to a timeout -- if Sync Word is not found by the timeout, the
  * RX is killed.  
  *
  * This is a non-blocking RX.  It starts an interrupt-driven process that runs
  * in the background until the packet is complete, the RX times-out, or the
  * RX is manually killed with rm2_kill().  These are the termination events.
  *
  * A callback function is used when any of the RX termination events occur or
  * any time a frame is successfully received.  Mode 2 supports multiframe 
  * packets, so the callback is used following the concept below:
  * 
  * void callback(ot_int arg1, ot_int arg2)
  * arg1: negative on RX error, 0 on RX complete, positive on frame complete
  * arg2: 0 on frame received successfully, negative on error.
  */
void rm2_rxinit_ff(ot_u8 channel, ot_u8 netstate, ot_int est_frames, ot_sig2 callback);



/** @brief  Initializes RX engine for "background" packet reception
  * @param  channel     (ot_u8) Mode 2 channel ID to look for background flood
  * @param  callback    (ot_sig2) callback for when RX is done, on error or complete
  * @retval None
  * @ingroup Radio
  * @sa rm2_rxinit_ff
  *
  * Basically identical to rm2_rxinit_ff, except that it is used to detect
  * background floods.  Background flood packets follow very specific rules in
  * the Mode 2 specification (they are used mostly for group synchronization).
  * 
  * Background RX terminates once a packet is received, it is killed, or if the
  * channel energy detection (carrier sense) fails.  Background packets contain
  * only one frame each.
  */
void rm2_rxinit_bf(ot_u8 channel, ot_sig2 callback);



/** @brief  Initializes TX engine for "foreground" packet transmission
  * @param  est_frames  (ot_int) Number of frames in packet to transmit
  * @param  callback    (ot_sig2) callback for when TX is done, on error or complete
  * @retval None
  * @ingroup Radio
  * @sa rm2_txinit_bf, rm2_txcsma
  *
  * Call to prepare the TX system and the TX callback for foreground packet.  
  * This function does not actually start TX -- rm2_txcsma() must be called to
  * run the csma-ca routine and kick off the packet.
  *
  * the callback: void callback(ot_int arg1, ot_int arg2)
  * - called on TX termination and whenever a frame is completed
  * - arg 1 is negative on error, 0 on complete, positive if more frames to TX
  * - arg 2 is ignored
  */
void rm2_txinit_ff(ot_int est_frames, ot_sig2 callback);



/** @brief  Initializes TX engine for "background" packet flooding
  * @param  channel     (ot_u8) Mode 2 channel ID to look for background flood
  * @param  callback    (ot_sig2) callback for when RX is done, on error or complete
  * @retval None
  * @ingroup Radio
  * @sa rm2_txinit_ff, rm2_txcsma, rm2_txstop_flood
  * 
  * Similar to rm2_txinit_ff()
  *
  * the callback: void callback(ot_int arg1, ot_int arg2)
  * - called after flood is complete, or when terminated
  * - arg 1 is negative on error, 0 on complete, positive if more frames to TX
  * - arg 2 is ignored
  */
void rm2_txinit_bf(ot_sig2 callback);



/** @brief  Stops the flood harmoniously (finishes the current packet and stops)
  * @param  None
  * @retval None
  * @ingroup Radio
  * @sa rm2_txinit_bf
  * 
  * This will cause the TX callback to occur.
  */
void rm2_txstop_flood();



/** @brief  Multi-call function for CSMA management and TX processing
  * @param  none
  * @retval ot_int      negative: error code/ positive: next event/ -1: TX started
  * @ingroup Radio
  * @sa rm2_txinit_ff, rm2_txinit_bf
  * 
  * Once the TX is queued-up from the init function, call this function to do
  * the CSMA required before TX (CSMA can be disabled by the system module).
  *
  * This function is often implemented as a multi-call function, because there
  * are incremental timeouts involved in the CSMA process.  The system module
  * can manage these timeouts via the return value.  If a positive value is
  * returned, this function must be called again by the system layer to do the
  * next round of CSMA.  If your radio (or radio driver) implements built-in
  * CSMA timing, you can just implement rm2_txcsma to return 0 immediately and
  * then use the callback established in the rm2_txinit function to tell the 
  * System module that there is an error related to CSMA.
  */
ot_int rm2_txcsma();


/** @brief  Terminates RX or TX process (typically for internal use)
  * @param  None
  * @retval None
  * @ingroup Radio
  */
void rm2_kill();


/** @brief  ISR that is called internally when a sync word is detected in RX
  * @param  None
  * @retval None
  * @ingroup Radio
  * 
  * __Best to ignore__.  If you are an expert you can call this to force radio 
  * actions, which may force callbacks.
  */
void rm2_rxsync_isr();



/** @brief  ISR that is called internally when FF RX times out
  * @param  None
  * @retval None
  * @ingroup Radio
  * 
  * __Best to ignore__.  If you are an expert you can call this to force radio 
  * actions, which may force callbacks.
  */
void rm2_rxtimeout_isr();



/** @brief  ISR that is called internally whenever the RX FIFO fills up
  * @param  None
  * @retval None
  * @ingroup Radio
  * 
  * __Best to ignore__.  If you are an expert you can call this to force radio 
  * actions, which may force callbacks.
  */
void rm2_rxdata_isr();



/** @brief  ISR/general-routine that is called when the RX process ends.
  * @param  None
  * @retval None
  * @ingroup Radio
  * 
  * __Best to ignore__.  If you are an expert you can call this to force RX 
  * termination.
  */
void rm2_rxend_isr();



/** @brief  ISR that is called internally whenever TX FIFO needs filling
  * @param  None
  * @retval None
  * @ingroup Radio
  * 
  * __Best to ignore__.  If you are an expert you can call this to force radio 
  * actions, which may force callbacks.
  */
void rm2_txdata_isr();
opentag/otlib/radio_h.txt · Last modified: 2012/03/09 16:25 by jpnorair