Locally connect the nrf BLE to Bluz gateway



I am working with BluzDK and I have changed it’s firmware as per my requirements. So, Now I want my gateway to communicate to my nrf ble(since I’ve changed the firmware so it is no more bluzDK).

For that I uploaded the particle bluz gateway code in the gateway shield with Photon P0, but it is not getting connected with the nrf ble, but on the other hand it has the capability to connect with another bluzDK.

What should I need to change so that the gateway can communicate to my NRF BLE?

Please help!


That depends on the changes you made. Did you change the underlying system firmware? Did you change the services and characteristics that bluz uses? If so, you would have to change the gateway accordingly.

Also, the gateway connects based on the advertised name, so you may have to change that as well. That can be done by calling a function on the gateway, however, and doesn’t require firmware changes.


I am flashing the following code in my photon(in the gateway). Is it the same code where I need to make changes so that the gateway starts connecting to nrf51 ble ?


// //Core
// #if PLATFORM_ID==0
// #define SLAVE_ALERT_PIN 16
// #define SLAVE_SELECT A2
// #endif

#define SLAVE_ALERT_PIN 16

// //P1
// #if PLATFORM_ID==8
// #define SLAVE_ALERT_PIN A0
// #endif

// //Electron
// #if PLATFORM_ID==10
// #define SLAVE_ALERT_PIN 16
// #define SLAVE_SELECT A2
// #endif

#define CLOUD_DOMAIN "device.spark.io"
// #define CLOUD_DOMAIN ""
#define RX_BUFFER 1024
#define MAX_CLIENTS 4

#define NRF51_SPI_BUFFER_SIZE 255


/**@brief Gateway Protocol states. */
typedef enum
} gateway_service_ids_t;

typedef enum
} gateway_socket_function_t;

typedef struct
    TCPClient socket;
    bool connected = false;
} client_t;

client_t m_clients[MAX_CLIENTS];

