/**
 * @file adcs_va.c
 *
 * @brief This file contains functions for vendor and OS abstracted
 * adcs functionalities
 *
 * @copyright Copyright 2023 Antaris, Inc.
 */
/*********************************************************************/

#include "adcs_va.h"
#include "adcs_vapi.h"
#include "adcs_bsk_sim.h"
#include "adcs_vapi_common.h"
#include "exo_io_al_sos_timer.h"
#include "eps_ctrlr.h"
#include "sm_api.h"
#include "exo_tctm_ipc.h"
#include "tc_tm_mngr_buffer.h"
#include "nvm.h"
#include "logger.h"
#include "adcs_vapi_fw.h"

/**
 * @brief Adcs Global structure declaration
 */
s_adcs_ctx adcs_ctx = {0};

// ADCS Interface error counter
extern uint8 adcs_interface_err;

// ADCS FSM State
uint8_t adcs_fsm_state_info = 0;

#ifdef LINUX_TEMP_PORT
//ADCS Interface Configuration
uint8_t adcs_itr = ADCS_UART;
#endif

// Health Metrics Maximum Buffer value
#define ADCS_HM_MAX_BUFFER_SIZE             (90)

// Health Metrics Global Buffers
s_adcs_hm_sen_cur PLACE_IN_EXT_RAM_MEM \
                      adcs_sen_cur_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_cons_cur PLACE_IN_EXT_RAM_MEM \
                       adcs_cons_cur_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_rw_cur PLACE_IN_EXT_RAM_MEM adcs_rw_cur_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_css_vector PLACE_IN_EXT_RAM_MEM \
                         adcs_css_vec_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_est_att_angl PLACE_IN_EXT_RAM_MEM \
                           adcs_est_att_angl_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_raw_mag_measure PLACE_IN_EXT_RAM_MEM \
                              adcs_raw_mag_meas_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_raw_rates PLACE_IN_EXT_RAM_MEM \
                        adcs_raw_rates_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_meas_rates PLACE_IN_EXT_RAM_MEM \
                         adcs_meas_rates_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_fss_vec PLACE_IN_EXT_RAM_MEM \
                      adcs_fss_vec_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_est_rates_sns PLACE_IN_EXT_RAM_MEM \
                            adcs_est_rate_sns_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_misc_cur PLACE_IN_EXT_RAM_MEM \
                       adcs_misc_cur_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_temp PLACE_IN_EXT_RAM_MEM adcs_temp_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_est_rate_sns_temp PLACE_IN_EXT_RAM_MEM \
                            adcs_est_rate_sns_temp_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_hm_crnt_state PLACE_IN_EXT_RAM_MEM \
                         adcs_crnt_state_hm[ADCS_HM_MAX_BUFFER_SIZE];
s_adcs_cur_temp adcs_cur_temp_hm;

// Health Metrics Count variable
static uint8 adcs_hm_cnt[ADCS_HM_MAX] = {0};
static uint8 adcs_hm_roll_back[ADCS_HM_MAX] = {0};

/**
 * @brief Abstracted API to set sensor parameters
 */
e_adcs_event adcs_set_sensor_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to set detumbling parameters
 */
e_adcs_event adcs_set_detumble_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to set coarse momentum parameters
 */
