/*
 * WiMOD_SAP_RadioLink_ProLink.cpp
 *
 *  Created on: Jan 4, 2022
 *      Author: tux
 */

//------------------------------------------------------------------------------
//! @file WiMOD_SAP_RadioLink_ProLink.cpp
//! @ingroup WiMOD_SAP_RadioLink_PROLINK
//! <!------------------------------------------------------------------------->
//! @brief Implementation of the commands of the RadioLink SericeAccessPoint for LoRaWAN ProLink firmware
//! @version 0.1
//! <!------------------------------------------------------------------------->
//!
//!
//!
//! <!--------------------------------------------------------------------------
//! Copyright (c) 2022
//! IMST GmbH
//! Carl-Friedrich Gauss Str. 2-4
//! 47475 Kamp-Lintfort
//! --------------------------------------------------------------------------->
//! @author (FB), IMST
//! <!--------------------------------------------------------------------------
//! Target OS:    none
//! Target CPU:   tbd
//! Compiler:     tbd
//! --------------------------------------------------------------------------->
//! @internal
//! @par Revision History:
//! <PRE>
//!-----------------------------------------------------------------------------
//! Version | Date       | Author | Comment
//!-----------------------------------------------------------------------------
//!
//! </PRE>
//------------------------------------------------------------------------------


/*
 * THIS IS AN EXAMPLE IMPLEMENTATION ACCORDING THE THE HCI SPEC: V1.3
 * FOR FIRMWARE: LoRaWAN PROLINK
 *
 * SEE FILE: ProLink_LoRaWAN_EndNode_Modem_HCI_Spec_v1_3.pdf for detailed information
 */


//------------------------------------------------------------------------------
//
// Section Includes Files
//
//------------------------------------------------------------------------------

#include "WiMOD_SAP_RadioLink_ProLink.h"
#include <string.h>

//------------------------------------------------------------------------------
//
// Section public functions
//
//------------------------------------------------------------------------------

//-----------------------------------------------------------------------------
/**
 * @brief Constructor
 *
 * @param hci       Pointer to HCI processor object
 *
 * @param buffer    pointer to storage area for building tx frames; MUST BE VALID
 *
 * @param bufferSize    size of the buffer
 *
 */
WiMOD_SAP_RadioLink_ProLink::WiMOD_SAP_RadioLink_ProLink(TWiMODLRHCI* hci, UINT8* buffer, UINT16 bufferSize) :
    WiMOD_SAP_RadioLink(hci, buffer, bufferSize)
{
}

//-----------------------------------------------------------------------------
/**
 * @brief Destructor
 *
 */
WiMOD_SAP_RadioLink_ProLink::~WiMOD_SAP_RadioLink_ProLink(void)
{

}

TWiMODLRResultCodes WiMOD_SAP_RadioLink_ProLink::SendCData(const TWiMODLR_RadioLink_Msg* txMsg,
        UINT8* statusRsp)
{
    (void) txMsg;
    // not supported in this firmware
    return unsupportedCmd(statusRsp);
}

bool WiMOD_SAP_RadioLink_ProLink::convert(TWiMODLR_HCIMessage& RxMsg,
        TWiMODLR_RadioLink_CdataInd* cDataTxInfo)
{
    (void) RxMsg;
    (void) cDataTxInfo;
    return false;
}

bool WiMOD_SAP_RadioLink_ProLink::convert(TWiMODLR_HCIMessage& RxMsg,
        TWiMODLR_AckTxInd_Msg* txAckIndInfo)
{
    (void) RxMsg;
    (void) txAckIndInfo;
    return false;
}

TWiMODLRResultCodes WiMOD_SAP_RadioLink_ProLink::SetAckData(const TWiMODLR_RadioLink_Msg* txMsg,
        UINT8* statusRsp)
{
    (void) txMsg;
    // not supported in this firmware
    return unsupportedCmd(statusRsp);
}


