/*$$$LICENCE_NORDIC_STANDARD<2016>$$$*/

#ifndef __M_AUDIO_GAUGES_H__
#define __M_AUDIO_GAUGES_H__

#include <stdint.h>
#include "nrf.h"
#include "nrf_atomic.h"
#include "app_util_platform.h"
#include "sr3_config.h"

typedef struct
{
    uint32_t    total_time;
    uint32_t    cpu_time;
    uint32_t    timestamp;
    uint8_t     min_cpu_usage;
    uint8_t     cur_cpu_usage;
    uint8_t     max_cpu_usage;
} m_audio_cpu_gauge_t;

typedef struct
{
    uint32_t    frames;
    uint32_t    bytes;
    uint16_t     min_bitrate;
    uint16_t     cur_bitrate;
    uint16_t     max_bitrate;
} m_audio_bitrate_gauge_t;

typedef struct
{
    nrf_atomic_u32_t    total;
    nrf_atomic_u32_t    lost;
    nrf_atomic_u32_t    discarded;
} m_audio_loss_gauge_t;

__STATIC_INLINE uint8_t m_audio_gauge_get_cur_cpu_usage(const m_audio_cpu_gauge_t *p_gauge)
{
    return p_gauge->cur_cpu_usage;
}

__STATIC_INLINE uint8_t m_audio_gauge_get_min_cpu_usage(const m_audio_cpu_gauge_t *p_gauge)
{
    return p_gauge->min_cpu_usage;
}

__STATIC_INLINE uint8_t m_audio_gauge_get_avg_cpu_usage(const m_audio_cpu_gauge_t *p_gauge)
{
    uint32_t total_time;
    uint32_t cpu_time;

    CRITICAL_REGION_ENTER();
    total_time  = p_gauge->total_time;
    cpu_time    = p_gauge->cpu_time;
    CRITICAL_REGION_EXIT();

    if (total_time == 0)
    {
        return 0;
    }

    return 100ull * cpu_time / total_time;
}

__STATIC_INLINE uint8_t m_audio_gauge_get_max_cpu_usage(const m_audio_cpu_gauge_t *p_gauge)
{
    return p_gauge->max_cpu_usage;
}

__STATIC_INLINE uint16_t m_audio_gauge_get_cur_bitrate(const m_audio_bitrate_gauge_t *p_gauge)
{
    return p_gauge->cur_bitrate;
}

__STATIC_INLINE uint16_t m_audio_gauge_get_min_bitrate(const m_audio_bitrate_gauge_t *p_gauge)
{
    return p_gauge->min_bitrate;
}

uint16_t m_audio_gauge_get_avg_bitrate(const m_audio_bitrate_gauge_t *p_gauge);
// __STATIC_INLINE uint16_t m_audio_gauge_get_avg_bitrate(const m_audio_bitrate_gauge_t *p_gauge)
// {
//     uint32_t frames;
//     uint32_t bytes;

//     CRITICAL_REGION_ENTER();
//     frames  = p_gauge->frames;
//     bytes   = p_gauge->bytes;
//     CRITICAL_REGION_EXIT();

//     if (frames == 0)
//     {
//         return 0;
//     }

//     return (8ull * bytes * CONFIG_AUDIO_REAL_SAMPLING_FREQUENCY) / (1000ull * frames * CONFIG_AUDIO_FRAME_SIZE_SAMPLES);
// }

__STATIC_INLINE uint16_t m_audio_gauge_get_max_bitrate(const m_audio_bitrate_gauge_t *p_gauge)
{
    return p_gauge->max_bitrate;
}

__STATIC_INLINE uint32_t m_audio_gauge_get_total_count(const m_audio_loss_gauge_t *p_gauge)
{
    return p_gauge->total;
}

__STATIC_INLINE uint32_t m_audio_gauge_get_lost_count(const m_audio_loss_gauge_t *p_gauge)
{
    return p_gauge->lost;
}

__STATIC_INLINE uint32_t m_audio_gauge_get_discarded_count(const m_audio_loss_gauge_t *p_gauge)
{
    return p_gauge->discarded;
}

#if CONFIG_AUDIO_GAUGES_ENABLED

void m_audio_cpu_gauge_reset(m_audio_cpu_gauge_t *p_gauge);
void m_audio_cpu_gauge_log(const m_audio_cpu_gauge_t *p_gauge, const char *p_prefix);
void m_audio_measure_cpu_usage_start(m_audio_cpu_gauge_t *p_gauge);
void m_audio_measure_cpu_usage_end(m_audio_cpu_gauge_t *p_gauge);

void m_audio_bitrate_gauge_reset(m_audio_bitrate_gauge_t *p_gauge);
void m_audio_bitrate_gauge_log(const m_audio_bitrate_gauge_t *p_gauge, const char *p_prefix);
void m_audio_measure_bitrate(m_audio_bitrate_gauge_t *p_gauge, unsigned int bytes);

void m_audio_loss_gauge_reset(m_audio_loss_gauge_t *p_gauge);
void m_audio_loss_gauge_log(const m_audio_loss_gauge_t *p_gauge, const char *p_prefix);
void m_audio_count_total(m_audio_loss_gauge_t *p_gauge);
void m_audio_count_lost(m_audio_loss_gauge_t *p_gauge);
void m_audio_count_discarded(m_audio_loss_gauge_t *p_gauge);

#else /* !CONFIG_AUDIO_GAUGES_ENABLED */

#define m_audio_cpu_gauge_reset(p_gauge)            do { } while (0)
#define m_audio_cpu_gauge_log(p_gauge, prefix)      do { } while (0)
#define m_audio_measure_cpu_usage_start(p_gauge)    do { } while (0)
#define m_audio_measure_cpu_usage_end(p_gauge)      do { } while (0)

#define m_audio_bitrate_gauge_reset(p_gauge)        do { } while (0)
#define m_audio_bitrate_gauge_log(p_gauge, prefix)  do { } while (0)
#define m_audio_measure_bitrate(p_gauge, bytes)     do { } while (0)

#define m_audio_loss_gauge_reset(p_gauge)           do { } while (0)
#define m_audio_loss_gauge_log(p_gauge, prefix)     do { } while (0)
#define m_audio_count_total(p_gauge)                do { } while (0)
#define m_audio_count_lost(p_gauge)                 do { } while (0)
#define m_audio_count_discarded(p_gauge)            do { } while (0)

#endif /* CONFIG_AUDIO_GAUGES_ENABLED */
#endif /* __M_AUDIO_GAUGES_H__ */
