/******************************************************************************
 * This program is protected under international and U.S. copyright laws as
 * an unpublished work. This program is confidential and proprietary to the
 * copyright owners. Reproduction or disclosure, in whole or in part, or the
 * production of derivative works therefrom without the express permission of
 * the copyright owners is prohibited.
 *
 *                Copyright (C) 2020 by Dolby Laboratories.
 *                            All rights reserved.
 ******************************************************************************/

/** @file */

#ifndef IHT_H
#define IHT_H

#include <stddef.h>


/** @defgroup version Version Information
 * This is the API for discovering the version number of
 * the time domain intelligent head tracking (IHT) library.
 * @{ */
/**
 * This macro is a string which states the version of this API. */
#define IHT_VERSION       "1.0.0"

/**
 * Get the version string of the API which the IHT library expects to be
 * used with.
 *
 * @return Version information string. */
const char *iht_get_version(void);



/**
 * This function is used to print log messages.
 * It takes a first parameter of a pointer to a constant character
 * and an arbitrary number of subsequent parameters of arbitrary type.
 */
typedef void (*iht_log_fn)(const char *p_str,...);
 
/**
 * Log levels
 */
#define IHT_LOG_LEVEL_MINIMAL          (0) /* Minimal logs will be printed out.*/
#define IHT_LOG_LEVEL_FULL             (1) /* Full(detailed) logs will be printed out.*/
 
/**
 * This is a structure used for logging.
 */
typedef struct {
 
    /* log function*/
    iht_log_fn fn_log;
 
    /**
     * Log level. Supported values
     * are IHT_LOG_LEVEL_MINIMAL and IHT_LOG_LEVEL_FULL.
     */
    unsigned int level;
} iht_log_info;



/**
 * Specifies the properties of input sensor data
 */
#define IHT_SENSOR_DATA_SAMPLERATE_DEFAULT  (20u)
#define IHT_SENSOR_DATA_BLOCK_SIZE_DEFAULT  (3u)

/**
 * IHT initialization information
 *
 * This structure is used to store information required during IHT
 * initialization. The fields of this structure must be configured
 * properly to initialize IHT successfully and correctly. For the
 * usage of each field, please refer to field descriptions.
 */
typedef struct
{
   /**
    * @brief Sample rate of the input signal being (in Hertz)
    *
    * Valid values are IHT_SENSOR_DATA_SAMPLERATE_DEFAULT. */
    unsigned long    sample_rate;
} iht_init_info;



/**
 * Opaque type representing an instance of the intelligent head-tracking
 * (IHT) library. Use ith_init() to obtain a valid instance handle.
 */
typedef struct iht_state_s iht_state;



/**
 * @brief Query ITH persistent memory requirements
 * Returns the amount of memory required for an instance of IHT.
 * Returns 0 if the configuration is invalid.
 *
 * @returns                     Size of memory required to store IHT state.
  *
 * @param p_info                IHT initialization information.
 */
size_t
iht_query_memory
    (const iht_init_info *p_info
    );



/**
 * @brief Initialize IHT 
 * This function creates a new IHT instance. 
 * p_mem must point to the amount of memory as returned by iht_query_memory().
 * The returned value is the IHT state handle which should be passed to 
 * iht_process(). 
 * The returned pointer will not necessarily be the same as p_mem.
 *
 * @returns                     Instance of IHT state structure.
 *
 * @param p_info                [IN] IHT initialization information.
 * @param p_mem                 [IN] Memory pointer with allocated size for IHT state.
 */
iht_state *
iht_init
    (const iht_init_info  *p_info
    ,void                 *p_mem
    );


/**
 * @brief Clean up any resources owned by this IHT instance.
 *
 * @param p_iht Instance of IHT state structure.
 */
void
iht_close
    (iht_state       *p_iht
    );