//-----------------------------------------------------------------------------
/**
 * @brief GetRadioConfig Cmd - Get the radio settings of the proprietary LR-BASE mode
 *
 *
 * @param   radioCfg    pointer to store the received information
 * @param   statusRsp   pointer to store status byte of response mesg from WiMOD
 *
 * @retval WiMODLR_RESULT_OK     if command transmit to WiMOD was ok
 */
TWiMODLRResultCodes WiMOD_SAP_RadioLink_ProLink::GetRadioConfig(TWiMODLR_ProLinkRadioLink_RadioConfig* radioCfg, UINT8* statusRsp)
{
    TWiMODLRResultCodes result = WiMODLR_RESULT_TRANMIT_ERROR;
    UINT8              offset = WiMODLR_HCI_RSP_STATUS_POS;

    if (radioCfg && statusRsp) {

        result = HciParser->SendHCIMessage(PROLINK_RADIOLINK_SAP_ID,
                                           PROLINK_RADIOLINK_MSG_GET_RADIO_CFG_REQ,
                                           PROLINK_RADIOLINK_MSG_GET_RADIO_CFG_RSP,
                                           NULL, 0);

        if (result == WiMODLR_RESULT_OK) {
            const TWiMODLR_HCIMessage& rx = HciParser->GetRxMessage();
            *statusRsp = rx.Payload[offset++];

            // status check
            if (*statusRsp == RADIOLINK_STATUS_OK) {
                    radioCfg->Status = *statusRsp;
                    radioCfg->RadioMode = (TRadioCfg_RadioModeProLink) rx.Payload[offset++];
                    radioCfg->GroupAddress = rx.Payload[offset++];
                    // reserved
                    offset++;
                    radioCfg->DeviceAddress = NTOH16(&rx.Payload[offset]);
                    offset += 0x02;
                    // reserved
                    offset += 0x02;
                    radioCfg->Modulation = (TRadioCfg_ModulationProLink) rx.Payload[offset++];
                    radioCfg->RfFreq_LSB = rx.Payload[offset++];
                    radioCfg->RfFreq_MID = rx.Payload[offset++];
                    radioCfg->RfFreq_MSB = rx.Payload[offset++];
                    radioCfg->LoRaBandWidth = (TRadioCfg_LoRaBandwidthProLink) rx.Payload[offset++];
                    radioCfg->LoRaSpreadingFactor = (TRadioCfg_LoRaSpreadingFactorProLink) rx.Payload[offset++];;
                    radioCfg->ErrorCoding = (TRadioCfg_ErrorCodingProLink) rx.Payload[offset++];;
                    radioCfg->PowerLevel =  (TRadioCfg_TxPowerLevelProLink)  rx.Payload[offset++];
                    // reserved
                    offset++;
                    radioCfg->RxControl = (TRadioCfg_RxControlProLink) rx.Payload[offset++];
                    radioCfg->RxWindowTime = NTOH16(&rx.Payload[offset]);
                    offset += 0x02;
                    // reserved
                    offset++;
                    radioCfg->MiscOptions = rx.Payload[offset++];
                    radioCfg->FskDatarate = (TRadioCfg_FskDatarateProLink) rx.Payload[offset++];
                    // reserved
                    offset++;
                    // reserved
                    offset += 0x02;
            }
        }
    }
    return result;
}

//-----------------------------------------------------------------------------
/**
 * @brief SetRadioConfig Cmd - Set the radio settings of the of the proprietary LR-BASE mode
 *
 *
 * @param   radioCfg    pointer to the new radio configuration
 * @param   statusRsp   pointer to store status byte of response mesg from WiMOD
 *
 * @retval WiMODLR_RESULT_OK     if command transmit to WiMOD was ok
 */
