/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
 *
 * The information contained herein is property of Nordic Semiconductor ASA.
 * Terms and conditions of usage are described in detail in NORDIC
 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
 *
 * Licensees are granted free, non-transferable use of the information. NO
 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
 * the file.
 *
 */

#ifndef ANT_ENCRYPT_CONFIG__
#define ANT_ENCRYPT_CONFIG__

/**@file
 *
 * @defgroup ant_encrypt_config ANT encryption configuration
 * @{
 * @ingroup  ant_sdk_utils
 *
 * @brief    Encryption configuration for the ANT stack and channels.
 *
 */

#include <stdint.h>

#include "sdk_errors.h"
#include "ant_stack_handler_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/** @name Advanced burst configuration for encryption modules
 * @{
 */
#define ADV_BURST_CFG_MIN_SIZE          8 ///< Minimum size of the advance burst configuration data.
#define ADV_BURST_CFG_PACKET_SIZE_INDEX 1 ///< Index of the packet size field in the configuration data.
#define ADV_BURST_CFG_REQUIRED_FEATURES 2 ///< Index of the required features field in the configuration data.
#define ADV_BURST_CFG_OPTIONAL_FEATURES 5 ///< Index of the optional features field in the configuration data.
/**@} */

/** @brief ANT channel cryptographic configuration. */
typedef struct
{
    uint8_t mode;            ///< Encryption mode. See the encrypted channel defines in ant_parameters.h.
    uint8_t key_index;       ///< Index of encryption key.
    uint8_t decimation_rate; ///< Division of the master channel rate by the slave’s tracking channel rate.
} ant_encrypt_channel_settings_t;

/** @brief ANT encryption information. */
typedef union
{
    uint8_t * pp_array[3]; // For array access support.
    struct
    {
        uint8_t * p_encryption_id;   ///< Pointer to the encryption ID of the device (4 bytes).
        uint8_t * p_user_info;       ///< Pointer to the user information string (19 bytes).
        uint8_t * p_random_num_seed; ///< Pointer to the random number seed (16 bytes).
    } items;
} ant_encrypt_info_settings_t;

/** @brief Advanced burst settings used by the encrypted channel. */
typedef struct
{
    uint8_t packet_length;    ///< RF payload size. See the advanced burst configuration defines in ant_parameters.h.
    uint8_t required_feature; ///< Required advanced burst modes. See the advanced burst configuration defines in ant_parameters.h.
    uint8_t optional_feature; ///< Optional advanced burst modes. See the advanced burst configuration defines in ant_parameters.h.
} ant_encrypt_adv_burst_settings_t;

/**@brief ANT stack cryptographic configuration. */
typedef struct
{
    ant_encrypt_info_settings_t        info;               ///< Pointer to the encryption information structure.
    uint8_t                        * * pp_key;             ///< Pointer to an array for pointers to encryption keys. Each key must have a length of 16 bytes.
    uint8_t                            key_number;         ///< Number of encryption keys.
    ant_encrypt_adv_burst_settings_t * p_adv_burst_config; ///< Advanced burst configuration. If NULL, the advanced burst must be configured externally.
} ant_encrypt_stack_settings_t;

/**
 * @brief ANT encryption negotiation events.
 */
typedef enum
{
    ANT_ENC_EVT_NEGOTIATION_SUCCESS, ///< Negotiation success.
    ANT_ENC_EVT_NEGOTIATION_FAIL,    ///< Negotiation failure.
    ANT_ENC_EVT_CHANNEL_LOST         ///< Lost a channel. It's relevant only for slave channels.
} ant_encrypt_user_evt_t;

/**
 * @brief Event handler for ANT encryption user events.
 */
typedef void (* ant_encryp_user_handler_t)(uint8_t channel, ant_encrypt_user_evt_t event);

/**
 * @brief Macro for initializing an ANT encryption information structure.
 *
 * @param[in] P_ENC_ID         Pointer to the encryption ID of the device (4 bytes).
 * @param[in] P_USER_INFO      Pointer to the user information string (19 bytes).
 * @param[in] P_RAND_NUM_SEED  Pointer to the random number seed (16 bytes).
 */
#define ANT_CRYPTO_INFO_SETTINGS_INIT(P_ENC_ID, P_USER_INFO, P_RAND_NUM_SEED) \
    {                                                                         \
        .items =                                                              \
        {                                                                     \
            .p_encryption_id   = P_ENC_ID,                                    \
            .p_user_info       = P_USER_INFO,                                 \
            .p_random_num_seed = P_RAND_NUM_SEED                              \
        }                                                                     \
    }

/**
 * @brief Macro for declaring the basic cryptographic configuration for the ANT stack.
 *
 * This macro configures the following settings:
 * - Cryptographic key
 * - Encryption ID
 * - Advanced burst mode with the maximum RF payload size
 *
 * Use @ref ANT_ENCRYPT_STACK_SETTINGS_BASE to access the created configuration instance.
 *
 * @param[in] NAME   Name for the created data instance.
 * @param[in] P_KEY  Pointer to the cryptographic key (16 bytes).
 * @param[in] P_ENC_ID Pointer to the encryption ID (4 bytes).
 */
#define ANT_ENCRYPT_STACK_SETTINGS_BASE_DEF(NAME, P_KEY, P_ENC_ID)                 \
    ant_encrypt_adv_burst_settings_t NAME##_ant_enc_adv_burst_set =                \
    {                                                                              \
        .packet_length    = ADV_BURST_MODES_MAX_SIZE,                              \
        .required_feature = 0,                                                     \
        .optional_feature = 0                                                      \
    };                                                                             \
    uint8_t                    * pp_##NAME##_key[1] = {P_KEY};                     \
    ant_encrypt_stack_settings_t NAME ## _ant_crypto_settings =                    \
    {                                                                              \
        .info               = ANT_CRYPTO_INFO_SETTINGS_INIT(P_ENC_ID, NULL, NULL), \
        .pp_key             = pp_##NAME##_key,                                     \
        .key_number         = 1,                                                   \
        .p_adv_burst_config = &NAME##_ant_enc_adv_burst_set                        \
    }


/** @brief Macro for accessing the configuration instance created
 *  by @ref ANT_ENCRYPT_STACK_SETTINGS_BASE_DEF.
 *
 * @param[in] NAME   Name of the settings instance.
 */
#define ANT_ENCRYPT_STACK_SETTINGS_BASE(NAME) (NAME##_ant_crypto_settings)

/**
 * @brief Function for applying an encryption configuration to a slave channel.
 *
 * This function enables encryption on a channel.
 *
 * This function should be used by the @ref ant_encrypt_negotiation_slave module and this module.
 *
 * @param[in] channel_number   ANT channel number.
 * @param[in] p_crypto_config  Pointer to the encryption configuration.
 *
 * @return Value returned by @ref sd_ant_crypto_channel_enable (for example, NRF_SUCCESS if
 * the configuration was successful).
 */
ret_code_t ant_channel_encrypt_config_perform(uint8_t                          channel_number,
                                              ant_encrypt_channel_settings_t * p_crypto_config);

/**
 * @brief Function for applying an encryption configuration to a master or slave channel.
 *
 * When called for a master channel, this function enables encryption
 * for that channel. When called for a slave channel, it saves
 * the encryption configuration for future use.
 *
 * This function should be used by the @ref ant_channel_config module.
 *
 * @param[in] channel_type     ANT channel type: CHANNEL_TYPE_SLAVE or CHANNEL_TYPE_MASTER.
 * @param[in] channel_num      ANT channel number.
 * @param[in] p_crypto_config  Pointer to the encryption configuration.
 *
 * @retval NRF_SUCCESS                      If the function completed successfully.
 * @retval NRF_ERROR_INVALID_PARAM          If the channel type is invalid.
 * @retval NRF_ERROR_MODULE_NOT_INITIALZED  If the stack is not configured for encryption.
 * @retval Other                            Otherwise, the error value returned by the @ref
 *                                          ant_channel_encrypt_config_perform function is returned.
 */
ret_code_t ant_channel_encrypt_config(uint8_t                          channel_type,
                                      uint8_t                          channel_num,
                                      ant_encrypt_channel_settings_t * p_crypto_config);

/**
 * @brief Function for configuring the cryptographic settings of the ANT stack.
 *
 * @param[in] p_crypto_info_set Pointer to the settings.
 */
ret_code_t ant_stack_encryption_config(ant_encrypt_stack_settings_t const * const p_crypto_info_set);


/**
 * @brief Function for handling ANT encryption events.
 *
 * This function should be used directly in the ANT event dispatching process.
 * It serves the ANT encryption events to the registered event handler.
 * If @ref ant_encrypt_negotiation_slave is used, this function is required.
 *
 * This function should be used by the @ref ant_encrypt_config module.
 *
 * @param[in] p_ant_evt  Pointer to the ANT stack event message structure.
 */
void ant_encrypt_event_handler(ant_evt_t * p_ant_evt);

/**
 * @brief Function for registering an event handler for ANT encryption events.
 *
 * The event handler should support all of the events in @ref ant_encrypt_user_evt_t.
 *
 * @param[in] p_handler Pointer to a handler function.
 */
void ant_enc_event_handler_register(ant_encryp_user_handler_t p_handler);

/**
 * @}
 */

#ifdef __cplusplus
}
#endif

#endif // ANT_ENCRYPT_CONFIG__