/**
 * @brief Reset IHT history state
 * This function is used to clear history data of IHT state and 
 * reset internal reference-axis and head-rotation calculation
 * parameters to its default values.
 * Dynamic parameters will not be cleared.
 *
 * @param p_iht                 [IN] Instance of IHT state structure.
 */
void
iht_reset
    (iht_state      *p_iht
    );



/**
 * @brief This function is used to manually re-calibrate reference axis for
 * head-rotation angle calculation, will take effect immediately.
 *
 * ### TIMING OF CALLING
 *    - When received BT AVRCP playing command, meanwhile earbuds are wearing
 *    - When pushed the button in mobile app, meanwhile earbuds are earing
 *
 * @param p_iht                 [IN] Instance of IHT state structure.
 */
void
iht_ref_axis_set
    (iht_state      *p_iht
    );


/**
 * Specifies the smoothing factor for automatic re-centering action of reference axis
 */
#define IHT_TIME_CONSTANT_IN_SEC_DEFAULT  (10u)

/**
 *  @brief This function is used to set time constant value of smoothing factor for
 *  automatic re-centering action of reference axis, when head keeps heading to one
 *  direction for a while.
 *
* ### DEFAULT VALUES
 *   IHT_TIME_CONSTANT_IN_SEC_DEFAULT.
 *
 * @param p_iht                 [IN] Instance of IHT state structure.
 * @param time_constant_in_sec  [IN] Time constant value in seconds.
 */
void
iht_time_constant_param_set
    (iht_state      *p_iht
    ,const int       time_constant_in_sec
    );


/**
 * @brief This function is used to enable or disable automatic re-centering action of reference axis 
 * 
 * ### INPUT RANGE
 *  - 0  - automatic re-centering is disabled.
 *  - !0 - automatic re-centering is enabled.
 *
 * ### DEFAULT VALUE
 *  - 1
 *
 * ### NOTES
 *    When  is disabled, there's no automatic re-centering when head keeps heading
 *    to one direction for a while.
 *
 * @param p_iht                 [IN] Instance of IHT state structure.
 * @param en                    [IN] Automatic re-centering enable select.
 */

void
iht_time_constant_smoothing_enable_set
    (iht_state      *p_iht
    ,int             en
    );



/**
 * ### HEAD ROTATION MATRIX
 *
 *   IHT takes head rotation matrix as a pointer to an array of length
 *   IHT_HEAD_ROTATION_MATRIX_SIZE. Head rotation is required to be a 3x3
 *   rotation matrix, represented as a 9-element vector, in a row-first ordering.
 *       [[ 0, 1, 2]
 *        [ 3, 4, 5]  = Ay . Ap . Ar
 *        [ 6, 7, 8]]
 *   Where:
 *            [[   cos(yaw),  -sin(yaw),           0]
 *       Ay =  [   sin(yaw),   cos(yaw),           0]
 *             [          0,          0,           1]]
 *
 *            [[ cos(pitch),          0,  sin(pitch)]
 *       Ap =  [          0,          1,           0]
 *             [-sin(pitch),          0,  cos(pitch)]]
 *
 *            [[          1,          0,           0]
 *       Ar =  [          0,  cos(roll),  -sin(roll)]
 *             [          0,  sin(roll),   cos(roll)]]
 *
 *   The rotation matrix should be approximately orthogonal with a determinant
 *   of approximately 1. The entries should be in a Q14 format with valid
 *   values in the range [-1.0, 1.0]. Values outside of these constraints are
 *   undefined.
 *
 *   The head rotation follows the right hand rule; with the +ve x-axis from
 *   the back to the front of the room, the +ve y-axis from the right to the
 *   left of the room and the +ve z-axis from the bottom to the top of the
 *   room.
 *    - Yaw represents a conterclockwise rotation around the z-axis.
 *    - Pitch represents a conterclockwise rotation around the y-axis.
 *    - Roll represents a conterclockwise rotation around the x-axis.
 *
 */
 
/**
 * Specifies the number of elements used to represent the input sensor YPR data.
 */
