Defines

Application Programming Interface (API) for the Gazell Link Layer
[Gazell Link Layer (gzll)]

Defines

#define GZLL_CRYPT_PAYLOAD_OVERHEAD   5
#define GZLL_MAX_INTERNAL_PAYLOAD_LENGTH   32
#define GZLL_MAX_CRYPT_PAYLOAD_LENGTH   (GZLL_MAX_INTERNAL_PAYLOAD_LENGTH - GZLL_CRYPT_PAYLOAD_OVERHEAD)
#define GZLL_MAX_PAYLOAD_LENGTH   GZLL_MAX_ACK_PAYLOAD_LENGTH
#define GZLL_INTERNAL_FW_PAYLOAD_LENGTH   GZLL_MAX_FW_PAYLOAD_LENGTH
#define GZLL_INTERNAL_ACK_PAYLOAD_LENGTH   GZLL_MAX_ACK_PAYLOAD_LENGTH
#define GZLL_MAX_CRYPT_PIPES_VAL   0x00
#define GZLL_INTERNAL_PAYLOAD_LENGTH   GZLL_INTERNAL_ACK_PAYLOAD_LENGTH
#define GZLL_US_PR_BYTE   8
#define GZLL_HAL_DATARATE   HAL_NRF_1MBPS
#define GZLL_HOST_CE_LOW_IDLE_DELAY   14
#define GZLL_AUTO_RETR_DELAY   250

General functions

These functions are useful on both the Host and Device side.


void gzll_init (void)
void gzll_set_address (hal_nrf_address_t pipe, const uint8_t *address)
void gzll_set_channels (uint8_t *channels, uint8_t size)
void gzll_set_param (gzll_dyn_params_t param, uint16_t value)
uint16_t gzll_get_param_max (gzll_dyn_params_t param)
uint16_t gzll_get_param (gzll_dyn_params_t param)
gzll_states_t gzll_get_state (void)
_Bool gzll_radio_active ()
void gzll_goto_idle (void)
_Bool gzll_rx_data_ready (uint8_t pipe)
uint8_t gzll_get_rx_data_ready_pipe_number (void)
_Bool gzll_rx_fifo_read (uint8_t *dst, uint8_t *length, uint8_t *pipe)
_Bool gzll_rx_power_high (void)
uint8_t gzll_get_channel_tab_size ()
void gzll_get_channels (uint8_t *channels)
void gzll_get_address (uint8_t pipe, uint8_t *address)
void gzll_tx_fifo_flush (void)
void gzll_rx_fifo_flush (void)
void gzll_set_crypt_key (uint8_t pipe, uint8_t *key128)
void gzll_get_crypt_key (uint8_t pipe, uint8_t *key128)
void gzll_radio_isr_function (void)
void gzll_timer_isr_function (void)

Device functions

These functions are only useful for a Device application.


_Bool gzll_dev_mode2_rx_channel_match (void)
_Bool gzll_tx_data (const uint8_t *src, uint8_t length, uint8_t pipe)
_Bool gzll_tx_success (void)
uint16_t gzll_get_tx_attempts (void)
uint16_t gzll_get_tx_channel_switches (void)

Host functions

These functions are only useful for a Host application.


void gzll_rx_start (void)
_Bool gzll_ack_payload_write (const uint8_t *src, uint8_t length, uint8_t pipe)
#define gzll_rx_stop()   gzll_goto_idle()

Hardware dependent functions

These functions must be customized for the MCU being used.


void gzll_set_timer_period (uint16_t period)

Define Documentation

#define gzll_rx_stop (  )    gzll_goto_idle()

Convenience function.

Definition at line 583 of file gzll.h.

#define GZLL_CRYPT_PAYLOAD_OVERHEAD   5

Definition at line 635 of file gzll.h.

#define GZLL_MAX_INTERNAL_PAYLOAD_LENGTH   32

Definition at line 636 of file gzll.h.

#define GZLL_MAX_CRYPT_PAYLOAD_LENGTH   (GZLL_MAX_INTERNAL_PAYLOAD_LENGTH - GZLL_CRYPT_PAYLOAD_OVERHEAD)

Definition at line 637 of file gzll.h.

#define GZLL_MAX_PAYLOAD_LENGTH   GZLL_MAX_ACK_PAYLOAD_LENGTH

Definition at line 642 of file gzll.h.

#define GZLL_INTERNAL_FW_PAYLOAD_LENGTH   GZLL_MAX_FW_PAYLOAD_LENGTH

Definition at line 657 of file gzll.h.

#define GZLL_INTERNAL_ACK_PAYLOAD_LENGTH   GZLL_MAX_ACK_PAYLOAD_LENGTH

Definition at line 658 of file gzll.h.

#define GZLL_MAX_CRYPT_PIPES_VAL   0x00

Definition at line 662 of file gzll.h.

#define GZLL_INTERNAL_PAYLOAD_LENGTH   GZLL_INTERNAL_ACK_PAYLOAD_LENGTH

Definition at line 686 of file gzll.h.

#define GZLL_US_PR_BYTE   8

Definition at line 701 of file gzll.h.

#define GZLL_HAL_DATARATE   HAL_NRF_1MBPS

Definition at line 702 of file gzll.h.

#define GZLL_HOST_CE_LOW_IDLE_DELAY   14

Definition at line 703 of file gzll.h.

#define GZLL_AUTO_RETR_DELAY   250

Definition at line 707 of file gzll.h.


Function Documentation

void gzll_init ( void   )

Initialization function for the Gazell Link Layer.

This function must be called before any other Gazell functions.

Definition at line 384 of file gzll.c.

