The firmware of the Grove Node

Dependencies:   BLE_API color_pixels mbed-src-nrf51822 nRF51822

Fork of BLE_LoopbackUART by Bluetooth Low Energy

main.cpp

Committer:
yihui
Date:
2015-06-04
Revision:
11:c0885b74a63a
Parent:
10:f34ff4e47741

File content as of revision 11:c0885b74a63a:

/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "mbed.h"
#include "BLEDevice.h"
#include "DFUService.h"
#include "UARTService.h"
#include "nrf_delay.h"
#include "battery.h"

#define DEBUG   0

#if DEBUG       // for Arch BLE
#define LOG(...)        { printf(__VA_ARGS__); }
#define BUTTON_DOWN     1
#define LED_ON          1
#define LED_OFF         0

DigitalOut  blue(p30);
DigitalOut  green(p17);
InterruptIn button(p5);
#else           // for Grove Node BLE
#define LOG(...)
#define BUTTON_DOWN     0
#define LED_ON          0
#define LED_OFF         1

DigitalOut  blue(p18);
DigitalOut  green(p17);
InterruptIn button(p30);
#endif

Battery battery(p5);

BLEDevice  ble;
UARTService *uartServicePtr;
Ticker ticker;

volatile bool ble_is_connected = false;

volatile bool button_event = false;

const int MAX_ARGS = 8;
char *argv[MAX_ARGS];

static const uint8_t SIZEOF_TX_RX_BUFFER = 32;
uint8_t rxPayload[SIZEOF_TX_RX_BUFFER] = {0,};

extern "C" void power_on();
extern "C" void power_off();

extern void node_init();
extern void node_tick();
extern void node_parse(int argc, char *argv[]);

int button_detect();

void connectionCallback(Gap::Handle_t handle, const Gap::ConnectionParams_t *params)
{
    LOG("Connected\n");
    ble_is_connected = true;
}

void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
{
    LOG("Disconnected!\n");
    LOG("Restarting the advertising process\n");
    ble.startAdvertising();
    ble_is_connected = false;
}

void onDataWritten(const GattCharacteristicWriteCBParams *params)
{
    if ((uartServicePtr != NULL) && (params->charHandle == uartServicePtr->getTXCharacteristicHandle())) {
        uint16_t bytesRead = params->len;
        LOG("received %u bytes\n\r", bytesRead);
        if (bytesRead < sizeof(rxPayload)) {
            memcpy(rxPayload, params->data, bytesRead);
            rxPayload[bytesRead] = '\0';
        }
        
        LOG("%s\n", (char *)rxPayload);

        char *piece = strtok((char *)rxPayload, " ");
        int argc = 0;
        while (piece && argc < MAX_ARGS) {
            argv[argc++] = piece;
            piece = strtok(0, " ");
        }
        
        if (argc > 0) {
           node_parse(argc, argv);
        }
        
    }
}

void tick(void)
{
    node_tick();
}

void button_down(void)
{
    button_event = true;
}

int main(void)
{
    power_on();
    blue = LED_ON;
    green = LED_ON;
    
#if BUTTON_DOWN
    button.mode(PullDown);
    button.rise(button_down);
#else
    button.mode(PullUp);
    button.fall(button_down);
#endif

    LOG("Initialising the nRF51822\n");
    ble.init();
    ble.onConnection(connectionCallback);
    ble.onDisconnection(disconnectionCallback);
    ble.onDataWritten(onDataWritten);

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

    DFUService dfu(ble);

    UARTService uartService(ble);
    uartServicePtr = &uartService;
    
    ble.setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */
    ble.startAdvertising();
    
    node_init();
    ticker.attach(tick, 1);

    blue = LED_OFF;
    green = LED_OFF;
    
    while (true) {
        if (button_event) {
            int click;
            
            green = LED_ON;
            click = button_detect();
            green = LED_OFF;
            LOG("click type: %d\n\r", click);
            
            button_event = false;
            
            if (1 == click) {
            } else if (2 == click) {
                //green = LED_ON;
            } else if (-1 == click) {
                green = LED_OFF;
                blue = LED_OFF;
                while (BUTTON_DOWN == button.read()) {
                    
                }
                nrf_delay_us(3000);
                
                power_off();
            } else {
                continue;
            }

        } else {
            ble.waitForEvent();
        }
    }
}

int button_detect(void)
{
    int t = 0;
    
    while (1) {
        if (button.read() != BUTTON_DOWN) {
            if (t < 30) {
                return 0;     // for anti shake
            } else {
                break;
            }
        }
        
        if (t > 30000) {        // More than 3 seconds
            return -1;          // long click
        }
        
        t++;
        nrf_delay_us(100);
    }
    
    if (t > 4000) {             // More than 0.4 seconds
        return 1;               // single click
    }
    
    while (true) {
        if (button.read() == BUTTON_DOWN) {
            nrf_delay_us(1000);
            if (button.read() == BUTTON_DOWN) {
                return 2;      // double click
            }
            
            t += 10;
        }
        
        if (t > 4000) {
            return 1;          // The interval of double click should less than 0.4 seconds, so it's single click
        }
        
        t++;
        nrf_delay_us(100);
    }
}