Simple program to enable me to write to a 128x64 OLED display over BLE

Dependencies:   Adafruit_GFX BLE_API mbed nRF51822 SemVer

main.cpp

Committer:
rosterloh84
Date:
2015-03-30
Revision:
1:9e9c52d8270a
Parent:
0:d89c10040630

File content as of revision 1:9e9c52d8270a:

/**
 *  @file
 *  @date   30 March 2015
 *  @author Richard Osterloh <richard.osterloh@gmail.com>
 */
 
#include "mbed.h"
#include "BLEDevice.h"
#include "DeviceInformationService.h"
#include "UARTService.h"

#include "Adafruit_SSD1306.h"
#include "SemVer.h"

#define NEED_CONSOLE_OUTPUT 1 /* Set this if you need debug messages on the console;
                               * it will have an impact on code-size and power consumption. */

#if NEED_CONSOLE_OUTPUT
#define DEBUG(...) { if (uartServicePtr) uartServicePtr->writeString(__VA_ARGS__); }
#else
#define DEBUG(...) /* nothing */
#endif /* #if NEED_CONSOLE_OUTPUT */

SemVer version("1.0.0");

BLEDevice  ble;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

InterruptIn btn1(BUTTON1);

DigitalOut oled_gnd(p3);

// an I2C sub-class that provides a constructed default
class I2CPreInit : public I2C
{
public:
    I2CPreInit(PinName sda, PinName scl) : I2C(sda, scl)
    {
        oled_gnd = 0;
        frequency(400000);
        start();
    };
};

I2CPreInit gI2C(p5, p4); // SDA, SCL
Adafruit_SSD1306_I2c gOled(gI2C, p2, 0x78, 64, 128); // I2C, RST, ADDRESS, WIDTH, HEIGHT

bool rxPayloadUpdated = false;
const static unsigned MAX_SIZEOF_RX_PAYLOAD = 20;
char rxPayload[MAX_SIZEOF_RX_PAYLOAD] = {0,};

UARTService *uartServicePtr;

const static char     DEVICE_NAME[] = "BLE DISPLAY";
static const uint16_t uuid16_list[] = {GattService::UUID_DEVICE_INFORMATION_SERVICE};
                    
/**
 *  Callback to write to connected client and display
 */
void buttonCallback(void)
{
    if(btn1) {
        gOled.clearDisplay();
        gOled.printf("%s", "BTN 0 released");
        gOled.display();
        uartServicePtr->writeString("Button 0 released\r\n");
    } else {
        gOled.clearDisplay();
        gOled.printf("%s", "BTN 0 pressed");
        gOled.display();
        uartServicePtr->writeString("Button 0 pressed\r\n");
    }
}

/**
 * Callback when new client connects to device
 * 
 * @param tHandle handle to this specific client
 * @param ePeerAddrType the type of the connected clients address
 * @param c6PeerAddr the address of the connected client
 * @param params requested connection parameters
 */
void connectionCallback(Gap::Handle_t tHandle, Gap::addr_type_t ePeerAddrType, const Gap::address_t c6PeerAddr, const Gap::ConnectionParams_t *params)
{
    //DEBUG("CONNECT: Handle:%u, eType:%d, Add:%u\r\n", tHandle, ePeerAddrType, c6PeerAddr);
    //DEBUG("         minInterval:%d, maxInterval:%d, latency:%d, timeout:%d\r\n",
    //          params->minConnectionInterval, params->maxConnectionInterval, params->slaveLatency, params->connectionSupervisionTimeout);
    DEBUG("CONNECTED\r\n");
    led2 = 1; led4 = 0;
}

/**
 * Callback called when a client disconnects
 * 
 * @param tHandle handle of the disconnected client
 * @param eReason the reason they disconnected
 */
void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
{
    DEBUG("Disconnected!\n\r");
    DEBUG("Restarting the advertising process\n\r");
    ble.startAdvertising();
    led2 = 0; led4 = 1;
}

/**
 * Callback called when a client writes to this device
 * 
 * @param params all parameters related to this data
 */
void onDataWritten(const GattCharacteristicWriteCBParams *params)
{
    if ((uartServicePtr != NULL) && (params->charHandle == uartServicePtr->getTXCharacteristicHandle())) {
        uint16_t bytesRead = params->len;
        if (bytesRead < MAX_SIZEOF_RX_PAYLOAD) {
            strncpy(rxPayload, (const char *)params->data, MAX_SIZEOF_RX_PAYLOAD - 1);
            rxPayload[bytesRead] = '\0';
            rxPayloadUpdated = true;
            ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(), params->data, bytesRead);
        }
    }
}

void periodicCallback(void)
{
    led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */
}

int main(void)
{
    led1 = 1; led2 = 1; led3 = 1; led4 = 1;
    Ticker ticker;
    ticker.attach(periodicCallback, 1);
    btn1.fall(buttonCallback);
    btn1.rise(buttonCallback);

    DEBUG("Initialising the nRF51822\n\r");
    ble.init();
    ble.onConnection(connectionCallback);
    ble.onDisconnection(disconnectionCallback);
    ble.onDataWritten(onDataWritten);
    
    DeviceInformationService deviceInfo(ble, "NORDIC", "NRF51-DK", DEVICE_NAME, "HW-00", version.getVersion().c_str());
    
    /* setup advertising */
    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(100));
    ble.startAdvertising();

    UARTService uartService(ble);
    uartServicePtr = &uartService;
    
    while (true) {
        if (rxPayloadUpdated) {
            gOled.clearDisplay();
            gOled.printf("%s", rxPayload);
            gOled.display();

            rxPayloadUpdated = false;
        }

        ble.waitForEvent();
    }
}