/**
 * @file comms_csw.c
 *
 * @brief This file has the S-Band driver 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 <stdio.h>
#include "sm_api.h"
#include "comms_sband_sim.h"
#include "comms_sband_csp.h"
#include "comms_ipc.h"
#include "comms_csw.h"
#include "exo_osal.h"
#include "exo_ral_cmn.h"
#include "exo_common.h"
#include "comms_sband_init.h"
#include "comms_sband_xlink_sock.h"
#include "comms_sband_csp.h"
#include "logger.h"
#include "comms_sband_xlink_api.h"
#include "comms_ftm.h"
#include "comms_sband_intf.h"

#include "exo_io_al_rtc_common.h"
#include "exo_io_al_sos_timer.h"
#include "exo_tctm_ipc.h"
#include "tc_tm_mngr_buffer.h"

sys_time_date_s tim_get_s_m; ///< Time/date structure

uint8_t PLACE_IN_EXT_RAM_MEM sband_radio_id = 0; ///< S-Band radio ID
uint16_t PLACE_IN_EXT_RAM_MEM sband_tc_seq_no = 0; ///< S-Band TC sequence number
uint16_t PLACE_IN_EXT_RAM_MEM sband_tc_tm_id = 0; ///< S-Band TC/TM ID

/**
 * @brief This function step-by-step process the COMMS states to the help
 *  of event thread request
 * @brief Main S-Band driver state machine handler. 
 * 
 * Handles stepping through S-Band driver states based on events.
 * 
 * @param[in] param Thread function parameter (unused).
 */
void comms_csw_main(void *param)
{

    int8_t status = COMMS_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;
    e_sm_sts sm_status;

    uint8_t state;

    os_itc_msg_handle_t comms_csw_recv_msg;              ///< COMMS state receive message

    comms_init_sband_cfg();

#ifndef LINUX_TEMP_PORT
    comms_ftm_init();
#endif
    sm_status = sm_alloc(COMMS_SBAND_FSM, COMMS_MAX_NUM_STATE);

    /** TM buffering FW queue request for each health data */
    tc_sband_buff_fw_req_queue(sizeof(s_sband_periodic_tm), MAX_SBAND_PERIODIC_TM, SBAND_PERIODIC_TM_QUEUE_ID);

    if(SM_OK == sm_status)
    {
        state = COMMS_INIT_STATE;
        //state = COMMS_ACTIVE_STATE;

        sm_set_state(COMMS_SBAND_FSM, state);

        while(1)
        {
            /** S-Band driver IPC receive */
            status = os_itc_msg_rcv(COMMS_SBAND_CTLR, &comms_csw_recv_msg, os_wait_forever);

            if(ral_success == status)
            {
#ifdef COMMS_TIME_DEBUG 
                get_crnt_time_date(&tim_get_s_m);
                DEBUG_CPRINT(("\nSBAND TIME IPC ENT %d:%d:%d",tim_get_s_m.hour, tim_get_s_m.minute, tim_get_s_m.seconds));
                log_id_with_three_arg(LOG_INFO_L1,LOG_COMMS,SBAND_TIME_IPC_ENT__u8__u8__u8_,tim_get_s_m.hour, tim_get_s_m.minute, tim_get_s_m.seconds);
#endif
                if((OBC_MAIN == comms_csw_recv_msg.src_entity) || (COMMS_SBAND_CTLR == comms_csw_recv_msg.src_entity)\
                        || (ORBIT_CONOPS_SCHEDULER == comms_csw_recv_msg.src_entity)|| (SDR_APP == comms_csw_recv_msg.src_entity)\
                        || (TC_TM_MANAGER_IPC_RECEIVE == comms_csw_recv_msg.src_entity)
                    || (OBC_OTSU == comms_csw_recv_msg.src_entity) || (HM_MANAGER_IPC_RECEIVE== comms_csw_recv_msg.src_entity))
                {
                    /** Invoke S-Band driver FSM*/
                    state = comms_fsm_hdlr_fn(state,comms_csw_recv_msg.Msg_id,comms_csw_recv_msg.pld.pld_ptr);
                }
                else
                {
                    uint8_t *tc_tm = (uint8_t *)comms_csw_recv_msg.pld.pld_ptr;
                    sband_tc_tm_id = comms_csw_recv_msg.Msg_id;

                    //Extract the sequence number
                    os_memcpy(&sband_tc_seq_no, comms_csw_recv_msg.pld.pld_ptr, sizeof(uint16_t));
                    os_memcpy(&sband_radio_id ,(uint8_t *) &tc_tm[TC_RADIO_MOD_IDX], sizeof(uint8_t));

                    /** Invoke S-Band driver FSM*/
                    //state = comms_fsm_hdlr_fn(state,comms_csw_recv_msg.Msg_id,comms_csw_recv_msg.pld.pld_ptr);

                    comms_tctm_hdlr(sband_radio_id, comms_csw_recv_msg.Msg_id,comms_csw_recv_msg.pld.pld_ptr, comms_csw_recv_msg.Msg_len);
                }

                /** Update S-Band driver state */
                sm_set_state(COMMS_SBAND_FSM, state);

                /** Freeing of payload pointer */
                if(NULL!=comms_csw_recv_msg.pld.pld_ptr)
                {
                    os_free(comms_csw_recv_msg.pld.pld_ptr);
                    comms_csw_recv_msg.pld.pld_ptr = NULL;
                }
#ifdef COMMS_TIME_DEBUG 
                get_crnt_time_date(&tim_get_s_m);
                DEBUG_CPRINT(("\nSBAND TIME IPC EXT %d:%d:%d",tim_get_s_m.hour, tim_get_s_m.minute, tim_get_s_m.seconds));
                log_id_with_three_arg(LOG_INFO_L1,LOG_COMMS,SBAND_TIME_IPC_EXT__u8__u8__u8_,tim_get_s_m.hour, tim_get_s_m.minute, tim_get_s_m.seconds);
#endif
            }
            else
            {
                DEBUG_CPRINT(("\n SBand Receive fail \n"));
            }
        }
    }
    /** Freeing memory of S-Band driver FSM FW */
    sm_status = sm_free(COMMS_SBAND_FSM);
}
/**
 * @brief This function create the COMMS state and event threads
 * @brief Initialize S-Band driver threads.
 * 
 * Creates the S-Band driver state machine and IQ threads.
 *
 * @return OS status code.
 */
