/* ----------------------------------------------------------------------------
 * Copyright (c) 2015-2017 Semiconductor Components Industries, LLC (d/b/a
 * ON Semiconductor), All Rights Reserved
 *
 * This code is the property of ON Semiconductor and may not be redistributed
 * in any form without prior written permission from ON Semiconductor.
 * The terms of use and warranty for this code are covered by contractual
 * agreements between ON Semiconductor and the licensee.
 *
 * This is Reusable Code.
 *
 * ----------------------------------------------------------------------------
 * ble_custom.c
 * - Bluetooth custom service functions
 * ----------------------------------------------------------------------------
 * $Revision: 1.14 $
 * $Date: 2017/12/04 22:53:32 $
 * ------------------------------------------------------------------------- */

#include "app.h"
#include "I2C.h"
#include <stdio.h>

/* Global variable definition */
struct cs_env_tag cs_env;
overflow_packet_t *unhandled_packets = NULL;

/* ----------------------------------------------------------------------------
 * Function      : void CustomService_Env_Initialize(void)
 * ----------------------------------------------------------------------------
 * Description   : Initialize custom service environment
 * Inputs        : None
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
void CustomService_Env_Initialize(void)
{
    /* Reset the application manager environment */
    memset(&cs_env, 0, sizeof(cs_env));

    cs_env.tx_cccd_value = ATT_CCC_START_NTF;
    cs_env.rx_cccd_value = 0;
    cs_env.sentSuccess = 1;
}

/* ----------------------------------------------------------------------------
 * Function      : void CustomService_ServiceAdd(void)
 * ----------------------------------------------------------------------------
 * Description   : Send request to add custom profile into the attribute
 *                 database.Defines the different access functions
 *                 (setter/getter commands to access the different
 *                 characteristic attributes).
 * Inputs        : None
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
void CustomService_ServiceAdd(void)
{
    struct gattm_add_svc_req *req = KE_MSG_ALLOC_DYN(GATTM_ADD_SVC_REQ,
                                                     TASK_GATTM, TASK_APP,
                                                     gattm_add_svc_req,
                                                     CS_IDX_NB * sizeof(struct
                                                                        gattm_att_desc));

    uint8_t i;
    const uint8_t svc_uuid[ATT_UUID_128_LEN] = CS_SVC_UUID;

    const struct gattm_att_desc att[CS_IDX_NB] =
    {
        /* Attribute Index  = Attribute properties: UUID,
         *                                          Permissions,
         *                                          Max size,
         *                                          Extra permissions */

        /* TX Characteristic */
                /* TX Characteristic */
                [CS_IDX_TX_VALUE_CHAR]     = ATT_DECL_CHAR(),
                [CS_IDX_TX_VALUE_VAL]      = ATT_DECL_CHAR_UUID_128(CS_CHARACTERISTIC_TX_UUID,
                                                 PERM(RD,ENABLE) | PERM(NTF,ENABLE),
                                                 CS_TX_VALUE_MAX_LENGTH),
                [CS_IDX_TX_VALUE_CCC]      = ATT_DECL_CHAR_CCC(),
                [CS_IDX_TX_VALUE_USR_DSCP] = ATT_DECL_CHAR_USER_DESC( CS_USER_DESCRIPTION_MAX_LENGTH ),

                /* RX Characteristic */
                [CS_IDX_RX_VALUE_CHAR]     = ATT_DECL_CHAR(),
                [CS_IDX_RX_VALUE_VAL]      = ATT_DECL_CHAR_UUID_128(CS_CHARACTERISTIC_RX_UUID,
                                                 PERM(RD, ENABLE) | PERM(WRITE_REQ,ENABLE) | PERM(WRITE_COMMAND,ENABLE),
                                                 CS_RX_VALUE_MAX_LENGTH),
                [CS_IDX_RX_VALUE_CCC]      = ATT_DECL_CHAR_CCC(),
                [CS_IDX_RX_VALUE_USR_DSCP] = ATT_DECL_CHAR_USER_DESC( CS_USER_DESCRIPTION_MAX_LENGTH ),
    };

    /* Fill the add custom service message */
    req->svc_desc.start_hdl = 0;
    req->svc_desc.task_id = TASK_APP;
    req->svc_desc.perm = PERM(SVC_UUID_LEN, UUID_128);
    req->svc_desc.nb_att = CS_IDX_NB;

    memcpy(&req->svc_desc.uuid[0], &svc_uuid[0], ATT_UUID_128_LEN);

    for (i = 0; i < CS_IDX_NB; i++)
    {
        memcpy(&req->svc_desc.atts[i], &att[i],
               sizeof(struct gattm_att_desc));
    }

    /* Send the message */
    ke_msg_send(req);
}

