Pair function with BLE_Paired_Sever. If missing BLE_Paired_Server side, BZ will ON for notice.

Dependencies:   BLE_API TextLCD mbed nRF51822 nRF51_LowPwr nRF51_Vdd

main.cpp

Committer:
kenjiArai
Date:
2016-06-12
Revision:
5:315161fd3d19
Parent:
4:ed7848c6d374

File content as of revision 5:315161fd3d19:

/*
 *  /////// Tested on Switch Science mbed TY51822r3 ///////
 *  Modified by Kenji Arai
 *      http://www.page.sannet.ne.jp/kenjia/index.html
 *      http://mbed.org/users/kenjiArai/
 *
 *      Started:  April     8th, 2016
 *      Revised:  June     12th, 2016
 *
 *  Original program:
 *      BLE_Nano_CentralTest
 *      https://developer.mbed.org/users/mbed_tw_hoehoe/code/BLE_Nano_CentralTest/
 *      S130 potential unstability case [closed] by Fabien Comte
 *      https://devzone.nordicsemi.com/question/49705/s130-potential-unstability-case/
 *  Tested Device:
 *      BLE_Paired_Server
 *
 */

//  Include ---------------------------------------------------------------------------------------
#include "mbed.h"
#include "BLE.h"
#include "DiscoveredCharacteristic.h"
#include "DiscoveredService.h"
#include "GapScanningParams.h"
#include "ble_radio_notification.h"
#include "ble_gap.h"
#include "nrf_delay.h"
#include "nRF51_Vdd.h"
#include "TextLCD.h"
#include "nRF51_lowpwr.h"

//  Definition ------------------------------------------------------------------------------------
//  Before using this function, please specify your program are used following functions or not.
#define    USE_DEVICE_STDIO_MESSAGES       0   // printf
#define    USE_DEVICE_SERIAL               1   // Serial or DEBUG & etc.
#define    USE_DEVICE_I2C                  1   // Sensors with I2C, LCD, EEPROM, Driver chips & etc.
#define    USE_DEVICE_SPI                  0   // Sensors with SPI, LCD, EEPROM, Driver chips & etc.
#define    USE_DEVICE_SPISLAVE             0   // Communication with master vis SPI
#define    USE_DEVICE_PWMOUT               0   // PWM duty output, Serve & etc.
#define    USE_DEVICE_ANALOGIN             0   // Analog adc

typedef struct {
    Gap::Handle_t   handle;
    Gap::Address_t  address;
    bool            connected;
    uint8_t*        deviceName;
} peripheral_t;

#define LIMIT_JUDGE_CNT         4

#if USE_DEVICE_SERIAL
#define BAUD(x)                 pc.baud(x)
#define GETC(x)                 pc.getc(x)
#define PUTC(x)                 pc.putc(x)
#define PRINTF(...)             pc.printf(__VA_ARGS__)
#define READABLE(x)             pc.readable(x)
#define ATTACH(x,y)             pc.attach(x,y)
#else
#define BAUD(x)
#define GETC(x)                 'c'
#define PUTC(x)
#define PRINTF(...)
#define READABLE(x)
#define ATTACH(x,y)
#endif

//  Object ----------------------------------------------------------------------------------------
BLE         ble;
DigitalOut  alivenessLED(LED1, 1);
DigitalOut  connectedLED(LED2, 0);
DigitalOut  buzzer(LED3, 0);
#if USE_DEVICE_SERIAL 
Serial      pc(USBTX, USBRX);
#endif
Ticker      ticker;
nRF51_Vdd   vdd(3.6f, 1.8f, ONLY4VDD);
I2C         i2c1(P0_28, P0_29);         // SDA, SCL
TextLCD_I2C_N   lcd(&i2c1, ST7036_SA2, TextLCD::LCD8x2, NC, TextLCD::ST7032_3V3);

//  ROM / Constant data ---------------------------------------------------------------------------
//#warning "You need to modify below values based on your board."
const Gap::Address_t    mac_board_0   = {0x98, 0x11, 0x9b, 0x73, 0x1a, 0xe7};   // FRISK
/* followings are other own board
const Gap::Address_t    mac_board_0   = {0x50, 0x2b, 0xea, 0x14, 0x95, 0xd2};   // Nano
const Gap::Address_t    mac_board_0   = {0x98, 0x11, 0x9b, 0x73, 0x1a, 0xe7};   // FRISK
const Gap::Address_t    mac_board_0   = {0x30, 0x74, 0x6d, 0xbd, 0x83, 0xf4};   // TY None Pin BLK
const Gap::Address_t    mac_board_0   = {0x59, 0x2c, 0xa8, 0x0e, 0xe2, 0xef};   // TY cut PCB
*/
const int8_t            tx_power_level[8] =
                        {
                            RADIO_TXPOWER_TXPOWER_Pos4dBm,      // 0
                            RADIO_TXPOWER_TXPOWER_0dBm,         // 1
                            RADIO_TXPOWER_TXPOWER_Neg4dBm,      // 2
                            RADIO_TXPOWER_TXPOWER_Neg8dBm,      // 3
                            RADIO_TXPOWER_TXPOWER_Neg12dBm,     // 4
                            RADIO_TXPOWER_TXPOWER_Neg16dBm,     // 5
                            RADIO_TXPOWER_TXPOWER_Neg20dBm,     // 6
                            RADIO_TXPOWER_TXPOWER_Neg30dBm      // 7
                        };

