/*******************************************************************************
* Project:      Amped'RF Bluetooth
* File name:    App_Main.c
* Description:  Main application.
*
* Copyright (c) 2010 Amped'RF Inc., AR Technology  All rights reserved.
*******************************************************************************/
#include "Common.h"
#include "App_Main.h"
#include "TM_ErrorHandler.h"
#include "hci_commands.h"
#include "hcidefs.h"
#include "bti.h"




//---------------------------------------------
//   Defines
//---------------------------------------------
//#define DEMO_HELLO
//#define DEMO_ACK
#define REMOTE_DEVICE_ADDR  0x00043e260e56


//---------------------------------------------
//   Globals
//---------------------------------------------
tAppVar AppVar;


/*******************************************************************************
* Function Name  : APP_DispatchSignal
* Description    : Target supervisor module signal dispatch function
*******************************************************************************/
tOS_TaskId APP_DispatchSignal(tOS_SignalNo SignalNo)
{
    return AppVar.TaskId;
}


/*******************************************************************************
* Structure for message passing
*******************************************************************************/
typedef struct {
    uint32 Transac;
    uint16 Length;
    char * pBuffer;
} tTextMsg;



/*******************************************************************************
* Function Name  : AllocBufferToSend
* Description    : Get msg buffer to send over the air to a device
*******************************************************************************/
void *AllocBufferToSend(uint16 Length)
{
    uint16 HdrLength;
    tBufferHeader *buf;

    HdrLength = BT_HDR_SIZE + sizeof(tSysBufHdr) + 16;

    if (buf = (tBufferHeader *)OS_getbuf(sizeof(tBufferHeader)+Length)+20)
    {
        buf->pData = (uint8 *)buf + HdrLength;
    }
    return buf;
}



/*******************************************************************************
* Function Name  : SendMessage
* Description    : Send a message using an allocated buffer
*******************************************************************************/
void SendMessage(char *s)
{
    tOS_Signal  * pSignal;
    tTextMsg    * pTextMsg;

    pSignal = OS_AllocSignal(SIG_APP_MESSAGE, sizeof(tTextMsg));
    pTextMsg = (tTextMsg *)OS_GetSignalDataPtr(pSignal);
    memset(pTextMsg, 0, sizeof(tTextMsg));
    if (pTextMsg->pBuffer = GKI_getbuf(50))
    {
        pTextMsg->Length = strlen(s);
        strcpy(pTextMsg->pBuffer, s);
        OS_Send(OS_APP, pSignal);
    }
    else {
        OS_ReleaseSignal(pSignal);
    }
}


/*******************************************************************************
* Function Name  : ShowMessage
* Description    : Show a message in an allocated buffer within a signal
*******************************************************************************/
void ShowMessage(tOS_Signal * pSignal)
{
    tTextMsg    * pTextMsg;

    if (pTextMsg = (tTextMsg *)OS_GetSignalDataPtr(pSignal)) {
        TM_printlf("MsgLen=%d, MsgText=\"%s\"", pTextMsg->Length, pTextMsg->pBuffer);
        TM_printflush();
        OS_Release(pTextMsg->pBuffer);
    }
}



/*******************************************************************************
* Function Name  : CommandComplete
* Description    : Results of command complete
********************************************************************************/
void App_CommandComplete(tHciEvent *pEvt)
{
    tUART_Command_Complete_Event *cc = &(pEvt->EvtType.Command_Complete);
    uint8 i;

    if (cc->Opcode && pEvt->Code==HCI_COMMAND_COMPLETE_EVT)
    {
        switch (cc->Opcode) {
        case HCI_READ_BD_ADDR:
            TM_print("BD_ADDR = ");
            for (i=0; i<6; i++) {
                TM_print("%02x", cc->Params[6-i]);
            }
            break;
        }
        TM_printlf("");
        TM_printflush();
    }
}