e_adcs_event adcs_set_coarse_momentum_params(void)
{
    e_adcs_event event;
    e_adcs_status status;

    status = vapi_adcs_set_coarse_momentum_params();
    if(OPERATION_SUCCESS == status)
    {
        event = COARSE_MOMENTUM_DONE;
    }
    else
    {
        event = COARSE_MOMENTUM_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to set fine momentum parameters
 */
e_adcs_event adcs_set_fine_momentum_params(void)
{
    e_adcs_event event;
    e_adcs_status status;

    status = vapi_adcs_set_fine_momentum_params();
    if(OPERATION_SUCCESS == status)
    {
        event = FINE_MOMENTUM_DONE;
    }
    else
    {
        event = FINE_MOMENTUM_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to set actuator parameters
 */
e_adcs_event adcs_set_acutuator_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to set configuration parameters
 */
e_adcs_event adcs_set_cfg_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to get sensor parameters
 */
e_adcs_event adcs_get_sensor_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to get detumble parameters
 */
e_adcs_event adcs_get_detumble_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to get coarse momentum parameters
 */
e_adcs_event adcs_get_coarse_momentum_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to get fine momentum parameters
 */
e_adcs_event adcs_get_fine_momentum_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to get actuator parameters
 */
e_adcs_event adcs_get_acutuator_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to get configuration parameters
 */
e_adcs_event adcs_get_cfg_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to set spg4 parameters
 */
e_adcs_event adcs_set_spg4_orbit_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to get spg4 parameters
 */
e_adcs_event adcs_get_spg4_orbit_params(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to set control mode parameters
 */
e_adcs_event adcs_set_ctrl_mode(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to get control mode parameters
 */
e_adcs_event adcs_get_ctrl_mode(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to set non-volatile memory parameters
 */
e_adcs_event adcs_set_nvm(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to get non-volatile memory parameters
 */
e_adcs_event adcs_get_nvm(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to set logging configuration
 */
e_adcs_event adcs_cfg_log(void)
{
    e_adcs_event event;
    e_adcs_status status;

    status = vapi_adcs_cfg_log();
    if(OPERATION_SUCCESS == status)
    {
        event = CONFIG_UPDT_DONE;
    }
    else
    {
        event = CONFIG_UPDT_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to command adcs boot
 */
e_adcs_event adcs_boot(void)
{
    e_adcs_event event;
    e_adcs_status status;

    status = vapi_adcs_boot();
    if(OPERATION_SUCCESS == status)
    {
        event = BOOT_INIT_DONE;
    }
    else
    {
        event = BOOT_INIT_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to command adcs reset
 */
e_adcs_event adcs_reset(void)
{
    e_adcs_event event = 0;
    e_adcs_status status;

    status = vapi_adcs_reset();
    if(OPERATION_SUCCESS == status)
    {
        event = RESET_DONE;
    }
    else
    {
        event = RESET_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to command adcs detumble
 */
e_adcs_event adcs_detumble(void)
{
    e_adcs_event event = 0;
    e_adcs_status status;

    status = vapi_adcs_detumble();
    if(OPERATION_SUCCESS == status)
    {
        event = DETUMBLE_DONE;
    }
    else
    {
        event = DETUMBLE_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to command adcs coarse_momentum
 */
e_adcs_event adcs_coarse_momentum(void)
{
    e_adcs_event event = 0;
    e_adcs_status status;

    status = vapi_adcs_coarse_momentum();
    if(OPERATION_SUCCESS == status)
    {
        event = COARSE_MOMENTUM_DONE;
    }
    else
    {
        event = COARSE_MOMENTUM_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to command adcs fine momentum
 */
e_adcs_event adcs_fine_momentum(void)
{
    e_adcs_event event = 0;
    e_adcs_status status;

    status = vapi_adcs_fine_momentum();
    if(OPERATION_SUCCESS == status)
    {
        event = FINE_MOMENTUM_DONE;
    }
    else
    {
        event = FINE_MOMENTUM_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to command magnetometer deployment
 */
e_adcs_event adcs_deploy_magntmtr(void)
{
    e_adcs_event event = 0;

    return event;
}

/**
 * @brief Abstracted API to command solar panel deployment
 */
e_adcs_event adcs_deploy_solar(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to initiliaze adcs sensors
 */
e_adcs_event adcs_sensor_init(void)
{
    e_adcs_event event;
    e_adcs_status status;

    status = vapi_adcs_sensor_init();
    if(OPERATION_SUCCESS == status)
    {
        event = SENSOR_INIT_DONE;
    }
    else
    {
        event = SENSOR_INIT_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to reset adcs sensors
 */
e_adcs_event adcs_sensor_reset(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to trigger adcs sensor calibration
 */
e_adcs_event adcs_sensor_calib_trgr(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to initiliaze adcs actuators
 */
e_adcs_event adcs_actuator_init(void)
{
    e_adcs_event event;
    e_adcs_status status;

    status = vapi_adcs_actuator_init();
    if(OPERATION_SUCCESS == status)
    {
        event = ACTUATOR_INIT_DONE;
    }
    else
    {
        event = ACTUATOR_INIT_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to reset adcs actuators
 */
e_adcs_event adcs_actuator_reset(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to trigger adcs actuator calibration
 */
e_adcs_event adcs_actuator_calib_trgr(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to read adcs sensor measurements
 */
e_adcs_event adcs_sensor_read_meas(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to read adcs actuator measurements
 */
e_adcs_event adcs_actuator_read_meas(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to trigger adcs sensor tests
 */
e_adcs_event adcs_sensor_test(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to trigger adcs actautor tests
 */
e_adcs_event adcs_actuator_test(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to initialize firmware update
 */
e_adcs_event adcs_frmwr_updt_init(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to initialize firmware download
 */
e_adcs_event adcs_frmwr_dwnld_file(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to perform firmware readback
 */
e_adcs_event adcs_frmwr_read_back(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to perform firmware checksum test
 */
e_adcs_event adcs_frmwr_checksum_test(void)
{
    e_adcs_event event = 0;
    return event;
}

/**
 * @brief Abstracted API to change attitude
 */
e_adcs_event adcs_change_attitude(s_attitude_param *param)
{
    e_adcs_event event = 0;
    e_adcs_status status;

    status = vapi_adcs_ground_tracking_control(param->longRef, param->latRef,
            param->altRef);
    if(OPERATION_SUCCESS == status)
    {
        event = CONTROL_DONE;
    }
    else
    {
        event = CONTROL_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to perform bypass mode operations
 */
e_adcs_event adcs_bypass_mode(uint8 *tx_data, uint8 *rx_data, uint16 tx_size,
        uint16 *rx_size)
{
    e_adcs_event event = 0;
    e_adcs_status status;
    /*
     * Selecting vendor
     */
#ifndef ADCS_HW_SIM
    status = vapi_adcs_bypass_mode(tx_data, rx_data, tx_size, rx_size);
#else
    status = adcs_basilisk_bypass_mode(tx_data, rx_data, tx_size, rx_size);
#endif
    if(OPERATION_SUCCESS == status)
    {
        event = ADCS_BYPASS_DONE;
    }
    else
    {
        event = ADCS_BYPASS_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to perform shutdown operations
 */
e_adcs_event adcs_shutdown_rqst(void)
{
    e_adcs_event event = 0;
    e_adcs_status status;
    status = vapi_adcs_shutdown();
    if(OPERATION_SUCCESS == status)
    {
        event = ADCS_SHUTDOWN_DONE;
    }
    else
    {
        event = ADCS_SHUTDOWN_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to perform testing operations
 */
e_adcs_event adcs_test_mode(void)
{
    e_adcs_event event = 0;
    e_adcs_status status;
    status = vapi_adcs_test_mode();
    if(OPERATION_SUCCESS == status)
    {
        event = ADCS_TEST_DONE;
    }
    else
    {
        event = ADCS_TEST_FAIL;
    }
    return event;
}

/**
 * @brief Abstracted API to perform execute fallback
 */
void adcs_exec_flbk(void)
{
    adcs_execute_fallback();
}

/**
 * @brief Abstracted API to perform execute sequence
 */
void adcs_exec_seq(uint8 *seq, uint16 size)
{
    adcs_execute_sequence(seq, size);
}

/**
 * @brief Abstracted API to initialize the adcs sequence.
 */
void adcs_init_seq()
{
    //Configuring system time
    adcs_sync_time(NULL);

    adcs_init_sequence();
}

/**
 * @brief API to handles ADCS telecommand's and telemetry's
 */
int8 adcs_unified_tctm_hdlr(uint8_t id, uint8_t *tx_data, uint8_t *rx_data,\
        uint16_t *rx_size)
{
    e_adcs_status status = OPERATION_FAILURE;
#ifndef LINUX_TEMP_PORT
    uint16 file_size = 0, tlm_blk_size = 0;
#endif
    switch(id)
    {
    case TC_SET_ADCS_RESET:
    {
        status = adcs_vapi_set_reset(&adcs_ctx,(s_adcs_reset*)tx_data);
    }
    break;
    case TC_SET_ADCS_UTC:
    {
        status = adcs_vapi_set_utc_time(&adcs_ctx, (s_adcs_time*)tx_data);
    }
    break;
    case TC_SET_ADCS_CLEAR_ERROR:
    {
        status = adcs_vapi_set_clear_error(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_SAVE_ORBIT:
    {
        status = adcs_vapi_set_save_orbit(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_TLE:
    {
        status = adcs_vapi_set_tle_params(&adcs_ctx,\
                (s_adcs_tle*)tx_data);
    }
    break;
    case TC_SET_ADCS_MOI:
    {
        status = adcs_vapi_set_mom_interia(&adcs_ctx, (s_adcs_moi*)tx_data);
    }
    break;
    case TC_SET_ADCS_PWR:
    {
        status = adcs_vapi_power_on(&adcs_ctx, (s_adcs_pwr_cmd*)tx_data);
    }
    break;
    case TC_SET_ADCS_MAGMTR_MODE_OPER:
    {
        status = adcs_vapi_set_magnetometer_mode(&adcs_ctx, \
                  tx_data[0]);
    }
    break;
    case TC_SET_ADCS_GYRO_CFG:
    {
        status = adcs_vapi_set_gyro_cfg(&adcs_ctx, (s_adcs_gyro_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_CSS_CFG:
    {
        status = adcs_vapi_set_css_cfg(&adcs_ctx,\
                (s_adcs_css_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_STAR_TRAC_CFG:
    {
        status = adcs_vapi_set_star_trkr_cfg(&adcs_ctx, \
                (s_adcs_star_trkr_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_MAGMTR_CFG:
    {
        status = adcs_vapi_set_mgmtr_cfg(&adcs_ctx, \
                (s_adcs_mgmtr_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_REDUN_MAGMTR_CFG:
    {
        status = adcs_vapi_set_red_mgmtr_cfg(&adcs_ctx, \
                (s_adcs_mgmtr_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_MAG_BOOM:
    {
        status = adcs_vapi_set_mgmtr_boom(&adcs_ctx, \
                (s_adcs_mgmtr_boom*)tx_data);
    }
    break;
    case TC_SET_ADCS_MGNTRQR_OUT:
    {
        status = adcs_vapi_set_mgntrqr_out(&adcs_ctx, \
                (s_adcs_mgntrqr_out*)tx_data);
    }
    break;
    case TC_SET_ADCS_RW_SPEED:
    {
        if(0 != tx_data[0])
        {
            status = adcs_vapi_set_rw_speed(&adcs_ctx, tx_data[0],\
                    (s_adcs_rw_speed*)&tx_data[1]);
        }
        else
        {
            status = TC_TM_ERROR;
        }
    }
    break;
    case TC_SET_ADCS_MGNTRQR_CFG:
    {
        status = adcs_vapi_set_mgntrqr_cfg(&adcs_ctx,\
                (s_adcs_mgntrqr_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_RW_CFG:
    {
        status = adcs_vapi_set_rw_cfg(&adcs_ctx,\
                (s_adcs_rw_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_CTRL_MODE:
    {
        status = adcs_vapi_set_ctrl_mode(&adcs_ctx,\
            (s_adcs_ctrl_mode*)tx_data, (u_control_mode_param*)&tx_data[3]);
    }
    break;
    case TC_SET_ADCS_DETUMBLE_CTRL:
    {
        status = adcs_vapi_set_detumble_ctrl(&adcs_ctx,\
                (s_adcs_detumble_ctrl*)tx_data);
    }
    break;
    case TC_SET_ADCS_Y_RW_CTRL:
    {
        status = adcs_vapi_set_y_rw_ctrl(&adcs_ctx,\
                (s_adcs_y_rw_ctrl*)tx_data);
    }
    break;
    case TC_SET_ADCS_RW_CTRL:
    {
        status = adcs_vapi_set_rw_ctrl(&adcs_ctx,\
                (s_adcs_rw_ctrl*)tx_data);
    }
    break;
    case TC_SET_ADCS_TRCK_CTRL_GAIN:
    {
        status = adcs_vapi_set_trck_ctrl_gain(&adcs_ctx,\
                (s_adcs_trck_ctrl_gain*)tx_data);
    }
    break;
    case TC_SET_ADCS_ATTITUDE_ANGL:
    {
        status = adcs_vapi_set_attitude_angle(&adcs_ctx,\
                (s_adcs_attitude_angl*)tx_data);
    }
    break;
    case TC_SET_ADCS_TRCK_TARGET:
    {
        status = adcs_vapi_set_trgt_trck(&adcs_ctx,\
                (s_adcs_trck_target*)tx_data);
    }
    break;
    case TC_SET_ADCS_INRTL_REF:
    {
        status = adcs_vapi_set_inrt_ref(&adcs_ctx,\
                (s_adcs_inrt_ref*)tx_data);
    }
    break;
    case TC_SET_ADCS_EST_MODE:
    {
        status = adcs_vapi_set_est_mode(&adcs_ctx,\
                (s_adcs_est_mode*)tx_data);
    }
    break;
    case TC_SET_ADCS_EST_PARAM:
    {
        status = adcs_vapi_set_est_param(&adcs_ctx,\
                (s_adcs_est_param*)tx_data);
    }
    break;
    case TC_SET_ADCS_SENSORS_CFG:
    {
        status = adcs_vapi_set_sensor_params(&adcs_ctx,\
                (e_adcs_sensor_type)tx_data[0],tx_data[1],\
                (u_adcs_sensor_config*)&tx_data[2]);
    }
    break;
    case TC_SET_ADCS_ACTUATORS_CFG:
    {
        status = adcs_vapi_set_actuator_params(&adcs_ctx,\
                (e_adcs_actuator_type)tx_data[0],tx_data[1],\
                (u_adcs_acutator_config*)&tx_data[2]);
    }
    break;
    case TC_SET_ADCS_FSS_CFG:
    {
        status = adcs_vapi_set_fss_cfg(&adcs_ctx,\
                (s_adcs_fss_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_NADIR_CFG:
    {
        status = adcs_vapi_set_nadir_cfg(&adcs_ctx,\
                (s_adcs_nadir_cfg*)tx_data);
    }
    break;
#ifndef ADCS_HW_SIM
    case TC_SET_ADCS_BOOT_INDEX:
    {
        status = adcs_vapi_set_boot_index(&adcs_ctx,\
                (s_adcs_boot_index*)tx_data);
    }
    break;
    case TC_SET_ADCS_RUN_SEL_PROG:
    {
        status = adcs_vapi_set_run_sel_prog(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_READ_PROG_INFO:
    {
        status = adcs_vapi_set_readprog_info(&adcs_ctx,\
                (s_adcs_read_prog*)tx_data);
    }
    break;
    case TC_SET_ADCS_COPY_PROG_TO_INT_FLASH:
    {
        status = adcs_vapi_copy_prog_to_interflash(&adcs_ctx,\
                (s_adcs_copy_p_to_interflash*)tx_data);
    }
    break;
    case TC_SET_ADCS_RESET_LOG_PTR:
    {
        status = adcs_vapi_set_reset_log_ptr(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_ADVANCE_LOG_PTR:
    {
        status = adcs_vapi_set_advance_log_ptr(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_RESET_BOOT_REG:
    {
        status = adcs_vapi_set_reset_boot_reg(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_FORMAT_SD_CARD:
    {
        status = adcs_vapi_set_format_sd_card(&adcs_ctx,\
                tx_data[0]);
    }
    break;
    case TC_SET_ADCS_ERASE_FILE:
    {
        status = adcs_vapi_set_erase_file(&adcs_ctx,\
                (s_adcs_erasefile*)tx_data);
    }
    break;
    case TC_SET_ADCS_LOAD_FILE_DWNLD_BLK:
    {
        status = adcs_vapi_set_load_file_dwnld_blk(&adcs_ctx,\
                (s_adcs_load_dwnld_blk*)tx_data);
    }
    break;
    case TC_SET_ADCS_ADVANCE_FILE_LIST:
    {
        status = adcs_vapi_set_advance_file_list(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_INIT_FILE_UPLD:
    {
        status = adcs_vapi_set_init_file_upld(&adcs_ctx,\
                (s_adcs_init_file_upld*)tx_data);
    }
    break;
    case TC_SET_ADCS_FILE_UPLD_PKT:
    {
        status = adcs_vapi_set_file_upld_pkt(&adcs_ctx,\
                (s_adcs_final_upld_pkt*)tx_data);
    }
    break;
    case TC_SET_ADCS_FLZE_UPLD_BLK:
    {
        status = adcs_vapi_set_flze_upld_blk(&adcs_ctx,\
                (s_adcs_flze_upld_blk*)tx_data);
    }
    break;
    case TC_SET_ADCS_RESET_UPLD_BLK:
    {
        status = adcs_vapi_set_reset_upld_blk(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_RST_FILE_LIST_PTR:
    {
        status = adcs_vapi_set_rstfile_listrd_ptr(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_INIT_DWNLD_BURST:
    {
        status = adcs_vapi_set_init_dwnld_burst(&adcs_ctx,\
                (s_adcs_init_dwnld_burst*)tx_data);
    }
    break;
    case TC_SET_ADCS_RUN_MODE:
    {
        status = adcs_vapi_set_run_mode(&adcs_ctx,\
                (e_adcs_run_mode)tx_data[0]);
    }
    break;
    case TC_SET_ADCS_TRIG_SIMU_SNS:
    {
        status = adcs_vapi_set_trig_simu_sns(&adcs_ctx,\
                (s_adcs_simu_sns_data*)tx_data);
    }
    break;
    case TC_SET_ADCS_ASGP4_RUN:
    {
        status = adcs_vapi_set_asgp4_run_mode(&adcs_ctx,\
                (e_adcs_asgp4_run_mode)tx_data[0]);
    }
    break;
    case TC_SET_ADCS_CONV_JPG:
    {
        status = adcs_vapi_set_conv_to_jpg(&adcs_ctx,\
                (s_adcs_con_to_jpg*)tx_data);
    }
    break;
    case TC_SET_ADCS_SAVE_IMG:
    {
        status = adcs_vapi_set_save_image(&adcs_ctx,\
                (s_adcs_save_img*)tx_data);
    }
    break;
    case TC_SET_ADCS_TRIG_LOOP:
    {
        status = adcs_vapi_set_trig_adcs_loop(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_ASGP4_TRIG:
    {
        status = adcs_vapi_set_asgp4_trig(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_SAVE_CFG:
    {
        status = adcs_vapi_set_save_cfg(&adcs_ctx);
    }
    break;
    case TC_SET_ADCS_CACHE_CMD:
    {
        status = adcs_vapi_set_cache_cmd(&adcs_ctx,\
                (s_adcs_cache_cmd*)tx_data);
    }
    break;
    case TC_SET_ADCS_SRAM_SCRUB:
    {
        status = adcs_vapi_set_sram_scrub(&adcs_ctx,\
                (s_adcs_sram_scrub*)tx_data);
    }
    break;
    case TC_SET_ADCS_UTC_FLASH:
    {
        status = adcs_vapi_set_utc_flash(&adcs_ctx,\
                (s_adcs_utc_flash*)tx_data);
    }
    break;
    case TC_SET_ADCS_ASGP4_PARAM:
    {
        status = adcs_vapi_set_asgp4_param(&adcs_ctx,\
                (s_adcs_asgp4_param*)tx_data);
    }
    break;
    case TC_SET_ADCS_USER_CTRLR_EST:
    {
        status = adcs_vapi_set_user_ctrlr_est_sett(&adcs_ctx,\
                (s_adcs_user_ctrlr_est_sett*)tx_data);
    }
    break;
    case TC_SET_ADCS_SD_LOG1_CFG_CFG:
    {
        status = adcs_vapi_set_sdlog1_cfg(&adcs_ctx,\
                (s_adcs_sdlog_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_SD_LOG2_CFG_CFG:
    {
        status = adcs_vapi_set_sdlog2_cfg(&adcs_ctx,\
                (s_adcs_sdlog_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_UART_LOG_CFG:
    {
        status = adcs_vapi_set_uart_log(&adcs_ctx,\
                (s_adcs_uart_log_cfg*)tx_data);
    }
    break;
    case TC_SET_ADCS_HOLE_MAP1:
    {
        status = adcs_vapi_set_hole_map1(&adcs_ctx,\
                (s_adcs_holemap*)tx_data);
    }
    break;
    case TC_SET_ADCS_HOLE_MAP2:
    {
        status = adcs_vapi_set_hole_map2(&adcs_ctx,\
                (s_adcs_holemap*)tx_data);
    }
    break;
    case TC_SET_ADCS_HOLE_MAP3:
    {
        status = adcs_vapi_set_hole_map3(&adcs_ctx,\
                (s_adcs_holemap*)tx_data);
    }
    break;
    case TC_SET_ADCS_HOLE_MAP4:
    {
        status = adcs_vapi_set_hole_map4(&adcs_ctx,\
                (s_adcs_holemap*)tx_data);
    }
    break;
    case TC_SET_ADCS_HOLE_MAP5:
    {
        status = adcs_vapi_set_hole_map5(&adcs_ctx,\
                (s_adcs_holemap*)tx_data);
    }
    break;
    case TC_SET_ADCS_HOLE_MAP6:
    {
        status = adcs_vapi_set_hole_map6(&adcs_ctx,\
                (s_adcs_holemap*)tx_data);
    }
    break;
    case TC_SET_ADCS_HOLE_MAP7:
    {
        status = adcs_vapi_set_hole_map7(&adcs_ctx,\
                (s_adcs_holemap*)tx_data);
    }
    break;
    case TC_SET_ADCS_HOLE_MAP8:
    {
        status = adcs_vapi_set_hole_map8(&adcs_ctx,\
                (s_adcs_holemap*)tx_data);
    }
    break;
#endif

    case TM_GET_ADCS_ID:
    {
        status = adcs_vapi_get_id(&adcs_ctx,\
                (s_adcs_id*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_STATE:
    {
        status = adcs_vapi_get_state(&adcs_ctx,\
                (s_adcs_state*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_TLE:
    {
        status = adcs_vapi_get_tle(&adcs_ctx,\
                (s_adcs_tle*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_MOI:
    {
        status = adcs_vapi_get_moi(&adcs_ctx,\
                (s_adcs_moi*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_PWR:
    {
        status = adcs_vapi_get_power(&adcs_ctx,\
                (s_adcs_pwr_cmd*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_MAG_FIELD_VEC:
    {
        status = adcs_vapi_get_mag_vector(&adcs_ctx,\
                (s_adcs_mag_vector*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_CSS_VEC:
    {
        status = adcs_vapi_get_css_sun_vector(&adcs_ctx,\
                (s_adcs_sun_vector*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_FSS_VEC:
    {
        status = adcs_vapi_get_fss_sun_vector(&adcs_ctx,\
                (s_adcs_sun_vector*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_NADIR_VEC:
    {
        status = adcs_vapi_get_nadir_vector(&adcs_ctx,\
                (s_adcs_nadir_vector*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_SENSOR_RATE:
    {
        status = adcs_vapi_get_sensor_rate(&adcs_ctx,\
                (s_adcs_rate_sens*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_STAR_TRKR_BVEC:
    {
        status = adcs_vapi_get_star_body(&adcs_ctx, tx_data[0],\
                (s_adcs_star_trkr_body*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_STAR_TRKR_OVEC:
    {
        status = adcs_vapi_get_star_orbit(&adcs_ctx, tx_data[0],\
                (s_adcs_star_trkr_orbit*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_NADIR_SEN:
    {
        status = adcs_vapi_get_raw_nadir(&adcs_ctx,\
                (s_adcs_nadir_sens*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_FSS_SEN:
    {
        status = adcs_vapi_get_raw_fss(&adcs_ctx,\
                (s_adcs_fss_sens*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_MAGMTR:
    {
        status = adcs_vapi_get_raw_magmtr(&adcs_ctx,\
                (s_adcs_raw_mgmtr*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_GPS_STS:
    {
        status = adcs_vapi_get_raw_gps_status(&adcs_ctx,\
                (s_adcs_gps_s*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_GPS_TIME:
    {
        status = adcs_vapi_get_raw_gps_time(&adcs_ctx,\
                (s_adcs_gps_time*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_GPS_X:
    {
        status = adcs_vapi_get_raw_gps_x(&adcs_ctx,\
                (s_adcs_gps_x*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_GPS_Y:
    {
        status = adcs_vapi_get_raw_gps_y(&adcs_ctx,\
                (s_adcs_gps_y*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_GPS_Z:
    {
        status = adcs_vapi_get_raw_gps_z(&adcs_ctx,\
                (s_adcs_gps_z*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_STAR_MAG:
    {
        status = adcs_vapi_get_star_magnitude(&adcs_ctx,\
                (s_adcs_star_trkr_mag*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_STAR_PERFORM:
    {
        status = adcs_vapi_get_star_performance(&adcs_ctx,\
                (s_adcs_star_trkr_perform*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_STAR_TIMING:
    {
        status = adcs_vapi_get_star_timing(&adcs_ctx,\
                (s_adcs_star_trkr_timing*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_SENS:
    {
        status = adcs_vapi_get_raw_sensor_measure(&adcs_ctx,\
                (s_adcs_raw_sensor*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_GPS:
    {
        status = adcs_vapi_get_raw_gps_measure(&adcs_ctx,\
                (s_adcs_raw_gps*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_STAR_TRAC:
    {
        status = adcs_vapi_get_raw_star_measure(&adcs_ctx,\
                (s_adcs_raw_star_trkr*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_STAR_RDATA:
    {
        status = adcs_vapi_get_raw_star_data(&adcs_ctx, tx_data[0],\
                (s_adcs_raw_star_trkr_data*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_SEC_MAGMTR:
    {
        status = adcs_vapi_get_sec_raw_magmtr_measure(&adcs_ctx,\
                (s_adcs_raw_mgmtr*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RAW_SENS_RATE:
    {
        status = adcs_vapi_get_raw_rates(&adcs_ctx,\
                (s_adcs_raw_rate_sens*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_STAR_EST_RATE:
    {
        status = adcs_vapi_get_star_est_rate(&adcs_ctx,\
                (s_adcs_star_est_rate*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_SENS_CUR:
    {
        status = adcs_vapi_get_sensor_current(&adcs_ctx,\
                (s_adcs_sens_cur*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RW_CUR:
    {
        if(0 != tx_data[0])
        {
            status = adcs_vapi_get_rw_current(&adcs_ctx, tx_data[0],\
                    (s_adcs_rw_cur*)&rx_data[5]);
            // Assign Reaction wheel count
            rx_data[4] = tx_data[0];
        }
        else
        {
            status = TC_TM_ERROR;
        }
    }
    break;
    case TM_GET_ADCS_TEMP:
    {
        status = adcs_vapi_get_temperature(&adcs_ctx,\
                (s_adcs_temperature*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_CON_CUR:
    {
        status = adcs_vapi_get_con_current_measure(&adcs_ctx,\
                (s_adcs_current*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_POW_TEMP:
    {
        status = adcs_vapi_get_power_temperature(&adcs_ctx,\
                    (s_adcs_cur_temp*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_SENS_RATE_TEMP:
    {
        status = adcs_vapi_get_rate_sensor_temperature(&adcs_ctx,\
                (s_adcs_rate_temperature*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_GYRO_CFG:
    {
        status = adcs_vapi_get_gyro_cfg(&adcs_ctx,\
                (s_adcs_gyro_cfg*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_STAR_TRAC_CFG:
    {
        status = adcs_vapi_get_star_trkr_cfg(&adcs_ctx,\
                (s_adcs_star_trkr_cfg*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_MAGMTR_CFG:
    {
        status = adcs_vapi_get_mgmtr_cfg(&adcs_ctx,\
                (s_adcs_mgmtr_cfg*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_CSS_CFG:
    {
        status = adcs_vapi_get_css_cfg(&adcs_ctx,\
                (s_adcs_css_cfg*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_FSS_CFG:
    {
        status = adcs_vapi_get_fss_cfg(&adcs_ctx,\
                (s_adcs_fss_cfg*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_NADIR_CFG:
    {
        status = adcs_vapi_get_nadir_cfg(&adcs_ctx,\
                (s_adcs_nadir_cfg*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RED_MAGMTR_CFG:
    {
        status = adcs_vapi_get_red_mgmtr_cfg(&adcs_ctx,\
                (s_adcs_mgmtr_cfg*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_MGNTRQR_CFG:
    {
        status = adcs_vapi_get_mgntrqr_cfg(&adcs_ctx,\
                (s_adcs_mgntrqr_cfg*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RW_CFG:
    {
        status = adcs_vapi_get_rw_cfg(&adcs_ctx,\
                (s_adcs_rw_cfg*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_DETUMBLE_CTRL:
    {
        status = adcs_vapi_get_detumble_param(&adcs_ctx,\
                (s_adcs_detumble_ctrl*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_Y_RW_CTRL:
    {
        status = adcs_vapi_get_y_rw_ctrl(&adcs_ctx,\
                (s_adcs_y_rw_ctrl*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RW_CTRL:
    {
        status = adcs_vapi_get_rw_ctrl(&adcs_ctx,\
                (s_adcs_rw_ctrl*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_TRCK_CTRL_GAIN:
    {
        status = adcs_vapi_get_trck_ctrl_gain(&adcs_ctx,\
                (s_adcs_trck_ctrl_gain*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_ATTITUDE_ANGL:
    {
        status = adcs_vapi_get_attitude(&adcs_ctx,\
                (s_adcs_attitude_angl*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_TRCK_TARGET:
    {
        status = adcs_vapi_get_target_track(&adcs_ctx,\
                (s_adcs_trck_target*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_INRTL_REF:
    {
        status = adcs_vapi_get_inertial_ref(&adcs_ctx,\
                (s_adcs_inrt_ref*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EST_PARAM:
    {
        status = adcs_vapi_get_est_param(&adcs_ctx,\
                (s_adcs_est_param*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_POS_ECI:
    {
        status = adcs_vapi_get_eci_postition(&adcs_ctx,\
                (s_adcs_eci_position*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_VEL:
    {
        status = adcs_vapi_get_sat_velocity(&adcs_ctx,\
                (s_adcs_eci_velocity*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_POS_LLH:
    {
        status = adcs_vapi_get_llh_psition(&adcs_ctx,\
                (s_adcs_trck_target*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EST_RATE:
    {
        status = adcs_vapi_get_est_rate(&adcs_ctx,\
                (s_adcs_est_rate*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EST_QUTRN:
    {
        status = adcs_vapi_get_est_qutrn(&adcs_ctx,\
                (s_adcs_est_qutrn*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_ECEF_POS:
    {
        status = adcs_vapi_get_ecef_position(&adcs_ctx,\
                (s_adcs_eci_position*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_MODL_MAG:
    {
        status = adcs_vapi_get_mog_mag_vector(&adcs_ctx,\
                (s_adcs_mag_vector*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_MODL_SUN:
    {
        status = adcs_vapi_get_mod_sun_vector(&adcs_ctx,\
                (s_adcs_sun_vector*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EST_GYRO:
    {
        status = adcs_vapi_get_est_gyro_measure(&adcs_ctx,\
                (s_adcs_est_gyro*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EST_INNOVN:
    {
        status = adcs_vapi_get_est_innovation(&adcs_ctx,\
                (s_adcs_est_innovn*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_QUTR_ERROR:
    {
        status = adcs_vapi_get_qutrn_error(&adcs_ctx,\
                (s_adcs_qutr_error*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_QUTR_COVR:
    {
        status = adcs_vapi_get_qutrn_covr(&adcs_ctx,\
                (s_adcs_qutr_covr*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_ANGL_COVR:
    {
        status = adcs_vapi_get_ang_rate_covr(&adcs_ctx,\
                (s_adcs_angl_rate_covr*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_RW_SPEED:
    {
        if(0 != tx_data[0])
        {
            status = adcs_vapi_get_rw_speed_cmd(&adcs_ctx, tx_data[0],\
                    (s_adcs_rw_speed*)&rx_data[5]);
            // Assign Reaction wheel count
            rx_data[4] = tx_data[0];
        }
        else
        {
            status = TC_TM_ERROR;
        }
    }
    break;
    case TM_GET_ADCS_RW_SPEED_MEASURE:
    {
        if(0 != tx_data[0])
        {
            status = adcs_vapi_get_rw_speed_measure(&adcs_ctx, tx_data[0],\
                    (s_adcs_rw_speed*)&rx_data[5]);
            // Assign Reaction wheel count
            rx_data[4] = tx_data[0];
        }
        else
        {
            status = TC_TM_ERROR;
        }
    }
    break;
    case TM_GET_ADCS_CTRL_MODE:
    {
        status = adcs_vapi_get_control_mode(&adcs_ctx,\
                &rx_data[4], (u_control_mode_param*)&rx_data[5]);
    }
    break;
#ifndef ADCS_HW_SIM
    case TM_GET_ADCS_BOOT_RUNG_PRGRM_STS:
    {
        status = adcs_vapi_get_boot_run_prog_status(&adcs_ctx,\
                (s_adcs_b_run_prog_sts*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_BOOT_INDX_STS:
    {
        status = adcs_vapi_get_boot_indx_status(&adcs_ctx,\
                (s_adcs_b_index_sts*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_LST_LGGD_EVNT:
    {
        status = adcs_vapi_get_last_log_evnt(&adcs_ctx,\
                (s_adcs_last_log_evnt*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_SRAM_LATCHUP_CNTR:
    {
        status = adcs_vapi_get_latchup_cntr(&adcs_ctx,\
                (s_adcs_latchup_cntr*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EDAC_ERR_CNTR:
    {
        status = adcs_vapi_get_edac_err_cntr(&adcs_ctx,\
                (s_adcs_edac_err_cntr*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_COMM_STS:
    {
        status = adcs_vapi_get_comm_sts(&adcs_ctx,\
                (s_adcs_comm_sts*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_FRMT_PRGRS:
    {
        status = adcs_vapi_get_sd_erase_prgrs(&adcs_ctx,\
                (s_adcs_erase_prgrs*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_TC_ACK:
    {
        status = adcs_vapi_get_tc_ack(&adcs_ctx,\
                (s_adcs_tc_ack*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_FILE_DWNLD_CNTNT:
    {
        status = adcs_vapi_get_file_dwnld(&adcs_ctx,\
                (s_adcs_file_dwnld_buffer*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_DWNLD_BLCK_RDY:
    {
        status = adcs_vapi_get_dwnld_blck_rdy(&adcs_ctx,\
                (s_adcs_dwnld_blck_ready*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_FILE_INFO:
    {
        status = adcs_vapi_get_file_info(&adcs_ctx,\
                (s_adcs_file_info*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_INITLZE_UPLD_CMPLT:
    {
        status = adcs_vapi_get_initialize_upld_cmplt(&adcs_ctx,\
                (s_adcs_init_upld*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_UPLD_BLCK_CMPLT:
    {
        status = adcs_vapi_get_upld_blck_cmplt(&adcs_ctx,\
                (s_adcs_upld_blck_cmplt*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_BLCK_CRC:
    {
        status = adcs_vapi_get_blck_crc(&adcs_ctx,\
                (s_adcs_blck_crc*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_BTLR_STATE:
    {
        status = adcs_vapi_get_btlr_state(&adcs_ctx,\
                (s_adcs_btlr_state*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_PRGRM_INFO:
    {
        status = adcs_vapi_get_prgrm_info(&adcs_ctx,\
                (s_adcs_prgm_info*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_CPY_INTRNL_FLSH_PRGRS:
    {
        status = adcs_vapi_get_cpy_intrnl_flsh_prgrs(&adcs_ctx,\
                (s_adcs_cpy_intrnl_flsh_prgrs*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_JPG_CNVRSN_PRGRS:
    {
        status = adcs_vapi_get_jpg_cnvrsn_prgrs(&adcs_ctx,\
                (s_adcs_jpg_cnvrsn_prgrs*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EXECN_TIME:
    {
        status = adcs_vapi_get_exec_time(&adcs_ctx,\
                (s_adcs_exec_time*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EXECN_STATE:
    {
        status = adcs_vapi_get_exec_state(&adcs_ctx,\
                (s_adcs_exec_state*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_IMG_CPTR_SAVE_OPR_STS:
    {
        status = adcs_vapi_get_img_sv_sts(&adcs_ctx,\
                (s_adcs_img_sv_sts*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_MGNTRQR_CMD:
    {
        status = adcs_vapi_get_mgntrqr_cmd(&adcs_ctx,\
                (s_adcs_mgntrqr_out*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_ACTUATOR_CMD:
    {
        status = adcs_vapi_get_actuator_cmd(&adcs_ctx,\
                (s_adcs_actuator_cmd*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EST_DATA:
    {
        status = adcs_vapi_get_estimation_data(&adcs_ctx,\
                (s_adcs_estmiation_data*)&rx_data[4]);
    }
    break;
    case TM_GET_STAR_EST_QUTRN:
    {
        status = adcs_vapi_get_star_qutr_attitude(&adcs_ctx,\
                (s_adcs_qutr_attitude*)&rx_data[4]);
    }
    break;
    case TM_GET_FINE_EST_RATE:
    {
        status = adcs_vapi_get_star_est_rates(&adcs_ctx,\
                (s_adcs_star_trckr_est_rates*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_MEASUREMENT:
    {
        status = adcs_vapi_get_adcs_measurement(&adcs_ctx,\
                (s_adcs_measurement*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_CACHE_CMD:
    {
        status = adcs_vapi_get_cache_cmd(&adcs_ctx,\
                (s_adcs_cache_cmd *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_SRAM_SCRUB:
    {
        status = adcs_vapi_get_sram_scrub(&adcs_ctx,\
                (s_adcs_sram_scrub *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_UTC_FLASH:
    {
        status = adcs_vapi_get_utc_flash(&adcs_ctx,\
                (s_adcs_utc_flash *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_ASGP4_PARAM:
    {
        status = adcs_vapi_get_asgp4_param(&adcs_ctx,\
                (s_adcs_asgp4_param *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_USER_CTRLR_EST:
    {
        status = adcs_vapi_get_user_ctrlr_est_sett(&adcs_ctx,\
                (s_adcs_user_ctrlr_est_sett *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_SDLOG1_CFG:
    {
        status = adcs_vapi_get_sdlog1_cfg(&adcs_ctx,\
                (s_adcs_sdlog_cfg *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_SDLOG2_CFG:
    {
        status = adcs_vapi_get_sdlog2_cfg(&adcs_ctx,\
                (s_adcs_sdlog_cfg *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_UART_LOG_CFG:
    {
        status = adcs_vapi_get_uart_log_cfg(&adcs_ctx,\
                (s_adcs_uart_log_cfg *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_HOLE_MAP1:
    {
        status = adcs_vapi_get_hole_map1(&adcs_ctx,\
                (s_adcs_holemap *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_HOLE_MAP2:
    {
        status = adcs_vapi_get_hole_map2(&adcs_ctx,\
                (s_adcs_holemap *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_HOLE_MAP3:
    {
        status = adcs_vapi_get_hole_map3(&adcs_ctx,\
                (s_adcs_holemap *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_HOLE_MAP4:
    {
        status = adcs_vapi_get_hole_map4(&adcs_ctx,\
                (s_adcs_holemap *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_HOLE_MAP5:
    {
        status = adcs_vapi_get_hole_map5(&adcs_ctx,\
                (s_adcs_holemap *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_HOLE_MAP6:
    {
        status = adcs_vapi_get_hole_map6(&adcs_ctx,\
                (s_adcs_holemap *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_HOLE_MAP7:
    {
        status = adcs_vapi_get_hole_map7(&adcs_ctx,\
                (s_adcs_holemap *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_HOLE_MAP8:
    {
        status = adcs_vapi_get_hole_map8(&adcs_ctx,\
                (s_adcs_holemap *)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_CRNT_UTC:
    {
        status = adcs_vapi_get_crnt_unix_time(&adcs_ctx,\
                (s_adcs_time*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EST_ATTITUDE_ANGL:
    {
        status = adcs_vapi_get_est_attitude(&adcs_ctx,\
                (s_adcs_attitude_angl*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_MISC_CUR:
    {
        status = adcs_vapi_get_misc_cur(&adcs_ctx,\
                (s_adcs_misc_cur*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_ASGP4_TLE:
    {
        status = adcs_vapi_get_asgp4_tle(&adcs_ctx,\
                (s_adcs_asgp4_tle*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_STAR_PERFORM2:
    {
        status = adcs_vapi_get_star_perform2(&adcs_ctx,\
                (s_adcs_star_perform2*)&rx_data[4]);
    }
    break;
    case TM_GET_ADCS_EST_MODE:
    {
        status = adcs_vapi_get_est_mode(&adcs_ctx, &rx_data[4]);
    }
    break;
    case TM_GET_ADCS_SENSORS_CFG:
    {
        status = adcs_vapi_get_sensor_params(&adcs_ctx,\
                (e_adcs_sensor_type)tx_data[0],tx_data[1],\
                (u_adcs_sensor_config*)&rx_data[6]);
        os_memcpy(&rx_data[4], tx_data, 2);
    }
    break;
    case TM_GET_ADCS_ACTUATORS_CFG:
    {
        status = adcs_vapi_get_actuator_params(&adcs_ctx,\
                (e_adcs_actuator_type)tx_data[0],tx_data[1],\
                (u_adcs_acutator_config*)&rx_data[6]);
        os_memcpy(&rx_data[4], tx_data, 2);
    }
    break;
    case TM_GET_ADCS_RAW_CSS:
    {
    	status = adcs_vapi_get_raw_css(&adcs_ctx, tx_data[0], (s_adcs_raw_css*)&rx_data[5]);
        os_memcpy(&rx_data[4], tx_data, 1);
    }
    break;
#endif
    case OBC_SET_ADCS_FDWNLD_PARAM:
    {
#ifndef LINUX_TEMP_PORT
        os_memcpy(&file_size, &tx_data[0], 2);
        os_memcpy(&tlm_blk_size, &tx_data[2], 2);
        status = adcs_set_fdwnld_param(file_size, tlm_blk_size);
#endif
    }
    break;
    case TM_GET_ADCS_HEALTH_METRICS:
    {
        status = adcs_get_health_metrics(tx_data[0], tx_data[1], &rx_data[4]);
    }
    break;
    case ADCS_INTERFACE_CFG:
    {
        if(tx_data[0] == SET_DATA)
        {
#ifdef LINUX_TEMP_PORT
            adcs_itr = tx_data[1];
            rx_data[4] = adcs_itr;
            status = OPERATION_SUCCESS;
#else
            status = adcs_interface_cfg(tx_data[1]);
            rx_data[4] = get_adcs_interface();
#endif
        }
        else
        {
#ifdef LINUX_TEMP_PORT
            rx_data[4] = adcs_itr;
            status = OPERATION_SUCCESS;
#else
            rx_data[4] = get_adcs_interface();
            status = OPERATION_SUCCESS;
#endif
        }

    }
    break;
    case TM_GET_ADCS_STATE_CFG:
    {
        nvm_parameter_read(NVM_DATA, NVM_ADCS_AUTO_COMMISIONING,
                                (uint8*)&rx_data[4]);
        rx_data[5] = sm_get_state(ADCS_FSM);
        status = OPERATION_SUCCESS;
    }
    break;
    case TM_GET_ADCS_FW_UPD_STS:
    {
        status = get_adcs_fw_upd_sts();
    }
    break;
    default:
    {
        status = ID_NOT_SUPPORT;
    }
    break;
    }
    if(status == 0)
    {
        if(TM_GET_ADCS_HEALTH_METRICS == id)
        {
            *rx_size = (adcs_get_hm_tlm_len(rx_data[4]) * rx_data[5]) + 2;
        }
        else if(TM_GET_ADCS_RAW_CSS == id)
        {
            if(0 == rx_data[4])
            {
                *rx_size = (bsk_get_tlm_len(id) * 10) + 1;
            }
            else
            {
                *rx_size = bsk_get_tlm_len(id) + 1;
            }
        }
        else if(TM_GET_ADCS_RW_SPEED == id || TM_GET_ADCS_RW_SPEED_MEASURE == id\
                || TM_GET_ADCS_RW_CUR == id)
        {
            *rx_size = (bsk_get_tlm_len(id) * rx_data[4]) + 1;
        }
        else
        {
            *rx_size = bsk_get_tlm_len(id);
        }
    }
    else
    {
        *rx_size = 0;
    }
        rx_data[0] = ADCS_TCTM_SOF1;
        rx_data[1] = ADCS_TCTM_SOF2;
        rx_data[ADCS_TC_TM_ID_IDX] = id;
        rx_data[3] = status;
        rx_data[4 + *rx_size] = ADCS_TCTM_EOF1;
        rx_data[5 + *rx_size] = ADCS_TCTM_EOF2;
        *rx_size = *rx_size + 6;
    return status;
}

/**
 * @brief API to handles ADCS telecommand & telemetry
 */
int8 adcs_tc_tm_hdlr(uint8_t* tx_data, uint8_t tx_size,\
        uint8_t *rx_data, uint16_t *rx_size)
{
    int8 status = -1;

    if(tx_data[2] == ADCS_OEM_CMD)
    {
        tx_size = tx_size - 5;
        status = adcs_bypass_mode(&tx_data[3], &rx_data[3], tx_size, rx_size);
        rx_data[0] = ADCS_TCTM_SOF1;
        rx_data[1] = ADCS_TCTM_SOF2;
        rx_data[2] = ADCS_OEM_CMD;
        rx_data[3 + *rx_size] = ADCS_TCTM_EOF1;
        rx_data[4 + *rx_size] = ADCS_TCTM_EOF2;
        *rx_size += 5;
    }
    else
    {
        status = adcs_unified_tctm_hdlr(tx_data[2], &tx_data[3], \
                rx_data, rx_size);
    }
    log_id_with_two_arg(LOG_INFO_L1,LOG_ADCS,ADCS_TC_TM_ID__u8__STATUS__s8_,
            tx_data[2],status);
    return status;
}

/**
 * @brief This API Update the health metrics in global buffer
 */
void adcs_health_info_event()
{
    static uint8 metrics_id = ADCS_HM_SESNOR_CURRENT;
    uint8 buf_idx = 0;
    uint64_t crnt_time;
    e_adcs_status status = OPERATION_FAILURE;
    crnt_time = get_crnt_time_date_in_epoch();

    switch(metrics_id)
    {
    case ADCS_HM_SESNOR_CURRENT:
    {
        status = adcs_vapi_get_power_temperature(&adcs_ctx, \
                (s_adcs_cur_temp*)&adcs_cur_temp_hm);
        buf_idx = adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT];
        adcs_sen_cur_hm[buf_idx].time = crnt_time;
        adcs_sen_cur_hm[buf_idx].status = status;
        os_memcpy(&adcs_sen_cur_hm[buf_idx].nadir_3v3_current,\
                &adcs_cur_temp_hm.sensor_current, sizeof(s_adcs_sens_cur));
        adcs_hm_enqueue_req((uint8_t*)&adcs_sen_cur_hm, \
                sizeof(s_adcs_hm_sen_cur), ADCS_HM_SESNOR_CURRENT);
        ++adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT];
        if(adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT] = 0;
            adcs_hm_roll_back[ADCS_HM_SESNOR_CURRENT] = 1;
        }

        buf_idx = adcs_hm_cnt[ADCS_HM_CONS_CURRENT];
        adcs_cons_cur_hm[buf_idx].time = crnt_time;
        adcs_cons_cur_hm[buf_idx].status = status;
        os_memcpy(&adcs_cons_cur_hm[buf_idx].current_3v3, \
                &adcs_cur_temp_hm.adcs_current, sizeof(s_adcs_current));
        adcs_hm_enqueue_req((uint8_t*)&adcs_cons_cur_hm,\
                sizeof(s_adcs_hm_cons_cur), ADCS_HM_CONS_CURRENT);
        ++adcs_hm_cnt[ADCS_HM_CONS_CURRENT];
        if(adcs_hm_cnt[ADCS_HM_CONS_CURRENT] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_CONS_CURRENT] = 0;
            adcs_hm_roll_back[ADCS_HM_CONS_CURRENT] = 1;
        }

        buf_idx = adcs_hm_cnt[ADCS_HM_RW_CURRENT];
        adcs_rw_cur_hm[buf_idx].time = crnt_time;
        adcs_rw_cur_hm[buf_idx].status = status;
        os_memcpy(&adcs_rw_cur_hm[buf_idx].rw1_current, \
                &adcs_cur_temp_hm.rw_current, sizeof(s_adcs_rw_cur));
        adcs_hm_enqueue_req((uint8_t*)&adcs_rw_cur_hm,
                sizeof(s_adcs_hm_rw_cur), ADCS_HM_RW_CURRENT);
        ++adcs_hm_cnt[ADCS_HM_RW_CURRENT];
        if(adcs_hm_cnt[ADCS_HM_RW_CURRENT] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_RW_CURRENT] = 0;
            adcs_hm_roll_back[ADCS_HM_RW_CURRENT] = 1;
        }

        buf_idx = adcs_hm_cnt[ADCS_HM_MISC_CURRENT];
        adcs_misc_cur_hm[buf_idx].time = crnt_time;
        adcs_misc_cur_hm[buf_idx].status = status;
        adcs_misc_cur_hm[buf_idx].cubestar_cur = \
                adcs_cur_temp_hm.star_trkr_current;
        adcs_misc_cur_hm[buf_idx].mgntqr_cur = \
                adcs_cur_temp_hm.magtrqr_current;
        adcs_misc_cur_hm[buf_idx].cubestar_mcu_temp = \
                adcs_cur_temp_hm.star_trkr_mcu_temp;
        adcs_hm_enqueue_req((uint8_t*)&adcs_misc_cur_hm,
                sizeof(s_adcs_hm_misc_cur), ADCS_HM_MISC_CURRENT);
        ++adcs_hm_cnt[ADCS_HM_MISC_CURRENT];
        if(adcs_hm_cnt[ADCS_HM_MISC_CURRENT] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_MISC_CURRENT] = 0;
            adcs_hm_roll_back[ADCS_HM_MISC_CURRENT] = 1;
        }

        buf_idx = adcs_hm_cnt[ADCS_HM_TEMPERATURE];
        adcs_temp_hm[buf_idx].time = crnt_time;
        adcs_temp_hm[buf_idx].status = status;
        os_memcpy(&adcs_temp_hm[buf_idx].mcu_temp, \
                &adcs_cur_temp_hm.adcs_temp, sizeof(s_adcs_temperature));
        adcs_hm_enqueue_req((uint8_t*)&adcs_temp_hm, \
                sizeof(s_adcs_hm_temp), ADCS_HM_TEMPERATURE);
        ++adcs_hm_cnt[ADCS_HM_TEMPERATURE];
        if(adcs_hm_cnt[ADCS_HM_TEMPERATURE] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_TEMPERATURE] = 0;
            adcs_hm_roll_back[ADCS_HM_TEMPERATURE] = 1;
        }

        buf_idx = adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE];
        adcs_est_rate_sns_temp_hm[buf_idx].time = crnt_time;
        adcs_est_rate_sns_temp_hm[buf_idx].status = status;
        os_memcpy(&adcs_est_rate_sns_temp_hm[buf_idx].x_rate_sns, \
                &adcs_cur_temp_hm.rate_sensor_temp, \
                sizeof(s_adcs_rate_temperature));
        adcs_hm_enqueue_req((uint8_t*)&adcs_est_rate_sns_temp_hm,\
                sizeof(s_adcs_hm_est_rate_sns_temp),
                ADCS_HM_RATE_SENSOR_TEMPERATURE);
        ++adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE];
        if(adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE] >=
                ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE] = 0;
            adcs_hm_roll_back[ADCS_HM_RATE_SENSOR_TEMPERATURE] = 1;
        }

        metrics_id = ADCS_HM_CSS_VECTOR;
    }
    break;
    case ADCS_HM_CSS_VECTOR:
    {
        buf_idx = adcs_hm_cnt[ADCS_HM_CSS_VECTOR];
        adcs_css_vec_hm[buf_idx].time = crnt_time;
        adcs_css_vec_hm[buf_idx].status =
                adcs_vapi_get_css_sun_vector(&adcs_ctx, \
            (s_adcs_sun_vector*)&adcs_css_vec_hm[buf_idx].coarse_sun_x);
        adcs_hm_enqueue_req((uint8_t*)&adcs_css_vec_hm,\
                sizeof(s_adcs_hm_css_vector), ADCS_HM_CSS_VECTOR);
        ++adcs_hm_cnt[ADCS_HM_CSS_VECTOR];
        if(adcs_hm_cnt[ADCS_HM_CSS_VECTOR] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_CSS_VECTOR] = 0;
            adcs_hm_roll_back[ADCS_HM_CSS_VECTOR] = 1;
        }
        metrics_id = ADCS_HM_EST_ATTITUDE_ANGLE;
    }
    break;
    case ADCS_HM_EST_ATTITUDE_ANGLE:
    {
        buf_idx = adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE];
        adcs_est_att_angl_hm[buf_idx].time = crnt_time;
#ifndef ADCS_HW_SIM
        adcs_est_att_angl_hm[buf_idx].status =
                adcs_vapi_get_est_attitude(&adcs_ctx,\
               (s_adcs_attitude_angl*)&adcs_est_att_angl_hm[buf_idx].roll);
#endif
        adcs_hm_enqueue_req((uint8_t*)&adcs_est_att_angl_hm,\
                sizeof(s_adcs_hm_est_att_angl),\
                ADCS_HM_EST_ATTITUDE_ANGLE);
        ++adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE];
        if(adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE] = 0;
            adcs_hm_roll_back[ADCS_HM_EST_ATTITUDE_ANGLE] = 1;
        }
        metrics_id = ADCS_HM_RAW_MAG_MEASURE;
    }
    break;
    case ADCS_HM_RAW_MAG_MEASURE:
    {
        buf_idx = adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE];
        adcs_raw_mag_meas_hm[buf_idx].time = crnt_time;
        adcs_raw_mag_meas_hm[buf_idx].status =
                adcs_vapi_get_raw_magmtr(&adcs_ctx,\
                 (s_adcs_raw_mgmtr*)&adcs_raw_mag_meas_hm[buf_idx].mag_raw_x);
        adcs_hm_enqueue_req((uint8_t*)&adcs_raw_mag_meas_hm,\
                sizeof(s_adcs_hm_raw_mag_measure),\
                ADCS_HM_RAW_MAG_MEASURE);
        ++adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE];
        if(adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE] = 0;
            adcs_hm_roll_back[ADCS_HM_RAW_MAG_MEASURE] = 1;
        }
        metrics_id = ADCS_HM_RAW_RATE_SENSOR_MEASURE;
    }
    break;
    case ADCS_HM_RAW_RATE_SENSOR_MEASURE:
    {
        buf_idx = adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE];
        adcs_raw_rates_hm[buf_idx].time = crnt_time;
        adcs_raw_rates_hm[buf_idx].status = adcs_vapi_get_raw_rates(&adcs_ctx,\
                (s_adcs_raw_rate_sens*)&adcs_raw_rates_hm[buf_idx].raw_rate_x);
        adcs_hm_enqueue_req((uint8_t*)&adcs_raw_rates_hm,\
                sizeof(s_adcs_hm_raw_rates),\
                ADCS_HM_RAW_RATE_SENSOR_MEASURE);
        ++adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE];
        if(adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE] >=
                ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE] = 0;
            adcs_hm_roll_back[ADCS_HM_RAW_RATE_SENSOR_MEASURE] = 1;
        }
        metrics_id = ADCS_HM_RATE_SENSOR_MEASURE;
    }
    break;
    case ADCS_HM_RATE_SENSOR_MEASURE:
    {
        buf_idx = adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE];
        adcs_meas_rates_hm[buf_idx].time = crnt_time;
        adcs_meas_rates_hm[buf_idx].status =
                adcs_vapi_get_sensor_rate(&adcs_ctx,\
                (s_adcs_rate_sens*)&adcs_meas_rates_hm[buf_idx].rate_x);
        adcs_hm_enqueue_req((uint8_t*)&adcs_meas_rates_hm,\
                sizeof(s_adcs_hm_meas_rates),\
                ADCS_HM_RATE_SENSOR_MEASURE);
        ++adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE];
        if(adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE] = 0;
            adcs_hm_roll_back[ADCS_HM_RATE_SENSOR_MEASURE] = 1;
        }
        metrics_id = ADCS_HM_FSS_VECTOR;
    }
    break;
    case ADCS_HM_FSS_VECTOR:
    {
        buf_idx = adcs_hm_cnt[ADCS_HM_FSS_VECTOR];
        adcs_fss_vec_hm[buf_idx].time = crnt_time;
        adcs_fss_vec_hm[buf_idx].status =
                adcs_vapi_get_fss_sun_vector(&adcs_ctx,\
                (s_adcs_sun_vector*)&adcs_fss_vec_hm[buf_idx].sun_x);
        ++adcs_hm_cnt[ADCS_HM_FSS_VECTOR];
        adcs_hm_enqueue_req((uint8_t*)&adcs_fss_vec_hm,\
                sizeof(s_adcs_hm_fss_vec), ADCS_HM_FSS_VECTOR);
        if(adcs_hm_cnt[ADCS_HM_FSS_VECTOR] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_FSS_VECTOR] = 0;
            adcs_hm_roll_back[ADCS_HM_FSS_VECTOR] = 1;
        }
        metrics_id = ADCS_HM_EST_RATES;
    }
    break;
    case ADCS_HM_EST_RATES:
    {
        buf_idx = adcs_hm_cnt[ADCS_HM_EST_RATES];
        adcs_est_rate_sns_hm[buf_idx].time = crnt_time;
        adcs_est_rate_sns_hm[buf_idx].status =
                adcs_vapi_get_est_rate(&adcs_ctx,\
                (s_adcs_est_rate*)&adcs_est_rate_sns_hm[buf_idx].est_rate_x);
        adcs_hm_enqueue_req((uint8_t*)&adcs_est_rate_sns_hm, \
                sizeof(s_adcs_hm_est_rates_sns), \
                ADCS_HM_EST_RATES);
        ++adcs_hm_cnt[ADCS_HM_EST_RATES];
        if(adcs_hm_cnt[ADCS_HM_EST_RATES] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_EST_RATES] = 0;
            adcs_hm_roll_back[ADCS_HM_EST_RATES] = 1;
        }
        metrics_id = ADCS_HM_CURRENT_STATE;
    }
    break;
    case ADCS_HM_CURRENT_STATE:
    {
        buf_idx = adcs_hm_cnt[ADCS_HM_CURRENT_STATE];
        adcs_crnt_state_hm[buf_idx].time = crnt_time;
        adcs_crnt_state_hm[buf_idx].status =
                adcs_vapi_get_state(&adcs_ctx,\
                (s_adcs_state*)&adcs_crnt_state_hm[buf_idx].att_est_mode);
        adcs_hm_enqueue_req((uint8_t*)&adcs_crnt_state_hm,\
                sizeof(s_adcs_hm_crnt_state),\
                ADCS_HM_CURRENT_STATE);
        ++adcs_hm_cnt[ADCS_HM_CURRENT_STATE];
        if(adcs_hm_cnt[ADCS_HM_CURRENT_STATE] >= ADCS_HM_MAX_BUFFER_SIZE)
        {
            adcs_hm_cnt[ADCS_HM_CURRENT_STATE] = 0;
            adcs_hm_roll_back[ADCS_HM_CURRENT_STATE] = 1;
        }
        metrics_id = ADCS_HM_SESNOR_CURRENT;
    }
    break;
    default:
    {
        //No Action
    }
        break;
    }

}

/**
 * @brief This API Copy the health metrics data from global buffer to rx_data
 */
int8 adcs_get_health_metrics(uint8 hm_id, uint8 hm_buf_cnt, uint8* rx_data)
{
    int8 status = OPERATION_SUCCESS;
    uint8 buffer_idx = 0, hm_struct_len = 0, prcd_data_len = 0;
    uint8 *rx_pld = &rx_data[2];
    hm_struct_len = adcs_get_hm_tlm_len(hm_id);
    switch(hm_id)
    {
    case ADCS_HM_SESNOR_CURRENT:
    {
        if(adcs_hm_roll_back[ADCS_HM_SESNOR_CURRENT] && hm_buf_cnt >
                adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE - (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT]);
            os_memcpy(rx_pld, &adcs_sen_cur_hm[buffer_idx], prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_sen_cur_hm,\
                    adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT] * hm_struct_len);

        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT];
            os_memcpy(rx_pld, adcs_sen_cur_hm, hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_SESNOR_CURRENT] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_sen_cur_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_CONS_CURRENT:
    {
        if(adcs_hm_roll_back[ADCS_HM_CONS_CURRENT] && hm_buf_cnt >
                      adcs_hm_cnt[ADCS_HM_CONS_CURRENT])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_CONS_CURRENT]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE - (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_CONS_CURRENT]);
            os_memcpy(rx_pld, &adcs_cons_cur_hm[buffer_idx], prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_cons_cur_hm, \
                    adcs_hm_cnt[ADCS_HM_CONS_CURRENT] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_CONS_CURRENT])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_CONS_CURRENT];
            os_memcpy(rx_pld, adcs_cons_cur_hm, hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_CONS_CURRENT] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_cons_cur_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_RW_CURRENT:
    {
        if(adcs_hm_roll_back[ADCS_HM_RW_CURRENT] && hm_buf_cnt >
                        adcs_hm_cnt[ADCS_HM_RW_CURRENT])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_RW_CURRENT]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
                    (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_RW_CURRENT]);
            os_memcpy(rx_pld, &adcs_rw_cur_hm[buffer_idx], prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_rw_cur_hm, \
                    adcs_hm_cnt[ADCS_HM_RW_CURRENT] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_RW_CURRENT])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_RW_CURRENT];
            os_memcpy(rx_pld, adcs_rw_cur_hm, hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_RW_CURRENT] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_rw_cur_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_CSS_VECTOR:
    {
        if(adcs_hm_roll_back[ADCS_HM_CSS_VECTOR] && hm_buf_cnt >
                    adcs_hm_cnt[ADCS_HM_CSS_VECTOR])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_CSS_VECTOR]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
                    (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_CSS_VECTOR]);
            os_memcpy(rx_pld, &adcs_css_vec_hm[buffer_idx], prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_css_vec_hm, \
                    adcs_hm_cnt[ADCS_HM_CSS_VECTOR] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_CSS_VECTOR])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_CSS_VECTOR];
            os_memcpy(rx_pld, adcs_css_vec_hm, hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_CSS_VECTOR] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_css_vec_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_EST_ATTITUDE_ANGLE:
    {
        if(adcs_hm_roll_back[ADCS_HM_EST_ATTITUDE_ANGLE] && hm_buf_cnt >
                      adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
                  (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE]);
            os_memcpy(rx_pld, &adcs_est_att_angl_hm[buffer_idx],\
                    prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_est_att_angl_hm, \
            adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE];
            os_memcpy(rx_pld, adcs_est_att_angl_hm, \
                    hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_EST_ATTITUDE_ANGLE] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_est_att_angl_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_RAW_MAG_MEASURE:
    {
        if(adcs_hm_roll_back[ADCS_HM_RAW_MAG_MEASURE] && hm_buf_cnt >
                     adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE - (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE]);
            os_memcpy(rx_pld, &adcs_raw_mag_meas_hm[buffer_idx], \
                    prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_raw_mag_meas_hm, \
                    adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE];
            os_memcpy(rx_pld, adcs_raw_mag_meas_hm, \
                    hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_RAW_MAG_MEASURE] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_raw_mag_meas_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_RAW_RATE_SENSOR_MEASURE:
    {
        if(adcs_hm_roll_back[ADCS_HM_RAW_RATE_SENSOR_MEASURE] && hm_buf_cnt >
                     adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE])
        {
            prcd_data_len = (hm_buf_cnt -
                adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
                (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE]);
            os_memcpy(rx_pld, &adcs_raw_rates_hm[buffer_idx], prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_raw_rates_hm, \
                adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE];
            os_memcpy(rx_pld, adcs_raw_rates_hm, hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_RAW_RATE_SENSOR_MEASURE] -
                    hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_raw_rates_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_RATE_SENSOR_MEASURE:
    {
        if(adcs_hm_roll_back[ADCS_HM_RATE_SENSOR_MEASURE] && hm_buf_cnt >
                          adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE])
        {
            prcd_data_len = (hm_buf_cnt -
            adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
        (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE]);
            os_memcpy(rx_pld, &adcs_meas_rates_hm[buffer_idx], prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_meas_rates_hm, \
            adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE];
            os_memcpy(rx_pld, adcs_meas_rates_hm, hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_RATE_SENSOR_MEASURE] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_meas_rates_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_FSS_VECTOR:
    {
        if(adcs_hm_roll_back[ADCS_HM_FSS_VECTOR] && hm_buf_cnt >
                     adcs_hm_cnt[ADCS_HM_FSS_VECTOR])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_FSS_VECTOR]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
                    (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_FSS_VECTOR]);
            os_memcpy(rx_pld, &adcs_fss_vec_hm[buffer_idx], \
                    prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_fss_vec_hm, \
                    adcs_hm_cnt[ADCS_HM_FSS_VECTOR] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_FSS_VECTOR])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_FSS_VECTOR];
            os_memcpy(rx_pld, adcs_fss_vec_hm, \
                    hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_FSS_VECTOR] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_fss_vec_hm[buffer_idx],\
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_EST_RATES:
    {
        if(adcs_hm_roll_back[ADCS_HM_EST_RATES] && hm_buf_cnt >
                         adcs_hm_cnt[ADCS_HM_EST_RATES])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_EST_RATES]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
                    (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_EST_RATES]);
            os_memcpy(rx_pld, &adcs_est_rate_sns_hm[buffer_idx], \
                    prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_est_rate_sns_hm, \
                    adcs_hm_cnt[ADCS_HM_EST_RATES] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_EST_RATES])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_EST_RATES];
            os_memcpy(rx_pld, adcs_est_rate_sns_hm, \
                    hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_EST_RATES] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_est_rate_sns_hm[buffer_idx],\
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_MISC_CURRENT:
    {
        if(adcs_hm_roll_back[ADCS_HM_MISC_CURRENT] && hm_buf_cnt >
                           adcs_hm_cnt[ADCS_HM_MISC_CURRENT])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_MISC_CURRENT]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
                    (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_MISC_CURRENT]);
            os_memcpy(rx_pld, &adcs_misc_cur_hm[buffer_idx], \
                    prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_misc_cur_hm, \
                    adcs_hm_cnt[ADCS_HM_MISC_CURRENT] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_MISC_CURRENT])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_MISC_CURRENT];
            os_memcpy(rx_pld, adcs_misc_cur_hm, hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_MISC_CURRENT] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_misc_cur_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_TEMPERATURE:
    {
        if(adcs_hm_roll_back[ADCS_HM_TEMPERATURE] && hm_buf_cnt >
                    adcs_hm_cnt[ADCS_HM_TEMPERATURE])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_TEMPERATURE]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
                    (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_TEMPERATURE]);
            os_memcpy(rx_pld, &adcs_temp_hm[buffer_idx], prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_temp_hm, \
                    adcs_hm_cnt[ADCS_HM_TEMPERATURE] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_TEMPERATURE])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_TEMPERATURE];
            os_memcpy(rx_pld, adcs_temp_hm, hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_TEMPERATURE] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_temp_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_RATE_SENSOR_TEMPERATURE:
    {
        if(adcs_hm_roll_back[ADCS_HM_RATE_SENSOR_TEMPERATURE] && hm_buf_cnt >
                        adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE])
        {
            prcd_data_len = (hm_buf_cnt -
                adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
                (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE]);
            os_memcpy(rx_pld, &adcs_est_rate_sns_temp_hm[buffer_idx], \
                    prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_est_rate_sns_temp_hm, \
                adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE];
            os_memcpy(rx_pld, adcs_est_rate_sns_temp_hm, \
                    hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx =
            adcs_hm_cnt[ADCS_HM_RATE_SENSOR_TEMPERATURE] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_est_rate_sns_temp_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    case ADCS_HM_CURRENT_STATE:
    {
        if(adcs_hm_roll_back[ADCS_HM_CURRENT_STATE] && hm_buf_cnt >
                       adcs_hm_cnt[ADCS_HM_CURRENT_STATE])
        {
            prcd_data_len = (hm_buf_cnt -
                    adcs_hm_cnt[ADCS_HM_CURRENT_STATE]) * hm_struct_len;
            buffer_idx = ADCS_HM_MAX_BUFFER_SIZE -
                    (hm_buf_cnt - adcs_hm_cnt[ADCS_HM_CURRENT_STATE]);
            os_memcpy(rx_pld, &adcs_crnt_state_hm[buffer_idx], \
                    prcd_data_len);

            os_memcpy(&rx_pld[prcd_data_len], adcs_crnt_state_hm, \
                    adcs_hm_cnt[ADCS_HM_CURRENT_STATE] * hm_struct_len);
        }
        else if(hm_buf_cnt > adcs_hm_cnt[ADCS_HM_CURRENT_STATE])
        {
            hm_buf_cnt = adcs_hm_cnt[ADCS_HM_CURRENT_STATE];
            os_memcpy(rx_pld, adcs_crnt_state_hm, hm_struct_len * hm_buf_cnt);
        }
        else
        {
            buffer_idx = adcs_hm_cnt[ADCS_HM_CURRENT_STATE] - hm_buf_cnt;
            os_memcpy(rx_pld, &adcs_crnt_state_hm[buffer_idx], \
                    hm_struct_len * hm_buf_cnt);
        }
    }
    break;
    default:
        status = ID_NOT_SUPPORT;
        break;
    }
    rx_data[0] = hm_id;
    rx_data[1] = hm_buf_cnt;
    return status;
}

/**
 * @brief This API Returns the heath metrics structure length for
 * heath metrics id
 */
uint8 adcs_get_hm_tlm_len(uint8 hm_id)
{
    uint8 length = 0;
    switch(hm_id)
    {
    case ADCS_HM_SESNOR_CURRENT:
    {
        length = sizeof(s_adcs_hm_sen_cur);
    }
    break;
    case ADCS_HM_CONS_CURRENT:
    {
        length = sizeof(s_adcs_hm_cons_cur);
    }
    break;
    case ADCS_HM_RW_CURRENT:
    {
        length = sizeof(s_adcs_hm_rw_cur);
    }
    break;
    case ADCS_HM_CSS_VECTOR:
    {
        length = sizeof(s_adcs_hm_css_vector);
    }
    break;
    case ADCS_HM_EST_ATTITUDE_ANGLE:
    {
        length = sizeof(s_adcs_hm_est_att_angl);
    }
    break;
    case ADCS_HM_RAW_MAG_MEASURE:
    {
        length = sizeof(s_adcs_hm_raw_mag_measure);
    }
    break;
    case ADCS_HM_RAW_RATE_SENSOR_MEASURE:
    {
        length = sizeof(s_adcs_hm_raw_rates);
    }
    break;
    case ADCS_HM_RATE_SENSOR_MEASURE:
    {
        length = sizeof(s_adcs_hm_meas_rates);
    }
    break;
    case ADCS_HM_FSS_VECTOR:
    {
        length = sizeof(s_adcs_hm_fss_vec);
    }
    break;
    case ADCS_HM_EST_RATES:
    {
        length = sizeof(s_adcs_hm_est_rates_sns);
    }
    break;
    case ADCS_HM_MISC_CURRENT:
    {
        length = sizeof(s_adcs_hm_misc_cur);
    }
    break;
    case ADCS_HM_TEMPERATURE:
    {
        length = sizeof(s_adcs_hm_temp);
    }
    break;
    case ADCS_HM_RATE_SENSOR_TEMPERATURE:
    {
        length = sizeof(s_adcs_hm_est_rate_sns_temp);
    }
    break;
    case ADCS_HM_CURRENT_STATE:
    {
        length = sizeof(s_adcs_hm_crnt_state);
    }
    break;
    default:
    {
        length = 0;
    }
    break;
    }
    return length;
}

/**
 * @brief This API Initialize Health metrics global buffer values to Zero
 *  and Health metrices queue initialize.
 */
void adcs_hm_buffer_init()
{
    //set default value 0 to avoid chunk values
    os_memset(adcs_sen_cur_hm, 0, sizeof(adcs_sen_cur_hm));
    os_memset(adcs_cons_cur_hm, 0, sizeof(adcs_cons_cur_hm));
    os_memset(adcs_rw_cur_hm, 0, sizeof(adcs_rw_cur_hm));
    os_memset(adcs_css_vec_hm, 0, sizeof(adcs_css_vec_hm));
    os_memset(adcs_est_att_angl_hm, 0, sizeof(adcs_est_att_angl_hm));
    os_memset(adcs_raw_mag_meas_hm, 0, sizeof(adcs_raw_mag_meas_hm));
    os_memset(adcs_raw_rates_hm, 0, sizeof(adcs_raw_rates_hm));
    os_memset(adcs_meas_rates_hm, 0, sizeof(adcs_meas_rates_hm));
    os_memset(adcs_fss_vec_hm, 0, sizeof(adcs_fss_vec_hm));
    os_memset(adcs_est_rate_sns_hm, 0, sizeof(adcs_est_rate_sns_hm));
    os_memset(adcs_misc_cur_hm, 0, sizeof(adcs_misc_cur_hm));
    os_memset(adcs_temp_hm, 0, sizeof(adcs_temp_hm));
    os_memset(adcs_est_rate_sns_temp_hm, 0, sizeof(adcs_est_rate_sns_temp_hm));
    os_memset(adcs_crnt_state_hm, 0, sizeof(adcs_crnt_state_hm));

    //Initilaize Health metrices queue
    adcs_hm_req_queue(sizeof(s_adcs_hm_sen_cur), ADCS_HM_MAX_BUFFER_SIZE, \
            ADCS_HM_SESNOR_CURRENT);
    adcs_hm_req_queue(sizeof(s_adcs_hm_cons_cur), ADCS_HM_MAX_BUFFER_SIZE, \
            ADCS_HM_CONS_CURRENT);
    adcs_hm_req_queue(sizeof(s_adcs_hm_rw_cur), ADCS_HM_MAX_BUFFER_SIZE, \
            ADCS_HM_RW_CURRENT);
    adcs_hm_req_queue(sizeof(s_adcs_hm_css_vector), ADCS_HM_MAX_BUFFER_SIZE, \
            ADCS_HM_CSS_VECTOR);
    adcs_hm_req_queue(sizeof(s_adcs_hm_est_att_angl), ADCS_HM_MAX_BUFFER_SIZE,\
            ADCS_HM_EST_ATTITUDE_ANGLE);
    adcs_hm_req_queue(sizeof(s_adcs_hm_raw_mag_measure), \
            ADCS_HM_MAX_BUFFER_SIZE, ADCS_HM_RAW_MAG_MEASURE);
    adcs_hm_req_queue(sizeof(s_adcs_hm_raw_rates), ADCS_HM_MAX_BUFFER_SIZE, \
            ADCS_HM_RAW_RATE_SENSOR_MEASURE);
    adcs_hm_req_queue(sizeof(s_adcs_hm_meas_rates), ADCS_HM_MAX_BUFFER_SIZE, \
            ADCS_HM_RATE_SENSOR_MEASURE);
    adcs_hm_req_queue(sizeof(s_adcs_hm_fss_vec), ADCS_HM_MAX_BUFFER_SIZE, \
            ADCS_HM_FSS_VECTOR);
    adcs_hm_req_queue(sizeof(s_adcs_hm_est_rates_sns), \
            ADCS_HM_MAX_BUFFER_SIZE, ADCS_HM_EST_RATES);
    adcs_hm_req_queue(sizeof(s_adcs_hm_misc_cur), ADCS_HM_MAX_BUFFER_SIZE, \
            ADCS_HM_MISC_CURRENT);
    adcs_hm_req_queue(sizeof(s_adcs_hm_temp), ADCS_HM_MAX_BUFFER_SIZE, \
            ADCS_HM_TEMPERATURE);
    adcs_hm_req_queue(sizeof(s_adcs_hm_est_rate_sns_temp), \
            ADCS_HM_MAX_BUFFER_SIZE, ADCS_HM_RATE_SENSOR_TEMPERATURE);
    adcs_hm_req_queue(sizeof(s_adcs_hm_crnt_state), ADCS_HM_MAX_BUFFER_SIZE, \
            ADCS_HM_CURRENT_STATE);

}

/**
 * @brief This api handle ADCS Health metrices queue create
 */
void adcs_hm_req_queue(uint32_t instance_size, \
        uint32_t num_of_instance, uint8_t queue_id)
{
    os_itc_msg_handle_t adcs_req_ipc;
    s_tc_tm_buffer_req *buff_req = os_malloc(sizeof(s_tc_tm_buffer_req));
    if(buff_req)
    {
        os_memset(buff_req, 0, sizeof(s_tc_tm_buffer_req));
        buff_req->queue_id = queue_id;
        buff_req->instance_size = instance_size;
        buff_req->num_instance = num_of_instance;
        buff_req->wrap_dsb = 0;
        buff_req->priority = 0;
        buff_req->strg_flag = 0;
        buff_req->thresh = 0;
        adcs_req_ipc.pld.pld_ptr = (void*)buff_req;
        adcs_req_ipc.src_entity = ADCS_CONTROLLER;
        adcs_req_ipc.Msg_id = OBC_TC_TM_BUFFER_REQ;
        os_itc_msg_send(&adcs_req_ipc, HM_MANAGER_IPC_RECEIVE, \
                os_send_itc_wait);
    }
}

/**
 * @brief This api enqueue ADCS health metrices data.
 */
void adcs_hm_enqueue_req(uint8_t* data, uint16_t data_len,uint8_t queue_id)
{
    os_itc_msg_handle_t adcs_req_ipc;
    adcs_req_ipc.pld.pld_ptr = os_malloc(data_len);
    adcs_req_ipc.pld.pld_data = queue_id;
    os_memcpy(adcs_req_ipc.pld.pld_ptr, data, data_len);
    adcs_req_ipc.src_entity = ADCS_CONTROLLER;
    adcs_req_ipc.Msg_id = OBC_TC_TM_ENQUEUE_REQ;
    os_itc_msg_send(&adcs_req_ipc, HM_MANAGER_IPC_RECEIVE, \
            os_send_itc_wait);
}

/**
 * ADCS FSM State Configuration
 */
e_adcs_status adcs_fsm_state_cfg(uint8_t* tx_data, uint8_t* rx_data)
{
    e_adcs_status status = OPERATION_FAILURE;
    // TODO need to map with state machine
    if(tx_data[0] == SET_DATA)
    {
        adcs_fsm_state_info = tx_data[1];
        rx_data[0] = adcs_fsm_state_info;
        status = OPERATION_SUCCESS;
    }
    else
    {
        rx_data[0] = adcs_fsm_state_info;
        status = OPERATION_SUCCESS;
    }

    return status;
}

#if !defined(ADCS_HW_SIM) && !defined(LINUX_TEMP_PORT)
/*
 * @Brief This API Self recover ADCS interface errors by switching interfaces
 * and power reset ADCS
 */
void adcs_intrface_error_recvry(void)
{
    s_adcs_id adcs_id = {0};
    int8 status = OPERATION_FAILURE;
    static uint8 adcs_intf_error_flag = PWR_ON;

    if(PWR_OFF == adcs_intf_error_flag)
    {
        status = eps_ctrl_en_chnl(HW_ADCS, PWR_ON);
        adcs_intf_error_flag = PWR_ON;
    }

    //Call error recovery function
    if(PWR_ON == sat_dev_sts[HW_ADCS].hw_sts)
    {
        status = adcs_vapi_get_id(&adcs_ctx, &adcs_id);
        if(OPERATION_SUCCESS == status && (adcs_id.id == 10 || 
                    adcs_id.id == 110))
        {
            // Recovery success erase error flags
            adcs_interface_err = 0;
        }
        else if(get_adcs_interface() == ADCS_UART)
        {
            adcs_interface_cfg(ADCS_CAN);
        }
        else
        {
            adcs_interface_cfg(ADCS_UART);
        }

        if(adcs_interface_err != 0)
        {
            // Self test function to verify its working status
            status = adcs_vapi_get_id(&adcs_ctx, &adcs_id);
            if(OPERATION_SUCCESS == status && (adcs_id.id == 10 || 
                        adcs_id.id == 110))
            {
                // Recovery success erase error flags
                adcs_interface_err = 0;
            }
            else
            {
                status = eps_ctrl_en_chnl(HW_ADCS, PWR_OFF);
                adcs_intf_error_flag = PWR_OFF;
            }

            if(adcs_interface_err != 0 && PWR_ON == 
                    sat_dev_sts[HW_ADCS].hw_sts)
            {
                // Self test function to verify its working status
                status = adcs_vapi_get_id(&adcs_ctx, &adcs_id);
                if(OPERATION_SUCCESS == status && (adcs_id.id == 10 || 
                            adcs_id.id == 110))
                {
                    // Recovery success erase error flags
                    adcs_interface_err = 0;
                }
                else
                {
                    // TBD
                }
            }
        }
    }
    else
    {
        // TBD
    }
}

/*
 * @Brief This API recovers temperature error by power off ADCS and
 * turn on after given period of time to verify temperature reduced
 * to normal range
 */
void adcs_temperature_error_rcvry(void)
{
    int8 status = OPERATION_FAILURE;
    static uint8 adcs_temp_error_flag = PWR_ON;
    s_adcs_temperature adcs_temperature = {0};
    if(PWR_OFF == adcs_temp_error_flag)
    {
        // Power On ADCS to verify temperature
        status = eps_ctrl_en_chnl(HW_ADCS, PWR_ON);
        adcs_temp_error_flag = PWR_ON;
    }
    if(PWR_ON == sat_dev_sts[HW_ADCS].hw_sts)
    {
        status = adcs_vapi_get_temperature(&adcs_ctx, &adcs_temperature);
        if(OPERATION_SUCCESS == status && 
                adcs_temperature.mcu_temperature > 50)
        {
            // Power off ADCS MCU to reduce temperature
            status = eps_ctrl_en_chnl(HW_ADCS, PWR_OFF);
            adcs_temp_error_flag = PWR_OFF;
        }
    }
}
#endif


/**
 * @brief Function to synchronize the ADCS Unix time
 */
void adcs_sync_time(uint8_t* data)
{
    e_adcs_status status = OPERATION_FAILURE;
    s_adcs_time recv_time = {0};
    sys_time_date_s cur_time = {0};
    s_adcs_ctx adcs_ctx = {0};
    struct tm timeinfo = {0};
    uint64_t epoch_time = 0;
    time_t conv_epoch = {0};
    os_memset(&cur_time, 0, sizeof(sys_time_date_s));
    if(NULL == data)
    {
        epoch_time = get_crnt_time_date_in_epoch();
        recv_time.utc_time = epoch_time;
        status = adcs_vapi_set_utc_time(&adcs_ctx, &recv_time);
    }
    else
    {
        os_memcpy(&cur_time,data,sizeof(sys_time_date_s));
        // Initialize the struct tm with values from gps_time_data
        timeinfo.tm_sec = cur_time.seconds;
        timeinfo.tm_min = cur_time.minute;
        timeinfo.tm_hour = cur_time.hour;
        timeinfo.tm_mday = cur_time.date;
        timeinfo.tm_mon = cur_time.month - 1;//Month is 0-based in struct tm

        timeinfo.tm_year = cur_time.year - 1900;
        // Convert the struct tm to epoch time
        conv_epoch = mktime(&timeinfo);
        recv_time.utc_time = (uint32_t)conv_epoch;
        status = adcs_vapi_set_utc_time(&adcs_ctx, &recv_time);
    }

    if(status != OPERATION_SUCCESS)
    {
        DEBUG_CPRINT(("ADCS UTC Time Sync Failed"));
    }
    else
    {
        DEBUG_CPRINT(("ADCS UTC Time Sync Success"));
    }

}

