/**
 * @file sdr_app_main.c
 *
 * @brief This file has the SDR Application thread functions and other main functions for S-Band control
 *
 * @copyright Copyright 2023 Antaris, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
/*********************************************************************/

#include "sdr_app_main.h"
#include "obc_main_fsm_hdlr.h"
#include "sm_api.h"
#include "sdr_app_intf.h"
#include "exo_common.h"
#include "sdr_app_ipc.h"
#include "exo_io_al_rtc_common.h"
#include "exo_io_al_sos_timer.h"
#include "exo_tctm_ipc.h"
#include "logger.h"
#include "comms_csw.h"
#include "exo_tctm_ipc.h"
#include "comms_uhf_main.h"
#include "comms_uhf_rf_cfg.h"
#include "comms_sband_xlink_ss.h"

/** Firmware update status variable */
uint8_t PLACE_IN_EXT_RAM_MEM fw_upd_sts = 0;

/** System date and time structure */
sys_time_date_s PLACE_IN_EXT_RAM_MEM  tim_get_sd_m;

/** Radio ID for SDR application */
uint8_t PLACE_IN_EXT_RAM_MEM sdr_app_radio_id = 0;
/** Telecommand sequence number for SDR application */
uint16_t PLACE_IN_EXT_RAM_MEM sdr_app_tc_seq_no = 0;
/*s_sdr_tmr_cfg_nvm sband_nvm_tmr_norm;
  s_sdr_tmr_cfg_nvm uhf_nvm_tmr_norm;
  s_sdr_tmr_cfg_nvm sband_nvm_tmr_safe;
  s_sdr_tmr_cfg_nvm uhf_nvm_tmr_safe;
  s_sdr_rssi_cfg_nvm sband_nvm_rssi_tmr;*/
/** SDR timer configurations array */  
extern s_sdr_tmr_cfg PLACE_IN_EXT_RAM_MEM sdr_tmr[MAX_SDR_CFG];
/** SDR RSSI configurations array */
extern s_sdr_rssi_cfg PLACE_IN_EXT_RAM_MEM sdr_rssi_cfg[MAX_SDR_CFG];
/** SDR radio id */
extern uint8_t radio_id_dest_map[MAX_SDR_CFG];
/** SDR NVM configuration structure */  
extern s_sdr_nvm_cfg PLACE_IN_EXT_RAM_MEM sdr_nvm_param;

/** Radio ID for beacon */
volatile uint8_t PLACE_IN_EXT_RAM_MEM beacon_radio_id = 0;
/** Beacon data status */
volatile uint8_t PLACE_IN_EXT_RAM_MEM beacon_data_sts = 0;
/** Beacon data request */ 
volatile uint8_t PLACE_IN_EXT_RAM_MEM beacon_data_req = 0;
/** Beacon data response */
volatile uint8_t PLACE_IN_EXT_RAM_MEM beacon_data_rsp = 0;

extern volatile uint8_t PLACE_IN_EXT_RAM_MEM uhf_gs_contact_valid;

extern volatile uint8_t PLACE_IN_EXT_RAM_MEM sband_gs_contact_valid;

/** Hello message for beacon */
uint8 hello_msg[BCON_MSG_SZ] = {"Hello, I am Janus2"};

/** Beacon payload structure */
s_sdr_beacon_pld PLACE_IN_EXT_RAM_MEM beacon_pld;

extern s_sdr_cfg PLACE_IN_EXT_RAM_MEM sdr_app_cfg[MAX_SDR_CFG];
extern s_sdr_tm_cfg PLACE_IN_EXT_RAM_MEM sdr_tm_cfg[MAX_SDR_CFG];
extern s_sdr_sens_cfg PLACE_IN_EXT_RAM_MEM sdr_sens_cfg[MAX_SDR_CFG];
extern s_sdr_beacon_pld PLACE_IN_EXT_RAM_MEM beacon_pld;

extern uint8_t PLACE_IN_EXT_RAM_MEM num_sdr;

/**
 * @brief This function create the SDR application state and event threads
 *
 * @return Status of initialization
 */
int32_t sdr_app_init(void)
{
    os_status_t status;

    /** Thread creation of SDR Application main thread */
    status = os_thread_create(SDR_APP,
            T_SDR_APP_STACK_SIZE,
            P_SDR_APP,
            "sdr_app_thread",
            sdr_app_main,
            NULL,
            NULL,
            NULL);

    return status;
}

/**
 * @brief This function handles the SDR application
 *  thread processing
 * @brief Main function for SDR application
 * 
 * This function contains the main processing loop for the SDR application.
 * It receives and dispatches messages and calls appropriate handlers.
 * @param[in] param Pointer to thread parameter
 */

