Callback in ble scan

// PROTOTYPE
int scan(BleOnScanResultCallback callback, void* context) const;

in ble scan callback what is the use of context variable

This is a variable that allows you to pass in whatever data you want to be known in the callback or have the callback manipulate according to the internal state of the callback.

The callback version of scan does not return until the scan has reached the end of the scan timeout.
You can stop scanning when the desired device is found instead of waiting until the timeout.

This is written in reference doc the Ble .
So now like i want to scan for 30 secs and when i am scanning if i found the beacon i am looking for then scanning can be stopped.
So in such a case i should go with Callback scan or array scan??
if callback scan then as what i think then should i pass the CONTENT with the beacon i am searching for?

That depends on the number of potential devices near your scanning device.
For one, each scan takes some time and hence your timeout might expire before you found the device you are looking for.
On the other hand if you don’t know how many devices you’ll be dealing with, how big would you choose your array to be?

I’m not entirely sure what that is supposed to mean.

well i am having 3 ble devices and what i want is that i want to scan for 30 secs and if in that 30 secs the ble beacon i am looking for if found , then stop the scanning if before 30 secs beacon is found or if beacon is not found at those 30 secs then one of digital pin should be set high.

now when i read the details of Callback Scan array

// PROTOTYPE
int scan(BleOnScanResultCallback callback, void* context) const;
//advantage of using this as stated in reference doc
You can stop scanning when the desired device is found instead of waiting until the timeout.

so how should i use this thing?

The answer is in the docs already
https://docs.particle.io/reference/device-os/firmware/argon/#ble-scan-callback-

This will deal with your 30 seconds condition
https://docs.particle.io/reference/device-os/firmware/argon/#ble-setscantimeout-

And this with the “found then stop” condition
https://docs.particle.io/reference/device-os/firmware/argon/#ble-stopscanning-

And you can use the context parameter to pass in the data you want to use for identifying the specific beacon you are looking for (whatever that criterion would be in your case)

e.g. like this (when looking for a specific name)

  char beaconName[] = "yourBeacon";
  int ret = BLE.scan(yourCallback, beaconName);

so like i am using the UUID of my beacon device for identenfying the specific beacon
like UUId of my beacon is FDA50693-A4E2-4FB1-AFCF-C6EB0

char beaconName=" FDA50693-A4E2-4FB1-AFCF-C6EB0";
BLE.setScanTimeout(3000);
BleScanResult scanResult;
void yourcallback(scanResult,beaconName);
int ret= BLE.scan(yourcallback,beaconName);

is this how should i proceeed ?
well i think their is some thing wrong in this code (that i have written ) ,because i am not able to figure out that how will scan get to know that it has to compare with the UUID only.
So please provide your suggestion and if possible please provide it in the form of code

First, the UUID is not a mere string but needs to be a BleUuid.
Next, even if it were a string, it wouldn’t have a leading blank in it.
Finally, you are not showing the contents of implementation of the callback to check how you’d be checking the scan result against your desired pattern.

However, there already is an example in the docs that shows how to check the address. This can easily be modified to check the UUID.

Finally, you are not showing the contents of implementation of the callback to check how you’d be checking the scan result against your desired pattern.

Well what i understand from this point is.that In the function **void yourcallback(scanResult,beaconName); **
I will set how to scan the ble parameters( like in my case UUID) in the function defination of yourcallback function?

And are you saying the example given here for callback scan.
https://docs.particle.io/reference/device-os/firmware/argon/#ble-scan-callback-

And also can u tell where in docs i will get to know about how to put argon in sleep mode and it’s related info and implementation of RTC and interrupts in argon .
I didn’t find the appropriate doc in the website, so can u please provide with the link.

Would be nice if you tried to find that yourself.
The docs do have a search feature and that will help finding most things (without the need for someone else to do the legwork for you)

Yes, I am.
This is the example code shown there

Well I can’t find where docs have a search feature i have looked a lot number of times but didn’t find that thing.

U can see in the pic i didn’t find the search engine anywhere in the docs.

And now back to ble thing.