#define IHT_SENSOR_YPR_DEGREE_DATA_SIZE                 (3)
#define IHT_SENSOR_YPR_DEGREE_FRAC_BITS                 (7)
#define IHT_SENSOR_YPR_DEGREE_DEFAULT                   {0, 0, 0}
#define IHT_SENSOR_YPR_DEGREE_VALUE_MIN                 (-0x5A00)
#define IHT_SENSOR_YPR_DEGREE_VALUE_MAX                 ( 0x5A00)

/**
 * Specifies the number of elements used to represent the head rotation matrix and rotation vector.
 */
#define IHT_HEAD_ROTATION_MATRIX_DATA_SIZE              (3 * 3)
#define IHT_HEAD_ROTATION_MATRIX_FRAC_BITS              (14)
#define IHT_HEAD_ROTATION_MATRIX_DEFAULT                { 0x4000, 0, 0, 0, 0x4000, 0, 0, 0, 0x4000}
#define IHT_HEAD_ROTATION_MATRIX_VALUE_MIN              (-0x4000)
#define IHT_HEAD_ROTATION_MATRIX_VALUE_MAX              ( 0x4000)


#define IHT_HEAD_ROTATION_AZIMUTH_ELEVATION_DATA_SIZE   (2)
#define IHT_HEAD_ROTATION_AZIMUTH_ELEVATION_FRAC_BITS   (0)
#define IHT_HEAD_ROTATION_AZIMUTH_ELEVATION_DEFAULT     {0, 0}
#define IHT_HEAD_ROTATION_AZIMUTH_VALUE_MIN             (-180)
#define IHT_HEAD_ROTATION_AZIMUTH_VALUE_MAX             ( 180)
#define IHT_HEAD_ROTATION_ELEVATION_VALUE_MIN           (-45)
#define IHT_HEAD_ROTATION_ELEVATION_VALUE_MAX           ( 90)

/**
 * @brief This function is to sensor data processing and head-rotation angle calculation,
 * based on sensor data in format of YPR, and give head-rotation matrix
 * or rotation azimuth and elevation data.
 *
 * ### DEFAULT VALUES
 *   - IHT_SENSOR_YPR_DEGREE_DEFAULT.
 *   - IHT_HEAD_ROTATION_MATRIX_DEFAULT.
 *   - IHT_HEAD_ROTATION_AZIMUTH_ELEVATION_DEFAULT
 * 
 * ### INPUT RANGE
 *  The type of input sensor YPR data is DEGREE.
 *  The valid range of this field is 
 *  [IHT_SENSOR_YPR_DEGREE_VALUE_MIN, IHT_SENSOR_YPR_DEGREE_VALUE_MAX].
 *
 * ### OUTPUT RANGE
 *  - The valid range of output rotation matrix is 
 *      [IHT_HEAD_ROTATION_MATRIX_VALUE_MIN, IHT_HEAD_ROTATION_MATRIX_VALUE_MAX]
 *  - The type of output azimuth and elevation scalar is DEGREE.
 *    The valid range of output azimuth data is 
 *      [IHT_HEAD_ROTATION_AZIMUTH_VALUE_MIN, IHT_HEAD_ROTATION_AZIMUTH_VALUE_MAX]
 *    The valid range of output elevation data is 
 *      [IHT_HEAD_ROTATION_ELEVATION_VALUE_MIN, IHT_HEAD_ROTATION_ELEVATION_VALUE_MAX]
 *
 * ### LOG MESSAGES
 *   If both the input log structure p_iht_log and log function p_iht_log->fn_log
 *   are not NULL, the log messages predefined in the function will be output.
 *   Otherwise, the log messages will be bypassed.
 *   The log levels supported are IHT_LOG_LEVEL_MINIMAL and IHT_LOG_LEVEL_FULL.
 *   Log messages included for different log levels are:
 *   IHT_LOG_LEVEL_MINIMAL
 *     - Output format when output format changes
 *     - IHT enabled/disabled status when IHT is switching between enabled and disabled.
 *     - Azimuth degree when azimuth changes more than 5 degrees compared with last call 
 *   IHT_LOG_LEVEL_FULL
 *     - Output format when output format changes
 *     - IHT enable/disable status when UHT is switching between enabled and disabled.
 *     - Azimuth degree when azimuth changes 
 *     - when iht_reset is called
 *
 * @param p_iht                     [IN] Instance of IHT state structure.
 * @param p_in_ypr                  [IN] sensor data in YPR format.
 * @param p_out_rotation_matrix     [OUT] head-rotation matrix (size：3x3).
 * @param p_out_azimuth_elevation   [OUT] head-rotation vector (size：2).
 * @param p_iht_log                 Instance of iht log info structure
 *
 * ### NOTE
 *   No head-rotation matrix output, when p_out_rotation_matrix value is NULL.
 *   No head-rotation vector output, when p_out_azimuth_elevation value is NULL.
 */
