/*
 * @Author       : stark1898y 1658608470@qq.com
 * @Date         : 2024-09-13 15:23:04
 * @LastEditors  : stark1898y 1658608470@qq.com
 * @LastEditTime : 2024-09-13 15:41:24
 * @FilePath     : \JT-DT-YD4N02A_RTT_MRS-4G\bsp\src\bsp_cpu_usage.c
 * @Description  :
 *
 * Copyright (c) 2024 by yzy, All Rights Reserved.
 */
#include <rthw.h>
#include <rtthread.h>

#include "bsp_cpu_usage.h"

#define LOG_TAG     "bsp_cpu_usage"          // 该模块对应的标签。不定义时，默认：NO_TAG
#define LOG_LVL     LOG_LVL_DBG     // 该模块对应的日志输出级别。不定义时，默认：调试级别
#include <ulog.h>                   // 必须在 LOG_TAG 与 LOG_LVL 下面

#if 1
#define CPU_USAGE_CALC_TICK 1000
#define CPU_USAGE_LOOP 100

static rt_uint8_t cpu_usage_major = 0, cpu_usage_minor = 0;
static rt_uint32_t total_count = 0;

static void _CPU_Usage_IdleHook(void)
{
    rt_tick_t tick;
    rt_uint32_t count;
    volatile rt_uint32_t loop;

    if (total_count == 0)
    {
        /* get total count */
        rt_enter_critical();
        tick = rt_tick_get();
        while (rt_tick_get() - tick < CPU_USAGE_CALC_TICK)
        {
            total_count++;
            loop = 0;
            while (loop < CPU_USAGE_LOOP)
                loop++;
        }
        rt_exit_critical();
    }

    count = 0;
    /* get CPU usage */
    tick = rt_tick_get();
    while (rt_tick_get() - tick < CPU_USAGE_CALC_TICK)
    {
        count++;
        loop = 0;
        while (loop < CPU_USAGE_LOOP)
            loop++;
    }

    /* calculate major and minor */
    if (count < total_count)
    {
        count = total_count - count;
        cpu_usage_major = (count * 100) / total_count;
        cpu_usage_minor = ((count * 100) % total_count) * 100 / total_count;
    }
    else
    {
        total_count = count;

        /* no CPU usage */
        cpu_usage_major = 0;
        cpu_usage_minor = 0;
    }
}

void CPU_Usage_Get(rt_uint8_t *major, rt_uint8_t *minor)
{
    RT_ASSERT(major != RT_NULL);
    RT_ASSERT(minor != RT_NULL);

    *major = cpu_usage_major;
    *minor = cpu_usage_minor;
}

int CPU_Usage_Init()
{
    LOG_I("CPU Usage Init");
    /* 设置空闲线程钩子函数 */
    return rt_thread_idle_sethook(_CPU_Usage_IdleHook);
}
#ifdef RT_USING_COMPONENTS_INIT
INIT_PREV_EXPORT(CPU_Usage_Init);
#endif

//static rt_thread_t get_cpu_use_thread = RT_NULL;
//
//static void get_cpu_use_thread_entry(void *parameter)
//{
//    rt_uint8_t major, minor;
//
//    while (1)
//    {
//        /* 获取CPU利用率数据 */
//        CPU_Usage_Get(&major, &minor);
//
//        /* 打印CPU利用率 */
//        rt_kprintf("CPU利用率 = %d.%d%%\r\n", major, minor);
//
//        rt_thread_delay(1000); /* 延时1000个tick */
//    }
//}

//static void hook_of_scheduler(struct rt_thread* from, struct rt_thread* to)
//{
//    rt_kprintf("from: %s -->  to: %s \n", from->name , to->name);
//}