void comms_sdr_init_cfg(void)
{
    os_memset(&sdr_tmr[MAX_SDR_CFG],0,sizeof(s_sdr_tmr_cfg));
    os_memset(&sdr_rssi_cfg[MAX_SDR_CFG],0,sizeof(s_sdr_rssi_cfg));
    os_memset(&sdr_nvm_param,0,sizeof(s_sdr_nvm_cfg));
    os_memset(&sdr_app_cfg[MAX_SDR_CFG],0,sizeof(s_sdr_cfg));
    os_memset(&sdr_sens_cfg[MAX_SDR_CFG],0,sizeof(s_sdr_sens_cfg));
    os_memset(&beacon_pld,0,sizeof(s_sdr_beacon_pld));
    os_memset(&tim_get_sd_m,0,sizeof(sys_time_date_s));
    os_memset(&sdr_tm_cfg[MAX_SDR_CFG],0,sizeof(s_sdr_tm_cfg));

    num_sdr =0;
    beacon_radio_id = 0;
    beacon_data_sts = 0;
    beacon_data_req = 0;
    beacon_data_rsp = 0;
    sdr_app_radio_id = 0;
    sdr_app_tc_seq_no = 0;
    fw_upd_sts = 0;

}

void sdr_app_main(void *param)
{
    int8_t status =0;
    status=status;
    os_itc_msg_handle_t sdr_app_recv_msg;
    //TODO: NVM Read
    comms_sdr_init_cfg();
    comms_sdr_cfg_nvm_read();
    while(1)
    {
#ifdef COMMS_TIME_DEBUG
        get_crnt_time_date(&tim_get_sd_m);
        DEBUG_CPRINT(("\nSDR_APP TIME ENT %d:%d:%d ",tim_get_sd_m.hour, tim_get_sd_m.minute, tim_get_sd_m.seconds));
        log_id_with_three_arg(LOG_INFO_L2,LOG_COMMS,UHF_TIMER_SDR_ENT__u8__u8__u8_,tim_get_sd_m.hour, tim_get_sd_m.minute, tim_get_sd_m.seconds);
#endif
        /** SDR Application IPC receive */
        status = os_itc_msg_rcv(SDR_APP, &sdr_app_recv_msg, os_wait_forever);

        if((OBC_MAIN == sdr_app_recv_msg.src_entity) || (SDR_APP == sdr_app_recv_msg.src_entity)\
                || (ORBIT_CONOPS_SCHEDULER == sdr_app_recv_msg.src_entity) || (COMMS_SBAND_CTLR == sdr_app_recv_msg.src_entity)\
                || (ADCS_CONTROLLER == sdr_app_recv_msg.src_entity) || (EPS_TASK == sdr_app_recv_msg.src_entity) ||\
                (COMMS_UHF_CTLR == sdr_app_recv_msg.src_entity) || (OBC_SENSOR_HDLR == sdr_app_recv_msg.src_entity) ||\
                (GPS_TASK == sdr_app_recv_msg.src_entity))
        {
            /** Invoke SDR Application handler */
            status = sdr_app_msg_hdlr(sdr_app_recv_msg.Msg_id,sdr_app_recv_msg.Msg_len,sdr_app_recv_msg.pld.pld_ptr);

            DEBUG_CPRINT(("[SDR_APP] IPC: %d",sdr_app_recv_msg.Msg_id));
        }
        else
        {
            uint8_t *tc_tm = (uint8_t *)sdr_app_recv_msg.pld.pld_ptr;

            //Extract the sequence number
            os_memcpy(&sdr_app_tc_seq_no, tc_tm, sizeof(uint16_t));
            os_memcpy(&sdr_app_radio_id ,(uint8_t *) &tc_tm[TC_RADIO_MOD_IDX], sizeof(uint8_t));

            /** Invoke SDR Application handler */
            status = sdr_app_msg_hdlr(sdr_app_recv_msg.Msg_id,sdr_app_recv_msg.Msg_len,sdr_app_recv_msg.pld.pld_ptr);

            DEBUG_CPRINT(("[SDR_APP] TC_TM: %d Radio_ID:%d",sdr_app_recv_msg.Msg_id,sdr_app_radio_id ));
            log_id_with_one_arg(LOG_INFO_L1,LOG_COMMS,INSIDE_SDR_APP_ELSE_RADIO_ID__u8_,sdr_app_radio_id);

            // NVM Read
            //comms_sdr_cfg_nvm_write();
        }

        /** Freeing of payload pointer */
        if(NULL!=sdr_app_recv_msg.pld.pld_ptr)
        {
            os_free(sdr_app_recv_msg.pld.pld_ptr);
            sdr_app_recv_msg.pld.pld_ptr = NULL;
        }

#ifdef COMMS_TIME_DEBUG 
        get_crnt_time_date(&tim_get_sd_m);
        DEBUG_CPRINT(("\nUHF TIME SDR EXT %d:%d:%d ",tim_get_sd_m.hour, tim_get_sd_m.minute, tim_get_sd_m.seconds));
        log_id_with_three_arg(LOG_INFO_L2,LOG_COMMS,UHF_TIMER_SDR_EXT__u8__u8__u8_,tim_get_sd_m.hour, tim_get_sd_m.minute, tim_get_sd_m.seconds);
#endif

    }
}