/*******************************************************************************
* Function Name  : APP_ReceiveSignal
* Description    : Target supervisor module signal dispatch function
********************************************************************************/
void APP_ReceiveSignal(tOS_Signal *pSignal)
{
    uint16 SigNo = OS_GetSignalNo(pSignal);
    tOS_Signal        * pNewSignal;
    tApp_HCI_Message  * pAppHciMessage;
    tSIG_AMPGapBond   * pBondMsg;
    tSIG_AMPGapResult * pGapResult;
    tSIG_ExtInterrupt * pExtInterrupt;
    uint64 BondAddress = REMOTE_DEVICE_ADDR;
    char * Pin = "1234";
    uint8 LastValue=0xFF;
    tSIG_AMPSppRecv* pAMPSppRecv;
#ifdef DEMO_HELLO
    const char Hello[]="Hello World";
#endif
#ifdef DEMO_ACK
    char msg[30];
    uint16 PortHandle;
#endif

    // Catch for NULL signals
    if (pSignal == NULL) {
        return;
    }

    switch (SigNo)
    {
    case SIG_OS_STARTUP:
        // Send signal in two seconds
/***
        GPIO_Config(GPIOB, GPIO_Pin_13, GPIO_Mode_Out_PP);
        while (1) {
            GPIO_BitWrite(GPIOB, 13, 1);
            NOP;
            GPIO_BitWrite(GPIOB, 13, 0);
            NOP;
        }
***/

#ifdef DEMO_HELLO
        OS_TimerRegisterRequest((uint32)Hello, APP_TMRID_HELLO, 3000, SIG_APP_HELLO);
#endif
        NOP;
        break;

    case SIG_OS_SHUTDOWN:
        OS_ReportTaskShutdownDone();
        break;

    case SIG_APP_ANOTHER:
        TM_printlf("**Another**");
        TM_printflush();
        break;

    case SIG_APP_HELLO:
        // Send message
        TM_printlf("\r\nAmped RF DevKit - Version %s, build %s", SDK_VERSION, SDK_BUILD);
        TM_printlf("%s", (char *)pSignal->Data.Transac);
        TM_printflush();
        // Create signal to send
        pNewSignal = OS_AllocSignal(SIG_SEND_HCI_MESSAGE, sizeof(tApp_HCI_Message));
        pAppHciMessage = (tApp_HCI_Message *)OS_GetSignalDataPtr(pNewSignal);
        memset(pAppHciMessage, 0, sizeof(tApp_HCI_Message));
        // Fill in the message fields and send the message
        pAppHciMessage->Opcode = HCI_READ_BD_ADDR;
        pAppHciMessage->Length = 0;
        OS_Send(OS_APP, pNewSignal);
        // Setup interrupt on GPIO 4, Set as a weak pull up IO
        Targ_EnablePioInterrupt(4, GPIO_Mode_IPU, SIG_APP_GPIO_INTERRUPT);
        break;

    case SIG_SEND_HCI_MESSAGE:
        // Get message from signal and send an HCI command
        pAppHciMessage = (tApp_HCI_Message*)OS_GetSignalDataPtr(pSignal);
        bti_SendCommand(pAppHciMessage->Opcode,
                        pAppHciMessage->Length,
                        pAppHciMessage->Params,
                        App_CommandComplete);
        // Send a timed signal
        OS_TimerRegisterRequest(1, APP_TMRID_BOND, 2000, SIG_APP_BOND);
        break;

    case SIG_APP_BOND:
        TM_printlf("Bonding...");
        TM_printflush();
        // Create signal to send
        pNewSignal = OS_AllocSignal(SIG_AMP_GAP_BOND, sizeof(tSIG_AMPGapBond));
        pBondMsg = (tSIG_AMPGapBond *)OS_GetSignalDataPtr(pNewSignal);
        memset(pBondMsg, 0, sizeof(tSIG_AMPGapBond));
        // Fill in the message fields and send the message
        pBondMsg->BdAddr = *(tBdAddr *)&BondAddress;
        pBondMsg->PinLength = strlen(Pin);
        memcpy(pBondMsg->Pin, Pin, strlen(Pin));
        OS_Send(OS_AMP, pNewSignal);
        //---------------------------------------
        SendMessage("Text in buffer. Success!");
        break;

    case SIG_APP_MESSAGE:
        ShowMessage(pSignal);
        break;

    case SIG_AMP_GAP_RESULT:
        pGapResult = (tSIG_AMPGapResult *)OS_GetSignalDataPtr(pSignal);
        switch(pGapResult->ResultCode)
        {
        case AMP_RESULT_ILLEGAL_OPERATION:
            TM_printlf("Illegal operation");
            TM_printflush();
            break;

        case AMP_RESULT_PENDING:
            TM_printlf("Result pending");
            TM_printflush();
            break;

        case AMP_WRONG_MODE:
            TM_printlf("Wrong Mode");
            TM_printflush();
            break;
        }
        break;

    case SIG_APP_GPIO_DEBOUNCE:
        LastValue = pSignal->Data.Transac;
        TM_printlf(LastValue ? "High":"Low", LastValue);
        TM_printflush();
        break;

    case SIG_APP_GPIO_INTERRUPT:
        pExtInterrupt = (tSIG_ExtInterrupt *)OS_GetSignalDataPtr(pSignal);
        if (pExtInterrupt->PioValue == LastValue) {
            TM_CancelTmrRequest(APP_TMRID_DEBOUNCE);
        }
        else {
            OS_TimerRegisterRequest(pExtInterrupt->PioValue, APP_TMRID_DEBOUNCE,
                                100, SIG_APP_GPIO_DEBOUNCE);
        }
        break;

    case SIG_AMP_SPP_RECV:
        pAMPSppRecv = (tSIG_AMPSppRecv*)OS_GetSignalDataPtr(pSignal);

        TM_print("BytesRead:  %d [", pAMPSppRecv->BytesRead);
        for (int i=0; i<pAMPSppRecv->BytesRead; i++) {
            int ch = pAMPSppRecv->pDataHdr->pData[i];
            TM_print("%c", (ch >=' ' && ch<='~') ? ch : '.');
        }
        TM_printlf("]");

        /***
        TM_print  ("Data:      ");
        TM_printflush();
        for (int i=0; i<pAMPSppRecv->BytesRead; i++) {
            TM_print(" %02x", pAMPSppRecv->pDataHdr->pData[i]);
        }
        TM_printlf("");
        ***/

        TM_printflush();
        OS_Release(pAMPSppRecv->pDataHdr);

        //----------------------------------------------------
#ifdef DEMO_ACK
        if (PortHandle = OS_GetCurrentPortHandle()) {
            sprintf(msg, "Got %d chars\r\n", pAMPSppRecv->BytesRead);
            AT_SendDataToHandle(PortHandle, msg, strlen(msg));
        }
#endif
        break;

    default:
        // Unhandled signal
        break;
    }

    // Release the signal
    OS_ReleaseSignal(pSignal);
}




/*******************************************************************************
* Function Name  : APP_InitTask
* Description    : Initialize App layer
********************************************************************************/
void APP_InitTask(void)
{
    // Initialize your variables here
}




/*******************************************************************************
* Function Name  : APP_InitModule
* Description    :
*       1. create APP module tasks
*       2. task independent functions or variables initialization
********************************************************************************/
void APP_InitModule(void)
{
    OS_RegisterDispatchFunc(OS_APP, APP_DispatchSignal);

    memset(&AppVar, 0, sizeof(AppVar));
    AppVar.TaskId = OS_CreateTask(
       "App",
       APP_InitTask,
       APP_ReceiveSignal,
       OS_DEFAULT_PRIO);
}


