Add support for notify (untested)

This commit is contained in:
Philip Gladstone 2022-01-06 02:10:53 +00:00
parent 7e123b215e
commit 7aa22335ac
2 changed files with 63 additions and 9 deletions

View File

@ -65,6 +65,7 @@ static uint8_t *gadget_mfg;
static size_t gadget_mfg_len; static size_t gadget_mfg_len;
static const struct ble_gatt_svc_def *gatt_svr_svcs; static const struct ble_gatt_svc_def *gatt_svr_svcs;
static const uint16_t *notify_handles;
static task_handle_t task_handle; static task_handle_t task_handle;
static QueueHandle_t response_queue; static QueueHandle_t response_queue;
@ -401,7 +402,7 @@ cleanup:
} }
static int static int
lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp) { lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp, const uint16_t **handlep) {
// We have to first figure out how big the allocated memory is. // We have to first figure out how big the allocated memory is.
// This is the number of services (ns) + 1 * sizeof(ble_gatt_svc_def) // This is the number of services (ns) + 1 * sizeof(ble_gatt_svc_def)
// + number of characteristics (nc) + ns * sizeof(ble_gatt_chr_def) // + number of characteristics (nc) + ns * sizeof(ble_gatt_chr_def)
@ -434,7 +435,7 @@ lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp) {
MODLOG_DFLT(INFO, "Discovered %d services with %d characteristics\n", ns, nc); MODLOG_DFLT(INFO, "Discovered %d services with %d characteristics\n", ns, nc);
int size = (ns + 1) * sizeof(struct ble_gatt_svc_def) + (nc + ns) * sizeof(struct ble_gatt_chr_def) + (ns + nc) * sizeof(ble_uuid_any_t); int size = (ns + 1) * sizeof(struct ble_gatt_svc_def) + (nc + ns) * sizeof(struct ble_gatt_chr_def) + (ns + nc) * sizeof(ble_uuid_any_t) + (nc + 1) * sizeof(uint16_t);
struct ble_gatt_svc_def *svcs = malloc(size); struct ble_gatt_svc_def *svcs = malloc(size);
@ -447,6 +448,9 @@ lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp) {
void *eom = ((char *) svcs) + size; void *eom = ((char *) svcs) + size;
struct ble_gatt_chr_def *chrs = (struct ble_gatt_chr_def *) (svcs + ns + 1); struct ble_gatt_chr_def *chrs = (struct ble_gatt_chr_def *) (svcs + ns + 1);
ble_uuid_any_t *uuids = (ble_uuid_any_t *) (chrs + ns + nc); ble_uuid_any_t *uuids = (ble_uuid_any_t *) (chrs + ns + nc);
uint16_t *handles = (uint16_t *) (uuids + ns + nc);
handles[0] = 0; // number of slots used
// Now fill out the data structure // Now fill out the data structure
// -1 is the services list // -1 is the services list
@ -496,11 +500,11 @@ lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp) {
int flags = 0; int flags = 0;
lua_getfield(L, -2, "read"); lua_getfield(L, -2, "read");
if (lua_isboolean(L, 1) && lua_toboolean(L, -1)) { if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
flags = BLE_GATT_CHR_F_READ; flags = BLE_GATT_CHR_F_READ;
} }
lua_getfield(L, -3, "write"); lua_getfield(L, -3, "write");
if (lua_isboolean(L, 1) && lua_toboolean(L, -1)) { if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
flags |= BLE_GATT_CHR_F_WRITE; flags |= BLE_GATT_CHR_F_WRITE;
} }
if (flags) { if (flags) {
@ -524,6 +528,16 @@ lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp) {
lua_pop(L, 3); // pop off value, read, write lua_pop(L, 3); // pop off value, read, write
} }
if (lua_getfield(L, -1, "notify") != LUA_TNIL) {
chr->flags |= BLE_GATT_CHR_F_NOTIFY;
handles[0]++;
lua_pushinteger(L, handles[0]);
lua_setfield(L, -2, "notify");
chr->val_handle = &handles[handles[0]];
}
lua_pop(L, 1);
// -1 is now the characteristic again // -1 is now the characteristic again
chr->arg = (void *) luaL_ref(L, LUA_REGISTRYINDEX); chr->arg = (void *) luaL_ref(L, LUA_REGISTRYINDEX);
chr->access_cb = lble_access_cb; chr->access_cb = lble_access_cb;
@ -534,6 +548,7 @@ lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp) {
lua_pop(L, 1); lua_pop(L, 1);
*resultp = result; *resultp = result;
*handlep = handles;
return 0; return 0;
} }
@ -546,7 +561,7 @@ gatt_svr_init(lua_State *L) {
struct ble_gatt_svc_def *svcs = NULL; struct ble_gatt_svc_def *svcs = NULL;
lble_build_gatt_svcs(L, &svcs); lble_build_gatt_svcs(L, &svcs, &notify_handles);
//free_gatt_svcs(L, gatt_svr_svcs); //free_gatt_svcs(L, gatt_svr_svcs);
gatt_svr_svcs = svcs; gatt_svr_svcs = svcs;
@ -736,7 +751,7 @@ lble_gap_event(struct ble_gap_event *event, void *arg)
return 0; return 0;
} }
static int static int
lble_update_adv_fields() { lble_update_adv_fields() {
struct ble_hs_adv_fields fields; struct ble_hs_adv_fields fields;
const char *name = gadget_name; const char *name = gadget_name;
@ -785,7 +800,7 @@ lble_update_adv_fields() {
fields.name_len = fields.name_len - 1; fields.name_len = fields.name_len - 1;
fields.name_is_complete = 0; fields.name_is_complete = 0;
} }
if (!fields.name_is_complete) { if (!fields.name_is_complete) {
struct ble_hs_adv_fields scan_response_fields; struct ble_hs_adv_fields scan_response_fields;
memset(&scan_response_fields, 0, sizeof scan_response_fields); memset(&scan_response_fields, 0, sizeof scan_response_fields);
@ -886,7 +901,7 @@ gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
} }
} }
static int static int
lble_update_adv_change(lua_State *L) { lble_update_adv_change(lua_State *L) {
free((void *) gadget_mfg); free((void *) gadget_mfg);
gadget_mfg = NULL; gadget_mfg = NULL;
@ -906,7 +921,7 @@ lble_update_adv_change(lua_State *L) {
return 0; return 0;
} }
static int static int
lble_update_adv(lua_State *L) { lble_update_adv(lua_State *L) {
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lble_update_adv_change(L); lble_update_adv_change(L);
@ -918,6 +933,23 @@ lble_update_adv(lua_State *L) {
return 0; return 0;
} }
static int lble_notify(lua_State *L) {
if (inited != RUNNING) {
return luaL_error(L, "ble is not yet running");
}
int handle = luaL_checkinteger(L, 1);
luaL_argcheck(L, handle <= 0 || handle > notify_handles[0], 1, "handle out of range");
ble_gatts_chr_updated(notify_handles[handle]);
/*
if (rc) {
return luaL_error(L, "Must supply a valid handle");
}
*/
return 0;
}
static int lble_init(lua_State *L) { static int lble_init(lua_State *L) {
if (inited != STOPPED) { if (inited != STOPPED) {
@ -1020,6 +1052,7 @@ static int lble_shutdown(lua_State *L) {
LROT_BEGIN(lble, NULL, 0) LROT_BEGIN(lble, NULL, 0)
LROT_FUNCENTRY( init, lble_init ) LROT_FUNCENTRY( init, lble_init )
LROT_FUNCENTRY( notify, lble_notify )
LROT_FUNCENTRY( advertise, lble_update_adv ) LROT_FUNCENTRY( advertise, lble_update_adv )
LROT_FUNCENTRY( shutdown, lble_shutdown ) LROT_FUNCENTRY( shutdown, lble_shutdown )
LROT_END(lble, NULL, 0) LROT_END(lble, NULL, 0)

View File

@ -36,6 +36,26 @@ local config = {name="MyGadget=", services={ myservice, battery }
ble.init(config) ble.init(config)
``` ```
## ble.notify()
This notifies the Bluetooth stack that a new value is available to be read from the characteristic.
#### Syntax
`ble.notify(characteristic)`
#### Parameters
- `characteristic` This is the table that was passed into the `init` method for the particular characteristic.
#### Returns
`nil`
#### Example
```lua
ble.notify(config.services[1].characteristics[1])
```
## ble.advertise() ## ble.advertise()
Updates the advertising data field for future advertising frames. Updates the advertising data field for future advertising frames.
@ -103,6 +123,7 @@ The characteristic table contains the following keys:
- `value` This is the actual value of the characteristic. This will be a string of bytes unless a `type` value is set. - `value` This is the actual value of the characteristic. This will be a string of bytes unless a `type` value is set.
- `read` This is a function that will be invoked to read the value (and so does not need the `value` entry). It should return a string of bytes (unless `type` is set). - `read` This is a function that will be invoked to read the value (and so does not need the `value` entry). It should return a string of bytes (unless `type` is set).
- `write` This is a function that will be invoked to write the value (and so does not need the `value` entry). It is given a string of bytes (unless `type` is set) - `write` This is a function that will be invoked to write the value (and so does not need the `value` entry). It is given a string of bytes (unless `type` is set)
- `notify` If this attribute is present with the value `true` then notifications are supported on this characteristic.
If the `value` key is present, then the characteristic is read/write. However, if one or `read` or `write` is set to `true`, then it restricts access to that mode. If the `value` key is present, then the characteristic is read/write. However, if one or `read` or `write` is set to `true`, then it restricts access to that mode.