/* tare control processing & position-mapping processing */
void
iht_process
    (iht_state           *p_iht
    ,const  short        *p_in_ypr
    ,short               *p_out_rotation_matrix
    ,short               *p_out_azimuth_elevation
    ,const iht_log_info  *p_log
    );



/**
 * Specifies the number of elements used to represent the head rotation vector of (Yaw,Pitch,Roll).
 */
#define IHT_HEAD_ROTATION_YPR_DEGREE_DATA_SIZE          (3)
#define IHT_HEAD_ROTATION_YPR_DEGREE_FRAC_BITS          (7)
#define IHT_HEAD_ROTATION_YPR_DEGREE_DEFAULT            {0, 0, 0}
#define IHT_HEAD_ROTATION_YPR_DEGREE_VALUE_MIN          (-0x5A00)
#define IHT_HEAD_ROTATION_YPR_DEGREE_VALUE_MAX          ( 0x5A00)

/**
 * @biref This function is to get intermediate head-rotation angle parameters,
 * in format of (Yaw,Pitch,Roll), for debugging and QA checking.
 *
 * ### DEFAULT VALUES
 *   IHT_HEAD_ROTATION_YPR_DEGREE_DEFAULT.
 *
 * ### OUTPUT RANGE
 *  The type of head rotation YPR data is DEGREE.
 *  The valid range of this field is 
 *    [IHT_HEAD_ROTATION_YPR_DEGREE_VALUE_MIN, IHT_HEAD_ROTATION_YPR_DEGREE_VALUE_MAX].
 *
 * ### NOTE
 *   No last YPR data output, when p_ypr_last value is NULL.
 *   No current YPR data output, when p_ypr_current value is NULL.
 *   No reference YPR data output, when p_ypr_reference value is NULL.
 *
 * @param p_iht             [IN] Instance of IHT state structure.
 * @param p_ypr_last        [OUT] Last calculated (Yaw,Pitch,Roll) data.
 * @param p_ypr_current     [OUT] Current calculated (Yaw,Pitch,Roll) data.
 * @param p_ypr_current     [OUT] Reference (Yaw,Pitch,Roll) of initial axis.
 */
void
iht_ypr_get
    (iht_state           *p_iht
    ,short               *p_ypr_last
    ,short               *p_ypr_current
    ,short               *p_ypr_reference
    );



/**
 * Specifies the state value of initial axis re-calibration.
 */
#define IHT_REF_AXIS_CAL_STATE_OFF              (0)
#define IHT_REF_AXIS_CAL_STATE_ONGOING          (1)
#define IHT_REF_AXIS_CAL_STATE_DONE             (2)
#define IHT_REF_AXIS_CAL_STATE_HEADTACKING      (3)

/**
 * @brief This function is to get intermediate state of reference axis re-calibration,
 *
 * @param p_iht             [IN] Instance of IHT state structure.
 */
int
iht_ref_axis_state_get
    (iht_state           *p_iht
    );

#endif /* IHT_H */
