

/**
 ******************************************************************************
 *
 * @file        app.C
 * @brief       BLE_MG126 app c Code. 
 *
 * @par         Project
 *              MG32x02z
 * @version     V1.04
 * @date        2022/09/27
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2020 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 *
 ******************************************************************************* 
 * @par Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/ 
#include <string.h>
#include <stdint.h>
#include "mg_api.h"
//#include "MG0404A_BSP"

/* Wizard menu ---------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/**********************************************************************************
                 *****DataBase****

01 - 06  GAP (Primary service) 0x1800
  03:04  name
07 - 0f  Device Info (Primary service) 0x180a
  0a:0b  firmware version
  0e:0f  software version
10 - 19  LED service (Primary service) 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
  11:12  6E400003-B5A3-F393-E0A9-E50E24DCCA9E(0x04)  RxNotify
  13     cfg
  14:15  6E400002-B5A3-F393-E0A9-E50E24DCCA9E(0x0C)  Tx
  16     cfg
  17:18  6E400004-B5A3-F393-E0A9-E50E24DCCA9E(0x0A)  BaudRate
  19     0x2901  info
************************************************************************************/

typedef struct ble_character16{
    uint16_t type16;          //type2
    uint16_t handle_rec;      //handle
    uint8_t  characterInfo[5];//property1 - handle2 - uuid2
    uint8_t  uuid128_idx;     //0xff means uuid16,other is idx of uuid128
}BLE_CHAR;

typedef struct ble_UUID128{
    uint8_t  uuid128[16];//uuid128 string: little endian
}BLE_UUID128;


/* Private define ------------------------------------------------------------*/
/// Characteristic Properties Bit
#define ATT_CHAR_PROP_RD                            0x02
#define ATT_CHAR_PROP_W_NORSP                       0x04
#define ATT_CHAR_PROP_W                             0x08
#define ATT_CHAR_PROP_NTF                           0x10
#define ATT_CHAR_PROP_IND                           0x20 
#define GATT_PRIMARY_SERVICE_UUID                   0x2800

#define TYPE_CHAR      0x2803
#define TYPE_CFG       0x2902
#define TYPE_INFO      0x2901
#define TYPE_xRpRef    0x2907
#define TYPE_RpRef     0x2908
#define TYPE_INC       0x2802
#define UUID16_FORMAT  0xff

#define SOFTWARE_INFO "SV3.3.3"
#define MANU_INFO     "megawin"

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static char DeviceInfo[] =  "megawin MG04-04A Board";  /*max len is 24 bytes*/

volatile uint16_t cur_notifyhandle = 0x12;  /* volatile *///Note: make sure each notify handle by invoking function: set_notifyhandle(hd);

/* Private function prototypes -----------------------------------------------*/
void updateDeviceInfoData(uint8_t* name, uint8_t len);
uint8_t GetCharListDim(void);

/* Exported variables --------------------------------------------------------*/
extern const BLE_CHAR AttCharList[];
extern BLE_UUID128 AttUuid128List[];

/* Exported functions --------------------------------------------------------*/
/* External vairables --------------------------------------------------------*/
extern void moduleOutData(uint8_t*data, uint8_t len);



//
///STEP0:Character declare
//
const BLE_CHAR AttCharList[] = {
// ======  gatt =====  Do NOT Change!!
    {GATT_PRIMARY_SERVICE_UUID,0x0001,{0,0,0,0,0},0},
    {TYPE_CHAR,0x0003, {ATT_CHAR_PROP_RD, 0x04,0, 0x00,0x2a}, UUID16_FORMAT},//name
    //05-06 reserved
// ======  device info =====    Do NOT Change if using the default!!!
    {GATT_PRIMARY_SERVICE_UUID,0x0007,{0,0,0,0,0},0},
    {TYPE_CHAR,0x0008, {ATT_CHAR_PROP_RD, 0x09,0, 0x29,0x2a}, UUID16_FORMAT},//manufacture
    {TYPE_CHAR,0x000a, {ATT_CHAR_PROP_RD, 0x0b,0, 0x26,0x2a}, UUID16_FORMAT},//firmware version
    {TYPE_CHAR,0x000e, {ATT_CHAR_PROP_RD, 0x0f,0, 0x28,0x2a}, UUID16_FORMAT},//sw version
    
// ======  User service or other services added here =====  User defined
    {GATT_PRIMARY_SERVICE_UUID,0x0010,{0,0,0,0,0},0},
    {TYPE_CHAR,0x0011, {ATT_CHAR_PROP_NTF,                     0x12,0, 0,0}, 1/*uuid128-idx1*/ },//RxNotify
    {TYPE_CFG, 0x0013, {ATT_CHAR_PROP_RD|ATT_CHAR_PROP_W},0},//cfg
    {TYPE_CHAR,0x0014, {ATT_CHAR_PROP_W|ATT_CHAR_PROP_W_NORSP, 0x15,0, 0,0}, 2/*uuid128-idx2*/ },//Tx     
};