/**
 * @brief This function handles the SDR application
 *  IPC messages and TC messages
 * @brief Message handler for SDR application
 *
 * This function handles messages received by the SDR application,
 * including telemetry requests, commands, events, etc.
 *
 * @param msg_id Message ID
 * @param msg_len Length of message
 * @param pld_ptr Pointer to message payload
 * 
 * @return int8_t Status of message handling
 */
int8_t sdr_app_msg_hdlr(uint16_t msg_id, uint16_t msg_len, void *pld_ptr)
{
#ifdef COMMS_TIME_DEBUG
    get_crnt_time_date(&tim_get_sd_m);
    DEBUG_CPRINT(("\nUHF TIME SDR_MSG ENT %d:%d:%d Msg-id %d ",tim_get_sd_m.hour, tim_get_sd_m.minute, tim_get_sd_m.seconds, msg_id));
    log_id_with_four_arg(LOG_INFO_L2,LOG_COMMS,UHF_TIME_SDR_MSG_ENT__u8__u8__u8__MSG_ID__u16,tim_get_sd_m.hour, tim_get_sd_m.minute, tim_get_sd_m.seconds, msg_id);
#endif

    int8_t ret =0;
    uint8_t *tc_tm_data;
    tc_tm_data = (uint8*)pld_ptr;

    switch(msg_id)
    {
        case TC_SET_SDR_CFG:
            {
                ret = sdr_app_tc_set_sdr_cfg(&tc_tm_data[TC_PLD_IDX]);
                sdr_app_tc_tm_set_rsp_hdlr(TM_SET_SDR_CFG, ret);
                comms_sdr_cfg_nvm_write_sdr_cfg();
            }
            break;

        case TC_GET_SDR_CFG:
            {
                ret = sdr_app_tc_get_sdr_cfg(&tc_tm_data[TC_PLD_IDX]);
            }
            break;

        case TC_SET_SDR_STS:
            {
                ret = sdr_app_tc_set_sdr_sts(&tc_tm_data[TC_PLD_IDX]);
                sdr_app_tc_tm_set_rsp_hdlr(TM_SET_SDR_STS, ret);
                comms_sdr_cfg_nvm_write_sdr_sts();
            }
            break;

        case TC_GET_SDR_STS:
            {
                ret = sdr_app_tc_get_sdr_sts(&tc_tm_data[TC_PLD_IDX]);
            }
            break;

        case TC_SET_SDR_TMR_CFG:
            {
                ret = sdr_app_tc_set_sdr_tmr_cfg(&tc_tm_data[TC_PLD_IDX]);
                sdr_app_tc_tm_set_rsp_hdlr(TM_SET_SDR_TMR_CFG, ret);
                comms_sdr_cfg_nvm_write_tmr_cfg();
            }
            break;

        case TC_GET_SDR_TMR_CFG:
            {
                ret = sdr_app_tc_get_sdr_tmr_cfg(&tc_tm_data[TC_PLD_IDX]);
            }
            break;

        case TC_SET_SDR_RX_RSSI_CFG:
            {
                ret = sdr_app_tc_set_sdr_rx_rssi_cfg(&tc_tm_data[TC_PLD_IDX]);
                sdr_app_tc_tm_set_rsp_hdlr(TM_SET_SDR_RX_RSSI_CFG, ret);
                comms_sdr_cfg_nvm_write_rssi_cfg();
            }
            break;

        case TC_SET_SDR_OVER_RULE_CFG:
            {
                ret = sdr_app_tc_set_over_rule_cfg((&tc_tm_data[TC_PLD_IDX]));
                sdr_app_tc_tm_set_rsp_hdlr(TM_SET_SDR_OVER_RULE_CFG, ret);
            }

            break;

        case TC_GET_SDR_OVER_RULE_CFG:
            {
             ret = sdr_app_tc_get_over_rule_cfg(&tc_tm_data[TC_PLD_IDX]);
            }
            break;

        case TC_SET_SDR_SCH_BEACON_CFG:
            {
                ret = sdr_app_tc_set_sdr_sch_beacon_cfg((&tc_tm_data[TC_PLD_IDX]));
                sdr_app_tc_tm_set_rsp_hdlr(TM_SET_SDR_SCH_BEACON_CFG, ret);
            }
            break;

        case TC_GET_SDR_SCH_BEACON_CFG:
            {
             ret = sdr_app_tc_get_sdr_sch_beacon_cfg(&tc_tm_data[TC_PLD_IDX]);
            }
            break;

        case TC_GET_SDR_RX_RSSI_CFG:
            {
                ret = sdr_app_tc_get_sdr_rx_rssi_cfg(&tc_tm_data[TC_PLD_IDX]);
            }
            break;

        case TC_SET_SDR_TM_CFG:
            {
                ret = sdr_app_tc_set_sdr_tm_cfg(&tc_tm_data[TC_PLD_IDX]);
                sdr_app_tc_tm_set_rsp_hdlr(TM_SET_SDR_TM_CFG, ret);
                comms_sdr_cfg_nvm_write_tm_cfg();
            }
            break;

        case TC_GET_SDR_TM_CFG:
            {
                ret = sdr_app_tc_get_sdr_tm_cfg(&tc_tm_data[TC_PLD_IDX]);
            }
            break;

        case TC_SET_SDR_SENS_CFG:
            {
                ret = sdr_app_tc_set_sdr_sens_cfg(&tc_tm_data[TC_PLD_IDX]);
                sdr_app_tc_tm_set_rsp_hdlr(TM_SET_SDR_SENS_CFG, ret);
                comms_sdr_cfg_nvm_write_sens_cfg();
            }
            break;

        case TC_GET_SDR_SENS_CFG:
            {
                ret = sdr_app_tc_get_sdr_sens_cfg(&tc_tm_data[TC_PLD_IDX]);
            }
            break;


        case SBAND_SDR_APP_BEACON_DATA_REQ:
            {
                if(!beacon_data_req)
                {
                    sdr_app_send_ipc(SDR_APP_ADCS_MH_REQ, ADCS_CONTROLLER);
                    sdr_app_send_ipc(SDR_APP_EPS_MH_REQ, EPS_TASK );
                    sdr_app_send_ipc(SDR_APP_OBC_MH_REQ, OBC_MAIN );
                    sdr_app_send_ipc(SDR_APP_SEN_MH_REQ, OBC_SENSOR_HDLR );
                    sdr_app_send_ipc(SDR_APP_GPS_MH_REQ, GPS_TASK );
                    sdr_app_send_ipc(SDR_APP_SBAND_MH_REQ, COMMS_SBAND_CTLR );
                    sdr_app_send_ipc(SDR_APP_UHF_MH_REQ, COMMS_UHF_CTLR );
                }
                beacon_data_req ++;
                beacon_radio_id |= SBAND_BEACON_REQ;
            }
            break;

        case UHF_SDR_APP_BEACON_DATA_REQ:
            {
                if(!beacon_data_req)
                {
                    sdr_app_send_ipc(SDR_APP_ADCS_MH_REQ, ADCS_CONTROLLER);
                    sdr_app_send_ipc(SDR_APP_EPS_MH_REQ, EPS_TASK );
                    sdr_app_send_ipc(SDR_APP_OBC_MH_REQ, OBC_MAIN );
                    sdr_app_send_ipc(SDR_APP_SEN_MH_REQ, OBC_SENSOR_HDLR );
                    sdr_app_send_ipc(SDR_APP_GPS_MH_REQ, GPS_TASK );
                    sdr_app_send_ipc(SDR_APP_SBAND_MH_REQ, COMMS_SBAND_CTLR );
                    sdr_app_send_ipc(SDR_APP_UHF_MH_REQ, COMMS_UHF_CTLR );
                }
                beacon_data_req ++;

                beacon_radio_id |= UHF_BEACON_REQ;
            }
            break;

        case UHF_SDR_APP_MH_RSP:
            {
                beacon_data_rsp |= UHF_BEACON_RSP;

                os_memcpy(&beacon_pld.sdr_uhf_mh,pld_ptr,sizeof(s_sdr_uhf_mh_info));
                DEBUG_CPRINT(("### RESPONSE FROM UHF_SDR_APP_MH_RSP ###"));
                log_id(LOG_INFO_L3,LOG_COMMS,RESPONSE_FROM_UHF_SDR_APP_MH_RSP);

            }
            break;

        case SBAND_SDR_APP_MH_RSP:
            {
                beacon_data_rsp |= SBAND_BEACON_RSP;

                os_memcpy(&beacon_pld.sdr_sband_mh,pld_ptr,sizeof(s_sdr_sband_mh_info));
                DEBUG_CPRINT(("### RESPONSE FROM SBAND_SDR_APP_MH_RSP ###"));
                log_id(LOG_INFO_L3,LOG_COMMS,RESPONSE_FROM_SBAND_SDR_APP_MH_RSP);
            }
            break;

        case ADCS_SDR_APP_MH_RSP:
            {
                beacon_data_rsp |= ADCS_BEACON_RSP;

                os_memcpy(&beacon_pld.adcs_mh,pld_ptr,sizeof(s_sdr_adcs_mh_pld));
                DEBUG_CPRINT(("### RESPONSE FROM ADCS_SDR_APP_MH_RSP ###"));
                log_id(LOG_INFO_L3,LOG_COMMS,RESPONSE_FROM_ADCS_SDR_APP_MH_RSP);
            }
            break;

        case EPS_SDR_APP_MH_RSP:
            {
                beacon_data_rsp |= EPS_BEACON_RSP;

                os_memcpy(&beacon_pld.eps_mh,pld_ptr,sizeof(s_sdr_eps_mh_pld));
                DEBUG_CPRINT(("### RESPONSE EPS_SDR_APP_MH_RSP ###"));
                log_id(LOG_INFO_L3,LOG_COMMS,RESPONSE_FROM_EPS_SDR_APP_MH_RSP);
            }
            break;

        case OBC_SDR_APP_MH_RSP:
            {
                beacon_data_rsp |= OBC_BEACON_RSP;

                os_memcpy(&beacon_pld.obc_mh,pld_ptr,sizeof(s_sdr_obc_mh_pld));
                DEBUG_CPRINT(("### RESPONSE OBC_SDR_APP_MH_RSP ###"));
                log_id(LOG_INFO_L3,LOG_COMMS,RESPONSE_FROM_OBC_SDR_APP_MH_RSP);
            }
            break;

        case SEN_SDR_APP_MH_RSP:
            {
                beacon_data_rsp |= SEN_BEACON_RSP;

                os_memcpy(&beacon_pld.sen_mh,pld_ptr,sizeof(s_sdr_sen_mh_pld));
                DEBUG_CPRINT(("### RESPONSE FROM SEN_SDR_APP_MH_RSP ###"));
                log_id(LOG_INFO_L3,LOG_COMMS,RESPONSE_FROM_SENSORS_SDR_APP_MH_RSP);
            }
            break;
        case GPS_SDR_APP_MH_RSP:
            {
                beacon_data_rsp |= GPS_BEACON_RSP;

                os_memcpy(&beacon_pld.bcon_utc_gps,pld_ptr,sizeof(s_sdr_bcon_utc_gps));
                DEBUG_CPRINT(("### RESPONSE FROM GPS_SDR_APP_MH_RSP ###"));
            }
            break;

        case TC_COMMS_CUSTOM_TX:
            {
                comms_cust_pattern_rf_tx_gen(tc_tm_data);
                sdr_app_tc_tm_set_rsp_hdlr(TC_COMMS_CUSTOM_TX, 0);
            }
            break;

        case OBC_SDR_APP_BAT_CH_IND:
            {
                if(sm_get_state(OBC_MAIN_FSM) == OBC_ACTIVE_PWR_NORM_STATE)
                {
                    /**Normal Time**/
                    if(fw_upd_sts & SBAND_FW_UPD_ST)
                    {
                        sdr_app_send_ipc(SBAND_FW_CFG_START_REQ, COMMS_SBAND_CTLR);
                    }
                    if (fw_upd_sts & UHF_FW_UPD_ST)
                    {
                        sdr_app_send_ipc(UHF_FW_CFG_START_REQ, COMMS_UHF_CTLR);
                    }
                    comms_upd_tmr_normal();
                    sdr_app_send_ipc_pld(SDR_APP_SDR_CTRL_TMR_CFG_REQ,radio_id_dest_map[COMMS_SBAND_IQS],sizeof(s_sdr_tmr_cfg),(uint8_t *)&sdr_tmr[COMMS_SBAND_IQS]);
                    sdr_app_send_ipc_pld(SDR_APP_SDR_CTRL_TMR_CFG_REQ,radio_id_dest_map[COMMS_UHF],sizeof(s_sdr_tmr_cfg),(uint8_t *)&sdr_tmr[COMMS_UHF]);
                }
                else if(sm_get_state(OBC_MAIN_FSM) == OBC_ACTIVE_PWR_SAFE_STATE)
                {
                    /**wider Time**/
                    comms_upd_tmr_safe();
                    sdr_app_send_ipc_pld(SDR_APP_SDR_CTRL_TMR_CFG_REQ,radio_id_dest_map[COMMS_SBAND_IQS],sizeof(s_sdr_tmr_cfg),(uint8_t *)&sdr_tmr[COMMS_SBAND_IQS]);
                    sdr_app_send_ipc_pld(SDR_APP_SDR_CTRL_TMR_CFG_REQ,radio_id_dest_map[COMMS_UHF],sizeof(s_sdr_tmr_cfg),(uint8_t *)&sdr_tmr[COMMS_UHF]);
                }
            }
            break;

        case SBAND_SDR_APP_BAT_STS_REQ:
            {
                if(sm_get_state(OBC_MAIN_FSM) == OBC_ACTIVE_PWR_NORM_STATE)
                {
                    /**Normal Bat start fw Upd**/
                    sdr_app_send_ipc(SBAND_FW_CFG_START_REQ, COMMS_SBAND_CTLR);
                }
                else if(sm_get_state(OBC_MAIN_FSM) == OBC_ACTIVE_PWR_SAFE_STATE)
                {
                    /**Bat in safe stop fw Upd**/
                    sdr_app_send_ipc(SBAND_FW_CFG_STOP_REQ, COMMS_SBAND_CTLR);

                    /** Set SBAND FW to be start on Normal battery**/
                    fw_upd_sts |= SBAND_FW_UPD_ST;
                }
            }
            break;

        case UHF_SDR_APP_BAT_STS_REQ:
            {
                if(sm_get_state(OBC_MAIN_FSM) == OBC_ACTIVE_PWR_NORM_STATE)
                {
                    /**Normal Bat start fw Upd**/
                    sdr_app_send_ipc(SDR_APP_UHF_FW_CFG_START_REQ, COMMS_UHF_CTLR);
                }
                else if(sm_get_state(OBC_MAIN_FSM) == OBC_ACTIVE_PWR_SAFE_STATE)
                {
                    /**Bat in safe stop fw Upd**/
                    sdr_app_send_ipc(SDR_APP_UHF_FW_CFG_STOP_REQ, COMMS_UHF_CTLR);

                    /** Set UHF FW to be start on Normal battery**/
                    fw_upd_sts |= UHF_FW_UPD_ST;
                }
            }
        default:
            {
            }
            break;
    }

    if((SDR_MH_READY == beacon_data_rsp)||(beacon_data_req > 3))
    {
        //GPS data to be filled
        DEBUG_CPRINT(("\nUHF TIME SDR_MH EXT %d",beacon_data_rsp));
        log_id_with_one_arg(LOG_INFO_L1,LOG_COMMS,UHF_SDR_MH_EXT__u8_,beacon_data_rsp);
        if(beacon_radio_id & UHF_BEACON_REQ)
        {
            sdr_app_send_ipc_pld(SDR_APP_UHF_BEACON_DATA_IND, COMMS_UHF_CTLR, sizeof(s_sdr_beacon_pld), (uint8_t *)&beacon_pld);
        }
        if(beacon_radio_id & SBAND_BEACON_REQ)
        {
            sdr_app_send_ipc_pld(SDR_APP_SBAND_BEACON_DATA_IND, COMMS_SBAND_CTLR, sizeof(s_sdr_beacon_pld), (uint8_t *)&beacon_pld);
        }

        beacon_radio_id = 0;
        beacon_data_rsp = 0;
        beacon_data_req = 0;
        os_memset((uint8_t *)&beacon_pld,0,sizeof(s_sdr_beacon_pld));
    }
#ifdef COMMS_TIME_DEBUG
    get_crnt_time_date(&tim_get_sd_m);
    DEBUG_CPRINT(("\nUHF TIME SDR_MSG EXT %d:%d:%d Msg-id %d ",tim_get_sd_m.hour, tim_get_sd_m.minute, tim_get_sd_m.seconds, msg_id));
    log_id_with_four_arg(LOG_INFO_L2,LOG_COMMS,UHF_TIME_SDR_MSG_EXT__u8__u8__u8__MSG_ID__u16,tim_get_sd_m.hour, tim_get_sd_m.minute, tim_get_sd_m.seconds, msg_id);
#endif
    return ret;
}