const nRF51_LOWPWR_TypeDef  lowpwr_table = 
                        {
                        #if USE_DEVICE_STDIO_MESSAGES 
                            true,
                        #else
                            false,
                        #endif
                        #if USE_DEVICE_SERIAL
                            true,
                        #else
                            false,
                        #endif
                        #if USE_DEVICE_I2C
                            true,
                        #else
                            false,
                        #endif
                        #if USE_DEVICE_SPI
                            true,
                        #else
                            false,
                        #endif
                        #if USE_DEVICE_SPISLAVE
                            true,
                        #else
                            false,
                        #endif
                        #if USE_DEVICE_PWMOUT
                            true,
                        #else
                            false,
                        #endif
                        #if USE_DEVICE_ANALOGIN
                            true
                        #else
                            false
                        #endif
                        };

//  RAM -------------------------------------------------------------------------------------------
Gap::Address_t  my_mac;
int             my_board_index  = -1;
int8_t          alive_board     = 0;
int8_t          judge_counter   = 0;
static peripheral_t         peripheral_inf;
DiscoveredCharacteristic    peripheral_dat_readChar;
DiscoveredCharacteristic    central_dat_readChar;
volatile bool   trigger5Sec_flag = false;
volatile bool   triggerRead_flag = false;
uint16_t        rcv_dt_len;
uint8_t         rcv_dt[32];
uint32_t        counter;
uint8_t         contrast;

//  Function prototypes ---------------------------------------------------------------------------
void periodicCallback(void);
uint32_t ble_advdata_parser(uint8_t type, uint8_t advdata_len, uint8_t *p_advdata,
                            uint8_t *len, uint8_t *p_field_data);
void scanCallback(const Gap::AdvertisementCallbackParams_t *params);
void serviceDiscoveryCallback(const DiscoveredService *service);
void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP);
void connectionCallback(const Gap::ConnectionCallbackParams_t *params);
void discoveryTerminationCallback(Gap::Handle_t connectionHandle);
void triggerRead(const GattReadCallbackParams *response);
void triggerToggledWrite(const GattWriteCallbackParams *response);
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params);
void serialRxCallback();
void periodicCallback(void);
bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2);
void osc_5KHz(uint32_t time_sec);
uint8_t auto_contrast(float vdd);

//-------------------------------------------------------------------------------------------------
//  Control Program
//-------------------------------------------------------------------------------------------------
int main(void) {
    uint8_t *p;

    nrf_delay_us(100);
    LowPwr set_lowpwr(&lowpwr_table);
    ticker.attach(periodicCallback, 5); /* Blink LED every second */
    ATTACH(&serialRxCallback, Serial::RxIrq);
    for (int k = 0; k < 20; k++) { PRINTF("\r\n");}
    PRINTF("Check paired Peripheral board\r\n"); // opening message
    wait(1.0);
    // lcd
    lcd.locate(0, 0);    // 1st line top
    //          12345678
    lcd.printf("TY51822r");
    lcd.locate(0, 1);    // 2nd line top
    //        12345678
    lcd.puts(" JH1PJL ");
    contrast = auto_contrast(vdd.read_real_value());
    lcd.setCursor(TextLCD::CurOff_BlkOff);
    lcd.setContrast(contrast);
    // BLE
    ble.init();
    ble.onConnection(connectionCallback);
    ble.onDisconnection(disconnectionCallback);
    ble.gattClient().onServiceDiscoveryTermination(discoveryTerminationCallback);
    ble.gattClient().onDataRead(triggerRead);
    ble.gap().setScanParams(500, 400);
    ble.gap().setTxPower(tx_power_level[0]);
    ble.gap().startScan(scanCallback);
    alive_board = 0;
    while (true) {
        if (trigger5Sec_flag == true){
            trigger5Sec_flag = false;
            peripheral_dat_readChar.read();
            if (alive_board){
                --judge_counter;
                if (judge_counter < 0){
                    judge_counter = -1;
                }
            }
        }
        if (triggerRead_flag == true){
            triggerRead_flag = false;
            alivenessLED = 0;
            PRINTF("%s", rcv_dt);
            PRINTF("\r\n");
            if (counter & 1UL){      // Change a screen contents
                p = rcv_dt + 2;
                lcd.locate(0, 0);    // 1st line top
                //          12345678
                lcd.printf(" Server "); 
                lcd.locate(0, 1);    // 2nd line top
                lcd.printf("%s", p);
            } else {
                lcd.locate(0, 0);    // 1st line top
                //          12345678
                lcd.printf(" Client "); 
                lcd.locate(0, 1);    // 2nd line top
                lcd.printf(" %3.2f[V]", vdd.read_real_value());
            }
            contrast = auto_contrast(vdd.read_real_value());
            lcd.setContrast(contrast);
            ++judge_counter;
            if (judge_counter > LIMIT_JUDGE_CNT){
                judge_counter = LIMIT_JUDGE_CNT;
                alive_board = 1;
            }
        }
        PRINTF("state %+d\r\n", judge_counter);
        if ( judge_counter == -1){
            PRINTF("%c", 0x07);  // Ring a PC terminal bell 
            lcd.locate(0, 0);    // 1st line top
            //          12345678
            lcd.printf(" Server "); 
            lcd.locate(0, 1);    // 2nd line top
            //          12345678
            lcd.printf("is gone!");
            alivenessLED = !alivenessLED;
            osc_5KHz(3);
        }
        ble.waitForEvent();
    }
}