int32_t comms_csw_init(void)
{
    os_status_t status;

    /** Thread creation of S-Band driver main thread */
    status = os_thread_create(COMMS_SBAND_CTLR,
            T_COMMS_STACK_SIZE,
            P_COMMS_SBAND_CTLR,
            "comms_sband_thread",
            comms_csw_main,
            NULL,
            NULL,
            NULL);

    os_thread_create(COMMS_SBAND_IQ,T_COMMS_IQ_STACK_SIZE,P_COMMS_SBAND_IQ,"sband_iq_spacecom",(app_entry_func_t)sband_xlink_rcv_thrd,NULL,NULL,NULL);

    return status;
}

/**
 * @brief Initialize S-Band macros.
 */
void comms_macro_init(void)
{

}

/**
 * @brief This function deletes the SBAND queue and release its memory
 * @brief Resume S-Band driver thread.
 * 
 * Resumes execution of the suspended S-Band driver thread.
 * 
 * @return OS status code.
 */
os_status_t comms_sband_suspend(void)
{
    os_status_t status;
    status = os_thread_suspend(COMMS_SBAND_CTLR);
    return status;
}

/**
 * @brief This functionalities resumes the SBAND thread
 * @brief Resume S-Band driver thread.
 * 
 * Resumes execution of the suspended S-Band driver thread.
 * 
 * @return OS status code.
 */
os_status_t comms_sband_resume(void)
{
    os_status_t status;
    status = os_thread_resume(COMMS_SBAND_CTLR);
    return status;
}

/**
 * @brief This function used to reqquest queue to push the health data 
 * @brief Request S-Band telemetry buffer.
 * 
 * Sends a request to allocate an S-Band telemetry buffer.
 * 
 * @param[in] instance_size Size of each telemetry instance. 
 * @param[in] num_of_instance Number of instances to store.
 * @param[in] queue_id ID of queue to allocate buffer for.
 */
void tc_sband_buff_fw_req_queue(uint32 instance_size, uint32 num_of_instance, uint8 queue_id)
{
    os_itc_msg_handle_t sband_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;
        sband_req_ipc.pld.pld_ptr = (void*)buff_req; 
        sband_req_ipc.src_entity = COMMS_SBAND_CTLR;
        sband_req_ipc.Msg_id = OBC_TC_TM_BUFFER_REQ;
        os_itc_msg_send(&sband_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 S-Band telemetry data.
 * 
 * Sends a request to enqueue new S-Band telemetry data.
 * 
 * @param[in] data Pointer to telemetry data to enqueue.
 * @param[in] queue_id ID of queue to enqueue data to.
 */

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