{
  uint8_t temp_adr[GZLL_ADDRESS_WIDTH] = GZLL_DEFAULT_ADDRESS_PIPE1;

  gzll_interupts_disable_rfck_enable();
  GZLL_RFCE_LOW();

  hal_nrf_enable_ack_payload(true);
  hal_nrf_enable_dynamic_payload(true);
  hal_nrf_setup_dynamic_payload(0xff);

  /*
  Initialize status variables.
  */
  gzll_channel_tab_index = 0;
  gzll_channel_tab_size = GZLL_DEFAULT_CHANNEL_TAB_SIZE;

  gzll_pending_goto_idle = false;
  gzll_timer_period_modified = false;

  gzll_current_tx_pipe = 0;
  gzll_pending_tx_start = false;
  gzll_tx_setup_modified = true;
  gzll_rx_setup_modified = true;
  gzll_radio_active_f = false;
  gzll_tx_success_f = true;

  gzll_sync_period = 0;
  gzll_sync_on = false;

  gzll_rx_dr = false;
  gzll_rx_power_high_f = false;
  gzll_ack_rx_pipe_fifo_cnt = 0;

  /*
  Set up default addresses.
  */
  hal_nrf_set_address(HAL_NRF_PIPE0, gzll_p0_adr);
  hal_nrf_set_address(HAL_NRF_PIPE1, temp_adr);

  temp_adr[0] = GZLL_DEFAULT_ADDRESS_PIPE2;
  hal_nrf_set_address(HAL_NRF_PIPE2, temp_adr);

  temp_adr[0] = GZLL_DEFAULT_ADDRESS_PIPE3;
  hal_nrf_set_address(HAL_NRF_PIPE3, temp_adr);

  temp_adr[0] = GZLL_DEFAULT_ADDRESS_PIPE4;
  hal_nrf_set_address(HAL_NRF_PIPE4, temp_adr);

  temp_adr[0] = GZLL_DEFAULT_ADDRESS_PIPE5;
  hal_nrf_set_address(HAL_NRF_PIPE5, temp_adr);

  /*
  Set up default channel.
  */
  hal_nrf_set_rf_channel(gzll_channel_tab[gzll_channel_tab_index]);

  /*
  Initialize dynamic parameters using default values.
  */
  gzll_dyn_params[GZLL_PARAM_DEVICE_MODE] = GZLL_DEFAULT_PARAM_DEVICE_MODE;
  gzll_dyn_params[GZLL_PARAM_TX_TIMEOUT] = GZLL_DEFAULT_PARAM_TX_TIMEOUT;
  gzll_dyn_params[GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_ON] = GZLL_DEFAULT_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_ON;
  gzll_dyn_params[GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_OFF] = GZLL_DEFAULT_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_OFF;
  gzll_dyn_params[GZLL_PARAM_HOST_MODE] = GZLL_DEFAULT_PARAM_HOST_MODE;
  gzll_dyn_params[GZLL_PARAM_RX_PIPES] = GZLL_DEFAULT_PARAM_RX_PIPES;
  gzll_dyn_params[GZLL_PARAM_CRYPT_PIPES] = GZLL_DEFAULT_PARAM_CRYPT_PIPES;
  gzll_dyn_params[GZLL_PARAM_RX_TIMEOUT] = GZLL_DEFAULT_PARAM_RX_TIMEOUT;
  gzll_dyn_params[GZLL_PARAM_HOST_MODE_1_CYCLE_PERIOD] = GZLL_DEFAULT_PARAM_HOST_MODE_1_CYCLE_PERIOD;
  gzll_dyn_params[GZLL_PARAM_RX_PERIOD] = GZLL_DEFAULT_PARAM_RX_PERIOD;
  gzll_dyn_params[GZLL_PARAM_RX_PERIOD_MODIFIER] = GZLL_DEFAULT_PARAM_RX_PERIOD_MODIFIER;
  gzll_dyn_params[GZLL_PARAM_RX_CHANNEL_HOLD_PERIODS] = GZLL_DEFAULT_PARAM_RX_CHANNEL_HOLD_PERIODS;
  gzll_dyn_params[GZLL_PARAM_OUTPUT_POWER] = GZLL_DEFAULT_PARAM_OUTPUT_POWER;
  gzll_dyn_params[GZLL_PARAM_POWER_DOWN_IDLE_ENABLE] = GZLL_DEFAULT_PARAM_POWER_DOWN_IDLE_ENABLE;
  gzll_dyn_params[GZLL_PARAM_MAX_SYNC_PERIOD] = GZLL_DEFAULT_PARAM_MAX_SYNC_PERIOD;
  gzll_dyn_params[GZLL_PARAM_COLLISION_CHANNEL_SWITCH_LIMIT] = GZLL_DEFAULT_PARAM_COLLISION_CHANNEL_SWITCH_LIMIT;

  /*
  Set up default output power.
  */
  hal_nrf_set_output_power((hal_nrf_output_power_t) gzll_dyn_params[GZLL_PARAM_OUTPUT_POWER]);

  /*
  Static radio setup.
  */
  hal_nrf_set_datarate(GZLL_HAL_DATARATE);
  hal_nrf_set_crc_mode(GZLL_CRC);
  hal_nrf_set_address_width(GZLL_ADDRESS_WIDTH);

  /*
  Clear radio IRQ flags.
  */
  //lint -esym(534, hal_nrf_get_clear_irq_flags) "return value ignored"
  hal_nrf_get_clear_irq_flags();

  hal_nrf_flush_rx();
  hal_nrf_flush_tx();

  gzll_set_timer_period(GZLL_DEFAULT_PARAM_RX_PERIOD);
  gzll_set_system_idle();
  gzll_interupts_enable_rfck_disable();
}
void gzll_set_address ( hal_nrf_address_t  pipe,
const uint8_t *  address 
)

Function for setting the address of a pipe.

When in receive mode, the radio can monitor up to six pipes simultaneously. Each pipe has its own address.

For pipes 0 and 1 all 5 address bytes have to be set. For pipes 2 to 5 the least significant address byte has to be set. The remaining address bytes for pipes 2 to 5 will be the same as for pipe 1.

Note:
The least significant address byte must be unique for all 6 pipes.

It is only allowed to modify the address in GZLL_IDLE state.

Parameters:
pipespecifies the pipe number (0-5).
addressis a pointer to the pipe address.
See also:
gzll_goto_idle(), gzll_get_state()

Definition at line 583 of file gzll.c.

{
  ASSERT((gzll_state_var == GZLL_IDLE));
  ASSERT((pipe <= 5));

  gzll_interupts_disable_rfck_enable();

  gzll_tx_setup_modified = true;
  gzll_rx_setup_modified = true;

  if(pipe == HAL_NRF_PIPE0)
  {
    memcpy(gzll_p0_adr, (uint8_t*)address, GZLL_ADDRESS_WIDTH);
  }

  hal_nrf_set_address(pipe, address);

  gzll_interupts_enable_rfck_disable();
}
void gzll_set_channels ( uint8_t *  channels,
uint8_t  size 
)

