/**
 * @file comms_uhf_csw.c
 *
 * @brief This file has the UHF driver thread functions and other main functions for UHF 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 <stdio.h>
#include <math.h>
#include "sm_api.h"
#include "comms_uhf_sim.h"
#include "comms_uhf_csp.h"
#include "comms_uhf_ipc.h"
#include "comms_uhf_main.h"
#include "exo_osal.h"
#include "exo_ral_cmn.h"
#include "exo_common.h"
#include "comms_uhf_init.h"
#include "comms_uhf_csp.h"
#include "exo_io_al_rtc_common.h"
#include "exo_io_al_sos_timer.h"
#include "exo_tctm_ipc.h"
#include "logger.h"
#include "tc_tm_mngr_buffer.h"

sys_time_date_s PLACE_IN_EXT_RAM_MEM  tim_get_u_m;

/** Flag denotes the scheduler based ground pass window status */
extern uint8_t PLACE_IN_EXT_RAM_MEM sch_gs_contact ;

/** Flag used for discrimating actual flight SW and devlopment mode SW */
extern volatile uint8_t PLACE_IN_EXT_RAM_MEM flight_mode ;

uint8_t PLACE_IN_EXT_RAM_MEM uhf_radio_id = 0;///< UHF radio ID
uint16_t PLACE_IN_EXT_RAM_MEM uhf_tc_seq_no = 0;///< UHF telemetry and command sequence number
uint16_t PLACE_IN_EXT_RAM_MEM uhf_tc_tm_id = 0;///< UHF telemetry and command time marker ID
extern uint8_t PLACE_IN_EXT_RAM_MEM comms_uhf_csw_rx_buf[512] ;///< UHF command and software receive buffer
uint8_t PLACE_IN_EXT_RAM_MEM uhf_tc_cmd_id = 0;///< UHF telemetry and command message ID
/**
 * @brief This function step-by-step process the COMMS states to the help
 *  of event thread request
 *
 * @brief CSW main task
 * 
 * This task handles the UHF command and software process.
 * 
 * @param[in] param Task parameter (unused)
 */
void comms_uhf_csw_main(void *param)
{
     int8_t status = COMMS_UHF_IPC_OK;
     /* The below line is the fix for the warning "variable set but not used"
      * Note to developer : Can be removed if needed
      */
     status = status;

    uint8_t state;
    e_sm_sts sm_status;

    os_itc_msg_handle_t comms_uhf_csw_recv_msg;              ///< COMMS state receive message

#ifndef UHF_SIM
    comms_uhf_init_uhf_cfg();
#endif
    sdr_uhf_init_reg_map();

    sm_status = sm_alloc(COMMS_UHF_FSM, COMMS_UHF_MAX_NUM_STATE);

    /** TM buffering FW queue request for each health data */
    tc_uhf_buff_fw_req_queue(sizeof(s_comms_uhf_tm_prop), PERI_UHF_HK_SYNC_ID, UHF_TM_PROP_QUEUE_ID);

    if(SM_OK == sm_status)
    {
       state = COMMS_UHF_INIT_STATE;
       //state = COMMS_UHF_BYPASS_STATE;

        sm_set_state(COMMS_UHF_FSM, state);

        while(1)
        {
#ifdef COMMS_TIME_DEBUG
        	get_crnt_time_date(&tim_get_u_m);
   			DEBUG_CPRINT(("\nUHF TIME IPC ENT %d:%d:%d",tim_get_u_m.hour, tim_get_u_m.minute, tim_get_u_m.seconds));
   			log_id_with_three_arg(LOG_INFO_L2,LOG_COMMS,UHF_TIME_IPC_ENT__u8__u8__u8_,tim_get_u_m.hour, tim_get_u_m.minute, tim_get_u_m.seconds);
#endif 

            /** UHF driver IPC receive */
            status = os_itc_msg_rcv(COMMS_UHF_CTLR, &comms_uhf_csw_recv_msg, os_wait_forever);

#ifndef UHF_SIM
            if((OBC_MAIN == comms_uhf_csw_recv_msg.src_entity) || (COMMS_UHF_CTLR == comms_uhf_csw_recv_msg.src_entity)\
                    || (ORBIT_CONOPS_SCHEDULER == comms_uhf_csw_recv_msg.src_entity) ||(SDR_APP == comms_uhf_csw_recv_msg.src_entity)||(TC_TM_MANAGER_IPC_RECEIVE == comms_uhf_csw_recv_msg.src_entity) || (HM_MANAGER_IPC_RECEIVE == comms_uhf_csw_recv_msg.src_entity))
            {
                /** Invoke UHF driver FSM */
                state = comms_uhf_fsm_hdlr_fn(state,comms_uhf_csw_recv_msg.Msg_id,comms_uhf_csw_recv_msg.pld.pld_ptr);
            }
            else
            {
                //if(TC_TM_MANAGER_IPC_SEND == comms_uhf_csw_recv_msg.src_entity)
                {
                    uint8_t *tc_tm = (uint8_t *)comms_uhf_csw_recv_msg.pld.pld_ptr;
                    uhf_tc_tm_id = comms_uhf_csw_recv_msg.Msg_id;

                    DEBUG_CPRINT(("\n[UHF]TC-TM ID Updated******"));
                    log_id(LOG_INFO_L2,LOG_COMMS,UHF_TC_TM_ID_UPDATED);
                    //Extract the sequence number
                    os_memcpy(comms_uhf_csw_rx_buf, tc_tm, sizeof(uint16_t));
                    os_memcpy(&comms_uhf_csw_rx_buf[TM_RADIO_MOD_IDX],(uint8_t *) &tc_tm[TC_RADIO_MOD_IDX], sizeof(uint8_t));
                    //Extract the sequence number to dedicate variable
                    os_memcpy(&uhf_tc_seq_no, comms_uhf_csw_recv_msg.pld.pld_ptr, sizeof(uint16_t));
                    os_memcpy(&uhf_radio_id ,(uint8_t *) &tc_tm[TC_RADIO_MOD_IDX], sizeof(uint8_t));
                }

                /** Invoke UHF driver FSM */

                state = comms_uhf_fsm_hdlr_fn(state,comms_uhf_csw_recv_msg.Msg_id,comms_uhf_csw_recv_msg.pld.pld_ptr);


            }

            /** Update UHF driver state */
            sm_set_state(COMMS_UHF_FSM, state);
#endif


            /** Freeing of payload pointer */
            if(NULL!=comms_uhf_csw_recv_msg.pld.pld_ptr)
            {
                os_free(comms_uhf_csw_recv_msg.pld.pld_ptr);
                comms_uhf_csw_recv_msg.pld.pld_ptr = NULL;
            }
#ifdef COMMS_TIME_DEBUG 
            get_crnt_time_date(&tim_get_u_m);
           	DEBUG_CPRINT(("\nUHF TIME IPC ExT %d:%d:%d",tim_get_u_m.hour, tim_get_u_m.minute, tim_get_u_m.seconds));
   			log_id_with_three_arg(LOG_INFO_L2,LOG_COMMS,UHF_TIME_IPC_EXT__u8__u8__u8_,tim_get_u_m.hour, tim_get_u_m.minute, tim_get_u_m.seconds);
#endif
        }
    }
    /** Freeing memory of UHF driver FSM FW */
    sm_status = sm_free(COMMS_UHF_FSM);
}