/**
 * @brief Generate beacon data for S-band
 * 
 * This function collects beacon data and packages it for
 * transmission over S-band.
 *
 * @return uint8_t Status of beacon data generation
 */
uint8 comms_sband_xlink_beacon_data(void)
{
    beacon_pld.bcon_utc_gps.utc_tim = 0x5d4c49be;
    beacon_pld.bcon_utc_gps.utc_gps_tim_sts = 0x79;
    beacon_pld.bcon_utc_gps.latitude = 53.116;
    beacon_pld.bcon_utc_gps.longitude = 40.574;
    beacon_pld.bcon_utc_gps.altitude = 23;
    memcpy(&beacon_pld.bcon_utc_gps.bcon_msg[0], hello_msg, BCON_MSG_SZ);

    return 0;
}

/**
 * @brief Generate custom pattern for RF transmission test
 *
 * This function generates a custom data pattern for transmitting
 * over the radio to test RF performance.
 * 
 * @param data Pointer to buffer to store generated data pattern
 * 
 * @return uint8_t Status of data pattern generation 
 */
uint8_t comms_cust_pattern_rf_tx_gen(uint8_t* data)
{
    uint32_t seq = 0; 
    uint32_t count = 0;
    uint32_t buff_idx=0;
    uint8_t	pat_chng = 0;
    uint8_t* sync_data=NULL;
    uint8_t radio_id = data[TC_RADIO_MOD_IDX];
    comms_sync_s* sync = (comms_sync_s*)&data[TC_PLD_IDX];
    sync_data = (uint8_t*)os_malloc(sync->size);
    switch(sync->type)
    {
        case 1:
            memset(sync_data,0,sync->size);
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                count++;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
#pragma GCC diagnostic pop
                comms_force_tx_ipc_sdr(radio_id,sync->size,sync_data);
                os_delay(sync->periodicity * 10);
            }
            break;
        case 2:
            memset(sync_data,1,sync->size);
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                count++;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
#pragma GCC diagnostic pop
                comms_force_tx_ipc_sdr(radio_id,sync->size, sync_data);
                os_delay(sync->periodicity * 10);
            }
            break;
        case 3:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                for(int start=0;start<sync->size;start++)
                {
                    sync_data[start] = start+1;
                }
                count++;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