Char addr[20];
char beaconaddress="D5:DE:16:73:81:8A";
BLE.setScanTimeout(3000);
BleScanResult scanResult;
void yourcallback(scanResult,beaconaddress);
{
int addrlen = scanResult->address.toString(addr,sizeof(addr));
if(strcmp(addr, beacon address)
Particle.publish("beacon found");
else
Particle.publish("beacon not found");
}
int ret= BLE.scan(yourcallback,beaconaddress);


This is how should things be done…
Now in this argon will scan for 30 secs and when scanning if it founds the ble with the specified address beaconaddress then it will publish beacon found.
Am i right or wrong?

Also just a thing to clarify that scanning will keep on happening for 30 secs and if it founds beacon with given address before 30 secs then scan() will return and ret will be equated to 1.
And if it does not find beacon with given address in those 30 secs then also scan() will return and ret will be equated to 0.

Have you tried landscape and/or desktop view?
On a desktop browser it would be in the right corner

Granted, not showing the search feature in on mobile browsers is a questionable decission. Maybe @marekparticle can chime in on that and forward this to the individual(s) responsible for the website design.

About your search logic: Again, you are treating non-string data (i.e. address and UUID) as strings.
It may work *) that way but it’s definetly not best practice.

Nope, that’s why I provided you with the other link about BLE.stopScanning().
Your code is responsible for stopping the scan and the BLE.scan() call wil return the number of devices it scanned up to the stop call.


*) Besides, the syntax is wrong

  • there is no datatype Char (with capital C)
  • char beaconaddress would only be a single character and not a string
  • function definitions are not supposed to be found inside other functions (unless it’s a lambda function)
  • there is a stray semicolon (;) after the function signature
  • strcmp() returns 0 when a match is found
  • the closing parenthesis on the condition is missing
  • you are using a illegal variable name beacon address (internal spaces are not allowed)

You should also not use Particle.publish() inside the callback handler and you should scope pubishes as PRIVATE.

1 Like

Well yeah okay In desktop view it shows and i found the docs i am looking for.

And i just typed the logic in the comment not focusing on syntax errors at that time so that things i have taken care of.

Now coming back to ble thing…

  1. You above in the comment 6 mentioned the beaconname as string and passed it in scan () as string with call back function and if beaconadress (which is my void context argument ) would be character then how will i compare for my specific beacon?
  2. and as you said Ble.scan will return number of devices it scanned up to the stop call. So what us the purpose of using it in form of callback ?
    as what i am thought is that using Ble.scan in the form if callback form – it will scan for 30 secs (setScanTimeout(3000)) and if it founds the specific beacon ( through context argument) then only Ble.scan () will return.

This was meant as an illustration not a suggestion as I also said

So when you are not checking for a name (type string) but an address (type BleAddress) or a UUID (type BleUuid) then you’d use the type you intend to be looking for.

The callback function is initiated for each device the scanning task finds - one callback call per device.
It’s up to that callback function to discern whether this particular found device is the one you are looking for. Since only you know what you are looking for it is up to you to provide the logic that performs the check (and optionally stop the scan when satisfied).

The context argument is not automatically used to recognise the device, it is just a way to “inject” extra data for the device check (or to communicate some data back to the calling function). Your own implementation must utilise it as required by your intent and function logic.

When you want to scan for a particular BleAddress and you actually pass in a context of that type you can use this function to check for a match
https://docs.particle.io/reference/device-os/firmware/argon/#equality-bleaddress-

Okay so now say if i want to compare by
address then it would be like this

BLE.setScanTimeout(3000)
BleAddress adress;
BleScanResult scanResult;
void yourcallback(scanResult, adress);
int ret= Ble.scan(yourcallback,adress);

Uuid then it would be like this

BLE.setScanTimeout(3000)
BleUuid uuid;
BleScanResult scanResult;
void yourcallback(scanResult, uuid);
int ret= Ble.scan(yourcallback,uuid);

And now suppose i passed nothing in my context and i find the specific beacon like this.
Is it also fine?

