/**
 * @file tc_tm_mngr_buffer.c
 *
 * @brief This file contains functions for using the buffering  
 *        framework
 *
 * The functions provided in the file provides demonstration on
 * usage of TC buffering FW APIs
 *
 * @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.
 *        usage of TC TM Library APIs
 */
/*********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tc_common.h"
#include "tc_tm_lib_common.h"
#include "tm_common.h"
#include "exo_osal.h"
#include "exo_common.h"
#include "exo_ral_cmn.h"
#include "tc_tm_mngr.h"
#include "tc_tm_mngr_buffer.h"
#include "exo_tctm_ipc.h"
#include "logger.h"

/** Array of FW applications  informations */
static s_tc_tm_buff_app buff_fw_apps[TC_TM_BUFFER_APP_MAX] PLACE_IN_EXT_RAM_MEM = {{ 0 }};
extern s_radio_module radio_mod[MAX_RADIO_MOD];
extern exo_sw_dbg_cb exo_sw_dbg;
os_itc_msg_handle_t hm_recv_msg;
e_hm_mngr_sts hm_mngr_init = 0;

/**
 * @brief This API invokes threads to handle transmit and
 * receive IPC messages for Health metric buffering framework
 */
os_status_t health_metric_buffer_main(void)
{
    os_status_t status=ral_success;

    status &= os_thread_create(HM_MANAGER_IPC_RECEIVE,
            T_HM_IPC_RECIEVE_STACK_SIZE,
            P_HM_MANAGER_IPC_RECEIVE,
            "HM manager IPC recv thread - IPC",
            health_metric_ipc_rcv,
            NULL,
            NULL,
            NULL);

    if(ral_success == status)
    {
        hm_mngr_init = HM_MNGR_OK;
    }
    else
    {
        hm_mngr_init = HM_MNGR_ERR;
    }

    return status;
}

void health_metric_ipc_rcv()
{
    tc_buff_fw_init();
    while(1)
    {

    os_itc_msg_rcv(HM_MANAGER_IPC_RECEIVE,
                &hm_recv_msg,
                os_wait_forever); 
    tc_process_buff_fw_ipc(&hm_recv_msg);

    if(hm_recv_msg.pld.pld_ptr)
    {
        os_free(hm_recv_msg.pld.pld_ptr);
        hm_recv_msg.pld.pld_ptr = NULL;
    }
 
    }
}

/**
 * @brief This API used to process the buffer framework related IPC's 
 * and return error if it is not handled
 */