/* ----------------------------------------------------------------------------
 * Function      : int GATTM_AddSvcRsp(ke_msg_id_t const msg_id,
 *                                     struct gattm_add_svc_rsp
 *                                     const *param,
 *                                     ke_task_id_t const dest_id,
 *                                     ke_task_id_t const src_id)
 * ----------------------------------------------------------------------------
 * Description   : Handle the response from adding a service in the attribute
 *                 database from the GATT manager
 * Inputs        : - msg_id     - Kernel message ID number
 *                 - param      - Message parameters in format of
 *                                struct gattm_add_svc_rsp
 *                 - dest_id    - Destination task ID number
 *                 - src_id     - Source task ID number
 * Outputs       : return value - Indicate if the message was consumed;
 *                                compare with KE_MSG_CONSUMED
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
int GATTM_AddSvcRsp(ke_msg_id_t const msg_id,
                    struct gattm_add_svc_rsp const *param,
                    ke_task_id_t const dest_id,
                    ke_task_id_t const src_id)
{
    cs_env.start_hdl = param->start_hdl;

    /* Add the next requested service  */
    if (!Service_Add())
    {
        /* All services have been added, go to the ready state
         * and start advertising */
        ble_env.state = APPM_READY;
        Advertising_Start();
    }

    return(KE_MSG_CONSUMED);
}

/* ----------------------------------------------------------------------------
 * Function      : int GATTC_ReadReqInd(ke_msg_id_t const msg_id,
 *                                      struct gattc_read_req_ind
 *                                      const *param,
 *                                      ke_task_id_t const dest_id,
 *                                      ke_task_id_t const src_id)
 * ----------------------------------------------------------------------------
 * Description   : Handle received read request indication
 *                 from a GATT Controller
 * Inputs        : - msg_id     - Kernel message ID number
 *                 - param      - Message parameters in format of
 *                                struct gattc_read_req_ind
 *                 - dest_id    - Destination task ID number
 *                 - src_id     - Source task ID number
 * Outputs       : return value - Indicate if the message was consumed;
 *                                compare with KE_MSG_CONSUMED
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
int GATTC_ReadReqInd(ke_msg_id_t const msg_id,
                     struct gattc_read_req_ind const *param,
                     ke_task_id_t const dest_id,
                     ke_task_id_t const src_id)
{
    uint8_t length = 0;
    uint8_t status = GAP_ERR_NO_ERROR;
    uint16_t attnum;
    uint8_t *valptr = NULL;

    struct gattc_read_cfm *cfm;

    /* Set the attribute handle using the attribute index
     * in the custom service */
    if (param->handle > cs_env.start_hdl)
    {
        attnum = (param->handle - cs_env.start_hdl - 1);
    }
    else
    {
        status = ATT_ERR_INVALID_HANDLE;
    }

    /* If there is no error, send back the requested attribute value */
    if (status == GAP_ERR_NO_ERROR)
    {
        switch (attnum)
        {
            case CS_IDX_RX_VALUE_VAL:
            {
                length = CS_RX_VALUE_MAX_LENGTH;
                valptr = (uint8_t *) &cs_env.rx_value;
            }
            break;
            case CS_IDX_RX_VALUE_CCC:
            {
                length = 2;
                valptr = (uint8_t *) &cs_env.rx_cccd_value;
            }
            break;
            case CS_IDX_RX_VALUE_USR_DSCP:
            {
                length = strlen(CS_RX_CHARACTERISTIC_NAME);
                valptr = (uint8_t *) CS_RX_CHARACTERISTIC_NAME;
            }
            break;
            case CS_IDX_TX_VALUE_VAL:
            {
                length = CS_TX_VALUE_MAX_LENGTH;
                valptr = (uint8_t *) &cs_env.tx_value;
            }
            break;
            case CS_IDX_TX_VALUE_CCC:
            {
                length = 2;
                valptr = (uint8_t *) &cs_env.tx_cccd_value;
            }
            break;
            case CS_IDX_TX_VALUE_USR_DSCP:
            {
                length = strlen(CS_TX_CHARACTERISTIC_NAME);
                valptr = (uint8_t *) CS_TX_CHARACTERISTIC_NAME;
            }
            break;
            default:
            {
                status = ATT_ERR_READ_NOT_PERMITTED;
            }
            break;
        }
    }

    /* Allocate and build message */
    cfm = KE_MSG_ALLOC_DYN(GATTC_READ_CFM,
                           KE_BUILD_ID(TASK_GATTC, ble_env.conidx), TASK_APP,
                           gattc_read_cfm,
                           length);

    if (valptr != NULL)
    {
        memcpy(cfm->value, valptr, length);
    }

    cfm->handle = param->handle;
    cfm->length = length;
    cfm->status = status;

    /* Send the message */
    ke_msg_send(cfm);

    return(KE_MSG_CONSUMED);
}