BLE_UUID128 AttUuid128List[] = {
    /*for supporting the android app [nRF UART V2.0], one SHOULD using the 0x9e,0xca,0xdc.... uuid128*/
    {0x9e,0xca,0xdc,0x24,0x0e,0xe5,0xa9,0xe0,0x93,0xf3,0xa3,0xb5,1,0,0x40,0x6e}, //idx0,little endian, service uuid
    {0x9e,0xca,0xdc,0x24,0x0e,0xe5,0xa9,0xe0,0x93,0xf3,0xa3,0xb5,3,0,0x40,0x6e}, //idx1,little endian, RxNotify
    {0x9e,0xca,0xdc,0x24,0x0e,0xe5,0xa9,0xe0,0x93,0xf3,0xa3,0xb5,2,0,0x40,0x6e}, //idx2,little endian, Tx
};


uint8_t* getDeviceInfoData(uint8_t* len)
{    
    *len = sizeof(DeviceInfo);
    return (uint8_t*)DeviceInfo;
}

void updateDeviceInfoData(uint8_t* name, uint8_t len)
{
    memcpy(DeviceInfo,name, len);
    
    ble_set_name(name,len);
}


uint8_t GetCharListDim(void)
{
    return sizeof(AttCharList)/sizeof(AttCharList[0]);
}

//////////////////////////////////////////////////////////////////////////
///STEP1:Service declare
// read by type request handle, primary service declare implementation
void att_server_rdByGrType( uint8_t pdu_type, uint8_t attOpcode, uint16_t st_hd, uint16_t end_hd, uint16_t att_type )
{
    //=========================================================
    //Prevent unused argument compilcation warning
    ((void)(end_hd));
    
 //!!!!!!!!  hard code for gap and gatt, make sure here is 100% matched with database:[AttCharList] !!!!!!!!!
                     
    if((att_type == GATT_PRIMARY_SERVICE_UUID) && (st_hd == 0x0001))//hard code for device info service
    {
        uint8_t t[] = {0x00,0x18};
        att_server_rdByGrTypeRspPrimaryService(pdu_type,0x1,0x6,(uint8_t*)(t),2);
        return;
    }
    else if((att_type == GATT_PRIMARY_SERVICE_UUID) && (st_hd <= 0x0007))//hard code for device info service
    {
        uint8_t t[] = {0x0a,0x18};
        att_server_rdByGrTypeRspPrimaryService(pdu_type,0x7,0x0f,(uint8_t*)(t),2);
        return;
    }
    
    else if((att_type == GATT_PRIMARY_SERVICE_UUID) && (st_hd <= 0x0010)) //usr's service
    {
        att_server_rdByGrTypeRspPrimaryService(pdu_type,0x10,0x15,(uint8_t*)(AttUuid128List[0].uuid128),16);
        return;
    }
    //other service added here if any
    //to do....

    ///error handle
    att_notFd( pdu_type, attOpcode, st_hd );
}

///STEP2:data coming
///write response, data coming....
void ser_write_rsp(uint8_t pdu_type/*reserved*/, uint8_t attOpcode/*reserved*/, 
                   uint16_t att_hd, uint8_t* attValue/*app data pointer*/, uint8_t valueLen_w/*app data size*/)
{
    switch(att_hd)
    {
        case 0x15://Tx
#ifdef LOOPBACK //ble directly send back the data to central/phone
            sconn_notifydata(attValue,valueLen_w);
#else
            moduleOutData(attValue,valueLen_w);
#endif
            ser_write_rsp_pkt(pdu_type);  //if the related character has the property of ATT_CHAR_PROP_W
            break;
        
        case 0x12://cmd
        case 0x13://cfg  
            ser_write_rsp_pkt(pdu_type);  /*if the related character has the property of WRITE(with response) or TYPE_CFG, one MUST invoke this func*/      
            break;
        
        default:
            att_notFd( pdu_type, attOpcode, att_hd );	/*the default response, also for the purpose of error robust */
            break;
    }
 }