TWiMODLRResultCodes WiMOD_SAP_RadioLink_ProLink::SetRadioConfig(const TWiMODLR_ProLinkRadioLink_RadioConfig* radioCfg, UINT8* statusRsp) {
    TWiMODLRResultCodes result = WiMODLR_RESULT_TRANMIT_ERROR;
    UINT8              offset = 0;

    if (radioCfg && statusRsp && (txPayloadSize >= 0x1A)) {
        txPayload[offset++] = (UINT8) radioCfg->StoreNwmFlag;
        txPayload[offset++] = (UINT8) radioCfg->RadioMode;
        txPayload[offset++] = (UINT8) radioCfg->GroupAddress;
        txPayload[offset++] = (UINT8) 0x00; // reserved
        HTON16(&txPayload[offset], radioCfg->DeviceAddress);
        offset += 0x02;
        HTON16(&txPayload[offset], 0x00); // reserved
        offset += 0x02;
        txPayload[offset++] = (UINT8) radioCfg->Modulation;
        txPayload[offset++] = (UINT8) radioCfg->RfFreq_LSB;
        txPayload[offset++] = (UINT8) radioCfg->RfFreq_MID;
        txPayload[offset++] = (UINT8) radioCfg->RfFreq_MSB;
        txPayload[offset++] = (UINT8) radioCfg->LoRaBandWidth;
        txPayload[offset++] = (UINT8) radioCfg->LoRaSpreadingFactor;
        txPayload[offset++] = (UINT8) radioCfg->ErrorCoding;
        txPayload[offset++] = (UINT8) radioCfg->PowerLevel;
        txPayload[offset++] = (UINT8) 0x00; // reserved
        txPayload[offset++] = (UINT8) radioCfg->RxControl;
        HTON16(&txPayload[offset], radioCfg->RxWindowTime);
        offset += 0x02;
        txPayload[offset++] = (UINT8) 0x00; // reserved
        txPayload[offset++] = (UINT8) radioCfg->MiscOptions;
        txPayload[offset++] = (UINT8) radioCfg->FskDatarate;
        txPayload[offset++] = (UINT8) 0x00; // reserved
        HTON16(&txPayload[offset], (UINT16) 0x00 ); // reserved
        offset += 0x02;

        result = HciParser->SendHCIMessage(PROLINK_RADIOLINK_SAP_ID,
                PROLINK_RADIOLINK_MSG_SET_RADIO_CFG_REQ,
                PROLINK_RADIOLINK_MSG_SET_RADIO_CFG_RSP,
                txPayload, offset);

        if (result == WiMODLR_RESULT_OK) {
            const TWiMODLR_HCIMessage& rx = HciParser->GetRxMessage();
            offset = WiMODLR_HCI_RSP_STATUS_POS;
            *statusRsp = rx.Payload[offset++];

            // status check
            if (*statusRsp == RADIOLINK_STATUS_OK) {


            } else {
            }
        }
    }
    return result;
}

//-----------------------------------------------------------------------------
/**
 * @brief ResetRadioConfig Cmd - Reset the radio config of the proprietary LR-BASE mode to factory defaults.
 *
 *
 * @param   statusRsp   pointer to store status byte of response mesg from WiMOD
 *
 * @retval WiMODLR_RESULT_OK     if command transmit to WiMOD was ok
 */
TWiMODLRResultCodes WiMOD_SAP_RadioLink_ProLink::ResetRadioConfig(UINT8* statusRsp) {
    TWiMODLRResultCodes result = WiMODLR_RESULT_TRANMIT_ERROR;
    if (statusRsp) {
        result = HciParser->SendHCIMessage(PROLINK_RADIOLINK_SAP_ID,
                PROLINK_RADIOLINK_MSG_RESET_RADIO_CFG_REQ,
                PROLINK_RADIOLINK_MSG_RESET_RADIO_CFG_RSP,
                NULL, 0);
        // copy response status
        if (WiMODLR_RESULT_OK == result) {
            *statusRsp = HciParser->GetRxMessage().Payload[WiMODLR_HCI_RSP_STATUS_POS];
        }
    }
    return result;
}



//-----------------------------------------------------------------------------
/**
 * @brief SetAesKey Cmd - Set the 128bit AES that is to be used for encryption
 *
 *
 * @param   key         pointer to the 128bit AES key (pointer to array of 16 UINT8 entries)
 * @param   statusRsp   pointer to store status byte of response mesg from WiMOD
 *
 * @retval WiMODLR_RESULT_OK     if command transmit to WiMOD was ok
 */