#pragma GCC diagnostic pop
                comms_force_tx_ipc_sdr(radio_id,sync->size, sync_data);
                os_delay(sync->periodicity * 10);
            }
            break;
        case 4:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                uint8_t temp = sync->size;
                for(uint32_t start=0;start<sync->size;start++)
                {
                    sync_data[start] = temp;
                    temp--;
                }
                count++;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
#pragma GCC diagnostic pop
                comms_force_tx_ipc_sdr(radio_id,sync->size, sync_data);
                os_delay(sync->periodicity * 10);
            }
            break;
        case 5:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                buff_idx=0;
                sync_data[buff_idx]=seq;
                buff_idx++;
                memset(&sync_data[buff_idx],0,sync->size-1);
                buff_idx=buff_idx+sync->size;
                count++;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
#pragma GCC diagnostic pop
                comms_force_tx_ipc_sdr(radio_id,sync->size, sync_data);
                os_delay(sync->periodicity * 10);
            }
            break;
        case 6:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                buff_idx=0;
                sync_data[buff_idx]=seq;
                buff_idx++;
                memset(&sync_data[buff_idx],1,sync->size-1);
                buff_idx=buff_idx+sync->size;
                count++;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
#pragma GCC diagnostic pop
                comms_force_tx_ipc_sdr(radio_id,sync->size, sync_data);
                os_delay(sync->periodicity * 10);
            }
            break;
        case 7:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                buff_idx=0;
                sync_data[buff_idx]=seq;
                buff_idx++;
                for(int start=0;start<sync->size-1;start++)
                {
                    sync_data[buff_idx] = start;
                    buff_idx++;
                }
                DEBUG_CPRINT(("\n"));
                count++;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