/* ----------------------------------------------------------------------------
 * Function      : int GATTC_WriteReqInd(ke_msg_id_t const msg_id,
 *                                       struct gattc_write_req_ind
 *                                       const *param,
 *                                       ke_task_id_t const dest_id,
 *                                       ke_task_id_t const src_id)
 * ----------------------------------------------------------------------------
 * Description   : Handle received write request indication
 *                 from a GATT Controller
 * Inputs        : - msg_id     - Kernel message ID number
 *                 - param      - Message parameters in format of
 *                                struct gattc_write_req_ind
 *                 - dest_id    - Destination task ID number
 *                 - src_id     - Source task ID number
 * Outputs       : return value - Indicate if the message was consumed;
 *                                compare with KE_MSG_CONSUMED
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
int GATTC_WriteReqInd(ke_msg_id_t const msg_id,
                      struct gattc_write_req_ind const *param,
                      ke_task_id_t const dest_id,
                      ke_task_id_t const src_id)
{
    struct gattc_write_cfm *cfm = KE_MSG_ALLOC(GATTC_WRITE_CFM,
                                               KE_BUILD_ID(TASK_GATTC,
                                                           ble_env.conidx),
                                               TASK_APP, gattc_write_cfm);

    uint8_t status = GAP_ERR_NO_ERROR;
    uint16_t attnum = 0;
    uint8_t *valptr = NULL;
    overflow_packet_t *traverse = NULL;
    int flag;

    /* Check that offset is not zero */
    if (param->offset)
    {
        status = ATT_ERR_INVALID_OFFSET;
    }

    /* Set the attribute handle using the attribute index
     * in the custom service */
    if (param->handle > cs_env.start_hdl)
    {
        attnum = (param->handle - cs_env.start_hdl - 1);
    }
    else
    {
        status = ATT_ERR_INVALID_HANDLE;
    }

    /* If there is no error, save the requested attribute value */
    if (status == GAP_ERR_NO_ERROR)
    {
        switch (attnum)
        {
        case CS_IDX_RX_VALUE_VAL:
                    {
                    	//Sys_GPIO_Set_High(6);
                    	int i = 0;
                    	            	int j = 0;
                    	                valptr = (uint8_t *) &cs_env.rx_value;
                    	                cs_env.rx_value_changed = 1;
                    	                if ( *valptr == 74){ // asci for J
                    	                	Sys_GPIO_Set_High(0);
                    	                	while (i < 100000) {
                    	                		i = i+1;
                    	                	}
                    	                	Sys_GPIO_Set_Low(0);
                    	                }
                    	                else if (*valptr == 75){ //K
                    	                	Sys_GPIO_Set_High(1);
                    	                	while (i < 100000) {
                    	                		i = i+1;
                    	                	}
                    	                	Sys_GPIO_Set_Low(1);
                    	                }
                    	                else if (*valptr == 76) { //L
                    	                	Sys_GPIO_Set_High(9);
                    	                	while (i < 100000) {
                    	                		i = i+1;
                    	                	}
                    	                	Sys_GPIO_Set_Low(9);
                    	                }
                    	                else if(*valptr == 77) { //M
                    	                	Sys_GPIO_Set_High(2);
                    	                	while (i < 100000) {
                    	                		i = i+1;
                    	                	}
                    	                	Sys_GPIO_Set_Low(2);
                    	                }
                    	                else if(*valptr == 78) { //N
                    	                	Sys_GPIO_Set_High(3);
                    	                	while (i < 100000) {
                    	                		i = i+1;
                    	                	}
                    	                	Sys_GPIO_Set_Low(3);
                    	                }
                    	                else if(*valptr == 80) { //N
                    	                	starti = 1;
                    	                }
                    	                else if (*valptr == 90) { //Z
                    	                	int jjj= 0;
                    	                	Sys_GPIO_Set_High(0);
                    	                	for(jjj=0;jjj<400000;jjj++){
												Sys_Delay_ProgramROM(0.5 * SystemCoreClock);
											}
											Sys_GPIO_Set_Low(0);
                    	                }





                    }
                    break;
            break;
            case CS_IDX_RX_VALUE_CCC:
            {
                valptr = (uint8_t *) &cs_env.rx_cccd_value;
            }
            break;
            case CS_IDX_TX_VALUE_CCC:
            {
                valptr = (uint8_t *) &cs_env.tx_cccd_value;
            }
            break;
            default:
            {
                status = ATT_ERR_WRITE_NOT_PERMITTED;
            }
            break;
        }
    }

    if (valptr != NULL)
    {
        memcpy(valptr, param->value, param->length);
    }

    cfm->handle = param->handle;
    cfm->status = status;

    /* Send the message */
    ke_msg_send(cfm);

    if (attnum == CS_IDX_RX_VALUE_VAL)
    {
        flag = 0;

        /* Start by trying to queue up any previously unhandled packets. If we
         * can't queue them all, set a flag to indicate that we need to queue
         * the new packet too. */
        while ((unhandled_packets != NULL) && (flag == 0))
        {
            if (UART_FillTXBuffer(unhandled_packets->length,
                                  unhandled_packets->data) !=
                UART_ERRNO_OVERFLOW)
            {
                /* Remove a successfully queued packet from the list of unqueued
                 * packets. */
                unhandled_packets = removeNode(unhandled_packets);
            }
            else
            {
                flag = 1;
            }
        }

        /* If we don't have any (more) outstanding packets, attempt to queue the
         * current packet. If this packet is successfully queued, exit. */
        if (flag == 0)
        {
            if (UART_FillTXBuffer(param->length, valptr) != UART_ERRNO_OVERFLOW)
            {
                return(KE_MSG_CONSUMED);
            }
        }
        /* We couldn't empty the list or we couldn't queue the new packet. In
         * both cases we need to save the current packet at the end of the list,
         * then exit. */
        if (unhandled_packets != NULL)
        {
            traverse = unhandled_packets;
            while (traverse->next != NULL)
            {
                traverse = traverse->next;
            }
            traverse->next = createNode(param->length, valptr);
        }
        else
        {
            unhandled_packets = createNode(param->length, valptr);
        }
    }

    return(KE_MSG_CONSUMED);
}