void osc_5KHz(uint32_t time_sec){
    for (int32_t t = 0; t < time_sec; t++){   // Durartion
        for (int32_t n = 0; n < 5000; n++){   // 1sec with 5KHz
            buzzer = 1;
            nrf_delay_us(100);
            buzzer = 0;
            nrf_delay_us(100);
        }
    }
    buzzer = 0;
}

uint8_t auto_contrast(float vdd){
    #define OFFSET_CONST    15
    #define SIZE_OF_TBL     50
    uint8_t n = 0;
    const static uint16_t const_table[] =
        {
          360, 355, 350, 345, 340, 335, 330, 325, 320, 315, 310, 305, 300,
          295, 290, 285, 280, 275, 270, 265, 260, 257, 253, 250, 247, 243,
          240, 237, 233, 230, 227, 223, 220, 217, 215, 212, 210, 208, 206,
          204, 202, 200, 197, 195, 193, 190, 185, 180, 170, 100
        };
    
    uint16_t v = (uint16_t)(vdd * 100);
    for (; n < 50; n++){
        if (v >= const_table[n]){
            break;
        }
    }
    return n + OFFSET_CONST;
}

void serialRxCallback(){
    char c = GETC();
    PUTC(c);
    if ( c == 0x1f ){           // Control+?
        NVIC_SystemReset();     // System RESET!!
    }
}

void periodicCallback(void){
    alivenessLED = 1;
    trigger5Sec_flag = true;
    counter++;
}

uint32_t ble_advdata_parser
(
    uint8_t type,
    uint8_t advdata_len,
    uint8_t *p_advdata,
    uint8_t *len,
    uint8_t *p_field_data
)
{
    uint8_t index=0;
    uint8_t field_length, field_type;
    
    while(index<advdata_len) {
        field_length = p_advdata[index];
        field_type   = p_advdata[index+1];
        PRINTF("len=%d, field_type=%x, type=%d\r\n", field_length, field_type, type);
        if(field_type == type) {
            memcpy(p_field_data, &p_advdata[index+2], (field_length-1));
            *len = field_length - 1;
            return NRF_SUCCESS;
        }
        index += field_length + 1;
    }
    return NRF_ERROR_NOT_FOUND;
}

