/*
 * Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
 * All rights reserved.
 *
 * Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
 * exclusively with CVA's microcontroller products. This file can be freely
 * distributed within development tools that are supporting such microcontroller
 * products.
 * 
 * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 */

#ifndef _IQMATH_H_
#define _IQMATH_H_

//! \brief  This is the default floating point implementation of IQ math library.
//!         Almost all the platforms can use it, but some may come across
//!         the performance issue. So use it carefully unless you know what
//!         you are doing.
//!

//###########################################################################
#ifndef _USING_CUSTOM_IQMATH_
//###########################################################################
// The default floating point IQ math
//===========================================================================

/*******************************************************************************
 * the includes
 ******************************************************************************/

#include <math.h>
#include <stdlib.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/*******************************************************************************
 * the defines
 ******************************************************************************/

#define MATH_PI                         (3.1415926535897932384626433832795f)
#define MATH_2PI                        (6.283185307179586476925286766559f)
#define MATH_ONE_OVER_THREE             (0.3333333333f)
#define MATH_ONE_OVER_SQRT_THREE        (0.5773502692f)
#define MATH_SQRT_THREE_OVER_TWO        (0.8660254038f)
#define IQMATH_ONE_OVER_THREE           (0.3333333333f)
#define IQMATH_ONE_OVER_SQRT_THREE      (0.5773502692f)
#define IQMATH_SQRT_THREE_OVER_TWO      (0.8660254038f)

/*******************************************************************************
 * the typedefs
 ******************************************************************************/

typedef   float   _iq;

/*******************************************************************************
 * the function prototypes
 ******************************************************************************/

#define _IQmpy2(A)          ((A)*2.0f)
#define _IQmpy4(A)          ((A)*4.0f)
#define _IQmpy8(A)          ((A)*8.0f)
#define _IQmpy16(A)         ((A)*16.0f)
#define _IQmpy32(A)         ((A)*32.0f)
#define _IQmpy64(A)         ((A)*64.0f)

#define _IQdiv2(A)          ((A)*0.5f)
#define _IQdiv4(A)          ((A)*0.25f)
#define _IQdiv8(A)          ((A)*0.125f)
#define _IQdiv16(A)         ((A)*0.0625f)
#define _IQdiv32(A)         ((A)*0.03125f)
#define _IQdiv64(A)         ((A)*0.015625f)

#define   _IQ(A)         (A)

#define   _IQtoF(A)      (A)

//! \note   In case for some compiler version, __fmax and __fmin are not defined
//!         Add a simple implementation here
#ifndef __fmax
#define __fmax(A, B)    (A>B ? A : B)
#endif
#ifndef __fmin
#define __fmin(A, B)    (A<B ? A : B)
#endif

#define   _IQsat(A, Pos, Neg)  (__fmax(((__fmin((A),(Pos)))),(Neg)))

#define   _IQtoQ15(A)    (int) ((A) * 32768.0f)
#define   _IQtoQ14(A)    (int) ((A) * 16384.0f)
#define   _IQtoQ13(A)    (int) ((A) * 8192.0f)
#define   _IQtoQ12(A)    (int) ((A) * 4096.0f)
#define   _IQtoQ11(A)    (int) ((A) * 2048.0f)
#define   _IQtoQ10(A)    (int) ((A) * 1024.0f)
#define   _IQtoQ9(A)     (int) ((A) * 512.0f)
#define   _IQtoQ8(A)     (int) ((A) * 256.0f)
#define   _IQtoQ7(A)     (int) ((A) * 128.0f)
#define   _IQtoQ6(A)     (int) ((A) * 64.0f)
#define   _IQtoQ5(A)     (int) ((A) * 32.0f)
#define   _IQtoQ4(A)     (int) ((A) * 16.0f)
#define   _IQtoQ3(A)     (int) ((A) * 8.0f)
#define   _IQtoQ2(A)     (int) ((A) * 4.0f)
#define   _IQtoQ1(A)     (int) ((A) * 2.0f)

#define   _Q15toIQ(A)    (((float) (A)) * 0.000030518f)
#define   _Q14toIQ(A)    (((float) (A)) * 0.000061035f)
#define   _Q13toIQ(A)    (((float) (A)) * 0.000122070f)
#define   _Q12toIQ(A)    (((float) (A)) * 0.000244141f)
#define   _Q11toIQ(A)    (((float) (A)) * 0.000488281f)
#define   _Q10toIQ(A)    (((float) (A)) * 0.000976563f)
#define   _Q9toIQ(A)     (((float) (A)) * 0.001953125f)
#define   _Q8toIQ(A)     (((float) (A)) * 0.003906250f)
#define   _Q7toIQ(A)     (((float) (A)) * 0.007812500f)
#define   _Q6toIQ(A)     (((float) (A)) * 0.015625000f)
#define   _Q5toIQ(A)     (((float) (A)) * 0.031250000f)
#define   _Q4toIQ(A)     (((float) (A)) * 0.062500000f)
#define   _Q3toIQ(A)     (((float) (A)) * 0.125000000f)
#define   _Q2toIQ(A)     (((float) (A)) * 0.250000000f)
#define   _Q1toIQ(A)     (((float) (A)) * 0.500000000f)

#define   _IQmpy(A,B)         ((A) * (B))

#define   _IQrmpy(A,B)        ((A) * (B))

#define   _IQrsmpy(A,B)       ((A) * (B))

#define   _IQdiv(A,B)         ((float)(A) / (float)(B))

#define   _IQsin(A)           sinf(A)

#define   _IQsinPU(A)         sinf((A)*6.283185307f)

#define   _IQasin(A)          asinf(A)

#define   _IQcos(A)           cosf(A)

#define   _IQcosPU(A)         cosf((A)*6.283185307f)

#define   _IQacos(A)          acosf(A)

#define   _IQatan(A)          atanf(A)

#define   _IQatan2(A,B)       atan2f(A,B)

#define   _IQatan2PU(A,B)     ((atan2f(A,B)*(1.0f/6.283185307f)) >= 0.0f ? (atan2f(A,B)*(1.0f/6.283185307f)) : (1.0f + (atan2f(A,B)*(1.0f/6.283185307f))))

#define   _IQsqrt(A)          sqrtf(A)

#define   _IQisqrt(A)         (1.0f/sqrtf(A))

#define   _IQexp(A)           expf(A)

#define   _IQint(A)           ((long) (A))

#define   _IQfrac(A)          ((A) - (float)((long) (A)))

#define   _IQmag(A,B)         sqrtf((A)*(A) + (B)*(B))

#define   _IQabs(A)           fabsf(A)

#define   _IQlog(A)           logf(A)


#ifdef __cplusplus
}
#endif /* extern "C" */

//###########################################################################
#else
//###########################################################################
// The custom IQ math
//===========================================================================

//! \note   It's the user's duty to undefine the macros that are different with ones
//!         defined above in the "iqmathcustom.h", which must be put in this folder.
//! \note   When building some kind of library and we cannot access the BSW, just create
//!         and fake the MCU folder.
//!
#include "iqmathcustom.h"
#endif

#endif /* _IQMATH_H_ */