New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
simple ble interface #623
simple ble interface #623
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks pretty good. The test function is pretty simple and readable for all the functionality it provides. A couple of comments for you.
return 0; | ||
} | ||
|
||
const char* get_error(int err) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, this has already been written: https://github.com/helena-project/tock/blob/master/userland/libtock/tock.c#L178
|
||
// BLE DATA FIELD | ||
uint8_t addr[] = {1, 2, 3, 4, 5, 6}; | ||
uint16_t advertising_itv_ms = 300; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would spell out interval here advertising_interval_ms
err = ble_initialize(advertising_itv_ms, | ||
LE_LIMITED_DISCOVERABLE | BREDR_NOT_SUPPORTED, | ||
addr, | ||
sizeof(addr)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, sizeof
on buffers allocated on the local stack (EDIT: see below) does work successfully. However, I'd argue that it's a bad practice to do so. In the general case, sizeof
does not work on buffers, and using them this way leads to mistakes (like someone making a buffer global instead of local and code suddenly breaking).
I'd suggest replacing them with explicit lengths.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, is this explanation really correct? I thought it has nothing to do whether there are stored on stack or in data segment since there are evaluated at compile-time? However, since arrays are automatically converted to pointers upon a function call you can not use sizeof then because you get the word size then. But send a link if I'm wrong this got me curious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing some research shows you to be correct Niklas. sizeof
works on any named buffer. So like you say, it fails when used on a buffer is passed through a function call, but works on any local buffer on the stack or global buffer in the same file.
I've always learned it to be a bad practice though, probably because beginning programmers do not notice the difference, and using sizeof
on the other side of a function boundary is a common mistake. I could see the argument that it is appropriate here.
userland/libtock/ble.h
Outdated
// initialize advertisement (should be used before invoken ble_start_advertising) | ||
// | ||
// advertising_itv_ms - advertisement interval in milliseconds | ||
// flags - flags in the advertisement defined in GapFlags_t enum |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why expose flags to the user rather than just selecting the right ones? For instance, users will always have to specify BREDR_NOT_SUPPORTED
.
I would suggest replacing this with a is_connectable
bool and then have the code automatically select the flags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure it is a better idea
userland/libtock/ble.h
Outdated
// start send BLE advertisement periodically according to the configured interval | ||
// if no interval is connected it will use a pre-configured value | ||
// data - array of bytes to write the received advertisment to | ||
// len - size in bytes of data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a maximum length, right? I'd rename it to max_len
(or something like that).
Also, how does the actual received size get returned?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it won't currently if I remember correct, the capsule only writes the number of bytes it receives and notifies the user-space app.
userland/libtock/ble.h
Outdated
// if no interval is connected it will use a pre-configured value | ||
// data - array of bytes to write the received advertisment to | ||
// len - size in bytes of data | ||
// callback - callback handler to call when an advertisement is received |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the type signature of the callback handler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static void callback(__attribute__((unused)) int unused0,
__attribute__((unused)) int unused1, __attribute__((unused)) int unused2,
__attribute__((unused)) void* ud);
It was like that before at least
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest documenting in that header file what the parameters in the callback actually mean. If I was going to write code that scanned for advertisements, I wouldn't know what the parameters I get in the callback actually mean without reading through the kernel code.
userland/libtock/ble.h
Outdated
// | ||
// device_name - device named to be used in the advertisement | ||
// len - size in bytes | ||
int ble_advertise_name(uint8_t *device_name, uint8_t size_b); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this class of advertisement functions, what are the possible return values? What value is returned if the advertisement data is now too long to advertise?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
turns out the "capsule" returned SUCCESS regardless good catch but now it returns ESIZE when the buffer is full.
userland/libtock/ble.c
Outdated
static int s_ble_cfg_gap_data (GapAdvertisementData_t header, uint8_t *data, uint8_t len); | ||
|
||
// local VARIABLES | ||
static uint8_t s_gap[GAP_DATA_MAX_SIZE]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does the s
stand for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static, well I named all things that have file scope as s_xxx_yyy but I can remove it if it's annoying
userland/libtock/ble.c
Outdated
if (data_len + 2 > GAP_DATA_MAX_SIZE) { | ||
return TOCK_FAIL; | ||
}else { | ||
memset(s_gap, 0, GAP_DATA_MAX_SIZE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not make s_gap
as a local buffer on the stack in this function instead of a file variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
Thank you @brghena for excellent feedback. |
the |
Yes, it will not work because it uses the old API, the only application that work with this is: I will not modify anything until we have reached consensus 馃槂 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really great! I think it's pretty close to being able to support pretty cleanly and simply the kinds of applications @brghena et al have been doing with the NRF5x anyway, which is pretty cool.
My main concern is thinking about how this interface works when there are multiple processes using it. In general, I think it's simple to just allow each process to configure a separate advertising packet, and interleave those, but the ble_initialize
function throws a wrench in that.
userland/libtock/ble.h
Outdated
// passed back to user-space thus userspace must loop through the entire | ||
// buffer. | ||
// | ||
// TODO: add functionlity in kernel to pass back the size of the received |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems important to do before merging.
userland/libtock/ble.c
Outdated
int err; | ||
|
||
// configure advertisement interval | ||
// if the interval is less than 20 or bigger than 10240 to kernel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"...the kernel..."
userland/libtock/ble.c
Outdated
* INTERNAL BLE HELPER FUNCTION Prototypes | ||
* | ||
* s_ - static (file scope) | ||
******************************************************************************/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be useful to have comments for what these functions do, even though they are internal helper functions.
userland/libtock/ble.c
Outdated
* USER-SPACE BLE API | ||
******************************************************************************/ | ||
|
||
int ble_initialize(uint16_t advertising_itv_ms, bool discoverable, uint8_t *addr, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think a good question is whether we want to allow users-pace to set the BLE address, or whether that should be in the kernel (or potentially in a separate driver that eventually is only accessible by privileged processes or something).
Consider the situation where we have two processes sending advertisements. We can interleave different advertising packets from each process with the same address no problem. We can also, in principle, send different advertising packets with different addresses from each process, but it becomes more complicated if they the device is connectable. Specifically, I'm not sure it will be as easy to have the device actually connect on two different addresses (though might be an interesting piece of engineering to attempt).
There are various ways we can imagine breaking ties, for example only actually responding to connection handshakes one address at a time, but it's worth considering what we actually want to do.
Regardless it's probably also worth allowing the process to not choose an address (perhaps by passing NULL
and 0
to addr
and addr_len
, respectively), and then defaulting to either an address a different process has already set, or something reasonable the kernel decides on (e.g. an address based on the hardware MAC address or something).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the busy flag in the capsule should at least protect against "races" in changing advertising address for now.
However it may limit concurrency which also is a valid question to consider as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't really think about it before, but it's probably a good idea for the kernel to set the BLE address of the device and for the application to have no input on it. However, this isn't how the nRF SDK works, so if we made that change, it would be a difference between serialized and native applications.
The exception would be if we really could virtualize everything about BLE, changing addresses with each advertisement and accepting connections to specific applications, but that sounds pretty tough.
(edit: I posted this somewhere else, but it really belongs here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, but it sounds like it is best to let kernel decide the address for now then?
Should be pretty easy to use the TRNG driver to generate 6 random bytes if you want that?
But should all functions be completely re-written because it is still possible have interleaving between configuring advertisement_interval, configure different data (device_name, uuids etc) in the packet.
But after _start
the busy flag will be set and block the entire thing as it is right now
I think you @alevy and @brghena has to decide this because I don't know how to approach this.
EDIT: well, I guess each process have its own grant but that doesn't matter because both are writing to the buffer which the DMA are reading from.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think for now having the kernel control the address is best.
From the perspective of this PR, just having passed into the driver as a configuration variable in the board setup seems fine. The point is it's not up to the process. There are several ways we can set the address in the kernel (e.g. there is also a 64-bit unique device identifier in the FICR controller for the NRF52; randomness could work too). But that's for a different PR, it's not about the interface.
As far as other functions in the userland interface are concerned, I don't think they are problematic in the same way. I think at the moment (i.e. given the current state of the driver in the kernel) interleaving won't work as we expect, but we know how to make it work. In particular, you'll just store the data for each process's configured advertising packet in a grant and, in the kernel, switch between which one you're sending to interleave them. So, for example, if I have two processes, one with a 50ms advertising interval, and another with a 100ms advertising interval, my actual on-air packets might look something like this:
Time Packet
==== ======
0 ---> "process 1 packet"
25 ms ---> "process 2 packet"
50 ms ---> "process 1 packet"
75 ms ---> no_data
100 ms ---> "process 1 packet"
125 ms ---> "process 2 packet"
150 ms ---> "process 1 packet"
Again, it's fine if the kernel driver doesn't do that just yet, as long as the interface supports it.
As for scanning, I think basically all incoming scanned packets should be delivered to all processes that have subscribed to scans. In the future we could maybe add functions that allow processes to configure filters for which packets they actually want to receive (and I can imagine implementing this in a combination of hardware and software in the kernel).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely what I was thinking too Amit.
userland/libtock/ble.c
Outdated
err = s_ble_cfg_flags(flags); | ||
if (err < TOCK_SUCCESS) return err; | ||
|
||
// if this is NULL advertisment address {0, 0, 0, 0, 0, 0} will be used |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does {0, 0, 0, 0, 0, 0}
have a particular meaning? If so, processes should be explicit rather than using NULL
. If not, than maybe this should promise less---i.e. it will use some preconfigured address either from another process or from the kernel.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it means that kernel will use preconfigured adress which is better.
I will change.
userland/libtock/ble.h
Outdated
int ble_stop_advertising(void); | ||
|
||
// reset the entire advertisement data packet | ||
// excluding flags and advertisement address |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this also implicitly stop advertising?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, but it perhaps should?
@niklasad1 how do you feel about the comments? Do you think that all the feedback you need or are there other open questions about the interface? |
Yeah, I think it is only to remove the configure advertisement option. But in there is more to do as follows: Progess
Thoughts? |
I think that division of work for this PR vs future PRs is right. |
Is this good enough for merge? I have removed |
userland/libtock/simple_ble.h
Outdated
// TODO: add functionlity in kernel to pass back the size of the received | ||
// advertisement | ||
// | ||
int ble_start_passive_scan_wip(uint8_t *data, uint8_t len, subscribe_cb callback); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to postfix the name with _wip
There is a superfluous |
some fixes according to feedback remove option to configure address in advertisement migrate to Tock 1.0 format simple ble interface
Pull Request Overview
This pull request simplifies the Bluetooth Low Energy API in user-space
Testing Strategy
This pull request was tested by running the test application tutorials/xx_ble_adv
A screenshot from Nordic Connect Android App can be found here:
Screenshot
TODO or Help Wanted
I want feedback on the BLE API and what should be different etc?
@brghena @alevy 馃槂
After feedback I will continue to add wrapper for Eddystone as @brghena suggested and update existing example apps since this will break those.
Documentation Updated
/docs
have been updated or no updates are required.Formatting
make formatall
has been run.