/* ----------------------------------------------------------------------------
 * Function      : void CustomService_SendNotification(uint8_t conidx,
 *                               uint8_t attidx, uint8_t *value, uint8_t length)
 * ----------------------------------------------------------------------------
 * Description   : Send a notification to the client device
 * Inputs        : - conidx       - connection index
 *                 - attidx       - index to attributes in the service
 *                 - value        - pointer to value
 *                 - length       - length of value
 * Outputs       : None
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
void CustomService_SendNotification(uint8_t conidx, uint8_t attidx,
                                    uint8_t *value, uint8_t length)
{
    struct gattc_send_evt_cmd *cmd;
    uint8_t firstDataReg = 0x32;
	int bytesRead2 = 1;
	uint8_t catchzhi = 0;
    //catchzhi = readAccel(firstDataReg,bytesRead2);
    uint16_t handle = (attidx + cs_env.start_hdl + 1);

    /* Prepare a notification message for the specified attribute */
    cmd = KE_MSG_ALLOC_DYN(GATTC_SEND_EVT_CMD,
                           KE_BUILD_ID(TASK_GATTC, conidx), TASK_APP,
                           gattc_send_evt_cmd,
                           length * sizeof(uint16_t));

    //Sys_GPIO_Set_Low(6);
    uint16_t new = 0;