bool mac_equals(const Gap::Address_t mac_1, const Gap::Address_t mac_2){
    PRINTF("\r\nAddress: ");
    for (int i = 0; i < 6; i++){
        PRINTF("0x%02x ", mac_1[i]);
    }
    PRINTF("\r\n");
    for (int i = 0; i < 6; i++){
        if (mac_1[i] != mac_2[i]){
            PRINTF("0x%02x != 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
            return false;
        } else {
            PRINTF("0x%02x == 0x%02x at %d\r\n", mac_1[i], mac_2[i], i);
        }
    }
    return true;
}

void scanCallback(const Gap::AdvertisementCallbackParams_t *params){
uint8_t     len;
uint8_t     adv_name[32];
uint32_t    action_result;

    PRINTF("adv peerAddr");
    PRINTF(
        "[%02x %02x %02x %02x %02x %02x] rssi %+4d, isScanResponse %u, AdvertisementType %u",
        params->peerAddr[5],
        params->peerAddr[4],
        params->peerAddr[3],
        params->peerAddr[2],
        params->peerAddr[1],
        params->peerAddr[0],
        params->rssi,
        params->isScanResponse,
        params->type
    );
    if (mac_equals(params->peerAddr, mac_board_0) == false){
        PRINTF(" not expected peripheral device\r\n");
        return;
    }
    action_result = ble_advdata_parser(
                            BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME,
                            params->advertisingDataLen,
                            (uint8_t *)params->advertisingData,
                            &len,
                            adv_name
                    );
    if( action_result == NRF_SUCCESS){
        PRINTF("NRF_SUCCESS\r\n");
        if(peripheral_inf.connected == false){
            memcpy(peripheral_inf.address, params->peerAddr, sizeof(params->peerAddr)); 
            peripheral_inf.deviceName = adv_name;
            ble.connect(params->peerAddr, BLEProtocol::AddressType::RANDOM_STATIC, NULL, NULL);
        }
        ble.stopScan();
    } else {
         PRINTF("NRF_ERROR_NOT_FOUND\r\n");
    }
}

void serviceDiscoveryCallback(const DiscoveredService *service) {
    PRINTF("service found...\r\n");
    if (service->getUUID().shortOrLong() == UUID::UUID_TYPE_SHORT) {
        PRINTF("Service UUID-%x attrs[%u %u]\r\n",
                service->getUUID().getShortUUID(),
                service->getStartHandle(),
                service->getEndHandle()
        );
    } else {
        PRINTF("Service UUID-");
        const uint8_t *longUUIDBytes = service->getUUID().getBaseUUID();
        for (unsigned i = 0; i < UUID::LENGTH_OF_LONG_UUID; i++) {
            PRINTF("%02x", longUUIDBytes[i]);
        }
        PRINTF(" attrs[%u %u]\r\n", service->getStartHandle(), service->getEndHandle());
    }
}

void characteristicDiscoveryCallback(const DiscoveredCharacteristic *characteristicP) {
    PRINTF("characteristicDiscoveryCallback\r\n");
    if (characteristicP->getUUID().getShortUUID() == 0xa001){
        PRINTF("UUID=0xa001\r\n");
        peripheral_dat_readChar = *characteristicP;
    }
    if(peripheral_inf.connected){
        ble.gattClient().read(
            characteristicP->getConnectionHandle(),
            characteristicP->getValueHandle(),
            0
        );
    }
}

void connectionCallback(const Gap::ConnectionCallbackParams_t *params) {
    PRINTF("connected\r\n");
    connectedLED = 1;
    if (params->role != Gap::CENTRAL) {
        return;
    }
    if(peripheral_inf.connected == false){
        peripheral_inf.handle = params->handle;
        peripheral_inf.connected = true;
    }
    PRINTF("connectionHandle = params->handle %u\r\n", params->handle);
    ble.gattClient().launchServiceDiscovery(
        params->handle,
        serviceDiscoveryCallback,
        characteristicDiscoveryCallback,
        0xa000,
        0xa001
    );
    printf("connected as device (handle = %d)\r\n\r", params->handle);
    printf(
        "Conn. params => min=%d, max=%d, slave=%d, supervision=%d\r\n",
        params->connectionParams->minConnectionInterval,
        params->connectionParams->maxConnectionInterval,
        params->connectionParams->slaveLatency,
        params->connectionParams->connectionSupervisionTimeout
    );
    Gap::ConnectionParams_t connectionParams;
    connectionParams.minConnectionInterval        = 200;
    connectionParams.maxConnectionInterval        = 500;
    connectionParams.slaveLatency                 = 0;
    connectionParams.connectionSupervisionTimeout = 1500;
    if (BLE::Instance(
        BLE::DEFAULT_INSTANCE).gap().updateConnectionParams(params->handle,
        &connectionParams) != BLE_ERROR_NONE
    ){
        printf("failed to update connection parameter\r\n");
    }
}

void discoveryTerminationCallback(Gap::Handle_t connectionHandle) {
    PRINTF("terminated SD for handle %u\r\n", connectionHandle);
}

void triggerRead(const GattReadCallbackParams *response) {
    rcv_dt_len = response->len;
    memcpy(rcv_dt, response->data, rcv_dt_len); 
    triggerRead_flag = true;
}

void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params){
    PRINTF("disconnected\r\n");
    judge_counter = -1;
    alive_board = 0;
    connectedLED = 0;
    if(peripheral_inf.handle == params->handle){
        peripheral_inf.connected = false;
        peripheral_inf.handle = 0xffff;
    }
    wait(2.0);
    ble.gap().startScan(scanCallback);
}