Function for setting the channels to be used by the Gazell protocol.

In order for several units running the Gazell protocol to be able to communicate, they have to use the same (or overlapping) set of channels.

It is recommended that the selected channels are distributed over a wide frequency range. The maximum channel range for the nRF24L01 radio is 0 to 123. However, in order to ensure compliance with world wide frequency regulations it is recommended to use channels 2 to 80 only.

Parameters:
channelsis a pointer to the channel array.
sizeis the number of channels in the array.

Definition at line 567 of file gzll.c.

{
  gzll_interupts_disable_rfck_enable();

  ASSERT((gzll_state_var == GZLL_IDLE));
  ASSERT((channel_tab_size <= GZLL_MAX_CHANNEL_TAB_SIZE));

  gzll_channel_tab_index = 0;
  gzll_channel_tab_size = channel_tab_size;
  memcpy(gzll_channel_tab, channels, gzll_channel_tab_size);

  hal_nrf_set_rf_channel(gzll_channel_tab[gzll_channel_tab_index]);

  gzll_interupts_enable_rfck_disable();
}
void gzll_set_param ( gzll_dyn_params_t  param,
uint16_t  value 
)

Function for setting a dynamic protocol parameter.

Parameters:
paramis the parameter to set. The possible parameters are:

  • GZLL_PARAM_DEVICE_MODE,
  • GZLL_PARAM_TX_TIMEOUT,
  • GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_SWITCH_SYNC_ON,
  • GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_SWITCH_SYNC_OFF,
  • GZLL_PARAM_HOST_MODE,
  • GZLL_PARAM_RX_PIPES,
  • GZLL_PARAM_CRYPT_PIPES,
  • GZLL_PARAM_RX_TIMEOUT,
  • GZLL_PARAM_HOST_MODE_1_BURST_PERIOD,
  • GZLL_PARAM_RX_PERIOD,
  • GZLL_PARAM_RX_PERIOD_MOD_CONST,
  • GZLL_PARAM_RX_CHANNEL_HOLD_PERIODS,
  • GZLL_PARAM_OUTPUT_POWER,
  • GZLL_PARAM_POWER_DOWN_IDLE_ENABLE,
  • GZLL_PARAM_MAX_SYNC_PERIOD,
  • GZLL_PARAM_COLLISION_CHANNEL_SWITCH_LIMIT
valueis the new value for the parameter.

Definition at line 487 of file gzll.c.

{
  ASSERT((gzll_state_var == GZLL_IDLE));
  ASSERT((param < GZLL_DYN_PARAM_SIZE));
  ASSERT(!(param == GZLL_PARAM_DEVICE_MODE && val > GZLL_DEVICE_MODE_4));
  ASSERT(!(param == GZLL_PARAM_HOST_MODE && val > GZLL_HOST_MODE_1));
  ASSERT(!(param == GZLL_PARAM_RX_PIPES && val > 0x3f));
  ASSERT(!(param == GZLL_PARAM_CRYPT_PIPES && val > GZLL_MAX_CRYPT_PIPES_VAL));
  ASSERT(!(param == GZLL_PARAM_OUTPUT_POWER && val > 3));

  gzll_interupts_disable_rfck_enable();

  if(param < GZLL_DYN_PARAM_SIZE)
  {
    gzll_dyn_params[param] = val;

    switch(param)
    {
      case GZLL_PARAM_DEVICE_MODE:
        if((val == GZLL_DEVICE_MODE_0 || val == GZLL_DEVICE_MODE_1))
        {
          gzll_sync_on = false;
        }
        break;
      case GZLL_PARAM_POWER_DOWN_IDLE_ENABLE:
        if(val == 1)
        {
          gzll_set_radio_power_on(false);
        }
        break;
      case GZLL_PARAM_RX_PERIOD:
        gzll_timer_period_modified = 1;
        break;
      case GZLL_PARAM_OUTPUT_POWER:
        hal_nrf_set_output_power((hal_nrf_output_power_t)gzll_dyn_params[GZLL_PARAM_OUTPUT_POWER]);
        break;
      case GZLL_PARAM_RX_PIPES:
        gzll_rx_setup_modified = true;
        break;
    }
  }

  gzll_interupts_enable_rfck_disable();
}
uint16_t gzll_get_param_max ( gzll_dyn_params_t  param )

Function returning the maximum allowed value for a dynamic parameter. The minimum value for a parameter is zero.

Parameters:
paramis the parameter for which to get the maximum value. Possible parameters are:

  • GZLL_PARAM_DEVICE_MODE,
  • GZLL_PARAM_TX_TIMEOUT,
  • GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_SWITCH_SYNC_ON,
  • GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_SWITCH_SYNC_OFF,
  • GZLL_PARAM_HOST_MODE,
  • GZLL_PARAM_RX_PIPES,
  • GZLL_PARAM_CRYPT_PIPES,
  • GZLL_PARAM_RX_TIMEOUT,
  • GZLL_PARAM_HOST_MODE_1_BURST_PERIOD,
  • GZLL_PARAM_RX_PERIOD,
  • GZLL_PARAM_RX_PERIOD_MOD_CONST,
  • GZLL_PARAM_RX_CHANNEL_HOLD_PERIODS,
  • GZLL_PARAM_OUTPUT_POWER,
  • GZLL_PARAM_POWER_DOWN_IDLE_ENABLE,
  • GZLL_PARAM_MAX_SYNC_PERIOD,
  • GZLL_PARAM_COLLISION_CHANNEL_SWITCH_LIMIT
Returns:
Maximum value for the parameter.

Definition at line 532 of file gzll.c.

{
  uint16_t param_max[GZLL_DYN_PARAM_SIZE] = GZLL_PARAMS_MAX;

  return param_max[param];
}
uint16_t gzll_get_param ( gzll_dyn_params_t  param )

Function returning the current value of a dynamic parameter.