///STEP2.1:Queued Writes data if any
void ser_prepare_write(uint16_t handle, uint8_t* attValue, uint8_t attValueLen, uint16_t att_offset)//user's call back api 
{
    //=========================================================
    //Prevent unused argument compilcation warning
    ((void)(att_offset));
    
    //queued data:offset + data(size)
    //when ser_execute_write() is invoked, means end of queue write.
    
    //to do    
    if (0x0015 == handle)
    {
#ifdef LOOPBACK //ble directly send back the data to central/phone
        sconn_notifydata(attValue,attValueLen);
#else
        moduleOutData(attValue,attValueLen);
#endif
    }
}

void ser_execute_write(void)//user's call back api 
{
    //end of queued writes  
    
    //to do...    
}

///STEP3:Read data
//// read response
void server_rd_rsp(uint8_t attOpcode, uint16_t attHandle, uint8_t pdu_type)
{
    uint8_t  d_len;
    uint8_t* ble_name = getDeviceInfoData(&d_len);
    
    switch(attHandle) //hard code
    {
        case 0x04: //GAP name
            att_server_rd( pdu_type, attOpcode, attHandle, ble_name, d_len);
            break;
                
        case 0x09: //MANU_INFO
            //att_server_rd( pdu_type, attOpcode, attHandle, (u8*)(MANU_INFO), sizeof(MANU_INFO)-1);
            att_server_rd( pdu_type, attOpcode, attHandle, get_ble_version(), (uint8_t)(strlen((const char*)get_ble_version()))); //ble lib build version
            break;
        
        case 0x0b: //FIRMWARE_INFO
        {
            //do NOT modify this code!!!
            att_server_rd( pdu_type, attOpcode, attHandle, GetFirmwareInfo(),(uint8_t)(strlen((const char*)GetFirmwareInfo())));
            break;
        }
        
        case 0x0f://SOFTWARE_INFO
            att_server_rd( pdu_type, attOpcode, attHandle, (uint8_t*)(SOFTWARE_INFO), sizeof(SOFTWARE_INFO)-1);
            break;
        
        case 0x13://cfg
            {
                uint8_t t[2] = {0,0};
                att_server_rd( pdu_type, attOpcode, attHandle, t, 2);
            }
            break;
        default:
            att_notFd( pdu_type, attOpcode, attHandle );/*the default response, also for the purpose of error robust */
            break;
    }
}

void server_blob_rd_rsp(uint8_t attOpcode, uint16_t attHandle, uint8_t dataHdrP,uint16_t offset)
{
    //=========================================================
    //Prevent unused argument compilcation warning
    ((void)(attOpcode));
    ((void)(attHandle));
    ((void)(dataHdrP));
    ((void)(offset));
}

//return 1 means found
int GetPrimaryServiceHandle(unsigned short hd_start, unsigned short hd_end,
                            unsigned short uuid16,
                            unsigned short* hd_start_r,unsigned short* hd_end_r)
{
    //=========================================================
    //Prevent unused argument compilcation warning
    ((void)(hd_end));
    
// example    
    if((uuid16 == 0xca9e) && (hd_start <= 0x10))// MUST keep match with the information save in function  att_server_rdByGrType(...)
    {
        *hd_start_r = 0x10;
        *hd_end_r = 0x15;
        return 1;
    }
    
    return 0;
}

//add user sending data notify operation ....
void gatt_user_send_notify_data_callback(void)
{
    //to do if any ...
    //add user sending data notify operation ....
}

static unsigned char gConnectedFlag=0;
char GetConnectedStatus(void)
{
    return gConnectedFlag;
}

void ConnectStausUpdate(unsigned char IsConnectedFlag) //porting api
{
    //[IsConnectedFlag] indicates the connection status

    if (IsConnectedFlag != gConnectedFlag)
    {
        gConnectedFlag = IsConnectedFlag;
    }
}

void UsrProcCallback_Central(uint8_t fin, uint8_t* dat_rcv, uint8_t dat_len)
{
    //=========================================================
    //Prevent unused argument compilcation warning
    ((void)(fin));
    ((void)(dat_rcv));
    ((void)(dat_len));
}

void att_cli_receive_callback(uint16_t att_hd, uint8_t* attValue/*app data pointer*/, uint8_t valueLen_w/*app data size*/)
{
    //=========================================================
    //Prevent unused argument compilcation warning
    ((void)(att_hd));
    ((void)(attValue));
    ((void)(valueLen_w));
}

void gatt_client_send_callback(void)
{
}