/**
 * @brief This function create the COMMS state and event threads
 *
 * @brief Initialize UHF CSW module
 * 
 * Performs initialization of data structures and hardware
 * for the UHF command and software module.
 * 
 * @return Result of initialization
 */
int32_t comms_uhf_csw_init(void)
{
    os_status_t status;

    /** Thread creation of UHF driver main thread */
    status = os_thread_create(COMMS_UHF_CTLR,
    		T_COMMS_UHF_STACK_SIZE,  //TODO stack size need to be optimized
            P_COMMS_UHF_CTLR,
            "comms_uhf_thread",
            comms_uhf_csw_main,
            NULL,
            NULL,
            NULL);

    return status;
}

/**
 * @brief This function is the callback function for the SBAND rx sync periodic timer
 *        This sync will be used to store parameter for every 2mins
 * @brief UHF telemetry storage callback
 * 
 * Callback function that is called periodically to store
 * UHF telemetry data.
 */
//void sband_periodic_tm_stor_cb(void)
void uhf_tm_periodic_stor_cb(void)
{
	uhf_send_ipc(UHF_TM_PERIODIC_READ, COMMS_UHF_CTLR);
}

/**
 * @brief This function deletes the UHF queue and release its memory
 * @brief Suspend UHF communications
 * 
 * This function suspends UHF communication operation
 * when the system enters low power mode.
 * 
 * @return Result of suspend operation
 */
os_status_t comms_uhf_suspend(void)
{
    os_status_t status;
    status = os_thread_suspend(COMMS_UHF_CTLR);
    return status;
}

/**
 * @brief This functionalities resumes the UHF thread
 * 
 * @brief Resume UHF communications
 * 
 * This function resumes UHF communication operation
 * when the system wakes from low power mode.
 * 
 * @return Result of resume operation
 */
os_status_t comms_uhf_resume(void)
{
    os_status_t status;
    status = os_thread_resume(COMMS_UHF_CTLR);
    return status;
}


/**
 * @brief This function used to request queue to push the health data 
 *
 * @brief Initialize UHF buffer forwarding request queue
 * 
 * This function initializes a queue for buffer forwarding requests.
 * 
 * @param[in] instance_size Size of each queue instance in bytes
 * @param[in] num_of_instance Number of instances in the queue
 * @param[in] queue_id ID to initialize the queue with
 */
void tc_uhf_buff_fw_req_queue(uint32 instance_size, uint32 num_of_instance, uint8 queue_id)
{
    os_itc_msg_handle_t uhf_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;
        uhf_req_ipc.pld.pld_ptr = (void*)buff_req; 
        uhf_req_ipc.src_entity = COMMS_UHF_CTLR;
        uhf_req_ipc.Msg_id = OBC_TC_TM_BUFFER_REQ;
        os_itc_msg_send(&uhf_req_ipc, HM_MANAGER_IPC_RECEIVE, os_send_itc_wait);
    }
}

/**
 * @brief This function used to enqueue the data into the health metric queue
 * @brief Enqueue UHF buffer forwarding request
 * 
 * This function enqueues a buffer forwarding request to the 
 * specified queue ID.
 * 
 * @param[in] data Pointer to data to enqueue
 * @param[in] queue_id ID of queue to enqueue request to
 */

void tc_uhf_buff_fw_enqueue_req(uint8* data, uint8 queue_id)
{
    os_itc_msg_handle_t uhf_req_ipc;
    uhf_req_ipc.pld.pld_data = queue_id; 
    uhf_req_ipc.pld.pld_ptr = data; 
    uhf_req_ipc.src_entity = COMMS_UHF_CTLR;
    uhf_req_ipc.Msg_id = OBC_TC_TM_ENQUEUE_REQ;
    os_itc_msg_send(&uhf_req_ipc, HM_MANAGER_IPC_RECEIVE, os_send_itc_wait);
}