Parameters:
paramis the parameter for which to get the current value. The possible parameters are:

  • GZLL_PARAM_DEVICE_MODE,
  • GZLL_PARAM_TX_TIMEOUT,
  • GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_SWITCH_SYNC_ON,
  • GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_SWITCH_SYNC_OFF,
  • GZLL_PARAM_HOST_MODE,
  • GZLL_PARAM_RX_PIPES,
  • GZLL_PARAM_CRYPT_PIPES,
  • GZLL_PARAM_RX_TIMEOUT,
  • GZLL_PARAM_HOST_MODE_1_BURST_PERIOD,
  • GZLL_PARAM_RX_PERIOD,
  • GZLL_PARAM_RX_PERIOD_MOD_CONST,
  • GZLL_PARAM_RX_CHANNEL_HOLD_PERIODS,
  • GZLL_PARAM_OUTPUT_POWER,
  • GZLL_PARAM_POWER_DOWN_IDLE_ENABLE,
  • GZLL_PARAM_MAX_SYNC_PERIOD,
  • GZLL_PARAM_COLLISION_CHANNEL_SWITCH_LIMIT
Returns:
Value for the parameter.

Definition at line 539 of file gzll.c.

{
  ASSERT((param < GZLL_DYN_PARAM_SIZE));

  gzll_interupts_disable_rfck_enable();

  if(param < GZLL_DYN_PARAM_SIZE)
  {
    gzll_interupts_enable_rfck_disable();
    return gzll_dyn_params[param];
  }
  else
  {
    gzll_interupts_enable_rfck_disable();
    return 0;
  }
}
gzll_states_t gzll_get_state ( void   )

Function for achieving the current protocol state.

Returns:
Returns the current Gazell protocol state.
Return values:
GZLL_IDLE
GZLL_DEVICE_ACTIVE
GZLL_HOST_ACTIVE
See also:
gzll_goto_idle()

Definition at line 897 of file gzll.c.

{
  return gzll_state_var;
}
_Bool gzll_radio_active (  )

Function telling if the radio is currently active (receiving or transmitting).

This function is used for assisting power management in the application.

For nRF24LE1, the application cannot enter any other power-saving mode deeper than standby when the radio is active.

Returns:
Returns true if the radio is active and false if the radio is not active.

Definition at line 902 of file gzll.c.

{
  return gzll_radio_active_f;
}
void gzll_goto_idle ( void   )

Function for forcing the protocol to GZLL_IDLE state.

The Gazell protocol has three states: GZLL_IDLE, GZLL_DEVICE_ACTIVE and GZLL_HOST_ACTIVE.

See also:
gzll_get_state()

Definition at line 1017 of file gzll.c.

{
  if(gzll_state_var == GZLL_DEVICE_ACTIVE)
  {
    gzll_pending_goto_idle = true;

    while(gzll_state_var != GZLL_IDLE)
    ;
  }
  else
  {
    if(gzll_state_var == GZLL_HOST_ACTIVE)
    {
      gzll_interupts_disable_rfck_enable();
      gzll_set_system_idle();
      gzll_interupts_enable_rfck_disable();
    }
  }
}
_Bool gzll_rx_data_ready ( uint8_t  pipe )

Function for checking for data in the RX FIFO.

The function checks if data is available on a given pipe.

If a packet is available, the packet can be read from the FIFO by using gzll_rx_fifo_read().

Parameters:
pipeis the pipe number.

  • 0-5 will check if a packet is available on this pipe.
  • >5 will check if a packet is available on any pipe.
Return values:
trueif data is available
falseif data is not available
See also:
gzll_rx_fifo_read(), gzll_get_rx_data_ready_pipe_number()

Definition at line 933 of file gzll.c.

{
  uint8_t available_rx_data_pipe;

  available_rx_data_pipe = gzll_get_rx_data_ready_pipe_number();

  return (available_rx_data_pipe <= 5 && (pipe == 0xff || pipe == available_rx_data_pipe));
}
uint8_t gzll_get_rx_data_ready_pipe_number ( void   )

Function for checking for data in the RX FIFO.

The function returns the pipe number for the available data.

If a packet is available, the packet can be read from the FIFO by using gzll_rx_fifo_read().

Returns:
The function returns the pipe number for the available data. If no data is available the function returns 0xff.
See also:
gzll_rx_fifo_read(), gzll_rx_data_ready()

Definition at line 907 of file gzll.c.

{
  uint8_t dr_rx_pipe;

  gzll_interupts_disable_rfck_enable();

  if(gzll_rx_dr)
  {
    if(gzll_ack_rx_pipe_fifo_cnt > 0)
    {
      dr_rx_pipe = gzll_ack_rx_pipe_fifo[gzll_ack_rx_pipe_fifo_cnt - 1];
    }
    else
    {
      dr_rx_pipe = hal_nrf_get_rx_data_source();
    }
  }
  else
  {
    dr_rx_pipe = 0xff;
  }

  gzll_interupts_enable_rfck_disable();
  return dr_rx_pipe;
}
_Bool gzll_rx_fifo_read ( uint8_t *  dst,
uint8_t *  length,
uint8_t *  pipe 
)

Function for reading a packet from the RX FIFO.

Reading the RX FIFO during GZLL_DEVICE_ACTIVE state can cause loss of packets.

Parameters:
*dstis the destination for the data. To avoid memory corruption the destination array should at least have space for GZLL_MAX_PAYLOAD_LENGTH bytes.
*lengthreturns the number of bytes read. By passing a NULL pointer this parameter will be ignored.
*pipereturns the pipe from which data was read. By passing a NULL pointer this parameter will be ignored.
Returns:
Status of RX FIFO read operation.
Return values:
trueif data was read from the RX FIFO.
falseif RX FIFO was empty.
See also:
gzll_get_rx_data_ready_pipe_number(), gzll_rx_data_ready()

Definition at line 942 of file gzll.c.

{
  uint8_t temp_pipe;
  uint8_t temp_length;
  uint16_t pipe_and_length;

  ASSERT(dst != NULL);

  gzll_interupts_disable_rfck_enable();

  if(gzll_rx_dr)
  {
    temp_length = hal_nrf_read_rx_payload_width();
    if(temp_length <= 32) //TODO: Remove or comment hardcoded value
    {
      pipe_and_length = hal_nrf_read_rx_payload(dst);
      if(gzll_ack_rx_pipe_fifo_cnt > 0)
      {
        gzll_ack_rx_pipe_fifo_cnt--;
        temp_pipe = gzll_ack_rx_pipe_fifo[gzll_ack_rx_pipe_fifo_cnt];
      }
      else
      {
        temp_pipe = (pipe_and_length >> 8);
      }

      /*
      Handles if two or more payloads were received while only one interrupt
      request serviced.
      */

      if(hal_nrf_rx_fifo_empty())
      {
        gzll_rx_dr = false;
      }

      if(pipe != NULL)
      {
        *pipe = temp_pipe;
      }

      if(length != NULL)
      {
        *length = temp_length;
      }

      gzll_interupts_enable_rfck_disable();
      return true;
    }
    else
    {
      gzll_rx_fifo_flush();
    }
  }

  gzll_interupts_enable_rfck_disable();
  return false;
}
_Bool gzll_rx_power_high ( void   )