BLE.setScanTimeout(3000)
BleScanResult scanResult;
uint8_t custom_data[BLE_MAX_ADV_DATA_LEN];   BLE_MAX_ADV_DATA_LEN=31bytes;
void yourcallback(scanResult, void * context)
{
    if (scanResult->advertisingData.customData(custom_data, sizeof(custom_data)) == 25)
    {
        if (custom_data[0] == 0x4c && custom_data[1] == 0x00 && custom_data[2] == 0x02 && custom_data[3] == 0x15)
        {   
       
            Serial.println("beacon found")
Ble.stopScanning();
        }
    }
    else
{Serial.println("beacon not found");}

int ret= Ble.scan(yourcallback,uuid);

As in this way i am just checking whether some scanned advertising data bytes are as per my ble device or not . So will it work?

So i can choose context as BleAdress, BleUuid, string , character , int …as per the comparison i prefer for searching my specific ble device.

Okay but how should i assign the
BleAddress address with the address that i want to be searched for , so that i can compare it for equality with the scanned address …which i get from this statement in addr variable.

int addrlen = scanResult->address.toString(addr,sizeof(addr));
( This line will be under the definition of callback function when using it with BleAddress type)

A few more points

  • void yourcallback(scanResult, adress) has no business there - if it is a function prototype it needs to be in the definition block (before any function implementation)
  • int ret= Ble.scan(yourcallback,adress); would need to be int ret= Ble.scan(yourcallback, &adress); as you are passing a pointer to the actual variable as context, not the variable itself
  • same goes for the UUID example.

I cannot really answer on the custom data sample as I don’t know your custom data payload, but in principle this could work.

Correct, you’d just pass in the pointer to that data.

The docs for BleAddress list a collection of constructors and setters to do that.
One way would be

BleAddress myAddr("D5:DE:16:73:81:8A", BleAddressType::PUBLIC);

The second parameter is optional but must match the address type you are looking for.

However, you still can use a string comparison like this

  // with unknown address type but only known MAC address
  if (!strcmp(scanResult->address.toString(), myAddr->toString()))

(myAddr would be your BleAddress variable that holds the address you are looking for)

Okay thanks for help :+1:

Good call-out. We only have a mobile search bar on support.particle.io (which can search the entire site), but that’s pretty opaque. Thanks for bringing this to my attention!

1 Like

payload of custom data is the Manufacture specific advertising data which contains bytes of company identifier bytes(0x4c00),advertising indicators (0x02 & 0x15) ,UUId, major, minor, power

The advertisement packet contains the Bluetooth MAC address and the payload. The payload is composed of two AD Structures, the first one(AD0) gives generic information using the Flags Data Type, and the second(AD1) is the Apple specific iBeacon information.–Manufacture specific advertising data

Now i have written code like this

const size_t SCAN_RESULT_MAX = 30;
// BlescanResult is the class in which the data of the scanned beacons is stored.
//scanResults is the object of that class

BleScanResult scanResults;


//custum_data[] stores the manufacture specific data of the beacon 
    //get_data[] stores the advertising data as a complete block of the beacon
    uint8_t custom_data[BLE_MAX_ADV_DATA_LEN];   //BLE_MAX_ADV_DATA_LEN=31bytes
    uint8_t get_data[BLE_MAX_ADV_DATA_LEN];      //BLE_MAX_ADV_DATA_LEN=31bytes

    void yourcallback(scanResults, NULL)
{
    if (scanResults->advertisingData.customData(custom_data, sizeof(custom_data)) == 25)
    {
        if (custom_data[0] == 0x4c && custom_data[1] == 0x00 && custom_data[2] == 0x02 && custom_data[3] == 0x15)
        {   
       
            Serial.println("beacon found")
            Ble.stopScanning();
        }
    }
    else
{Serial.println("beacon not found");}


void setup() 

{

   pinMode(D5,OUTPUT);
   pinMode(D7,OUTPUT);
    Serial.begin(9600);
  Serial.println("Adafruit GPS library basic test!");

}

void loop()

{
    
    BLE.setScanTimeout(50);
    //this statement do the scanning , if in scanning it detects ble beacon then
    //all the  scanned data can be accesed by scanResults object.
     // and this function does not return untill it scans for any beacon device

    int count= Ble.scan(yourcallback,NULL);

    itoa(count,buffera,10);
    Particle.publish("noofdevices",buffera);

 }
 

Now i am getting error like this and i am not to makeout how to solve these errors.
So any suggestions…

When you hit the SHOW RAW button you can get more info about the reasons.

But you cannot put ‘NULL’ in the function definition. It is only allowed in the function call.
For a function definition your parameter list also must state the data types for them.

Adopting a consistent indentation scheme makes it also easier to not forget closing braces (} - which you are lacking one before void setup()).

It appears that you may be lacking the C fundamentals to tackle these kinds of projects on your own.