//    if (countA <149){
//    	AccStore[countA] = X;
//    	countA++;
//    	AccStore[countA] = Y;
//    	countA++;
//    	AccStore[countA] = Z;
//    	countA++;
//    }else{

//    switch(vals){
//    	case 0x01:
//    		new = 0x1122;
//    		break;
//    	case 0x02:
//    		new = X;
//    		break;
//    	case 0x03:
//    		new = Y;
//    		break;
//    	case 0x04:
//    		new = Z;
//    		break;
//    	case 0x05:
//    		new = 0x8899;
//    		break;
//    }
    new = AccStore[t];
    cmd->handle = handle;
    cmd->length = 0x02;
    cmd->operation = GATTC_NOTIFY;
    cmd->seq_num = 0;
    uint16_t *newp = &new;
//    Sys_GPIO_Set_Low(9);
//    Sys_GPIO_Set_Low(0);
//    Sys_GPIO_Set_Low(1);
//    Sys_GPIO_Set_Low(2);
//    Sys_GPIO_Set_Low(3);
    //uint8_t lengtht = 0x02;
    memcpy(cmd->value, newp, length);

    cs_env.sentSuccess = 0;

    /* Send the message */
    ke_msg_send(cmd);
   // }
}

/* ----------------------------------------------------------------------------
 * Function      : int GATTC_CmpEvt(ke_msg_id_t const msg_id,
 *                                  struct gattc_cmp_evt
 *                                  const *param,
 *                                  ke_task_id_t const dest_id,
 *                                  ke_task_id_t const src_id)
 * ----------------------------------------------------------------------------
 * Description   : Handle received GATT controller complete event
 * Inputs        : - msg_id     - Kernel message ID number
 *                 - param      - Message parameters in format of
 *                                struct gattc_cmp_evt
 *                 - dest_id    - Destination task ID number
 *                 - src_id     - Source task ID number
 * Outputs       : return value - Indicate if the message was consumed;
 *                                compare with KE_MSG_CONSUMED
 * Assumptions   : None
 * ------------------------------------------------------------------------- */
int GATTC_CmpEvt(ke_msg_id_t const msg_id,
                 struct gattc_cmp_evt const *param,
                 ke_task_id_t const dest_id, ke_task_id_t const src_id)
{
    if (param->operation == GATTC_NOTIFY)
    {
        if (param->status == GAP_ERR_NO_ERROR)
        {
            cs_env.sentSuccess = 1;
        }

        if (param->status == GAP_ERR_DISCONNECTED)
        {
            cs_env.sentSuccess = 1;
        }
    }

    return(KE_MSG_CONSUMED);
}