TWiMODLRResultCodes WiMOD_SAP_RadioLink_ProLink::SetAesKey(const UINT8* key, UINT8* statusRsp) {
    TWiMODLRResultCodes result = WiMODLR_RESULT_TRANMIT_ERROR;
    if (statusRsp && key && (txPayloadSize >= PROLINK_RADIOLINK_AES_KEY_LEN)) {

        memcpy(txPayload, key, PROLINK_RADIOLINK_AES_KEY_LEN);
        result = HciParser->SendHCIMessage(PROLINK_RADIOLINK_SAP_ID,
                PROLINK_RADIOLINK_MSG_SET_AES_KEY_REQ,
                PROLINK_RADIOLINK_MSG_SET_AES_KEY_RSP,
                txPayload, PROLINK_RADIOLINK_AES_KEY_LEN);
        // copy response status
        if (WiMODLR_RESULT_OK == result) {
            *statusRsp = HciParser->GetRxMessage().Payload[WiMODLR_HCI_RSP_STATUS_POS];
        }
    } else {
        result = WiMODLR_RESULT_PAYLOAD_PTR_ERROR;
    }
    return result;
}


//-----------------------------------------------------------------------------
/**
 * @brief GetAesKey Cmd - Get the 128bit AES that that is used for encryption
 *
 *
 * @param   key         pointer where to store the 128bit AES key (pointer to array of 16 UINT8 entries)
 * @param   statusRsp   pointer to store status byte of response mesg from WiMOD
 *
 * @retval WiMODLR_RESULT_OK     if command transmit to WiMOD was ok
 */
TWiMODLRResultCodes WiMOD_SAP_RadioLink_ProLink::GetAesKey(UINT8* key, UINT8* statusRsp) {
    TWiMODLRResultCodes result = WiMODLR_RESULT_TRANMIT_ERROR;
    if (statusRsp && key) {

        result = HciParser->SendHCIMessage(PROLINK_RADIOLINK_SAP_ID,
                PROLINK_RADIOLINK_MSG_GET_AES_KEY_REQ,
                PROLINK_RADIOLINK_MSG_GET_AES_KEY_RSP,
                NULL, 0);

        // copy response status
        if (WiMODLR_RESULT_OK == result) {
            *statusRsp = HciParser->GetRxMessage().Payload[WiMODLR_HCI_RSP_STATUS_POS];
            memcpy(key, &HciParser->GetRxMessage().Payload[WiMODLR_HCI_RSP_CMD_PAYLOAD_POS],  PROLINK_RADIOLINK_AES_KEY_LEN);
        }
    } else {
        result = WiMODLR_RESULT_PAYLOAD_PTR_ERROR;
    }
    return result;
}


//------------------------------------------------------------------------------
/**
 * @internal
 *
 * @brief Dispatch messages from the WiMOD (aka indications)
 *
 * @param rxMsg reference to the complete received HCI message; DO NOT MODIFIY it!
 *
 * @endinternal
 */
void
WiMOD_SAP_RadioLink_ProLink::DispatchRadioLinkProLinkMessage(TWiMODLR_HCIMessage& rxMsg) {

    DispatchRadioLinkMessage(rxMsg);
}

//------------------------------------------------------------------------------
//
// Section protected functions
//
//------------------------------------------------------------------------------
/**
 * @internal
 * @brief default cmd handler for unknown / unsupported commands
 * @params statusRsp    pointer to HCI status response code to set
 * @endinternal
 */
TWiMODLRResultCodes WiMOD_SAP_RadioLink_ProLink::unsupportedCmd(UINT8* statusRsp) {
    if (statusRsp) {
        *statusRsp = RADIOLINK_STATUS_CMD_NOT_SUPPORTED;
    }
    return WiMODLR_RESULT_TRANMIT_ERROR;
}
