Merck / Mbed OS SmartCap_OS5

Dependencies:   nRF51822

Source/BLE_Stuff.cpp

Committer:
sgetz7908
Date:
2019-07-30
Revision:
32:749e1c060d03
Parent:
30:76b51e525c40
Child:
34:c122d842ad9a

File content as of revision 32:749e1c060d03:


/// @file BLE_Stuff.cpp
#include <events/mbed_events.h>
#include <mbed.h>
#include "ble/BLE.h"
#include "ble/Gap.h"
#include "ble/services/UARTService.h"

#include "BLE_Stuff.h"
#include "infoService.h"
#include "hw.h"
#include "log.h"
#include "main.h"
#include "log.h"
#include "nrf_soc.h"

extern EventQueue eventQueue; //(/* event count */ 16 * EVENTS_EVENT_SIZE);
UARTService *uartServicePtr = NULL;

int timeout_id = 0;

int adv_timeout_ID = 0;

int adv_state = false;
char dev_name[15] = "";

volatile int batt_voltage = 0; // actual battery voltage * 100

bool m_isConnected = false;

void process_cmd(char * cmd);

void cancel_ble_activity_timeout(void)
{
   if(timeout_id) { eventQueue.cancel(timeout_id); timeout_id = 0; }
}

void disconnect(void)
{
    cancel_ble_activity_timeout();
#if UART_DEBUGGING==0
    BLE &ble = BLE::Instance();
    ble.gap().disconnect(Gap::CONNECTION_TIMEOUT ); // force disconnect
#endif
}

void dis(void)
{
    disconnect();
}

void ble_activity_timeout(void)
{
    eventQueue.call(dis);
}
    
void reset_ble_activity_timer(void)
{
    cancel_ble_activity_timeout();
    timeout_id = eventQueue.call_in(BLE_INACTIVITY_TIMEOUT*1000UL, ble_activity_timeout);
}

void disconnect_happened()
{
    m_isConnected = false;
    cancel_ble_activity_timeout();
    BLE &ble = BLE::Instance();
    ble.gap().setAdvertisingInterval(ADV_INTERVAL);
    if(adv_state) ble.gap().startAdvertising();
}
    
/// Called when the Bluetooth connection is disconnected.
void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    eventQueue.call(disconnect_happened);
}

void connect_happened(void)
{
    m_isConnected = true;
    BLE &ble = BLE::Instance();
    ble.gap().setAdvertisingInterval(CONN_INTERVAL);
    reset_ble_activity_timer(); 
}
    
void connectionCallback(const Gap::ConnectionCallbackParams_t *params)
{
    eventQueue.call(connect_happened);  
}

bool isConnected(void)
{
    return m_isConnected;
}

/// Called to write a string to the Bluetooth UART.
// used for writting to the BLE UART
void BLE_UART_xmit(const char * str)
{
    if (uartServicePtr != NULL) {
        uartServicePtr->writeString(str);
    }
}

void BLE_UART_xmit(int i)
{
    BLE_UART_xmit(uli2a(i));
}

char cmd_str[21];

/// Called when data is rcv'd from connected BLE device
void onDataWritten(const GattWriteCallbackParams *params)
{
    if ((uartServicePtr != NULL) && (params->handle == uartServicePtr->getTXCharacteristicHandle())) {
        uint16_t bytesRead = params->len;
        strncpy(cmd_str, (const char *)params->data, bytesRead);
        cmd_str[bytesRead] = 0; // add end of string char
        
        // Start process: process_cmd(cmd_str) as regular non-irq routine
        eventQueue.call(process_cmd, cmd_str);
        // the dispatch method executes events
        //queue.dispatch();
        
        //ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(), params->data, bytesRead); // send back whatever is sent to us
        eventQueue.call(reset_ble_activity_timer);
        //reset_ble_activity_timer();
    }
}


/// Called when data is rcv'd from connected BLE device
void dataReadCallback(const GattReadCallbackParams *params)
{
    //if ((uartServicePtr != NULL) && (params->handle == uartServicePtr->getRXCharacteristicHandle())) {
        // Start process: process as regular non-irq routine
        eventQueue.call(dataWasRead);
    //}
}


/// Turn on or off advertising
// When turned on, it will only advertise for a limited time, or until turned off.
void set_radio(int state)
{
    BLE &ble = BLE::Instance();
    adv_state = state;

    if(state) {
        //adv_state = true;
        ble.gap().setAdvertisingInterval(ADV_INTERVAL);
        ble.gap().startAdvertising();
    } else {
        //adv_state = false;
        ble.gap().stopAdvertising();
        disconnect();
    }
}

#if 0
void stop_radio_and_wait(void)
{
    set_radio(false);
    
    // If radio is active, wait for it to become inactive.
    //wait(0.5);
    while (isConnected())// || isRadioActive())
    {
        // Do nothing (just wait for radio to become inactive).
         sd_app_evt_wait();
    }
}
#endif

void authorize_client_write(GattWriteAuthCallbackParams *e)
{
    e->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
}
    
ble_init_status_t ble_init_status = BLE_INIT_IN_PROGRESS;
    
/// Called to setup the Bluetooth link.
void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
    BLE&        ble   = params->ble;
    ble_error_t error = params->error;

    if (error != BLE_ERROR_NONE) {
        ble_init_status = BLE_INIT_ERROR;
        return;
    }

    /* Ensure that it is the default instance of BLE */
    if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
        return;
    }

    ble.gap().onDisconnection(disconnectionCallback);
    ble.gap().onConnection(connectionCallback);
    ble.gattServer().onDataWritten(onDataWritten);

    //ble.gattServer().onDataRead( dataReadCallback ); //const DataReadCallback_t & callback)
    //ble.onDataRead( dataReadCallback);

    strcpy(dev_name, DEV_NAME);
    //strcat(dev_name, char2hex(NRF_FICR->DEVICEADDR[0] & 0xfff, 3));
    strcat(dev_name, char2hex(NRF_FICR->DEVICEADDR[1] | 0xc000, 4));
    strcat(dev_name, char2hex(NRF_FICR->DEVICEADDR[0], 8));
    int len = strlen(dev_name);

    ble.gap().setDeviceName((std::uint8_t *)dev_name);
    
    /* Setup primary service */
    uartServicePtr = new UARTService(ble);

    /* setup advertising */
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
                                     (const uint8_t *)dev_name, len);
    //ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
    //                                 (const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed));


    ble.gap().setAdvertisingInterval(ADV_INTERVAL);
    ble.gap().setAdvertisingTimeout(BLE_ADVERTISING_DURATION);
    ble.gap().setTxPower(-20); // -30, -20, -16, -12, -8, -4, 0, and 4 dBm

    ble_init_status = BLE_INIT_OK;

    set_radio(true);
}

/// Process BLE Events
void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
    BLE &ble = BLE::Instance();
    eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
}

/// Initialize the BLE Stack
// Returns 0 if OK
ble_init_status_t Init_BLE_Stuff(void)
{
    ble_init_status = BLE_INIT_IN_PROGRESS;
    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(scheduleBleEventsProcessing);
    ble.init(bleInitComplete);

    // Wait for initialization to complete. This is necessary because the
    // BLE object is used after this.
    while(ble_init_status == BLE_INIT_IN_PROGRESS) { wait(0.05);}
    // set up BLE Information services in infoService.cpp
    //ble.gattServer().addService(infoServicePtr);
    return ble_init_status;
}