Seeking advice on BLE periph function vs central. Actually, a process flow of sorts...

For CircuitPython issues, ask in the Adafruit CircuitPython forum.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
lmolter
 
Posts: 61
Joined: Wed Jan 01, 2014 1:29 pm

Seeking advice on BLE periph function vs central. Actually, a process flow of sorts...

Post by lmolter »

Is it more acceptable that a peripheral store a value upon its initialization (not connection) and then advertise? The central will connect and then ask for the value? Or... upon connection, the peripheral will notify the central that it has a value and the central can then read it?

<disclaimer> BLE is all new to me, and I haven't seen an example yet that helps answer my questions.

The project (and I've posted requests earlier for thoughts but there were none): A small IoT device (nrf52832 + Music Maker Featherwing) has an SD card with music tracks stored on it. The tracks are guitar backing tracks and once selected, the track will play until stopped. When my phone connects to it, I need a list of the files to display on the phone for selection and subsequent playback on the IoT device (details withheld for simplicity).

Not knowing the correct or acceptable way to do this, I thought about this flow:

1) IoT reads card and stores the track count and the track list in persistent (global?) variables;

2) IoT goes into advertise mode;

3) Central connects to IoT (manually for now) and asks for the track count via a READ characteristic on the IoT;

4) If track count > 0, central will read the track names via another READ characteristic for as many tracks there
are and fill a listbox. Not sure how to implement the looping;

5) User will select a track from the phone and WRITE the index (not the filename) to a characterisitic on the IoT which will play it continuously;

6) Other buttons on the phone will WRITE control messages to STOP and PAUSE to another characteristic;

7) A volume slider will WRITE to a volume characteristic;

So, in this implementation suggestion, the central does all the controlling of the peripheral. Only the track count is read from the peripheral at connection time.

Any constructive thoughts?

User avatar
lmolter
 
Posts: 61
Joined: Wed Jan 01, 2014 1:29 pm

Re: Seeking advice on BLE periph function vs central. Actually, a process flow of sorts...

Post by lmolter »

I over-complicated it. The peripheral will read the directory into an array at startup and will send the filenames (8.3) one by one to the central upon connection. No need for a read request from central for the file count. If there's no SD card inserted or if it's empty, maybe send an error packet. That's phase 2. Not sure how to handshake the sending. Maybe not necessary.

I like replying to myself -- it helps me sort things out.

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: Seeking advice on BLE periph function vs central. Actually, a process flow of sorts...

Post by adafruit_support_mike »

Explaining a problem to someone else is a common way of finding solutions yourself. It forces you to arrange the ideas in a reasonably sensible way, and to really think about all the half-formed ideas that seem good enough while they're in your head.
lmolter wrote: Mon Feb 27, 2023 1:02 pm Is it more acceptable that a peripheral store a value upon its initialization (not connection) and then advertise? The central will connect and then ask for the value? Or... upon connection, the peripheral will notify the central that it has a value and the central can then read it?
Those are alternatives rather than solutions that can be ranked as better or worse. The question is, "what do you gain or lose either way?"

The general topic that covers your question is the programming concept of 'early or late binding'.. basically, when do you have to commit to choosing the value of a variable?

Early binding includes setting values as literals or constants in source code: the value is determined before the code even goes through the compiler, which is about as early as you can get. Early binding is useful when calculating a value is expensive, or when you need to share lots of copies of it. You can do the expensive part once and then pass around copies of the result that are cheap and easy to create. There's also a category of shared-information and resource allocation problems that are easier to handle efficiently if you define a value early and never change it.

Early binding becomes a disaster if anything changes after you choose the initial value though. Trying to keep track of copies and propagate changes through a bunch of shared information is Very Hard.

Late binding gives you the flexibility to deal with new information as long as possible, at the cost of more complexity in handling the values. The extreme forms are known as 'lazy execution' and 'promises'.

With lazy execution, you store the calculation that will produce a value as a piece of code that hasn't been executed yet, and only run the code at the last possible moment. That allows for some neat applications, like defining the integers as a sequence of functions that return two values: the value for N and the function to call when you want N+1 (which returns N+1 and the function for N+2). You can pass a lazy list to a function that will need some part of the list, even when you don't know how much. The function will keep generating (value,next-item) pairs until it decides it's done, then return.

A 'promise' (at least one form) is similar to a lazy list in the sense of returning an 'execute this next' item, but it's used for complex operations with parts that can fail. If you have to fill a large data structure with information pulled from databases, other servers, or other programs, a function can't just chunk it out all at once. Instead, it returns a function whose return value is either the data structure or another promise to create the data structure. The sequence of 'call this next' items can traverse an intensely complicated path of functions to get information, error recovery functions, fallback values, and so on, eventually ending when one of them can finally deliver a well-formed data structure.


Both early and late binding have complicated relationships with 'side effects'.. things a function can do that are visible outside the function, but aren't included in the return value. The print() function is one of the most common examples of a side effect: you get output on the screen/printer/Serial Monitor that has no obvious relationship to the return value of the function where the print() occurs in code. If you imagine the 'execute this next' items from a lazy list or promise printing information when they're executed, it's easier to imagine the difference between passing around a dozen copies of an integer and passing around a dozen copies of a promise to generate an integer.

There are no right or wrong answers to which is better though.. if you're building a security system you might want every attempt to use a password to go through a full 2FA authorization challenge. OTOH, if logging is expensive and the value isn't important, you might prefer to calculate it once and then pass around copies of the result.


Coming back to the project you described, we can imagine asking, "should the peripheral create a single value that any central will see?" or "would it be desirable for the peripheral to remember a separate value for each central it's seen in the past?"

User avatar
lmolter
 
Posts: 61
Joined: Wed Jan 01, 2014 1:29 pm

Re: Seeking advice on BLE periph function vs central. Actually, a process flow of sorts...

Post by lmolter »

@adafruit_support_mike

I really appreciate the time you spent explaining early and late binding. I feel bad for admitting this, but I have scrapped this BLE project for the foreseeable future. The biggest issues were: 1) Lack of pertinent examples (yes, I know Adafruit has a plethora of example code -- it was just an issue of finding what I was specifically looking for; 2) Not BLE-related, but the lack of long filename support on the nrf52832 was a deal-breaker.

So... I wimped out and bought a Bluetooth dongle with a miniature phone jack to connect to my amp, and a suitable, gapless mp3/wav playback app for my Android phone. I've solved my problems with no programming, no more hair pulling, and no more frustration having to design and build both the Feather and the phone apps. More time to play the blues now.

<shameless plug> Adafruit has the best stuff and the best support (once you get their attention).

Regards,
Larry Molter

User avatar
adafruit_support_mike
 
Posts: 67391
Joined: Thu Feb 11, 2010 2:51 pm

Re: Seeking advice on BLE periph function vs central. Actually, a process flow of sorts...

Post by adafruit_support_mike »

No worries. That's the nature of the development process. Sometimes you decide an approach isn't as attractive as it seemed, and move on to something else. Glad to hear you've found an option you like better.

Happy hacking!

Locked
Please be positive and constructive with your questions and comments.

Return to “Wireless: WiFi and Bluetooth”