/*
 * @Author: wzh
 * @Date: 2024-11-26 11:09:09
 * @LastEditors: mypx mypx_coder@163.com
 * @LastEditTime: 2025-08-12 11:04:14
 * @Description:
 *
 * Copyright (c) 2024 by wzh, All Rights Reserved.
 */
#include "et_encoder_utils.h"
#include "et_encoder.h"
/**
 * @brief Calculate the shaft rotation speed (RPS) based on encoder count and current tick.
 * @param current_count The current encoder count.
 * @param last_count The last encoder count.
 * @param overflow_cnt The overflow count from HAL_TIM_PeriodElapsedCallback.
 * @param encoder_max_counter The maximum counter value of the encoder.This is a
 *        const value config in TIM Period args.
 * @param cur_tick The current tick value(ms).
 * @return The calculated shaft rotation speed in RPS. Return -1 if division by zero occurs.
 * note: Note the macro ET_ENCODER_MAX_COUNT&ET_ENCODER_TOTAL_PPR should defined in you project.
 */
float et_encoder_calculate_rps(int32_t current_count, int64_t *last_count, volatile int32_t *overflow_cnt,
                               uint32_t cur_tick)
{
    static uint32_t last_time = 0;

    uint32_t time       = cur_tick;
    uint32_t delta_time = time - last_time;
    int32_t  delta_count;
    float    shaft_rps = 0.0;

    if (delta_time == 0)
    {
        return -1;
    }
    delta_count = et_encoder_get_delta_count(current_count, last_count, overflow_cnt, ET_ENCODER_MAX_COUNT, true);

    last_time = time;

#define RPS_CALC_FACTOR (1000 / ET_ENCODER_TOTAL_PPR)
    // calculate RPS
    shaft_rps = (float)delta_count / delta_time * RPS_CALC_FACTOR;

    return shaft_rps;
}

/**
 * @brief Calculate the total count based on encoder count, overflow count,
 * and encoder maximum counter.
 * @param current_count The current encoder count form TIM Encoder.
 * @param last_count The last encoder whole count.
 * @param overflow_cnt The overflow count from HAL_TIM_PeriodElapsedCallback.
 * @param encoder_max_counter The maximum counter value of the encoder.This is a
 *        const value config in TIM Period args.
 * @param of_reset The last_count&overflow reset flag.
 * @return The total count between current_count and last_count.
 */
int64_t et_encoder_get_delta_count(int32_t current_count, int64_t *last_count, volatile int32_t *overflow_cnt,
                                   uint32_t encoder_max_count, bool of_reset)
{
    int64_t delta_count         = 0;
    int64_t current_whole_count = 0;

    current_whole_count = et_encoder_get_whole_count(current_count, overflow_cnt, encoder_max_count);
    delta_count         = current_whole_count - *last_count;
    if (of_reset)
        *last_count = current_whole_count;

    return delta_count;
}

/**
 * @brief Calculate the total encoder count by combining the current counter value 
 *        and accumulated overflow counts.
 * 
 * @param current_count Current reading from the encoder's timer counter (TIMx->CNT).
 * @param overflow_cnt Pointer to the overflow counter that tracks net overflows.
 *                    Increments on forward overflow, decrements on backward overflow.
 * @param encoder_max_count Maximum value of the encoder counter (TIMx->ARR register setting).
 * 
 * @return int64_t The combined 64-bit position value of the encoder.
 */
int64_t et_encoder_get_whole_count(int32_t current_count, volatile int32_t *overflow_cnt, uint32_t encoder_max_count)
{
    int64_t total_count = 0;

    if (overflow_cnt == NULL)
    {
        return 0; // Invalid pointer
    }
    // Total count calculation:
    // 1. (encoder_max_count + 1) represents the full counting range (modulus)
    //    Example: For 16-bit timer (max=65535), modulus=65536 (0x10000)
    // 2. Multiply overflow count by modulus:
    //    - Each forward overflow: +1 * (max+1)
    //    - Each backward overflow: -1 * (max+1)
    // 3. Add current counter value (0 to encoder_max_count) to get precise position
    //    within the current counting cycle
    total_count = (int64_t)current_count + (int64_t)(*overflow_cnt) * (int64_t)(encoder_max_count + 1);

    return total_count;
}