Function returning true if the receive signal level for the previous received packet was above -64 dBm. This function is useful for estimating the relative proximity of the transmitting device.

Return values:
trueif receive signal level >= -64 dBm.
falseif receive signal level < -64 dBm.
See also:
gzll_set_address(), gzll_rx_start(), gzll_rx_fifo_read(), gzll_rx_data_ready()

Definition at line 1001 of file gzll.c.

{
  return gzll_rx_power_high_f;
}
uint8_t gzll_get_channel_tab_size (  )

Function returning the number of channels set up for Gazell.

See also:
gzll_set_channels()

Definition at line 557 of file gzll.c.

{
  return gzll_channel_tab_size;
}
void gzll_get_channels ( uint8_t *  channels )

Function returning the channel table set for Gazell.

See also:
gzll_set_channels(), gzll_get_channel_tab_size()

Definition at line 562 of file gzll.c.

{
  memcpy(channels, gzll_channel_tab, gzll_channel_tab_size);
}
void gzll_get_address ( uint8_t  pipe,
uint8_t *  address 
)

Function for getting the address of a pipe.

Parameters:
pipeis the pipe number(0-5).
*addressreturns the address of the pipe. For pipes 0 and 1, five address bytes are returned. For pipes 2 to 5 one address byte is returned.
See also:
gzll_set_address()

Definition at line 603 of file gzll.c.

{
  ASSERT((pipe <= 5));
  ASSERT(address != NULL);

  gzll_interupts_disable_rfck_enable();

  hal_nrf_get_address(pipe, address); //lint !e534 "return value ignored"

  gzll_interupts_enable_rfck_disable();
}
void gzll_tx_fifo_flush ( void   )

Function for flushing the transmit (TX) FIFO.

This function will only have effect in the GZLL_IDLE state.

Definition at line 887 of file gzll.c.

{
  gzll_interupts_disable_rfck_enable();

  hal_nrf_flush_tx();

  gzll_interupts_enable_rfck_disable();
}
void gzll_rx_fifo_flush ( void   )

Function for flushing the receive (RX) FIFO.

The function can be used in any protocol state.

Definition at line 1006 of file gzll.c.

{
  gzll_interupts_disable_rfck_enable();

  hal_nrf_flush_rx();
  gzll_ack_rx_pipe_fifo_cnt = 0;
  gzll_rx_dr = false;

  gzll_interupts_enable_rfck_disable();
}
void gzll_set_crypt_key ( uint8_t  pipe,
uint8_t *  key128 
)

Function for setting the 16 byte (128 bit) AES key to be used for encrypting/decrypting data.

This key must be distributed in a secure manner to the transmitter and the receiver.

Afterwards, AES 128 bit "Counter mode" is used for the communication. In Counter mode a given plaintext payload will be encrypted differently each time.

Each pipe can use different AES keys.

Parameters:
key128is a pointer to the 16 byte AES key to be used.
pipeis the pipe number for which to set the AES key. The pipe number must be < than the constant GZLL_MAX_CRYPT_PIPES.
See also:
gzll_get_crypt_key()
void gzll_get_crypt_key ( uint8_t  pipe,
uint8_t *  key128 
)

Function for getting the 16 byte (128 bit) AES key set for a given pipe.

Parameters:
key128is a pointer to where the 16 byte AES shall be copied.
pipeis the pipe number for which to get the AES key. The pipe number must be < than the constant GZLL_MAX_CRYPT_PIPES.
See also:
gzll_set_crypt_key()
void gzll_radio_isr_function ( void   )

Function to be called by the radio interrupt service routine.

Definition at line 1171 of file gzll.c.