#pragma GCC diagnostic pop
                comms_force_tx_ipc_sdr(radio_id,sync->size, sync_data);
                os_delay(sync->periodicity * 10);
            }
            break;
        case 8:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                buff_idx=0;
                sync_data[buff_idx]=seq;
                buff_idx++;
                for(int start=sync->size-2;start>=0;start--)
                {
                    sync_data[buff_idx] = start;
                    buff_idx++;
                }
                count++;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
#pragma GCC diagnostic pop
                comms_force_tx_ipc_sdr(radio_id,sync->size, sync_data);
                os_delay(sync->periodicity * 10);
            }
            break;
        case 10:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                os_delay(sync->periodicity * 10);
            }
            break;
        case 11:
            for (seq = 0; seq <sync->pld_count; seq++)
            {
                buff_idx=0;
                sync_data[buff_idx]=seq;
                buff_idx++;
                if (pat_chng == 0)
                {
                    for(int start=0;start<sync->size-1;start++)
                    {
                        sync_data[buff_idx] = start;
                        buff_idx++;
                    }
                    pat_chng = 1;
                }
                else if (pat_chng == 1)
                {
                    for(int start=0;start<sync->size-1;start++)
                    {
                        sync_data[buff_idx] = 0xAA;
                        buff_idx++;
                    }
                    pat_chng = 2;
                }
                else if (pat_chng == 2)
                {
                    for(int start=0;start<sync->size-1;start++)
                    {
                        sync_data[buff_idx] = 0xBB;
                        buff_idx++;
                    }
                    pat_chng = 3;
                }
                else if (pat_chng == 3)
                {
                    for(int start=0;start<sync->size-1;start++)
                    {
                        sync_data[buff_idx] = 0xCC;
                        buff_idx++;
                    }
                    pat_chng = 0;
                }
                DEBUG_CPRINT(("\n"));
                count++;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
                DEBUG_CPRINT(("\n\rCSP PING COUNT: %ld",count));
#pragma GCC diagnostic pop
                comms_force_tx_ipc_sdr(radio_id,sync->size, sync_data);
                os_delay(sync->periodicity * 10);
            }
            break;
    }
    DEBUG_CPRINT(("OBC comms sync data:"));
    os_free(sync_data);
    return 0;
}