void debugPrint(String msg) {
    Serial.println(String(millis()) + ":DEBUG: " + msg);

String gatewayID = "No gateway detected yet.";
int timeGatewayConnected;
bool gatewayIDDiscovered;

void handle_custom_data(uint8_t *data, int length) {
    //if you use BLE.send from any connected DK, the data will end up here

void setup() {
    timeGatewayConnected = -1;
    gatewayIDDiscovered = false;
    Particle.variable("gatewayID", gatewayID);
    digitalWrite(SLAVE_SELECT, HIGH);
    digitalWrite(MASTER_READY_PIN, LOW);

// bool requestIDFlag = false;
// void requestRequestID() {
//     requestIDFlag = true;
// }

void requestID() {
    uint8_t dummy[6] = {(( (6-SPI_HEADER_SIZE-BLE_HEADER_SIZE) & 0xFF00) >> 8), ( (6-SPI_HEADER_SIZE-BLE_HEADER_SIZE) & 0xFF), MAX_CLIENTS-1, INFO_DATA_SERVICE, 0, 0};
    spi_send(dummy, 6);

// Timer timer(20000, requestRequestID, true);

char hexToAscii(uint8_t byte)
    static const char asciimap[] = "0123456789abcdef";
    return asciimap[byte & 0x0f];

void parseID(char *destination, uint8_t *buffer)
    int gatewayIndex = 0;
    for (int i = 0; i < 12; i++) {
        destination[gatewayIndex++] = hexToAscii( ((buffer[i] >> 4) & 0xF) );
        destination[gatewayIndex++] = hexToAscii( (buffer[i] & 0xF) );
    destination[gatewayIndex] = 0x00;

void spi_data_process(uint8_t *buffer, uint16_t length, uint8_t clientId)
    uint8_t serviceID = buffer[0];
    debugPrint("Processing message of size " + String(length) + " with clientID " + String(clientId) + " and service ID " + String(serviceID));
    switch (serviceID) 
            uint8_t type = (buffer[1] >> 4 & 0x0F);
            uint8_t socketId = (buffer[1] & 0xF);
            switch (type) {
                case SOCKET_CONNECT:
                    // Particle.publish("Connecting Client", String(clientId));
                    debugPrint("Connecting Client" + String(clientId));
                    if (m_clients[clientId].connected) {
                        m_clients[clientId].connected = false;
                    while (!m_clients[clientId].socket.connected()) {
                        m_clients[clientId].socket.connect(CLOUD_DOMAIN, 5683);
                    m_clients[clientId].connected = true;
                    if (clientId == MAX_CLIENTS-1) {
                        //this is the gateway nrf, get the ID
                        // timer.start();
                        timeGatewayConnected = millis();
                case SOCKET_DISCONNECT:
                    // Particle.publish("Disconnecting Client", String(clientId));
                    debugPrint("Disconnecting Client" + String(clientId));
                    if (m_clients[clientId].connected) {
                        m_clients[clientId].connected = false;
                case SOCKET_DATA:
                    m_clients[clientId].socket.write(buffer+BLE_HEADER_SIZE, length-BLE_HEADER_SIZE);
                    // Particle.publish("Wrote bytes to cloud", String(clientId) + "->Cloud  - " + String(i));
                    debugPrint(String(clientId) + "->Cloud  - " + String(length-BLE_HEADER_SIZE));
        case INFO_DATA_SERVICE:
            char id[25];
            parseID(id, buffer+1);
            gatewayID = String(id);
            debugPrint("You're gateway ID is " + String(id));
            Particle.publish("bluz gateway device id", String(id));
            handle_custom_data(buffer+1, length-1);

void spi_retreive() {
    debugPrint("In SPI Receive");
    digitalWrite(MASTER_READY_PIN, HIGH);
    while (digitalRead(SLAVE_ALERT_PIN) == LOW) { }
    digitalWrite(MASTER_READY_PIN, LOW);
    debugPrint("Handshake complete");
    //get the length of data available to read
    digitalWrite(SLAVE_SELECT, LOW);
    uint8_t byte1 = SPI.transfer(0xFF);
    uint8_t byte2 = SPI.transfer(0xFF);
    digitalWrite(SLAVE_SELECT, HIGH);
    //if the nrf51 isn't ready yet, we receve 0xAA, so we wait
    while (byte1 == 0xAA && byte2 == 0xAA) {
        digitalWrite(SLAVE_SELECT, LOW);
        byte1 = SPI.transfer(0xFF);
        byte2 = SPI.transfer(0xFF);
        digitalWrite(SLAVE_SELECT, HIGH);
    int serialBytesAvailable = (byte1 << 8) | byte2;
    debugPrint("Receiving SPI data of size " + String(serialBytesAvailable));
    //if there is no data, we're done
    if (serialBytesAvailable == 0) { return; }
    uint8_t tx_buffer[TX_BUFFER];
    //read the data one chunk at a time
    for (int chunkIndex = 0; chunkIndex < serialBytesAvailable; chunkIndex+=NRF51_SPI_BUFFER_SIZE)
        while (digitalRead(SLAVE_ALERT_PIN) == LOW) { }
        digitalWrite(SLAVE_SELECT, LOW);
        uint16_t chunkSize = (serialBytesAvailable-chunkIndex > NRF51_SPI_BUFFER_SIZE ? NRF51_SPI_BUFFER_SIZE : serialBytesAvailable-chunkIndex);
        debugPrint("Reading chunk of size " + String(chunkSize));
        for (int innerIndex = 0; innerIndex < chunkSize; innerIndex++) {
            tx_buffer[chunkIndex+innerIndex] = SPI.transfer(0xFF);
        digitalWrite(SLAVE_SELECT, HIGH);
        //give the nrf51 time to resognize end of transmission and set SA back to LOW
        //if the nrf51 wasn't ready yet, we will receive this
        if (tx_buffer[chunkIndex] == 0xAA && tx_buffer[chunkIndex+chunkSize-1] == 0xAA) {
    //now process the data one message at a time
    int msgPointer = 0;
    while (msgPointer < serialBytesAvailable) {
        int msgLength = (tx_buffer[msgPointer] << 8) | tx_buffer[msgPointer+1];
        uint8_t clientId = tx_buffer[msgPointer+2];
        //move the pointer past the header
        msgPointer += SPI_HEADER_SIZE;
        spi_data_process(tx_buffer+msgPointer, msgLength+BLE_HEADER_SIZE, clientId);
        debugPrint("Read length = " + String(msgLength));
        msgPointer += msgLength+BLE_HEADER_SIZE;

void spi_send(uint8_t *buf, int len) {
    uint8_t rxBuffer[len];
    debugPrint("Starting to send data");
    //nrf51822 can't handle SPI data in chunks bigger than 256 bytes. split it up
    for (int i = 0; i < len; i+=254) {
        uint16_t size = (len-i > 254 ? 254 : len-i);
        digitalWrite(SLAVE_SELECT, LOW);
        for (int j = 0; j < size; j++) {
            rxBuffer[j+1] = SPI.transfer(buf[j+i]);
        if (size >= 254) {
        digitalWrite(SLAVE_SELECT, HIGH);
        //if the nrf51 wasn't ready yet, we will receive this
        if (rxBuffer[i] == 0xAA && rxBuffer[i+size-1] == 0xAA) {
            debugPrint("Resetting the counter since i only see AA");
    debugPrint("Completed Sending");

void loop() {
    //Electron, just connect
    //WiFi device, enter listening mode if need be
    if (!Particle.connected()) {
        if (!waitFor(Particle.connected, 60000)) {
    for (int clientId = 0; clientId < MAX_CLIENTS; clientId++) {
        if (!m_clients[clientId].connected) {continue;}
        if (!m_clients[clientId].socket.connected()) {
            // debugPrint("We think we are connected, but this socket is closed: " + String(clientId));
        int bytesAvailable = m_clients[clientId].socket.available();
        if (bytesAvailable > 0) {
            //Spark devices only support 128 byte buffer, but we want one SPI transaction, so buffer the data
            uint8_t rx_buffer[RX_BUFFER+BLE_HEADER_SIZE+SPI_HEADER_SIZE];
            int rx_buffer_filled = BLE_HEADER_SIZE+SPI_HEADER_SIZE;
            while (bytesAvailable > 0) {
                for (int i = 0; i < bytesAvailable; i++) {
                    rx_buffer[i+rx_buffer_filled] = m_clients[clientId].socket.read();
                rx_buffer_filled += bytesAvailable;
                bytesAvailable = m_clients[clientId].socket.available();
            //add SPI header
            rx_buffer[0] = (( (rx_buffer_filled-BLE_HEADER_SIZE-SPI_HEADER_SIZE) & 0xFF00) >> 8);
            rx_buffer[1] = ( (rx_buffer_filled-BLE_HEADER_SIZE-SPI_HEADER_SIZE) & 0xFF);
            rx_buffer[2] = (uint8_t)clientId;
            //add BLE header, default to socket id of 0 for now since we only support one at the moment
            rx_buffer[3] = SOCKET_DATA_SERVICE;
            rx_buffer[4] = ((SOCKET_DATA << 4) & 0xF0) | (0 & 0x0F);;
            // Spark.publish("Bytes Available", String(rx_buffer_filled));
            spi_send(rx_buffer, rx_buffer_filled);
            // Particle.publish("Sending bytes through SPI", String(clientId) + "->BLE    - " + String(rx_buffer_filled));
            debugPrint(String(clientId) + "->BLE    - " + String(rx_buffer_filled));
            //now send the data
            // Spark.publish("Pushed this many bytes through SPI", String(totalBytes));
    if (digitalRead(SLAVE_PTS_PIN))
    if (timeGatewayConnected > 0 && millis() - timeGatewayConnected > 20000 && !gatewayIDDiscovered) {
        debugPrint("Asking for id");
        gatewayIDDiscovered = true;
        // requestIDFlag = false;


First, if posting a large amount of code, can please you put markdown back-ticks around it? That prevents large walls of code that make the forum harder to browse. Or, you can post code to something like GitHub Gist and post a link. I edited your previous post to make it easier to read.

On to your question. This is probably not the code you want to change, but I am not sure as I don’t know what you changed in the bluz DK code. If you changed the services/characteristics that bluz uses, you will have to change the gateway source code. That is the firmware that runs on the nrf51 board on the gateway itself.

What did you change in bluz?


I actually flashed a firmware a heart rate monitor. I am able to use it locally only using Bluetooth and an app. But I want to use the same over the cloud also, that’s why I wan to use the Bluz gateway. Can you please let me show the path about how can I achieve this ?


That would be pretty difficult. If you’ve completely wiped out the system firmware of bluz and replaced it, then having it talk to the cloud through the gateway is impossible.

The system firmware of bluz handles things like encryption with the cloud and the processing of events. It uses specific services and characteristics to talk to gateways which relay that data to the cloud. What you really would want to do is adapt the heart rate monitor code to run on top of the bluz system firmware, not simply replace it. Depending on your use case and the code you are trying to run, that may be difficult or hard.

Are you interfacing with an external sensor? It may be possible to write the code that talks to it as a bluz app, it would be the easiest way


Hi Eric,

I found this Direct Bluetooth connection from App(No Particle Cloud) conversation. I think I want to do something similar like this only. Following these instructions will help me OR not ?

Thanks Eric.


I’m still not quite sure what you are trying to do, so it is difficult to give advice. Have you replaced the bluz system firmware?

In the end, you can certainly use bluz as an nrf51822 development board and flash whatever firmware that you like. But if you have done that, getting it to work with other bluz accessories, like our gateways, wild be hard and require a lot of custom work. Plus, you wouldn’t be able to talk to the Particle cloud.

Can you perhaps provide more detail on what you are trying to accomplish and what specifically you have tried so far?


Hi Eric,

Yes, I have replaced bluz system firmware. And I am using nrf connect app to read and write the characteristics. And this is working locally within the bluetooth range.

But now I want to do this OTA also means, locally + OTA control to my device.
And I understand you that if I change the firmware of bluz then it will not talk to particle cloud.

So should I make some changes in bluz firmware and flash it in my bluz so that both the things i.e. local communication and OTA communication can take place?

Thanks again.


Thanks for the details.

Yes, it sounds like like should try to merge the application you want to use (heart rate monitor) into the bluz firmware stack. To do this, you should rewrite the application using the standard bluz firmware functions and calls.

This will not allow you to keep the same services and characteristics that the application currently has. To do that, you would have to alter the bluz system firmware, which could be done, it is just a lot more work.

If ultimately you are trying to get data from a sensor and send it to the cloud, I would recommend trying to interface directly to the sensor from the bluz user firmware. It will give you all the Particle support and allow you to read from the device. What kind of sensor are you trying to talk to?


Thanks Eric,

I am using a simple digital pulse sensor connected with bluzdk. As you said that I need to make change in bluz firmware and application, I am following this https://github.com/bluzDK/bluzDK-firmware/blob/develop/docs/gettingstarted.md to do so. Am I following the correct path ?

If yes, then I am getting several errors while running make commands. I think I am doing something wrong in downloading and installing crc32 thing. Please let me know how can I proceed from here.

Thank You :slight_smile:


Those commands aren’t quite correct, they are from the Particle side and don’t directly translate to bluz. I will put that on my list to update.

You can use the commands here to compile, this is about all you need: Direct Bluetooth connection from App(No Particle Cloud)


Hi Eric,

Thanks for your support, I tried to run above commands as per your instructions and still I am getting this error:

> Invoking: ARM GNU Create Flash Image
> arm-none-eabi-objcopy -O binary ../../../build/target/system-part1/platform-103-m/system-part1.elf ../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc
> if [ -s ../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc ]; then \
>         head -c $((`stat --print %s ../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc` - 38)) ../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc > ../../../build/target/system-part1/platform-103-m/system-part1.bin.no_crc && \
>         tail -c 38 ../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc > ../../../build/target/system-part1/platform-103-m/system-part1.bin.crc_block && \
>         test "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20280078563412" = `xxd -p -c 500 ../../../build/target/system-part1/platform-103-m/system-part1.bin.crc_block` && \
>         ../../../build/bin/win32/sha256sum ../../../build/target/system-part1/platform-103-m/system-part1.bin.no_crc | cut -c 1-65 | xxd -r -p | dd bs=1 of=../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc seek=$((`stat --print %s ../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc` - 38)) conv=notrunc  && \
>         head -c $((`stat --print %s ../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc` - 4)) ../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc > ../../../build/target/system-part1/platform-103-m/system-part1.bin.no_crc && \
>          crc32 ../../../build/target/system-part1/platform-103-m/system-part1.bin.no_crc | cut -c 1-10 | xxd -r -p | dd bs=1 of=../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc seek=$((`stat --print %s ../../../build/target/system-part1/platform-103-m/system-part1.bin.pre_crc` - 4)) conv=notrunc ;\
>         fi
> /bin/sh: line 1: stat: command not found
> /bin/sh: line 3: xxd: command not found
> /bin/sh: line 3: test: 0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20280078563412: unary operator expected
> make[1]: *** [../../../build/target/system-part1/platform-103-m/system-part1.bin] Error 2
> make[1]: Leaving directory `E:/Electronics/Particle/Bluz/bluzDK-firmware/modules/bluz/system-part1'
> make: *** [E:/Electronics/Particle/Bluz/bluzDK-firmware/modules/bluz/system-part1/makefile] Error 2

> E:\Electronics\Particle\Bluz\bluzDK-firmware\modules>

Please suggest me How can I resolve this error.

Thank again :slight_smile:


I think there are some extra steps for compiling on Windows, I am a Mac and Linux user so I am not the specialist for the Windows setup.

However, since our firmware is directly derived from Particle, all their advice is valid here. There is a good thread on their forums about compiling for Windows: https://community.particle.io/t/toolchain-for-windows-installer/13217

It was written to by @mumblepins who is active on both forums and may be able to provide assistance as well.

Let me know if that helps to fix your issue


Hi Eric,

I am using linux ubuntu now and still getting some errors…like:

Invoking: ARM GCC C Compiler
mkdir -p ../build/target/communication/platform-103-m-prod-103/./lib/mbedtls/library/
arm-none-eabi-gcc -DSTM32_DEVICE -DNRF51 -DPLATFORM_THREADING=0 -DPLATFORM_ID=103 -DPLATFORM_NAME=bluz -DUSBD_VID_SPARK=0x1D50 -DUSBD_PID_DFU=0x607F -DUSBD_PID_CDC=0x607D -g3 -Os -mcpu=cortex-m0 -mthumb -mfloat-abi=soft -mabi=aapcs -DSOFTDEVICE_PRESENT -DBLE_STACK_SUPPORT_REQUIRED -DNRF51 -DNRF51822_QFAA_CA -DBLE_STACK_SUPPORT_REQD -DUSE_CUSTOM_STATIC_ASSERT -DBLUZ -DPRODUCT_ID=103 -DPRODUCT_FIRMWARE_VERSION=65535 -DSYSTEM_VERSION_STRING=2.0.50 -DRELEASE_BUILD -Werror -I./src -I../hal/inc -I../hal/shared -I../dynalib/inc -I../services/inc -I./lib/mbedtls/include -I./lib/tropicssl/include -Ilib/tropicssl/include -I. -MD -MP -MF ../build/target/communication/platform-103-m-prod-103/./lib/mbedtls/library/debug.o.d -ffunction-sections -fdata-sections -Wall -Wno-switch -Wno-error=deprecated-declarations -fmessage-length=0 -fno-strict-aliasing -DSPARK=1 -DPARTICLE=1 -DSTART_DFU_FLASHER_SERIAL_SPEED=14400 -DSTART_YMODEM_FLASHER_SERIAL_SPEED=28800 -DMBEDTLS_CONFIG_FILE="<mbedtls_config.h>" -DUSER_FIRMWARE_IMAGE_SIZE=0x9000 -DUSER_FIRMWARE_IMAGE_LOCATION=0x00033000 -DMODULAR_FIRMWARE=1 -DMODULE_VERSION=7 -DMODULE_FUNCTION=4 -DMODULE_INDEX=1 -DMODULE_DEPENDENCY=0,0,0 -std=gnu99 -Wno-pointer-sign -std=gnu99 -c -o ../build/target/communication/platform-103-m-prod-103/./lib/mbedtls/library/debug.o lib/mbedtls/library/debug.c
/bin/sh: arm-none-eabi-gcc: command not found
../build/module.mk:211: recipe for target '../build/target/communication/platform-103-m-prod-103/./lib/mbedtls/library/debug.o' failed
make[2]: *** [../build/target/communication/platform-103-m-prod-103/./lib/mbedtls/library/debug.o] Error 127
make[2]: Leaving directory '/home/amitt/Downloads/bluzDK-firmware/communication'
../../../build/recurse.mk:11: recipe for target 'communication' failed
make[1]: *** [communication] Error 2
make[1]: Leaving directory '/home/amitt/Downloads/bluzDK-firmware/modules/bluz/system-part1'
makefile:94: recipe for target '/home/amitt/Downloads/bluzDK-firmware/modules/bluz/system-part1/makefile' failed
make: *** [/home/amitt/Downloads/bluzDK-firmware/modules/bluz/system-part1/makefile] Error 2

I am using gcc 4.8.5. I have installed all dependencies. When I am running make command in modules folder, getting this type of error. Please help me in finding the issue.

Thanks. :slight_smile:


Hi Eric,

I was doing something wrong. Now I am on right track. I followed the instructions of Launchpad to install the gcc arm compiler and invoking gcc.

I am successfully able to create binary files of my application code. Thank you for your continuous support.
Now I’m trying to merge my locally connect code into the bluz firmware so please let me know what should I change and what should I need to add to bluz firmware for locally communication.



Hi @eric

We are following the steps as recommended by you in your previous reply. From that we are able to generate the hex and the bin files of our application code.(For eg. blinky.hex and blinky.bin). And when we tried the the make command from firmware root directory, we were able to generate the bootloader.hex file, But when we are flashing it in bluzDK using STLinkV2, no result can be seen on Bluz.

It neither behaves as a BLE device nor it’s RGB led lids up. So we tried to to flash a bootloader.hex and softdevice.hex with the blinky.hex, but then also, no positive results. When we tried > adalink nrf51822 -p stlink -i the output is:

SD version: None (SD version before flashing it was: S110 8.0.0)

So, basically when we are flashing our application code, it wipes the whole firmware and application only gets into it. And we also tried to flash bootloader.hex with that and separately also, but it does not worked!

Please let us know about how can we compile and flash whole firmware ?

Thanks :slight_smile:


There are 4 parts to the bluz firmware, you can read more here: http://docs.bluz.io/tutorials/updates/

You do need to flash all 4 parts every time if you are using the STLink as it erases the flash before it programs the device.

You only need to do this if you are altering the underlying system firmware. If you are writing an app on top, you can use the Web IDE instead.


Hey guys, just wanted to say that this is an amazing topic to follow and read. Thank you!


HI @eric,
I am flashing the firmware successfully with the help of STLink as per your guidance. Thanks a ton :slight_smile:

I am using the custom data service to send data directly to bluz. In the firmware, where can I define my particular data which will be sent to bluz? I am not understanding what format should I use to write the data on bluz. I have read somewhere on forum that the data format will be 0x04 + Data + 0x0304 but actually not getting about this.

I am using NRF Connect app to send data.

Thanks :slight_smile: