Direct Bluetooth connection from App(No Particle Cloud)


#62

The callback first gets called when data is written down in BLE here: https://github.com/bluzDK/bluzDK-firmware/blob/develop/platform/MCU/NRF51/SPARK_Firmware_Driver/src/nrf51_callbacks.c#L198

Then, it goes to the feedData command and that is where it checks the ID of the registered service and sends the data to the correct one: https://github.com/bluzDK/bluzDK-firmware/blob/develop/platform/MCU/NRF51/SPARK_Firmware_Driver/src/data_management_layer.cpp#L35

What you are doing looks perfectly valid. Let me try a simple test from my end, but this should be working just fine.


#63

Ah, I found the issue! In your custom_data_service.cpp file, the getServiceID() function is returning the wrong ID. It is still returning the info data service ID of 2, so the system firmware isn’t detecting it properly.

Changing this:

To this:

//DataService functions
int32_t CustomDataService::getServiceID()
{
return CUSTOM_DATA_SERVICE;
}

Fixes the issue and I can now send data down. I had my callback just set the LED on D7, it worked like a charm :smile:


#64

I had actually noticed this and changed it earlier and changed it to what you suggested. But if it is working for you then it must work so I will get to it again first thing tomorrow.

Did you use the code that I posted just as it is above?

Thanks again @eric!


#65

Yes, I had copy+pasted the code exactly. The only difference was that my DataCallback only set the LED and did nothing else. Also, I used the normal bluz iOS app and just added the code to send the same byte stream you had. Otherwise it was the same.


#66

Hey @eric,

Do you have the source for that iOS app on github or is it open source?


#67

I haven’t open sourced it yet, but I really should. Was waiting to get the Android app done first so I could open them both, but there are still a few issues there. If you send me your GutHub username, I can add you.


#68

Hey @eric,

Back on this again. Still nothing yet this morning.

I did have one question though. When I try to call:

nrf_gpio_pin_set(30);

From custom_data_service.cpp I get an error:

MCU/NRF51/SPARK_Firmware_Driver/src/custom_data_service.cpp:25:21: error: 'nrf_gpio_pin_set' was not declared in this scope

To rectify this error I added
#include "nrf_gpio.h"
To custom_data_service.h Did you have to do this as well in order to control the D7 gpio from custom_data_service.cpp? I am just wondering if there is something wrong with my build environment. If something is wrong here I would never know because turning that LED on is currently my only way of knowing if the Data Handler is running or not.


#69

Yes, you would need to include that header file.

Could you also add the line:

nrf_gpio_cfg_output(30);

Directly before you call the _set function? This should work, I was able to get it working on my side.


#70

Hey @eric,

Any way you could zip the project up and send it over? I am just at a loss currently as to why this is working for you but not me. Really strange. What directory are you compiling from also?


#71

Compiling from the modules/ folder.

Let me send you my binaries, that way you can try it from your side and if it doesn’t work, it indicates a problem with the app. I am not home at the moment but will be soon, give me about 45 minutes so I can test first.


#72

Sounds like an awesome plan @eric!!! :slight_smile:


#73

So for a little troubleshooting I added the line:

nrf_gpio_cfg_output(30);

To the top of the data handler in info_data_service.cpp like this:

int32_t InfoDataService::DataCallback(uint8_t *data, int16_t length)
{
	nrf_gpio_pin_set(30);
    switch (data[0]) {
        case GET_ID:
            uint8_t id[12];
            HAL_device_ID(id, 12);
            
            uint8_t rsp[13];
            rsp[0] = INFO_DATA_SERVICE & 0xFF;
            memcpy(rsp+1, id, 12);
            
            DataManagementLayer::sendData(13, rsp);
            break;
    }
    return 1;
}

I then flashed the system-part but not user part as there were no changes made there.

Then I just ran the stock Bluz app. The LED did not turn on. I did hit connect in the app and I have a console print out in the Bluz iOS app to let me know when func requestParticleId runs, and it did. I am really missing something here. That LED should have turned on for sure. I have this in my application.cpp:

/* Includes ------------------------------------------------------------------*/
#include "application.h"

CustomDataService *dService;

int LED = D7;

/* This function is called once at start up ----------------------------------*/
void setup()
{
//	Serial1.begin(115200);
	pinMode(LED,OUTPUT);
//	digitalWrite(LED, LOW);
//	dService = CustomDataService::instance();
}

/* This function loops forever --------------------------------------------*/
void loop()
{
//	Serial1.print("availableBytes: ");
//	Serial1.println(dService->availableBytes);
//	delay(1000);

}

Something is amiss.


#74

You can download my binary files here: http://bluz-scratch.s3-website-us-west-2.amazonaws.com/bluz_custom_data_service.zip

That should tell you if the app is working or not


#75

Ok. I flashed that in there and then ran my app. Did not work. So I took the Bluz app and modified the requestParticleID function like this:

func requestParticleId() {
    NSLog("requestParticleId")
    let nameBuffer = [0x03, 0x00] as [UInt8]
    sendParticleData(NSData(bytes: nameBuffer, length: nameBuffer.count), header: nil)
}

It is now sending 0x03 as the header. I ran that and the LED turned on. Slight sigh of relief.

I then built my code and flashed it into the module and ran the Bluz iOS app just as it was and did not get anything. So there is something wrong with my iOS app and my firmware. However since I now know that I can use the modified version of the Bluz app and it will work I at least have a control in my experimentation here so I can focus on just the firmware, then once I get that working I can move over to the iOS app side.

I really do not know what is different between your Bluz firmware and mine though. When you build the binary outputs go to /build/target/system-part1/platform-103-m/ and /build/target/user-part/platform-103-m/ right? I am just sanity checking at this point.

Is there any way you could upload your firmware source as a zip so I could take a look?

Thanks again @eric I at least feel like I am making a little progress now! :slight_smile:


#76

I actually just checked my code into the develop branch, I figured that was probably easier and it makes a good starting point for anyone that would like to try this out. So if you get latest, than you should have these changes that are working for me.

Let me know if you need anything else.


#77

Success!!! my callback is firing.

Here was the issue. I was including nrf_gpio in the custom_data_service.h file Then I was including the custom_data_service.h file in application.h This seems to have caused a conflict so custom_data_service.cpp was not able to light the LED. That is why your’s worked and mine did not.

I can now move on haha.

Sheesh!!!


#78

How should I reference the CustomDataService object in my application?

This is what I currently have:

custom_data_service.h:

#ifndef CUSTOM_DATA_SERVICE_H_
#define CUSTOM_DATA_SERVICE_H_

#ifdef __cplusplus

#include <stdint.h>
#include <stdlib.h>
#include "data_service.h"
//#include "nrf_gpio.h"

class CustomDataService : public DataService
{
public:
    static CustomDataService* instance();

    //DataService functions
    virtual int32_t getServiceID();
    virtual int32_t DataCallback(uint8_t *data, int16_t length);
    int32_t availableBytes;

private:
    //this is a singleton class, so these all need to be private so they can't be called
    CustomDataService(){
    	availableBytes = 0;
    };
    CustomDataService(CustomDataService const&){
    	availableBytes = 0;
    };
    CustomDataService& operator=(CustomDataService const&);
    static CustomDataService* m_pInstance;
};

#endif
#endif /* CUSTOM_DATA_SERVICE_H_ */

custom_data_service.cpp:

#include <string.h>
#include "custom_data_service.h"
#include "data_management_layer.h"
#include "registered_data_services.h"
#include "deviceid_hal.h"

CustomDataService* CustomDataService::m_pInstance = NULL;

CustomDataService* CustomDataService::instance()
{
    if (!m_pInstance)   // Only allow one instance of class to be generated.
        m_pInstance = new CustomDataService;
    return m_pInstance;

}

//DataService functions
int32_t CustomDataService::getServiceID()
{
    return CUSTOM_DATA_SERVICE;
}
int32_t CustomDataService::DataCallback(uint8_t *data, int16_t length)
{
    switch (data[0]) {
        case 0:
        	availableBytes +=length;
            uint8_t id[12];
            HAL_device_ID(id, 12);

            uint8_t rsp[13];
            rsp[0] = CUSTOM_DATA_SERVICE & 0xFF;
            memcpy(rsp+1, id, 12);

            DataManagementLayer::sendData(13, rsp);
            break;
    }
    return 1;
}

application.cpp:

/* Includes ------------------------------------------------------------------*/
#include "application.h"

SYSTEM_MODE(AUTOMATIC);

int LED = D7;

CustomDataService *cData;

/* This function is called once at start up ----------------------------------*/
void setup()
{
	//Setup the Tinker application here

	//Register all the Tinker functions
//	Particle.function("digitalread", tinkerDigitalRead);
//        Particle.function("digitalwrite", tinkerDigitalWrite);
//
//	Particle.function("analogread", tinkerAnalogRead);
//	Particle.function("analogwrite", tinkerAnalogWrite);
	cData = CustomDataService::instance();
	pinMode(LED, OUTPUT);
	Serial1.begin(115200);
}

/* This function loops forever --------------------------------------------*/
void loop()
{
//    System.sleep(SLEEP_MODE_CPU);
	//This will run in a loop
    Serial1.print("availableBytes: ");
    Serial1.println(cData->availableBytes);
    delay(1000);
}

availableBytes always prints to the log as 0 even though I am absolutely certain that the DataCallback is firing and it is receiving 1 byte each time it fires. Am I referencing my object of the CustomDataService class incorrectly?


#79

That is actually more challenging as it needs to be added to the Wiring level, the HAL layer, and exposed through the dynalib functions. So, I made the change and checked it in. :grinning: If you get latest, you will have the changes in the develop branch.

You can see I made a demo user app called ‘custom_data_service’ that looks just like this:

void dataCallbackHandler(uint8_t *data, uint16_t length) {
digitalWrite(D7, HIGH);
}

void setup() {
pinMode(D7, OUTPUT);
BLE.registerDataCallback(dataCallbackHandler);
}

void loop() {
System.sleep(SLEEP_MODE_CPU);
}

So, you can now just use the BLE.registerDataCallback function and give it your function, then it will be called whenever there is data ready. You would then create a buffer at the user-app level and can store the data in there, if you like, or act upon it immediately. You could keep track of the bytes in the buffer, completely up to you.

Let me know if you have any questions or need anything else.


#80

Should that be available here under the develop branch?


#81

Ah, yes, it is there now. I have created so many example applications that I added the user/applications folder to my .gitignore file to avoid accidentally checking them all in. But of course, it but me on this one!

Sorry about that, the example is now checked in.


Lat-long stamping