/**
 * @brief Force transmission over IPC to SDR 
 * 
 * This function sends a forced transmission message over IPC to 
 * the SDR with provided data.
 *
 * @param radio_id Radio ID 
 * @param pld_len Length of payload data
 * @param pld_ptr Pointer to payload data
 */
void comms_force_tx_ipc_sdr(uint8_t radio_id, uint16_t pld_len, uint8_t* pld_ptr)
{
    switch(radio_id)
    {
        case COMMS_S_BAND:
        case COMMS_SBAND_IQS:
            {
                sdr_app_send_ipc_pld_custom_tx(radio_id,COMMS_SBAND_TX,pld_len,pld_ptr);
            }
            break;
        case COMMS_UHF:
        case GS2_BACK_DOOR_SOC:
            {
                sdr_app_send_ipc_pld_custom_tx(radio_id,COMMS_UHF_TX,pld_len,pld_ptr);
            }
            break;
    }
}

/**
 * @brief Update safe mode timers
 *
 * This function updates the safe mode timer configurations
 * for the SDR based on current mode. 
 */
void comms_upd_tmr_safe(void)
{
    sdr_tmr[COMMS_SBAND_IQS].beacon_enb_tmr = sdr_nvm_param.beacon_safe_enb_tmr; // 30 seconds
    sdr_tmr[COMMS_SBAND_IQS].beacon_prd_tmr = sdr_nvm_param.beacon_safe_prd_tmr;// 10 seconds
    sdr_tmr[COMMS_SBAND_IQS].beacon_rep_tmr = sdr_nvm_param.beacon_safe_rep_tmr; // 2 second
    sdr_tmr[COMMS_SBAND_IQS].sdr_tm_tx_tmr = sdr_nvm_param.sdr_safe_tm_tx_tmr;// 2 minute
    sdr_tmr[COMMS_SBAND_IQS].sdr_tx_on_tmr = sdr_nvm_param.sdr_safe_tx_on_tmr; // 30 seconds
    sdr_tmr[COMMS_SBAND_IQS].tx_data_rep_cnt = 0;

    sdr_tmr[COMMS_UHF].beacon_enb_tmr = sdr_nvm_param.beacon_safe_enb_tmr; // 30 seconds
    sdr_tmr[COMMS_UHF].beacon_prd_tmr = sdr_nvm_param.beacon_safe_prd_tmr;  // 10 seconds
    sdr_tmr[COMMS_UHF].beacon_rep_tmr = sdr_nvm_param.beacon_safe_rep_tmr;  // 2 second
    sdr_tmr[COMMS_UHF].sdr_tm_tx_tmr = sdr_nvm_param.sdr_safe_tm_tx_tmr;  // 2 minute
    sdr_tmr[COMMS_UHF].sdr_tx_on_tmr = sdr_nvm_param.sdr_safe_tx_on_tmr; // 30 seconds

    /** TODO: to be updated in NVM sheet */
    sdr_tmr[COMMS_SBAND_IQS].beacon_enb_tmr = 5*60*60*1000; // 5 hours 
    sdr_tmr[COMMS_SBAND_IQS].beacon_prd_tmr = 3*60*60*1000;// 3 hours
    sdr_tmr[COMMS_SBAND_IQS].beacon_rep_tmr = 5*60*1000; // 5 min

    sdr_tmr[COMMS_UHF].tx_data_rep_cnt = 1;
}