{
  #ifndef GZLL_HOST_ONLY
  //lint -esym(644,tries) "Variable may not have been initialized"
  uint8_t tries;
  uint16_t timer_mod_period, temp;
  #endif
  uint8_t status;

  GZLL_INTERRUPTS_DISABLE();
  GZLL_RFCK_ENABLE();

  status = hal_nrf_clear_irq_flags_get_status();

  //If "received data ready" interrupt from radio
  if(status & ((1<<RX_DR)))
  {
    gzll_rx_dr = true;
    gzll_rx_power_high_f = hal_nrf_get_carrier_detect();
    gzll_chm_hold_rx_channel();

    #ifndef GZLL_HOST_ONLY
    /*
    If ACK payload has been received . Here, the actual RX pipe is always 0, so
    rx_pipe_fifo[] needs to store the current tx pipe.
    */
    if(gzll_state_var == GZLL_DEVICE_ACTIVE)
    {
      gzll_ack_rx_pipe_fifo[gzll_ack_rx_pipe_fifo_cnt] = gzll_current_tx_pipe;
      if(gzll_ack_rx_pipe_fifo_cnt < 2)
      {
        gzll_ack_rx_pipe_fifo_cnt++;
      }
    }
    #endif
  }

  //Read radio retransmit attempt counter and update affected variables.
  #ifndef GZLL_HOST_ONLY
  if((status & (1<<MAX_RT)) || (status & ((1<<TX_DS))))
  {
    tries = hal_nrf_get_transmit_attempts() + 1;
    gzll_tries_pr_channel_counter -= tries;
    gzll_try_counter += tries;
  }
  #endif

  //If "data sent" interrupt from radio
  if(status & (1<<TX_DS))
  {
    #ifndef GZLL_HOST_ONLY
    if(gzll_state_var == GZLL_DEVICE_ACTIVE)
    {
      gzll_timer_period_modified = 1;

      timer_mod_period = gzll_dyn_params[GZLL_PARAM_RX_PERIOD] - (gzll_dyn_params[GZLL_PARAM_RX_PERIOD_MODIFIER] + ((uint16_t)((GZLL_CONST_BYTES_PR_PACKET * 2) + gzll_current_tx_payload_length) * GZLL_US_PR_BYTE));
      if(status & ((1<<RX_DR)))
      {
        timer_mod_period -= (GZLL_US_PR_BYTE * GZLL_INTERNAL_ACK_PAYLOAD_LENGTH);
      }

      gzll_set_timer_period(timer_mod_period);

      gzll_chm_reset_rx_channel_index();
      gzll_chm_hold_rx_channel();

      temp = gzll_dyn_params[GZLL_PARAM_DEVICE_MODE];

      gzll_sync_period = gzll_dyn_params[GZLL_PARAM_MAX_SYNC_PERIOD];

      if(temp == GZLL_DEVICE_MODE_2 || temp == GZLL_DEVICE_MODE_3 || temp == GZLL_DEVICE_MODE_4)
      {
        gzll_sync_on = true;
      }

      /*
      Goto IDLE state if TX FIFO empty.
      */
      if(hal_nrf_tx_fifo_empty())
      {
        gzll_tx_success_f = true;
        gzll_set_system_idle();
      }
      else
      {
        gzll_reload_tries_pr_channel_counter();
        gzll_timeout_counter = 0;
        gzll_try_counter = 0;
        GZLL_RFCE_PULSE();
      }
    }
    #endif
  }

  /*
  If "max retransmit" interrupt from radio
  */
  #ifndef GZLL_HOST_ONLY
  if(status & (1<<MAX_RT))
  {
    GZLL_RFCE_LOW();

    gzll_timeout_counter += tries;
    temp = gzll_dyn_params[GZLL_PARAM_TX_TIMEOUT];

    // If TX has timed out, or user has called gzll_goto_idle()
    if((temp != 0 && gzll_timeout_counter >= temp) ||
      gzll_pending_goto_idle)
    {
      gzll_set_system_idle();
    }
    else
    {
      // If tries per channel has elapsed
      if(gzll_tries_pr_channel_counter == 0)
      {
        // If possible unintended sync to another device
        if(gzll_channel_switch_counter > gzll_dyn_params[GZLL_PARAM_COLLISION_CHANNEL_SWITCH_LIMIT])
        {
          gzll_sync_period = 0;
          gzll_sync_on = false;
          gzll_start_new_tx(GZLL_CHANNEL_RANDOM);
        }
        else
        {
          if(gzll_sync_on)
          {
            // If < 1 timer period until radio active -> state shall not go to !radio_active
            if(gzll_chm_get_tx_ce_offset() > 1)
            {
              gzll_radio_active_f = false;
            }
            gzll_start_new_tx(GZLL_CHANNEL_ESTIMATED);
          }
          else
          {
            gzll_start_new_tx(GZLL_CHANNEL_NEXT_INDEX);
          }
        }
      }
      else
      {
        gzll_set_radio_auto_retries();      // Continue retransmits on same channel
        GZLL_RFCE_PULSE();
      }
    }
  }
  #endif

  GZLL_RFCK_DISABLE();
  GZLL_INTERRUPTS_ENABLE();
}
void gzll_timer_isr_function ( void   )

Function to be called by the protocol timer interrupt service routine.

Definition at line 1324 of file gzll.c.

{
  uint16_t temp;

  GZLL_INTERRUPTS_DISABLE();
  gzll_chm_execute();                         // Execute radio channel manager

  // If timer period temporaly modified - restore correct setting.
  #ifndef GZLL_HOST_ONLY
  if(gzll_timer_period_modified == 1)
  {
    gzll_set_timer_period(gzll_dyn_params[GZLL_PARAM_RX_PERIOD]);
    gzll_timer_period_modified = 0;
  }
  #endif

  // If receive state
  #ifndef GZLL_DEVICE_ONLY
  if(gzll_state_var == GZLL_HOST_ACTIVE)
  {
    temp = gzll_chm_get_current_rx_channel();      // Get channel radio should be monitoring
    GZLL_RFCK_ENABLE();

    // If new channel should be monitored
    if(temp != gzll_channel_tab_index)
    {
      GZLL_RFCE_LOW();
      hal_nrf_set_rf_channel(gzll_channel_tab[temp]); // Change channel
      GZLL_RFCE_HIGH();                       // Set CE high here to minimize RX off time
      gzll_channel_tab_index = temp;
    }

    temp = gzll_chm_get_rx_ce_offset();       // Get number of periods until CE should be set high

    // Radio CE handling
    if(gzll_chm_get_rx_ce_offset() == 0)
    {
      gzll_set_radio_power_on(true);
      gzll_radio_active_f = true;
      GZLL_RFCE_HIGH();
    }
    else
    {
      GZLL_RFCE_LOW();
      gzll_radio_active_f = false;
      gzll_set_radio_power_on(false);
    }

    gzll_timeout_counter++;

    temp = gzll_dyn_params[GZLL_PARAM_RX_TIMEOUT];
    if(gzll_dyn_params[GZLL_PARAM_RX_TIMEOUT] > 0 && (gzll_timeout_counter >= temp))
    {
      gzll_set_system_idle();
    }
  }
  else
  #endif
  {
    // If transmit state
    #ifndef GZLL_HOST_ONLY
    if(gzll_state_var == GZLL_DEVICE_ACTIVE)
    {
      // If pending TX payload
      if(gzll_pending_tx_start)
      {
        temp = gzll_chm_get_tx_ce_offset();

        if( !gzll_sync_on ||
              (temp == 0 && (gzll_channel_tab_index == gzll_chm_get_current_rx_channel()))
        )
        {
          GZLL_RFCE_PULSE();
          gzll_radio_active_f = true;
          gzll_pending_tx_start = 0;
        }
      }
    }
    #endif
  }

  #ifndef GZLL_HOST_ONLY
  if(gzll_sync_period > 0)
  {
    gzll_sync_period--;
  }
  else
  {
    gzll_sync_on = false;
  }
  #endif

  GZLL_RFCK_DISABLE();
  GZLL_INTERRUPTS_ENABLE();
}
_Bool gzll_dev_mode2_rx_channel_match ( void   )

Function used during device mode 2 for minimizing the delay from gzll_tx_data() is called and until the transmission is started.

Device mode 2 is the synchronous frequency agility mode. This means that the Gazell link layer for every new transmission will use the previous successful transmission channel, and await starting the transmission until the host is actually monitoring this channel.

This wait time will be minimized if the gzll_tx_data() function is called when gzll_dev_mode2_rx_channel_match() returns true.