int8 tc_process_buff_fw_ipc(os_itc_msg_handle_t *tc_recv_msg)
{
  //  DEBUG_CPRINT(("HM_MANAGER: tc_process_buff_fw_ipc entry \n"));
    log_id(LOG_INFO_L3,LOG_HM,tc_process_buff_fw_ipc_entry);

    /** variable used for return status */
    int8 sts = TC_TM_BUFFER_SUCC;

    /** Variables used for iteraion and buffer indexing */
    int i = 0;
    uint8 app_idx;
    uint8 buff_idx;
    uint8 mod_id;
    uint8 pri_idx;
    uint8 mod_pri;
#ifndef LINUX_TEMP_PORT
    void* health_buff_cb;
    void* health_buff_mb;
#endif

    /** variable to store queue status*/
    os_status_t q_sts;    

    /** local pointer to dequeue temp instance and free it */
    void *tc_local_q_instance = NULL;

    /** Control variable for debugging - total IPC received */
    exo_sw_dbg.hm_dbg.no_ipc_rcvd++;

     /** Get the app id based on source entity */
     uint8 app_id = tc_get_app_id_from_src_entity(tc_recv_msg->src_entity);

    /** Switch based on source layer */
    switch(tc_recv_msg->src_entity)
    {
        case OBC_MAIN:
        default:
            {
             /*   DEBUG_CPRINT(("HM_MANAGER: tc_process_buff_fw_ipc src %d and msg_id %d \n", tc_recv_msg->src_entity, \
                            tc_recv_msg->Msg_id));*/
                log_id_with_two_arg(LOG_INFO_L3,LOG_HM,tc_process_buff_fw_ipc_src__u8__msgid__u16_,tc_recv_msg->src_entity,\
                         tc_recv_msg->Msg_id);
                /**  - Switch based on Message ID */
                switch(tc_recv_msg->Msg_id)
                {

                    /**   - Buffer request from application */
                    case OBC_TC_TM_BUFFER_REQ:
                        {

                            /** Control variable for debugging - Increments on receiving buffer request */
                            exo_sw_dbg.hm_dbg.buffer_req++;

                            /**    - Payload present */
                            if(tc_recv_msg->pld.pld_ptr)
                            {
                                /**     - Use number of queue as buff_idx for buffer request alone */
                                buff_idx = buff_fw_apps[app_id].num_of_queue;

                                /**     - Copy the structure information to corresponding app information */
                                os_memcpy(&buff_fw_apps[app_id].buffer_info[buff_idx], \
                                                      tc_recv_msg->pld.pld_ptr, sizeof(s_tc_tm_buffer_req));

                                /**     - Queue id must be less than the max queue id */
                                if(buff_fw_apps[app_id].buffer_info[buff_idx].queue_id < TC_BUFF_MAX_QUEUE)
                                {
#ifdef LINUX_TEMP_PORT
                                    /**      - Create queue and store the queue reference to structure */
                                    q_sts = os_queue_create(&buff_fw_apps[app_id].\
                                            queue[buff_fw_apps[app_id].buffer_info[buff_idx].\
                                            queue_id], buff_fw_apps[app_id].buffer_info[buff_idx].num_instance, \
                                            buff_fw_apps[app_id].buffer_info[buff_idx].instance_size,NULL);
#else
                                    health_buff_mb = os_malloc_eram(buff_fw_apps[app_id].buffer_info[buff_idx].num_instance * \
                                            buff_fw_apps[app_id].buffer_info[buff_idx].instance_size);

                                    if(health_buff_mb)
                                    {
                                        //health_buff_mb = os_malloc_eram(sizeof(StaticQueue_t));
                                        health_buff_cb = os_malloc_eram(2000);// this has to be changed
                                        if(health_buff_cb)
                                        {
                                        /**      - Create queue and store the queue reference to structure */
                                        q_sts = os_queue_create_static(&buff_fw_apps[app_id].\
                                                queue[buff_fw_apps[app_id].buffer_info[buff_idx].\
                                            queue_id], buff_fw_apps[app_id].buffer_info[buff_idx].num_instance, \
                                            buff_fw_apps[app_id].buffer_info[buff_idx].instance_size, health_buff_cb, health_buff_mb, NULL);
                                        }
                                        else
                                        {
                                            os_free(health_buff_cb);
                                            q_sts = ral_err_invld_ptr;
                                        }
                                    }
                                    else
                                    {
                                        //malloc error
                                        q_sts = ral_err_invld_ptr;
                                    }
#endif

                                    if(ral_success != q_sts)
                                    {
                                        DEBUG_CPRINT(("HM_MANAGER: os_queue_create failure in tc_buffer_fw\n"));
                                        log_id(LOG_ERROR,LOG_HM,os_queue_create_failure_in_tc_buffer_fw);

                                        /**      - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_BUFFER_RSP, \
                                                TC_TM_BUFFER_QUEUE_ERROR, tc_recv_msg->src_entity);
                                    }
                                    else
                                    {
                                        /** Set the bit map of queue id received */
                                        tc_set_queue_bitmap(buff_fw_apps[app_id].buffer_info[buff_idx].queue_id, \
                                                &buff_fw_apps[app_id].queue_bitmap);

                                        buff_fw_apps[app_id].num_of_queue++;

                                        DEBUG_CPRINT(("HM_MANAGER:Buff idx %d\n",buff_idx)); 
                                        log_id_with_one_arg(LOG_INFO_L3,LOG_HM,Buff_idx__u8_,buff_idx);

                                        DEBUG_CPRINT(("HM_MANAGER: Queue ID %d and context %x \n", \
                                            buff_fw_apps[app_id].buffer_info[buff_idx].queue_id, \
                                            (uint32)(long)buff_fw_apps[app_id].queue[buff_fw_apps[app_id].buffer_info[buff_idx].\
                                            queue_id]));
                                        log_id_with_two_arg(LOG_INFO_L2,LOG_HM,Queue_ID__u8__context__hex_,\
                                                 buff_fw_apps[app_id].buffer_info[buff_idx].queue_id, \
                                                 (uint32)(long)buff_fw_apps[app_id].queue[buff_fw_apps[app_id].buffer_info[buff_idx].\
                                                 queue_id]);
                                        /**     - Set the submodule default priority */
                                    /** Note: This can be changed via TC */
                                    buff_fw_apps[app_id].sub_mod_priority = app_id;

                                    /**     - Send response to the source layer */
                                    tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_BUFFER_RSP, \
                                            TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);
                                    }
                                }
                                else
                                {
                                    DEBUG_CPRINT(("HM_MANAGER: QueueID not supported for OBC_TC_TM_BUFFER_REQ\n"));
                                    log_id(LOG_ERROR,LOG_HM,QueueID_not_supported_for_OBC_TC_TM_BUFFER_REQ);

                                    /**     - Send response to the source layer */
                                    tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_BUFFER_RSP, \
                                            TC_TM_BUFFER_QUEUE_NOT_VALID, tc_recv_msg->src_entity);
                                }

                            }
                            else
                            {
                                /**     - Send back the failure response to source layer */
                                DEBUG_CPRINT(("HM_MANAGER: No payload found for OBC_TC_TM_BUFFER_REQ\n"));
                                log_id(LOG_ERROR,LOG_HM,No_payload_found_for_OBC_TC_TM_BUFFER_REQ);

                                /**     - Send response to the source layer */
                                tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_BUFFER_RSP, \
                                        TC_TM_BUFFER_FAIL, tc_recv_msg->src_entity);
                            }
                        }
                        break;

                    case OBC_TC_TM_ENQUEUE_REQ:
                        {
                            /** Control variable for debugging - Increments on receiving enqueue request */
                            exo_sw_dbg.hm_dbg.enqueue_req++;

                            /**    - Payload present */
                            if(tc_recv_msg->pld.pld_ptr)
                            {
                                /**     - Get the queue id */
                                uint8 queue_id = tc_recv_msg->pld.pld_data;

                                /**     - Check queue is valid */
                                if((TC_BUFF_MAX_QUEUE > queue_id)) 
                                {
                                    /**     - Check if queue is active*/
                                    if(TC_TM_BUFFER_SUCC == tc_check_queue_sts(queue_id, &buff_fw_apps[app_id].queue_bitmap))
                                    {
                                        /**     - get the buffer index for corresponding queue id */
                                        buff_idx = tc_get_buff_idx(queue_id, app_id);

                                        /**     - pld_ptr will have the instances to be queued */
                                        if(ral_success != os_queue_send(buff_fw_apps[app_id].queue[queue_id],
                                                    tc_recv_msg->pld.pld_ptr, 0))
                                        {
                                            /**      - Wrapping enabled, dequeue the queue and push the new one */
                                            if(buff_fw_apps[app_id].buffer_info[buff_idx].wrap_dsb == TC_BUFFER_WRAP_DSB)
                                            {
                                                /**       - Allocation to dequeue the data from queue */
                                                tc_local_q_instance = os_malloc(buff_fw_apps[app_id].\
                                                        buffer_info[buff_idx].instance_size);

                                                if(tc_local_q_instance)
                                                {
                                                    /**       - dequeue an instnace */
                                                    if(ral_success == os_queue_receive(
                                                                buff_fw_apps[app_id].queue[queue_id],
                                                                tc_local_q_instance,0))
                                                    {
                                                        DEBUG_CPRINT((" Q was full, Success \n"));
                                                        log_id(LOG_INFO_L1,LOG_HM,Q_was_full_Success);
                                                    }
                                                    else
                                                    {
                                                        DEBUG_CPRINT((" Q was full, but dequeue failed \n"));
                                                        log_id(LOG_ERROR,LOG_HM,Q_was_full_but_dequeue_failed);
                                                    }

                                                    /**        - dequeue succeeded free the data */
                                                    os_free(tc_local_q_instance);
                                                    tc_local_q_instance = NULL;

                                                    /**       - retry the new one */
                                                    if(ral_success == os_queue_send(buff_fw_apps[app_id].queue[queue_id],
                                                                tc_recv_msg->pld.pld_ptr, 0))
                                                    {
                                                        /** TBD: Check threshold and move to SSD if flag enabled */

                                                     /*  DEBUG_CPRINT(("HM_MANAGER: BUFFER_ENQUEUE_SUCCESS for submod %d \
                                                                                         queue %d\n",app_id, queue_id));*/
                                                        log_id_with_two_arg(LOG_INFO_L1,LOG_HM,Buffer_enqueue_success_for_submod__u8__queue__u8_,app_id, queue_id);

                                                        /**     - Send response to the source layer */
                                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_ENQUEUE_RSP, \
                                                                TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);
                                                    }
                                                    else
                                                    {
                                                        /**     - Send response to the source layer */
                                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_BUFFER_RSP, \
                                                                TC_TM_BUFFER_DEQUEUE_FAIL, tc_recv_msg->src_entity);
                                                    }
                                                }
                                                else
                                                {
                                                    DEBUG_CPRINT(("Mem_alloc failed while queue deque, critical error\n"));
                                                    log_id(LOG_ERROR,LOG_HM,Mem_alloc_failed_while_queue_dequeue_critical_error);
                                                }
                                            }
                                            else
                                            {
                                                DEBUG_CPRINT(("Wrap disabled, dropping the new data\n"));
                                                log_id(LOG_ERROR,LOG_HM,Wrap_disabled_dropping_the_new_data);

                                                /**     - Send response to the source layer */
                                                tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_ENQUEUE_RSP, \
                                                    TC_TM_BUFFER_DATA_DROPPED, tc_recv_msg->src_entity);

                                            }
                                        }
                                        else
                                        {
                                            /** TBD: Check threshold and move to SSD if flag enabled */
                                         /*   DEBUG_CPRINT(("HM_MANAGER: BUFFER_ENQUEUE_SUCCESS for submod %d \
                                                                                         queue %d\n",app_id, queue_id));*/
                                            log_id_with_two_arg(LOG_INFO_L1,LOG_HM,Buffer_enqueue_success_for_submod__u8__queue__u8_, app_id, queue_id);

                                            /**     - Send response to the source layer */
                                            tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_ENQUEUE_RSP, \
                                                    TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);

                                        }
                                    }
                                    else
                                    {
                                        DEBUG_CPRINT(("HM_MANAGER:  Queue not active for OBC_TC_TM_ENQUEUE_REQ\n"));
                                        log_id(LOG_ERROR,LOG_HM,Queue_not_Active_for_OBC_TC_TM_ENQUEUE_REQ);
                                        DEBUG_CPRINT(("APP_ID:%d, QUEUE_ID:%d\n",app_id,queue_id));
                                        log_id(LOG_INFO_L1,LOG_HM,APP_ID__u8__QUEUE_ID__u8_);

                                        /**     - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_ENQUEUE_RSP, \
                                            TC_TM_BUFFER_QUEUE_NOT_ACTIVE, tc_recv_msg->src_entity);
                                    }
                                }
                                else
                                {
                                    /**     - Send back the failure response to source layer */
                                    DEBUG_CPRINT(("HM_MANAGER:  Queue not valid for OBC_TC_TM_ENQUEUE_REQ\n"));
                                    log_id(LOG_ERROR,LOG_HM,Queue_not_valid_for_OBC_TC_TM_ENQUEUE_REQ);

                                    /**     - Send response to the source layer */
                                    tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_ENQUEUE_RSP, \
                                            TC_TM_BUFFER_QUEUE_NOT_VALID, tc_recv_msg->src_entity);
                                }
                            }
                            else
                            {
                                /**     - Send back the failure response to source layer */
                                DEBUG_CPRINT(("HM_MANAGER: No payload found for OBC_TC_TM_ENQUEUE_REQ\n"));
                                log_id(LOG_ERROR,LOG_HM,No_payload_found_for_OBC_TC_TM_ENQUEUE_REQ);

                                /**     - Send response to the source layer */
                                tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_ENQUEUE_RSP, \
                                        TC_TM_BUFFER_FAIL, tc_recv_msg->src_entity);
                            }
                        }
                        break;
                    case OBC_TC_TM_ENQUEUE_FRONT_REQ:
                        {
                            /** TBD : Need RAL,OSAL changes for xQueueSendToFront */
                        }
                        break;

                    case OBC_TC_TM_DL_BUFFER_REQ:
                        {
                            /** Control variable for debugging - Increments on receiving dl request */
                            exo_sw_dbg.hm_dbg.dl_req++;

                            DEBUG_CPRINT(("OBC_TC_TM_DL_BUFFER_REQ received\n"));
                            log_id(LOG_INFO_L2,LOG_HM,OBC_TC_TM_BUFFER_REQ_received);

                            /**    - Getting TC_TM DL request */
                            s_tc_tm_dl_q_req *dl_req = (s_tc_tm_dl_q_req*)tc_recv_msg->pld.pld_ptr;

                            /**    - Check the radio module is activeness, if not active return */
                            if((radio_mod[tc_recv_msg->pld.pld_data].gs_contact_valid == NULL) ||\
                                    !radio_mod[tc_recv_msg->pld.pld_data].radio_set_flag || \
                                    !radio_mod[tc_recv_msg->pld.pld_data].gs_contact_valid())
                            {
                                DEBUG_CPRINT(("Radio %d not active\n",(uint8)tc_recv_msg->pld.pld_data));
                                log_id_with_one_arg(LOG_ERROR,LOG_HM,Radio__u8__not_active,(uint8)tc_recv_msg->pld.pld_data);
                                return TC_TM_BUFFER_RADIO_NOT_ACTIVE;
                            }

                            /**    - Valid submodule found, get the app_id */
                            mod_id = tc_get_app_id_from_src_entity(dl_req->submod_id);

                            /**    - Check valid submodule found */
                            if(dl_req->submod_id != TC_INVLD_SUB_MODULE && TC_TM_BUFFER_APP_MAX > mod_id)
                            {
                                DEBUG_CPRINT(("valid module id %d \n", mod_id));
                                log_id_with_one_arg(LOG_INFO_L2,LOG_HM,Valid_module_id__u8_,mod_id);

                                /**    - check for valid queue */
                                if(dl_req->queue_id != TC_INVLD_SUB_MODULE && TC_BUFF_MAX_QUEUE > dl_req->queue_id)
                                {
                                    DEBUG_CPRINT(("valid queue id %d \n", dl_req->queue_id));
                                    log_id_with_one_arg(LOG_INFO_L2,LOG_HM,Valid_queue_id__u8_,dl_req->queue_id);

                                    /**     - Check if queue is active*/
                                    if(TC_TM_BUFFER_SUCC == tc_check_queue_sts(dl_req->queue_id, &buff_fw_apps[mod_id].queue_bitmap))
                                    {
                                        /**       - get the buffer index for corresponding queue id */
                                        buff_idx = tc_get_buff_idx(dl_req->queue_id, app_id);

                                        /**      - Valid queueid found, DL only the queue */
                                        sts = tc_buffer_dequeue_and_send_tm(buff_fw_apps[mod_id].\
                                                queue[dl_req->queue_id], app_id, buff_idx, tc_recv_msg->pld.pld_data);

                                        /**     - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_DL_BUFFER_RSP, \
                                                sts, tc_recv_msg->src_entity);
                                    }
                                    else
                                    {
                                        DEBUG_CPRINT(("Queue not active %d", dl_req->queue_id));
                                        log_id_with_one_arg(LOG_ERROR,LOG_HM,Queue_not_active__u8_,dl_req->queue_id);

                                        /**     - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_DL_BUFFER_RSP, \
                                                TC_TM_BUFFER_QUEUE_NOT_ACTIVE, tc_recv_msg->src_entity);
                                    }
                                }
                                else
                                {
                                    DEBUG_CPRINT(("Not valid queue id, check priority"));
                                    log_id(LOG_ERROR,LOG_HM,Not_valid_queue_id_check_priority);

                                    /**    - Invalid submodules, check the priority */
                                    if(dl_req->priority < TC_BUFFER_APP_QUEUE_PRIORITY_MAX)
                                    {
                                        /**      - Iterate all the priorities and send based on high priority */
                                        for(pri_idx = 0; pri_idx < TC_BUFFER_APP_QUEUE_PRIORITY_MAX; pri_idx++)
                                        {
                                            /**     - Iterate all the queues in a submodule */
                                            for(i = 0; i < buff_fw_apps[mod_id].num_of_queue;i++)
                                            {
                                                /**       - Check wether priority of Q is less than or equal to requested
                                                 *          priority and send based on higher priority */
                                                if(buff_fw_apps[mod_id].buffer_info[i].priority <= dl_req->priority &&\
                                                        buff_fw_apps[mod_id].buffer_info[i].priority == pri_idx)
                                                {
                                                    /**      - Check if queue is active*/
                                                    if(TC_TM_BUFFER_SUCC == tc_check_queue_sts(buff_fw_apps[mod_id].\
                                                                buffer_info[i].queue_id, &buff_fw_apps[mod_id].queue_bitmap))
                                                    {
                                                        /**      - Deque all the contents in this queue and pack it as TM and send */
                                                        sts = tc_buffer_dequeue_and_send_tm(buff_fw_apps[mod_id].\
                                                                queue[buff_fw_apps[mod_id].buffer_info[i].queue_id], \
                                                                app_id, i, tc_recv_msg->pld.pld_data);
                                                    }

                                                }
                                            }
                                        }

                                        /**     - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_DL_BUFFER_RSP, \
                                                sts, tc_recv_msg->src_entity);
                                    }
                                    else
                                    {
                                        DEBUG_CPRINT(("Not valid queue priority, send error response"));
                                        log_id(LOG_ERROR,LOG_HM,Not_valid_queue_priority_send_error_response);

                                        /**     - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_DL_BUFFER_RSP, \
                                                TC_TM_BUFFER_INVLD_PRIORITY, tc_recv_msg->src_entity);
                                    }
                                }
                            }
                            else
                            {
                                DEBUG_CPRINT(("Invalid submodule %d->%d\n",dl_req->submod_id, mod_id));
                                log_id_with_two_arg(LOG_ERROR,LOG_HM,Invalid_submodule__u8___u8_,dl_req->submod_id, mod_id);

                                /**    - Invalid submodules, check the priority */
                                if(dl_req->priority < TC_TM_BUFFER_APP_MAX)
                                {
                                    /**      - Iterate all the priorities and send based on high priority */
                                    for(pri_idx = 0; pri_idx < TC_BUFFER_APP_QUEUE_PRIORITY_MAX; pri_idx++)
                                    {
                                        /**     - Iterate all sub module priority */
                                        for(mod_pri =0; mod_pri < TC_TM_BUFFER_APP_MAX; mod_pri++)
                                        {
                                            /**     - Iterate all sub modules */
                                            for(app_idx =0; app_idx < TC_TM_BUFFER_APP_MAX; app_idx++)
                                            {
                                                /**      - Check if module priority based on high priority*/
                                                if(buff_fw_apps[app_idx].sub_mod_priority == mod_pri)
                                                {
                                                    /**       - Iterate all the queues in a submodule */
                                                    for(i = 0; i < buff_fw_apps[app_idx].num_of_queue;i++)
                                                    {

                                                        /**       - Check wether priority of Q is less than or equal to requested
                                                         *          priority and send based on higher priority */
                                                        if((buff_fw_apps[app_idx].buffer_info[i].priority <= dl_req->priority) && \
                                                                (buff_fw_apps[app_idx].buffer_info[i].priority == pri_idx)) 

                                                        {
                                                            /**      - Check if queue is active*/
                                                            if(TC_TM_BUFFER_SUCC == tc_check_queue_sts(buff_fw_apps[app_idx].\
                                                                buffer_info[i].queue_id, &buff_fw_apps[app_idx].queue_bitmap))
                                                            {
                                                                /**        - Deque all the contents in this queue and pack it as TM and send */
                                                                tc_buffer_dequeue_and_send_tm(buff_fw_apps[app_idx].\
                                                                        queue[buff_fw_apps[app_idx].buffer_info[i].queue_id], \
                                                                        app_idx, i, tc_recv_msg->pld.pld_data);
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    /**     - Send response to the source layer */
                                    /** TBD: Always considred succ, this has to be handled 
                                     *  TBD: We are sending to OBC main task since there is no valid submod in this case */
                                    tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_DL_BUFFER_RSP, \
                                            TC_TM_BUFFER_SUCC, OBC_MAIN);
                                }
                                else
                                {
                                    /**   - No valid priority found */
                                    DEBUG_CPRINT(("Not valid queue priority, send error response"));
                                    log_id(LOG_ERROR,LOG_HM,Not_valid_queue_priority_send_error_response);

                                    /**     - Send response to the source layer */
                                    tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_DL_BUFFER_RSP, \
                                            TC_TM_BUFFER_INVLD_PRIORITY, tc_recv_msg->src_entity);
                                }
                            }
                        }
                        break;

                    case OBC_TC_TM_FLUSH_QUEUE_REQ:
                        {
                            /** Control variable for debugging - Increments on receiving flush request */
                            exo_sw_dbg.hm_dbg.flush_req++;

                            DEBUG_CPRINT(("FLUSH REQ RECEIVED\n"));
                            log_id(LOG_INFO_L3,LOG_HM,FLUSH_REQ_RECEIVED);
 
                            /**    - Getting TC_TM Flush queue request */
                            s_tc_tm_flush_q_req *flush_req = (s_tc_tm_flush_q_req*)tc_recv_msg->pld.pld_ptr;

                            /**    - Valid submodule found, get the app_id */
                            mod_id = tc_get_app_id_from_src_entity(flush_req->submod_id);

                            /**    - Check valid submodule found */
                            if(flush_req->submod_id != TC_INVLD_SUB_MODULE && TC_TM_BUFFER_APP_MAX > mod_id)
                            {
                                DEBUG_CPRINT(("valid Submodule id %d\n", flush_req->submod_id));
                                log_id_with_one_arg(LOG_INFO_L2,LOG_HM,Valid_Submodule_ID__u8_,flush_req->submod_id);

                                /**    - check for valid queue */
                                if(flush_req->queue_id != TC_INVLD_SUB_MODULE && TC_BUFF_MAX_QUEUE > flush_req->queue_id)
                                {
                                    DEBUG_CPRINT(("valid queue id %d\n", flush_req->queue_id));
                                    log_id_with_one_arg(LOG_INFO_L2,LOG_HM,Valid_queue_id__u8_,flush_req->queue_id);

                                    /**     - Check if queue is active*/
                                    if(TC_TM_BUFFER_SUCC == tc_check_queue_sts(flush_req->queue_id, &buff_fw_apps[mod_id].queue_bitmap))
                                    {
                                        DEBUG_CPRINT(("queue %d is active \n", flush_req->queue_id));
                                        log_id_with_one_arg(LOG_INFO_L2,LOG_HM,Queue__u8__is_active,flush_req->queue_id);

                                        /**    - Specific modules, specific queue has to be flushed */
                                        if(ral_success != os_queue_flush(buff_fw_apps[mod_id].\
                                                    queue[flush_req->queue_id]))
                                        {
                                            /**     - Send response to the source layer */
                                            tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_FLUSH_QUEUE_RSP, \
                                                    TC_TM_BUFFER_FAIL, tc_recv_msg->src_entity);
                                        }
                                        else
                                        {
                                            /**     - Send response to the source layer */
                                            tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_FLUSH_QUEUE_RSP, \
                                                    TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);
                                        }
                                    }
                                    else
                                    {
                                        DEBUG_CPRINT(("queue %d is not active bitmap %d \n", flush_req->queue_id, \
                                                        buff_fw_apps[mod_id].queue_bitmap));

                                        log_id_with_two_arg(LOG_ERROR,LOG_HM,Queue__u8__is_not_active_bitmap__u32_,flush_req->queue_id,\
                                                buff_fw_apps[mod_id].queue_bitmap);

                                        /**     - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_FLUSH_QUEUE_RSP, \
                                                TC_TM_BUFFER_QUEUE_NOT_ACTIVE, tc_recv_msg->src_entity);
                                    }
                                }
                                else
                                {
                                    /**    - If the priority given is valid , priority based flushing */
                                    if(flush_req->priority < TC_BUFFER_APP_QUEUE_PRIORITY_MAX)
                                    {
                                        /**     - Iterate all the queues in a submodule */
                                        for(i = 0; i < buff_fw_apps[0].num_of_queue;i++)
                                        {
                                            /**      - priority of a queue in a submodule is less than or equal to flush priority */
                                            if(buff_fw_apps[mod_id].buffer_info[i].priority <= flush_req->priority)
                                            {
                                                /**     - Check if queue is active*/
                                                if(TC_TM_BUFFER_SUCC == tc_check_queue_sts(buff_fw_apps[mod_id].\
                                                            buffer_info[i].queue_id, &buff_fw_apps[mod_id].queue_bitmap))
                                                {
                                                    /**      - Flush the complete queue */
                                                    if(ral_success != os_queue_flush(buff_fw_apps[mod_id].\
                                                                queue[buff_fw_apps[mod_id].buffer_info[i].queue_id]))
                                                    {
                                                        DEBUG_CPRINT(("queue flush failed\n"));
                                                        log_id(LOG_ERROR,LOG_HM,QUEUE_FLUSH_FAILED);
                                                    }
                                                }
                                            }
                                        }
                                        /** TBD: Proper succ/resp has to be sent */
                                        /**     - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_FLUSH_QUEUE_RSP, \
                                                TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);
                                    }
                                    else
                                    {
                                    tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_FLUSH_QUEUE_RSP, \
                                    		TC_TM_BUFFER_INVLD_PRIORITY, tc_recv_msg->src_entity);
                                    }
                                }
                            }
                            /**    - Special case, where all submodules queue flushed based on priority */
                            else
                            {
                                DEBUG_CPRINT(("Submodule id invalid %x\n", flush_req->submod_id));
                                log_id_with_one_arg(LOG_ERROR,LOG_HM,Submodule_id_invalid__u8_,flush_req->submod_id);

                                /**    - If the priority given is valid */
                                if(flush_req->priority < TC_BUFFER_APP_QUEUE_PRIORITY_MAX)
                                {
                                    /**    - Iterate all sub modules */
                                    for(app_idx =0; app_idx < TC_TM_BUFFER_APP_MAX; app_idx++)
                                    {
                                        /**     - Iterate all the queues in a submodule */
                                        for(i = 0; i < buff_fw_apps[app_idx].num_of_queue;i++)
                                        {
                                            /**      - priority of queue in submodule is less than or equal to flush priority */
                                            if(buff_fw_apps[app_idx].buffer_info[i].priority <= flush_req->priority)
                                            {
                                                /**      - Flush the complete queue */
                                                os_queue_flush(buff_fw_apps[app_idx].\
                                                        queue[buff_fw_apps[app_idx].buffer_info[i].queue_id]);
                                            }
                                        }
                                    }
                                    tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_FLUSH_QUEUE_RSP, \
                                            TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);
                                }
                                else
                                {
                                    tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_FLUSH_QUEUE_RSP, \
                                            TC_TM_BUFFER_INVLD_PRIORITY, tc_recv_msg->src_entity);
                                }
                            }
                        }
                        break;

                    case OBC_TC_TM_QUEUE_RESIZE_REQ:
                        {
                            /** TBD : */
                        }
                        break;
                    case OBC_TC_TM_DEL_QUEUE_REQ:
                        {
                            /** Control variable for debugging - Increments on receiving delete queue request */
                            exo_sw_dbg.hm_dbg.del_queue_req++;

                            /**     - Get the queue id */
                            uint8 queue_id = tc_recv_msg->pld.pld_data;

                            /**     - get the buffer index for corresponding queue id */
                            buff_idx = tc_get_buff_idx(queue_id, app_id);

                            /**     - Check queue is valid */
                            if((TC_BUFF_MAX_QUEUE > queue_id)) 
                            {
                                /**     - Check if queue is active*/
                                if(TC_TM_BUFFER_SUCC == tc_check_queue_sts(queue_id, &buff_fw_apps[app_id].queue_bitmap))
                                {
                                    DEBUG_CPRINT((" QUEUE ID %d is active que ctx %x \n",queue_id, (uint32)(long)buff_fw_apps[app_id].queue[queue_id]));
                                    log_id_with_two_arg(LOG_INFO_L1,LOG_HM,Queue_ID__u8__is_active_que_ctx__u32_,\
                                            queue_id, (uint32)(long)buff_fw_apps[app_id].queue[queue_id]);

                                    if(ral_success == os_queue_delete(buff_fw_apps[app_id].queue[queue_id]))
                                    {
                                    	DEBUG_CPRINT((" QUEUE ID %d deleted \n",queue_id));
                                        log_id_with_one_arg(LOG_ERROR,LOG_HM,Queue_ID__u8__deleted,queue_id);

                                        /** clear the bit map of queue id received */
                                        /*Delete queue has to be requested in reverse order as of now*/
                                        /* TBD - change has to be done in Delete queue of HM layer*/

                                        tc_clear_queue_bitmap(queue_id, \
                                                &buff_fw_apps[app_id].queue_bitmap);

                                        buff_fw_apps[app_id].num_of_queue--;

                                        os_memset(&buff_fw_apps[app_id].buffer_info[buff_idx],0,sizeof(s_tc_tm_buffer_req));

                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_DEL_QUEUE_RSP, \
                                                            TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);
                                    }
                                    else
                                    {
                                    	DEBUG_CPRINT(("QUEUE ID %d is not deleted \n",queue_id));
                                        log_id_with_one_arg(LOG_ERROR,LOG_HM,Queue_ID__u8__is_not_deleted,queue_id);
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_DEL_QUEUE_RSP, \
                                                TC_TM_BUFFER_DELETE_QUEUE_FAIL, tc_recv_msg->src_entity);
                                    }
                                }
                                else
                                {
                                	DEBUG_CPRINT((" QUEUE ID %d is not active \n",queue_id));
                                        log_id_with_one_arg(LOG_ERROR,LOG_HM,Queue_ID__u8__is_not_active,queue_id);
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_DEL_QUEUE_RSP, \
                                            TC_TM_BUFFER_DELETE_QUEUE_FAIL, tc_recv_msg->src_entity);
                                }
                            }
                        }
                        break;
                    case OBC_TC_TM_CHNG_QUEUE_PRIORITY_REQ:
                        {
                            /** Control variable for debugging - Increments on receiving change queue pri request */
                            exo_sw_dbg.hm_dbg.queue_pri_chnge_req++;

                            DEBUG_CPRINT(("OBC_TC_TM_CHNG_QUEUE_PRIORITY_REQ request \n"));
                            log_id(LOG_INFO_L2,LOG_HM,OBC_TC_TM_CHNG_QUEUE_PRIORITY_REQ_request);

                            /**    - Getting TC_TM priority change request */
                            s_tc_tm_chng_q_priority *pri_req = (s_tc_tm_chng_q_priority*)tc_recv_msg->pld.pld_ptr;

                            /**    - Valid submodule found, get the app_id */
                            mod_id = tc_get_app_id_from_src_entity(pri_req->submod_id);

                            /**    - Check valid submodule found */
                            if(pri_req->submod_id != TC_INVLD_SUB_MODULE && TC_TM_BUFFER_APP_MAX > mod_id)
                            {
                                /**    - check for valid queue */
                                if(pri_req->queue_id != TC_INVLD_SUB_MODULE && TC_BUFF_MAX_QUEUE > pri_req->queue_id)
                                {
                                    DEBUG_CPRINT(("valid queue id %d \n", pri_req->queue_id));
                                    log_id_with_one_arg(LOG_INFO_L3,LOG_HM,Valid_queue_id__u8_,pri_req->queue_id);
                                        /**     - Check if queue is active*/
                                        if(TC_TM_BUFFER_SUCC == tc_check_queue_sts(pri_req->queue_id, \
                                                    &buff_fw_apps[mod_id].queue_bitmap))
                                        {
                                            /**     - get the buffer index for corresponding queue id */
                                            buff_idx = tc_get_buff_idx(pri_req->queue_id, mod_id);

                                            DEBUG_CPRINT(("Submod %d QUEUE %d priority changed from %d ", \
                                                        mod_id, pri_req->queue_id, buff_fw_apps[mod_id].buffer_info[buff_idx].priority));
                                            log_id_with_three_arg(LOG_INFO_L2,LOG_HM,Submod__u8__Queue__u8__Priority_changed_from__u8_,mod_id, pri_req->queue_id, buff_fw_apps[mod_id].buffer_info[buff_idx].priority);

                                            /**     - change the priority of the queue */
                                            buff_fw_apps[mod_id].buffer_info[buff_idx].priority = pri_req->priority;

                                            DEBUG_CPRINT(("To %d\n", buff_fw_apps[mod_id].buffer_info[buff_idx].priority));
                                            log_id_with_one_arg(LOG_INFO_L2,LOG_HM,To__u8_,\
                                                    buff_fw_apps[mod_id].buffer_info[buff_idx].priority);

                                        /**      - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_CHNG_QUEUE_PRIORITY_RSP, \
                                                TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);
                                    }
                                    else
                                    {
                                        DEBUG_CPRINT(("Queue:%d not active on OBC_TC_TM_CHNG_QUEUE_PRIORITY_REQ\n",\
                                                    pri_req->queue_id));
                                        log_id_with_one_arg(LOG_ERROR,LOG_HM,Queue__u8__not_active_on_OBC_TC_TM_CHNG_QUEUE_PRIORITY_REQ,\
                                                pri_req->queue_id);


                                        /**      - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_CHNG_QUEUE_PRIORITY_RSP, \
                                                TC_TM_BUFFER_QUEUE_NOT_ACTIVE, tc_recv_msg->src_entity);
                                    }
                                }
                            
                             else
                                {
                                    DEBUG_CPRINT(("Not valid queue id, check priority"));
                                    log_id(LOG_ERROR,LOG_HM,Not_valid_queue_id_check_priority);

                                    /**    - Invalid submodules, check the priority */
                                    if(pri_req->priority < TC_BUFFER_APP_QUEUE_PRIORITY_MAX)
                                    {
                                            /**     - Iterate all the queues in a submodule */
                                            for(i = 0; i < buff_fw_apps[mod_id].num_of_queue;i++)
                                            {
                                                /**      - priority of a queue in a submodule is less than or equal to flush priority */
                                                if(buff_fw_apps[mod_id].buffer_info[i].priority == pri_req->cur_priority)
                                                {
                                                    /**      - Check if queue is active*/
                                                    if(TC_TM_BUFFER_SUCC == tc_check_queue_sts(buff_fw_apps[mod_id].\
                                                                buffer_info[i].queue_id, &buff_fw_apps[mod_id].queue_bitmap))
                                                    {
                                                        DEBUG_CPRINT(("submod %d QUEUE %d priority changed from %d ", \
                                                                    mod_id, i, buff_fw_apps[mod_id].buffer_info[i].priority));
                                                        log_id_with_three_arg(LOG_INFO_L1,LOG_HM,Submod__u8__Queue__u8__Priority_changed_from__u8_,mod_id, i, buff_fw_apps[mod_id].buffer_info[i].priority);
                                                        /**     - change the priority of the queue */
                                                        buff_fw_apps[mod_id].buffer_info[i].priority = pri_req->priority;

                                                        DEBUG_CPRINT(("To %d\n", buff_fw_apps[mod_id].buffer_info[i].priority));
                                                        log_id_with_one_arg(LOG_INFO_L1,LOG_HM,To__u8_,\
                                                                buff_fw_apps[mod_id].buffer_info[i].priority);
                                                    }

                                                }
                                            }
                                        /**     - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_CHNG_QUEUE_PRIORITY_RSP, \
                                                TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);
                                    }
                                    else
                                    {
                                        DEBUG_CPRINT(("Not valid queue priority, send error response"));
                                        log_id(LOG_ERROR,LOG_HM,Not_valid_queue_priority_send_error_response);

                                        /**     - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_CHNG_QUEUE_PRIORITY_RSP, \
                                                TC_TM_BUFFER_INVLD_PRIORITY, tc_recv_msg->src_entity);
                                    }
                                }
                            }    
                            else
                            {
                                DEBUG_CPRINT(("WARNING: No submodule invalid %x\n", pri_req->submod_id));
                                log_id_with_one_arg(LOG_ERROR,LOG_HM,No_submodule_invalid__u8_,pri_req->submod_id);

                                /**   - Iterate all the submodules */
                                for(app_idx = 0; app_idx < TC_TM_BUFFER_APP_MAX ;app_idx++)
                                {
                                    /**    - Priority based priority change on all submodules */
                                    for(i = 0; i < buff_fw_apps[app_idx].num_of_queue;i++)
                                    {
                                        /**      - priority of a queue in a submodule is less than or equal to flush priority */
                                        if(buff_fw_apps[app_idx].buffer_info[i].priority == pri_req->cur_priority)
                                        {
                                            /**     - Check if queue is active*/
                                            if(TC_TM_BUFFER_SUCC == tc_check_queue_sts(buff_fw_apps[app_idx].\
                                                        buffer_info[i].queue_id, &buff_fw_apps[app_idx].queue_bitmap))
                                            {
                                                DEBUG_CPRINT(("submod %d QUEUE %d priority changed from %d ", \
                                                            app_idx, i, buff_fw_apps[app_idx].buffer_info[i].priority));
                                                log_id_with_three_arg(LOG_INFO_L2,LOG_HM,Submod__u8__Queue__u8__Priority_changed_from__u8_,app_idx, i, buff_fw_apps[app_idx].buffer_info[i].priority);
                                                /**     - change the priority of the queue */
                                                buff_fw_apps[app_idx].buffer_info[i].priority = pri_req->priority;

                                                DEBUG_CPRINT(("To %d\n",buff_fw_apps[app_idx].buffer_info[i].priority));
                                                log_id_with_one_arg(LOG_INFO_L2,LOG_HM,To__u8_,buff_fw_apps[app_idx].buffer_info[i].priority);

                                            }
                                        }
                                    }
                                }
                                /**      - Send response to the source layer */
                                tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_CHNG_QUEUE_PRIORITY_RSP, \
                                        TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);
                            }
                        }
                        break;

                    case OBC_TC_TM_CHNG_SUB_MOD_PRIORITY_REQ:
                        {
                            /** Control variable for debugging - Increments on receiving change mod pri request */
                            exo_sw_dbg.hm_dbg.mod_pri_chnge_req++;

                            DEBUG_CPRINT(("OBC_TC_TM_CHNG_MODULE_PRIORITY_REQ request \n"));
                            log_id(LOG_INFO_L3,LOG_HM,OBC_TC_TM_CHNG_MODULE_PRIORITY_REQ_request);

                            /**    - Getting TC_TM priority change request */
                            s_tc_tm_chng_mod_priority *pri_req = (s_tc_tm_chng_mod_priority*)tc_recv_msg->pld.pld_ptr;

                            /**    - Valid submodule found, get the app_id */
                            mod_id = tc_get_app_id_from_src_entity(pri_req->submod_id);

                            /**    - Check valid submodule found */
                            if(pri_req->submod_id != TC_INVLD_SUB_MODULE && TC_TM_BUFFER_APP_MAX > mod_id)
                            {
                                /**    - If the priority given is valid , priority based priority change */
                                if(pri_req->priority < TC_TM_BUFFER_APP_MAX)
                                {

                                        DEBUG_CPRINT(("Submod %d\n Current priority %d\n Priority to be changed %d\n ", \
                                                    pri_req->submod_id, pri_req->cur_priority,pri_req->priority));

                                        log_id_with_three_arg(LOG_INFO_L2,LOG_HM,Submod__u8__Current_priority__u8__Priority_to_be_changed__u8_,pri_req->submod_id, pri_req->cur_priority,pri_req->priority);

                                        /*TBD - Check the priority to be changed with all submodules
                                         * if it is already existing, how to handle it*/

                                        /**     - change the priority of the queue */
                                        buff_fw_apps[mod_id].sub_mod_priority = pri_req->priority;

                                        DEBUG_CPRINT(("Priority Changed to  %d\n", buff_fw_apps[mod_id].sub_mod_priority));
                                        log_id_with_one_arg(LOG_INFO_L2,LOG_HM,Priority_Changed_to__u8_,\
                                                buff_fw_apps[mod_id].sub_mod_priority);

                                        /**      - Send response to the source layer */
                                        tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_CHNG_SUB_MOD_PRIORITY_RSP, \
                                                TC_TM_BUFFER_SUCC, tc_recv_msg->src_entity);
                                }    
                                else
                                {
                                    DEBUG_CPRINT(("ERROR: Priority is not valid\n"));
                                    log_id(LOG_ERROR,LOG_HM,Priority_is_not_valid);
                                    /**      - Send response to the source layer */
                                    tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_CHNG_SUB_MOD_PRIORITY_RSP, \
                                            TC_TM_BUFFER_INVLD_PRIORITY, tc_recv_msg->src_entity);
                                }
                            }
                            else
                            {
                                DEBUG_CPRINT(("ERROR Submodule invalid %x\n", pri_req->submod_id));
                                log_id_with_one_arg(LOG_ERROR,LOG_HM,Submodule_invalid__u8_,pri_req->submod_id);

                                /**      - Send response to the source layer */
                                tc_buffer_send_itc_wo_pld(HM_MANAGER_IPC_RECEIVE, OBC_TC_TM_CHNG_SUB_MOD_PRIORITY_RSP, \
                                        TC_TM_BUFFER_INVLD_MODULE, tc_recv_msg->src_entity);
                            }
                        }
                        break;


                    default:
                        {
                            sts = -1;
                        }
                        break;
                }
            }
            break;
    }
    return sts;
    
}
/**
 * @brief This API used to get the fw app id mapping  
 * of corresponding layer
 */
uint8 tc_get_app_id_from_src_entity(uint8 src_entity)
{
    /** Initialize it to maximum task */
    uint8 app_id = TC_TM_BUFFER_APP_MAX;
    switch(src_entity)
    {
        case ADCS_CONTROLLER:
            {
                app_id = TC_TM_BUFFER_APP_ADCS;
            }
            break;
        case EPS_TASK:
            {
                app_id = TC_TM_BUFFER_APP_EPS;
            }
            break;
        case COMMS_SBAND_CTLR:
            {
                app_id = TC_TM_BUFFER_APP_COMMSS_SBAND;
            }
            break;
        case COMMS_UHF_CTLR:
            {
                app_id = TC_TM_BUFFER_APP_COMMSS_UHF;
            }
            break;
        case COMMS_SBAND_IQ:
            {
            }
            break;
        case COMMS_SBAND_TX:
            {
            }
            break;
        case COMMS_XBAND_CTLR:
            {
            }
            break;
        case OBC_SENSOR_HDLR:
            {
                app_id = TC_TM_BUFFER_APP_SENSOR;
            }
            break;
        case OBC_MAIN:
            {
                app_id = TC_TM_BUFFER_APP_OBC;
            }
            break;
        case ERR_HANDLER:
            {
                app_id = TC_TM_BUFFER_APP_ERROR_HANDLER;
            }
            break;

#if defined(TEST_LAYER)
        case TEST_TASK:
            {
                app_id =TC_TM_BUFFER_TEST_TASK;
            }
            break;
#endif
        default:
            {
            }
            break;
    }
    return app_id;
}

/**
 * @brief This API used to set the queue bit map  
 * 
 */
void tc_set_queue_bitmap(uint8 queue_id, uint32 *bit_map)
{
    *bit_map |= (1 << queue_id);
}


/**
 * @brief This API used to clear the queue bit map
 *
 */
void tc_clear_queue_bitmap(uint8 queue_id, uint32 *bit_map)
{
    *bit_map &= ~(1 << queue_id);
}


/**
 * @brief This API used to check queue is active or not
 * 
 */
uint8 tc_check_queue_sts(uint8 queue_id, uint32 *bit_map)
{
    uint8 sts = TC_TM_BUFFER_SUCC; 
    if(*bit_map & (1 << queue_id))
    {
        sts = TC_TM_BUFFER_SUCC;
    }
    else
    {
        sts = TC_TM_BUFFER_QUEUE_NOT_ACTIVE;
    }
    return sts;
}
/**
 * @brief This API used to get the buffer index based on queue id
 * 
 */
uint8 tc_get_buff_idx(uint8 queue_id, uint8 app_id)
{
    int i;
    uint8 buff_idx = TC_INVLD_SUB_MODULE;
    for(i = 0; i < buff_fw_apps[app_id].num_of_queue; i++)
    {
        if(buff_fw_apps[app_id].buffer_info[i].queue_id == queue_id)
        {
            buff_idx = i;
            break;
        }
    }
    return buff_idx;
}

/**
 * @brief This API used to dequeue all data from a queue and put it in a TM and send
 * 
 */
uint8 tc_buffer_dequeue_and_send_tm(os_queue_handle_ptr queue_id, uint8 app_id, uint8 buff_idx, uint8 radio_id)
{
    DEBUG_CPRINT(("APP_ID:%d buff_idx: %d \n", app_id, buff_idx));
    if(!radio_mod[radio_id].gs_contact_valid())
    {
        DEBUG_CPRINT(("Ground contact not valid for radio %d\n", radio_id));
        log_id_with_one_arg(LOG_INFO_L1,LOG_HM,Ground_contact_not_valid_for_radio__u8_,radio_id);
        return TC_TM_BUFFER_RADIO_NOT_ACTIVE;
    }

    /** variable to store the buffer success */
    uint8 sts = TC_TM_BUFFER_SUCC;

    /** total lenght of single queue */
    uint32 data_len = 0;

    /** Varibale to hold the buffer to be sent on TM */
    uint8 *data_ptr = NULL;

    /** Data index for copying */
    uint32 data_idx = 0;

    /** Get the remaining space available in the queue */
    uint32 rem_space = os_queue_get_remain_count(queue_id);
    
    /** Check if we have any item in queue */
    if(rem_space >= 0)
    {
        DEBUG_CPRINT(("Remaining space in queue %d \n", rem_space));
        log_id_with_one_arg(LOG_INFO_L1,LOG_HM,Remaining_space_in_queue__u32_,rem_space);
        DEBUG_CPRINT(("Buff idx %d \n", buff_idx));
        log_id_with_one_arg(LOG_INFO_L1,LOG_HM,Buff_idx__u8_,buff_idx);

        DEBUG_CPRINT(("Num instance %d and size %d\n", buff_fw_apps[app_id].buffer_info[buff_idx].num_instance, \
                    buff_fw_apps[app_id].buffer_info[buff_idx].instance_size));
        log_id_with_two_arg(LOG_INFO_L1,LOG_HM,Num_of_instance__u16__Instance_size__u32_,buff_fw_apps[app_id].buffer_info[buff_idx].num_instance, buff_fw_apps[app_id].buffer_info[buff_idx].instance_size);

        data_len = (buff_fw_apps[app_id].buffer_info[buff_idx].num_instance - rem_space) * \
                    buff_fw_apps[app_id].buffer_info[buff_idx].instance_size;
        
        DEBUG_CPRINT(("Actual number of bytes to be packed in TM %d \n", data_len));
        log_id_with_one_arg(LOG_INFO_L1,LOG_HM,Actual_number_of_bytes_to_be_packed_in_TM__u32_,data_len);

        /** - we have data in the queue */
        if(data_len)
        {
            /**  - Allocate memory to hold the data from the queue */
            data_ptr = os_malloc_eram(data_len + TM_HEADER_OVERHEAD);

            /**  - Memory allocation success */
            if(data_ptr)
            {
                /**   - Memset the allocated memory */
                os_memset(data_ptr, 0, data_len);

                /**   - Reset the index back to 0 */
                data_idx = 0;

                /**   - Dequeue the queue until empty */
                /** TBD: if GS contact loss, what will happen to existing buffer */
                while(os_queue_get_remain_count(queue_id) >= 0)
                {
                    /**    - Dequeue an instance */
                    /** 4 bytes + 2bytes : seq,0x70,radio_id, submod id, queue id, number of instance */
                    if(ral_success == os_queue_receive(queue_id, &data_ptr[data_idx + 8],0))
                    {
                        /**     - Move the index to fill up next instance */
                        data_idx += buff_fw_apps[app_id].buffer_info[buff_idx].instance_size;
                    }
                    else
                    {
                        DEBUG_CPRINT((" Dequeue failed \n"));
                        log_id(LOG_ERROR,LOG_HM,Dequeue_failed);
                        sts = TC_TM_BUFFER_DEQUEUE_FAIL;
                        break;
                    }
                }
                if(sts != TC_TM_BUFFER_DEQUEUE_FAIL || data_idx > 0)
                {
                    /**    - Send the TM */
                    /**    - Check radio activeness before sending */
                    sts = tc_send_queue_as_tm(data_ptr, data_idx, radio_id, app_id, \
                            buff_fw_apps[app_id].buffer_info[buff_idx].queue_id, \
                            (data_idx/buff_fw_apps[app_id].buffer_info[buff_idx].instance_size));
                }
                else
                {
                    /**   - Dequeue failed , send the data in array if available */
                }
            }
            /**  - Memory allocation failed */
            else
            {
                DEBUG_CPRINT((" Q was full, but dequeue failed \n"));
                log_id(LOG_ERROR,LOG_HM,Q_was_full_but_dequeue_failed);
                sts = TC_TM_BUFFER_MEM_FAIL;
            }
        }
        else
        {
            DEBUG_CPRINT(("QUEUE empty\n"));
            log_id(LOG_ERROR,LOG_HM,Queue_empty);

            /**  - Allocate memory to hold the data from the queue */
            /**  - 7Bytes is just to hold TM header and payload data like submod_id,queue_id and num of instance */
            data_ptr = os_malloc(8);

            /**  - Memory allocation successfull */
            if(data_ptr)
            {
                sts = tc_send_queue_as_tm(data_ptr,0, radio_id, app_id, \
                        buff_fw_apps[app_id].buffer_info[buff_idx].queue_id, 0);
            }
            else
            {
                DEBUG_CPRINT((" Q was full, but dequeue failed \n"));
                log_id(LOG_ERROR,LOG_HM,Q_was_full_but_dequeue_failed);
                sts = TC_TM_BUFFER_MEM_FAIL;
            }
        }
    }
    else
    {
        /** Error returned from RTOS */
        sts = TC_TM_BUFFER_QUEUE_ERROR;

        DEBUG_CPRINT(("unable to get remaining space\n"));
        log_id(LOG_ERROR,LOG_HM,Unable_to_get_remaining_space);
    }

    return sts;
}

/**
 * @brief This API used to dequeue all data from a queue and put it in a TM and send
 * 
 */
uint8 tc_send_queue_as_tm(uint8 *data_ptr, uint32 data_len, uint8 radio_id, uint8 submod_id, uint8 queue_id, uint16 num_instance)
{
    DEBUG_CPRINT(("tc_send_queue_as_tm entry \n"));
    log_id(LOG_INFO_L1,LOG_HM,tc_send_queue_as_tm_entry);
    DEBUG_CPRINT(("DATA LEN %d\n",data_len));
    log_id_with_one_arg(LOG_INFO_L1,LOG_HM,DATA_LEN__u32_,data_len);

    /** variable to store the buffer success */
    uint8 sts = TC_TM_BUFFER_SUCC;

    /** This is used for TM packing */
    os_itc_msg_handle_t local_msg;

    /** This is used to send actual ITC to comms */
    os_itc_msg_handle_t tm_local_msg;

    /** Pointer to store the actual TM data */
    uint8 *tx_data;

    /** Variable to store the TM size */
    uint32 tm_size;
    
    /** Fill the data in message structure, since handle_tm_data support only this data type as args */
    local_msg.Msg_id = TM_GET_HEALTH_METRICS;

    /** 4Bytes added since we are packing the submod_id and queue id  and number of instance */
    local_msg.Msg_len = data_len + 4;
    local_msg.pld.pld_ptr = data_ptr;

    /** Seq number is reserved 0xFFFF */
    data_ptr[0] = 0xFF;
    data_ptr[1] = 0xFF;

    /** TM_CTRL */
    data_ptr[2] = 0x70;

    /** radio id */
    data_ptr[3] = radio_id;

    /** Append the submod_id and queue_id on top of payload */
    data_ptr[4] = submod_id;
    data_ptr[5] = queue_id;
    os_memcpy(&data_ptr[6],&num_instance,2);
  //data_ptr[6] = num_instance;
    
    /** Allocate memory for packed TM */
    tx_data = os_malloc_eram(data_len + TM_HEADER_OVERHEAD);

    /** Check for valid pointer */
    if(tx_data)
    {
        /** - Pack the TM header */
        tm_size = handle_tm_data(&local_msg,tx_data);

        /** - TM packaging success */
        if(tm_size > 0)
        {
            /**  - Send ITC to S-BAND */
            /**  - Need to check with nithilane , where to send */
            tm_local_msg.Msg_id = OBC_SBAND_DL_HEALTH_REQ;
            tm_local_msg.pld_info = radio_id; //need discussion
            tm_local_msg.src_entity = HM_MANAGER_IPC_RECEIVE;
            tm_local_msg.pld.pld_ptr = tx_data;
            tm_local_msg.Msg_len = tm_size;
            //os_itc_msg_send(&tm_local_msg, COMMS_TX,os_send_itc_wait);
            DEBUG_CPRINT(("IPC Sent for submod id %d and queue id %d\n", submod_id, queue_id));
            log_id_with_two_arg(LOG_INFO_L1,LOG_HM,IPC_sent_for_submod_id__u8__queue_id__u8_, submod_id, queue_id);

            //variable to count number of tm sent to comms
            exo_sw_dbg.hm_dbg.hm_tm_ipc_sent++;
            /*All module Health data receiving only if we give Itc wait time as 2secs*/
            os_itc_msg_send(&tm_local_msg, radio_mod[radio_id].thread_id, 2000);
            /** Delay for UHF is needed since flow control is not enabled 
             *  As per the UHF data rate 1 sec delay is required for
             *  every 250 Bytes, so N/250 = delay, where N is Byte size 
             */
            /** TBD: This has to be removed after flow control enable */
            if(COMMS_UHF == radio_id)
            {
                os_delay(((tm_size/250) ? ((tm_size/250)*1000) : 1000));
            }
#ifdef LINUX_TEMP_PORT
            /** Note: Even with this delay, TM getting lost in GS , 1sec is too much which is
             * blocking linux validation so reducing it to 200 
             */
            os_delay(200);
#endif
        }
        else
        {
            DEBUG_CPRINT(("TM Packing failed \n"));
            log_id(LOG_ERROR,LOG_HM,TM_Packing_failed);
            sts = TC_TM_BUFFER_TM_PACK_FAILED;
            if(tx_data)
            {
                os_free(tx_data);
                tx_data = NULL;
            }
        }
    }
    else
    {
        /** Memory failed */
        DEBUG_CPRINT(("TM memory allocation failed \n"));
        log_id(LOG_ERROR,LOG_HM,TM_memory_allocation_failed);
        sts = TC_TM_BUFFER_MEM_FAIL;
    }
    
    /** Free the data pointer allocated for single queue */
    if(data_ptr)
    {
        os_free(data_ptr);
    }
    return sts;
}

/**
 * @brief This API used to dequeue all data from a queue and put it in a TM and send
 * 
 */
void tc_buffer_send_itc_wo_pld(uint8 src_entity, uint16 Msg_id, uint32 pld_data, uint32 dst_id)
{
    /*Control variable - Increments on every response IPC sent*/
    exo_sw_dbg.hm_dbg.no_rsp_ipc_sent++;
  //  DEBUG_CPRINT(("HM_MANAGER: Sending message to %d  \n",src_entity));
    log_id_with_one_arg(LOG_INFO_L1,LOG_HM,sending_message_to__u8_,src_entity);
    os_itc_msg_handle_t rsp_ipc_msg;
    /** This is one dependency since, OBC MAIN considering pld_info as msg_id for this 
     * TC_TM_IPC_RECEIVE TASK and has to be discussed */
    if(OBC_MAIN == dst_id)
    {
        rsp_ipc_msg.pld_info = Msg_id;
    }
    rsp_ipc_msg.src_entity = src_entity;
    rsp_ipc_msg.Msg_id = Msg_id;
    rsp_ipc_msg.pld.pld_ptr = NULL;
    rsp_ipc_msg.pld.pld_data = pld_data;
    os_itc_msg_send(&rsp_ipc_msg, dst_id, os_send_itc_wait);
}

/**
 * @brief This API used to init variables related to buffering FW 
 * 
 */
void tc_buff_fw_init(void)
{
    /** Variable to iterate the submodules */
    uint8 app_idx;

    /** Itearte submods and memset it to 0 */
    for(app_idx = 0; app_idx < TC_TM_BUFFER_APP_MAX; app_idx++)
    {
        os_memset((void*)&buff_fw_apps[app_idx], 0, sizeof(s_tc_tm_buff_app));
    }
}