void comms_upd_tmr_normal(void)
{
    sdr_tmr[COMMS_SBAND_IQS].beacon_enb_tmr = sdr_nvm_param.beacon_normal_enb_tmr; // 30 seconds
    sdr_tmr[COMMS_SBAND_IQS].beacon_prd_tmr = sdr_nvm_param.beacon_normal_prd_tmr; // 10 seconds
    sdr_tmr[COMMS_SBAND_IQS].beacon_rep_tmr = sdr_nvm_param.beacon_normal_rep_tmr; // 2 second
    sdr_tmr[COMMS_SBAND_IQS].sdr_tm_tx_tmr = sdr_nvm_param.sdr_normal_tm_tx_tmr; // 2 minute
    sdr_tmr[COMMS_SBAND_IQS].sdr_tx_on_tmr = sdr_nvm_param.sdr_normal_tx_on_tmr; // 30 seconds

    sdr_tmr[COMMS_UHF].beacon_enb_tmr = sdr_nvm_param.beacon_normal_enb_tmr; // 30 seconds
    sdr_tmr[COMMS_UHF].beacon_prd_tmr = sdr_nvm_param.beacon_normal_prd_tmr; // 10 seconds
    sdr_tmr[COMMS_UHF].beacon_rep_tmr = sdr_nvm_param.beacon_normal_rep_tmr; // 2 second
    sdr_tmr[COMMS_UHF].sdr_tm_tx_tmr = sdr_nvm_param.sdr_normal_tm_tx_tmr; // 2 minute
    sdr_tmr[COMMS_UHF].sdr_tx_on_tmr = sdr_nvm_param.sdr_normal_tx_on_tmr; // 30 seconds
}

/**
 * @brief This function send the uhf ground contact status
 * 
 * @param state Current UHF ground contact state
 */
void sdr_gs_contact_status_upd_itc(void)
{
    uint8_t radio_id = 0xFF;
    uint8 prev_val_uhf = uhf_gs_contact_valid;
    uint8 prev_val_sband = sband_gs_contact_valid;

    sband_gs_contact_status_upd(SBAND_TC_TM_ST_REQ);
    uhf_gs_contact_status_upd(UHF_TC_TM_ST_REQ);

    if((uhf_gs_contact_valid != prev_val_uhf)||(sband_gs_contact_valid != prev_val_sband))
    {
        DEBUG_CPRINT(("\n TM Storage IPC %d",radio_id));
        log_id_with_one_arg(LOG_INFO_L1,LOG_COMMS,TM_STORAGE_IPC__u16_,radio_id);
        sdr_app_send_ipc_pld(SBAND_TC_TM_ST_REQ,TM_STORAGE,sizeof(uint8),&radio_id);
    }
}