Definition at line 845 of file gzll.c.

{
  if(gzll_sync_on)
  {
    if(gzll_channel_tab_index == gzll_chm_get_next_rx_channel())
    {
      if((gzll_dyn_params[GZLL_PARAM_HOST_MODE] == GZLL_HOST_MODE_0) ||
         gzll_chm_get_tx_ce_offset() == 1)
      {
        return true;
      }
    }
    return false;
  }
  else
  {
    return true;
  }
}
_Bool gzll_tx_data ( const uint8_t *  src,
uint8_t  length,
uint8_t  pipe 
)

Function for uploading data to TX FIFO and start data transmission (Device operation).

The protocol does not have to be in GZLL_IDLE state to issue this function.

If the protocol is in GZLL_DEVICE_ACTIVE state, the data will be uploaded to the TX FIFO and sent immediately after the ongoing transmission has completed. This can be used to stream data.

For this to happen the following must be fulfilled:

  • The TX FIFO must not be full. (The TX FIFO can hold up to 3 payloads).
  • The destination pipe for the data must be the same as for the ongoing transmission.

If the protocol is in GZLL_HOST_ACTIVE state (Host operation) when issuing gzll_tx_data(), reception will be terminated and the protocol will switch to GZLL_DEVICE_ACTIVE state (Device operation).

Parameters:
*srcis the payload to be transmitted.
lengthis the number of bytes in the payload.
pipeis the pipe to be used. The TX address for the pipe is set using gzll_set_address().
Return values:
trueif data was successfully uploaded to the TX FIFO. This does NOT indicate that the packet was successfully transmitted, which should instead be checked with gzll_tx_success()
falseif data was not uploaded. In this case any the protocol state remains the same as before the function was called.
See also:
gzll_tx_success(), gzll_get_state(), gzll_goto_idle(void), gzll_set_address()

Definition at line 681 of file gzll.c.

{
  uint8_t temp_address[GZLL_ADDRESS_WIDTH];
  uint16_t temp;

  ASSERT(length <= GZLL_MAX_FW_PAYLOAD_LENGTH && length > 0);
  ASSERT(pipe <= 5);

  /*
  Length check to prevent memory corruption. (Note, assertion
  will capture this as well).
  */
  if(length == 0 || length > GZLL_MAX_FW_PAYLOAD_LENGTH)
  {
    return false;
  }

  gzll_current_tx_payload_length = length;

  if(gzll_state_var == GZLL_HOST_ACTIVE)
  {
    gzll_goto_idle();
  }

  gzll_interupts_disable_rfck_enable();

  /*
  If the specified pipe is different from the previous TX pipe,
  the TX setup must be updated
  */
  if(pipe != gzll_current_tx_pipe)
  {
    gzll_current_tx_pipe = pipe;
    gzll_tx_setup_modified = true;
  }

  /*
  Here, state can be GZLL_IDLE or GZLL_DEVICE_ACTIVE
  */
  if(gzll_state_var == GZLL_IDLE)
  {
    if(gzll_tx_setup_modified)       // TX setup has to be restored?
    {
      gzll_tx_setup_modified = false;
      gzll_rx_setup_modified = true;

      hal_nrf_set_operation_mode(HAL_NRF_PTX);
      hal_nrf_open_pipe(HAL_NRF_PIPE0, EN_AA);

       //Read out the full RX address for pipe number "pipe"
      if(pipe == HAL_NRF_PIPE0)
      {
        hal_nrf_set_address(HAL_NRF_TX, gzll_p0_adr);
        hal_nrf_set_address(HAL_NRF_PIPE0, gzll_p0_adr);
      }
      else
      {
        //lint -esym(550,bytes_in_buffer) "variable not accessed"
        //lint -esym(438,bytes_in_buffer) "last assigned value not used"
        uint8_t bytes_in_buffer;
        bytes_in_buffer = hal_nrf_get_address(HAL_NRF_PIPE1, temp_address);
        if(pipe != HAL_NRF_PIPE1)
        {
          switch(pipe)
          {
            default:
            case HAL_NRF_PIPE2:
              bytes_in_buffer = hal_nrf_get_address(HAL_NRF_PIPE2, temp_address);
              break;
            case HAL_NRF_PIPE3:
              bytes_in_buffer = hal_nrf_get_address(HAL_NRF_PIPE3, temp_address);
              break;
            case HAL_NRF_PIPE4:
              bytes_in_buffer = hal_nrf_get_address(HAL_NRF_PIPE4, temp_address);
              break;
            case HAL_NRF_PIPE5:
              bytes_in_buffer = hal_nrf_get_address(HAL_NRF_PIPE5, temp_address);
              break;
          }
        }

        //Here, temp_address will contain the full TX address
        hal_nrf_set_address(HAL_NRF_PIPE0, temp_address);
        hal_nrf_set_address(HAL_NRF_TX, temp_address);

        /*
        Change seed for random generator. Will prevent different devices
        transmitting to the same host from using the same channel hopping
        sequence.
        */
        //lint -esym(534, gzll_lfsr_get) "return value ignored"
        gzll_lfsr_get(pipe, 1);
      }
    }

    // Prepare for new transmission
    gzll_timeout_counter = 0;
    gzll_channel_switch_counter = 0;
    gzll_try_counter = 0;
    hal_nrf_flush_tx();

    GZLL_UPLOAD_PAYLOAD_TO_RADIO();

    gzll_tx_success_f = false;                // Transmission by default "failure"

    temp = gzll_dyn_params[GZLL_PARAM_DEVICE_MODE];

    gzll_set_radio_power_on(true);
    if(gzll_sync_on)
    {
      switch(temp)
      {
        case GZLL_DEVICE_MODE_2:
        default:
          gzll_start_new_tx(GZLL_CHANNEL_PREVIOUS_SUCCESS);
          break;
        case GZLL_DEVICE_MODE_3:
          gzll_start_new_tx(GZLL_CHANNEL_RANDOM);
          break;
        case GZLL_DEVICE_MODE_4:
          gzll_start_new_tx(GZLL_CHANNEL_ESTIMATED);
          break;
      }
    }
    else
    {
      switch(temp)
      {
        case GZLL_DEVICE_MODE_0:
        case GZLL_DEVICE_MODE_2:
          gzll_start_new_tx(GZLL_CHANNEL_PREVIOUS_SUCCESS);
          break;
        default:
          gzll_start_new_tx(GZLL_CHANNEL_RANDOM);
          break;
      }
    }

    gzll_state_var = GZLL_DEVICE_ACTIVE;
    gzll_interupts_enable_rfck_disable();
    return true;                              // Payload successfully written to TX FIFO
  }
  else                                        // Else TRANSMIT state
  {
    /*
    Check if criteria for starting new transmission when already transmitting
    is fulfilled
    */
    if(!gzll_tx_setup_modified &&
       !hal_nrf_tx_fifo_full()
    )
    {
      GZLL_UPLOAD_PAYLOAD_TO_RADIO();
      gzll_interupts_enable_rfck_disable();
      return true;                            // Payload successfully written to TX FIFO
    }
    else
    {
      gzll_interupts_enable_rfck_disable();
      return false;                           // Payload not written to TX FIFO
    }
  }
}
_Bool gzll_tx_success ( void   )