int CPU_Usage(void)
{
    /* 设置调度器钩子 */
//    rt_scheduler_sethook(hook_of_scheduler);
//    CPU_Usage_Init();

//    get_cpu_use_thread =                           /* 线程控制块指针 */
//        rt_thread_create("get_cpu_use",            /* 线程名字 */
//                         get_cpu_use_thread_entry, /* 线程入口函数 */
//                         RT_NULL,                  /* 线程入口函数参数 */
//                         512,                      /* 线程栈大小 */
//                         5,                        /* 线程的优先级 */
//                         20);                      /* 线程时间片 */
//
//    /* 启动线程，开启调度 */
//    if (get_cpu_use_thread != RT_NULL)
//        rt_thread_startup(get_cpu_use_thread);
//    else
//        return -1;
    rt_uint8_t major, minor;
    /* 获取CPU利用率数据 */
    CPU_Usage_Get(&major, &minor);

    /* 打印CPU利用率 */
    LOG_D("CPU利用率 = %d.%d%%", major, minor);

    return 0;
}
#ifdef FINSH_USING_MSH
MSH_CMD_EXPORT(CPU_Usage, CPU_Usage);
#endif

#endif

#if 0

#include <rtdevice.h>

#define HWTIMER_DEV_NAME   "timer1"

/* 递增 count 作为 cpu tick 使用，不可被设置，只可单调递增 */
rt_uint64_t count = 0;

/* 当 CPU tick 到达 timeout_tick 时触发回调 */
rt_uint64_t timeout_tick = 0;

void (*hwtimer_timeout)(void *param);
void *parameter = RT_NULL;

/* 精度 ns */
static float cortexm_cputime_getres(void)
{
    return 10000;
}

/* cpu tick */
static uint64_t cortexm_cputime_gettime(void)
{
    return count;
}

// /* 设置超时时间及函数 */
// static int cortexm_cputime_settimeout(uint64_t tick, void (*timeout)(void *param), void *param)
// {
//     timeout_tick = tick;
//     hwtimer_timeout = timeout;
//     parameter = param;
//     return 0;
// }

/* 定义 ops */
const static struct rt_clock_cputime_ops _cpustime_ops =
{
    cortexm_cputime_getres,
    cortexm_cputime_gettime
    // cortexm_cputime_settimeout
};

/* 初始化 ops */
int cortexm_cputime_init(void)
{
    /* bsp 在这样使用的时候，不用管内部有没有实现，这个函数会覆盖掉内部的实现 */
    clock_cpu_setops(&_cpustime_ops);
    return 0;
}
INIT_BOARD_EXPORT(cortexm_cputime_init);

/* 硬件定时器超时函数 */
static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
{
    count++;
    if(count == timeout_tick)
    {
        /* 到达指定时间后清空到达时间，并触发回调 */
        timeout_tick = 0;
        if(hwtimer_timeout != RT_NULL)
            hwtimer_timeout(parameter);
    }
    return 0;
}

/* 硬件定时器初始化 */
static int hwtimer_init()
{
    rt_err_t ret = RT_EOK;
    rt_hwtimerval_t timeout_s;
    rt_device_t hw_dev = RT_NULL;
    rt_hwtimer_mode_t mode;
    rt_uint32_t freq = 1000000;

    hw_dev = rt_device_find(HWTIMER_DEV_NAME);
    if (hw_dev == RT_NULL)
    {
        /* 硬件定时器失败时，清空设置超时的函数，使 cputime 不可用，
        防止使用 rt_cputime_sleep() 时卡死 */
        // _cpustime_ops.cputime_settimeout = RT_NULL;
        LOG_E("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
        return RT_ERROR;
    }

    ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
    if (ret != RT_EOK)
    {
        // _cpustime_ops.cputime_settimeout = RT_NULL;
        LOG_E("open %s device failed!\n", HWTIMER_DEV_NAME);
        return ret;
    }
    /* 设置硬件定时器的超时时间 */
    rt_device_set_rx_indicate(hw_dev, timeout_cb);

    rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
    mode = HWTIMER_MODE_PERIOD;
    ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
    if (ret != RT_EOK)
    {
        // _cpustime_ops.cputime_settimeout = RT_NULL;
        LOG_E("set mode failed! ret is :%d\n", ret);
        return ret;
    }
    timeout_s.sec = 0;
    timeout_s.usec = 10;

    /* 设置硬件定时器的精度，这里应和上述的 cortexm_cputime_getres 函数保持一致 */
    if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
    {
        // _cpustime_ops.cputime_settimeout = RT_NULL;
        LOG_E("set timeout value failed\n");
        return RT_ERROR;
    }
    return ret;
}
INIT_APP_EXPORT(hwtimer_init);
#endif