Function for checking the result of the latest transmit operation.

The return value from this function is only reliable when the protocol is in GZLL_IDLE state

Return values:
trueif the latest packet was successfully transmitted.
falseif the latest packet was not successfully transmitted.
See also:
gzll_tx_data(), gzll_get_state(), gzll_goto_idle()

Definition at line 865 of file gzll.c.

{
  ASSERT(gzll_state_var != GZLL_DEVICE_ACTIVE);

  return gzll_tx_success_f;
}
uint16_t gzll_get_tx_attempts ( void   )

Function returning the number of transmission attempts for the latest packet.

This function is useful for checking the current radio conditions and whether the protocol is in sync or not.

The returned value from this function is only reliable when the protocol is in GZLL_IDLE state.

Returns:
The number of transmission attempts for the latest packet.
See also:
gzll_get_tx_channel_switches()

Definition at line 872 of file gzll.c.

{
  ASSERT(gzll_state_var != GZLL_DEVICE_ACTIVE);

  return gzll_try_counter;
}
uint16_t gzll_get_tx_channel_switches ( void   )

Function returning the number of channel switches during transmission of the latest packet. A large number of channel switches will be an indication of heavy radio interference.

The returned value from this function is only reliable when the protocol is in GZLL_IDLE state.

Returns:
The number of channel switches needed during the latest transmission.
See also:
gzll_get_state(), gzll_goto_idle()

Definition at line 879 of file gzll.c.

{
  ASSERT(gzll_state_var != GZLL_DEVICE_ACTIVE)
  return  gzll_channel_switch_counter;
}
void gzll_rx_start ( void   )

Function for starting reception.

This function will make the protocol enter GZLL_HOST_ACTIVE state and start listening for incoming data.

If this function is called during the GZLL_DEVICE_ACTIVE state, the transmission will be terminated and the protocol will enter GZLL_HOST_ACTIVE state.

See also:
gzll_set_address(), gzll_rx_data_ready(), gzll_rx_fifo_read().

Definition at line 618 of file gzll.c.

{
  uint8_t i;

  gzll_goto_idle();

  if(gzll_rx_setup_modified)
  {
    gzll_interupts_disable_rfck_enable();

    gzll_rx_setup_modified = false;
    gzll_tx_setup_modified = true;

    /*
    Restore pipe 0 address (this may have been altered during transmission)
    */
    hal_nrf_set_address(HAL_NRF_PIPE0, gzll_p0_adr);

    /*
    Enable the receive pipes selected by gzll_set_param()
    */
    hal_nrf_close_pipe(HAL_NRF_ALL);
    for(i = 0; i < 6; i++)
    {
      if(gzll_dyn_params[GZLL_PARAM_RX_PIPES] & (1 << i))
      {
        hal_nrf_open_pipe((hal_nrf_address_t)i, EN_AA);
      }
    }
    hal_nrf_set_operation_mode(HAL_NRF_PRX);
  }

  gzll_set_radio_power_on(true);
  gzll_timeout_counter = 0;
  gzll_state_var = GZLL_HOST_ACTIVE;

  GZLL_RFCE_HIGH();
  gzll_interupts_enable_rfck_disable();
}
_Bool gzll_ack_payload_write ( const uint8_t *  src,
uint8_t  length,
uint8_t  pipe 
)

Function for uploading the payload to be piggybacked onto the next acknowledgement packet (ACK) for the selected pipe.

It is recommended that the Gazell Link Layer is in IDLE state when uploading an acknowledgement packet. Alternatively, the application can upload packets during HOST_ACTIVE state as long as the TX FIFO for the given pipe is not empty.

Uploading acknowledgement packet during HOST_ACTIVE state when the TX FIFO is empty can cause loss of packets.

Parameters:
*srcis a pointer to the payload.
lengthis the number of bytes of the payload. The maximum number of bytes in an ACK payload is GZLL_MAX_ACK_PAYLOAD_LENGTH.
pipeis the receive pipe. The payload will be sent as part of the next ACK packet for this pipe.
Return values:
trueif uploading of the ACK payload to TX FIFO was successful.
falseif uploading of the ACK payload failed due to full TX FIFO or length above GZLL_MAX_ACK_PAYLOAD_LENGTH.
See also:
gzll_set_address(), gzll_rx_start()

Definition at line 658 of file gzll.c.

{
  ASSERT(length <= GZLL_MAX_ACK_PAYLOAD_LENGTH && length > 0);
  ASSERT(pipe <= 5);

  gzll_interupts_disable_rfck_enable();

  if(length == 0 || (length > GZLL_MAX_ACK_PAYLOAD_LENGTH) || hal_nrf_tx_fifo_full())
  {
    gzll_interupts_enable_rfck_disable();
    return false;                             // ACK payload not written
  }
  hal_nrf_write_ack_payload(pipe, src, length);
  gzll_interupts_enable_rfck_disable();
  return true;                                // ACK payload successfully written
}
void gzll_set_timer_period ( uint16_t  period )

Function used by the Gazell protocol for setting the protocol timer period.

The implementation of this function must be customized for the actual MCU used.

Definition at line 30 of file gzll_mcu.c.

{
  hal_rtc_start(false);                             
  hal_rtc_start(true);                              // Start/stop to reset counter  

  period = (int)((float)period * 32768 / 1000000 + 0.5);

  hal_rtc_set_compare_value(period - 1);
}