First attempt to add name support to characteristics
This commit is contained in:
parent
94833123a8
commit
aaaa440d16
|
@ -56,6 +56,16 @@
|
||||||
|
|
||||||
#define PERROR() MODLOG_DFLT(INFO, "pcall failed: %s\n", lua_tostring(L, -1))
|
#define PERROR() MODLOG_DFLT(INFO, "pcall failed: %s\n", lua_tostring(L, -1))
|
||||||
|
|
||||||
|
#ifdef CONFIG_LUA_VERSION_51
|
||||||
|
#define lua_rawlen lua_objlen
|
||||||
|
static int lua_geti (lua_State *L, int index, lua_Integer i) {
|
||||||
|
index = lua_absindex(L, index);
|
||||||
|
lua_pushinteger(L, i);
|
||||||
|
lua_gettable(L, index);
|
||||||
|
return lua_type(L, -1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void ble_hs_lock();
|
extern void ble_hs_lock();
|
||||||
extern void ble_hs_unlock();
|
extern void ble_hs_unlock();
|
||||||
|
|
||||||
|
@ -249,7 +259,8 @@ lble_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_acces
|
||||||
|
|
||||||
int rc = BLE_ATT_ERR_UNLIKELY;
|
int rc = BLE_ATT_ERR_UNLIKELY;
|
||||||
|
|
||||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR ||
|
||||||
|
ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||||
rc = message.errcode;
|
rc = message.errcode;
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
if (os_mbuf_append(ctxt->om, message.buffer, message.length)) {
|
if (os_mbuf_append(ctxt->om, message.buffer, message.length)) {
|
||||||
|
@ -282,6 +293,8 @@ lble_task_cb(task_param_t param, task_prio_t prio) {
|
||||||
lua_getfield(L, -1, "type");
|
lua_getfield(L, -1, "type");
|
||||||
// -1 is the struct mapping (if any), -2 is the table
|
// -1 is the struct mapping (if any), -2 is the table
|
||||||
|
|
||||||
|
size_t datalen;
|
||||||
|
const char *data = 0;
|
||||||
if (task_block->ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
if (task_block->ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||||
// if there is a read method, then invoke it
|
// if there is a read method, then invoke it
|
||||||
lua_getfield(L, -2, "read");
|
lua_getfield(L, -2, "read");
|
||||||
|
@ -326,20 +339,15 @@ lble_task_cb(task_param_t param, task_prio_t prio) {
|
||||||
lua_remove(L, -2); // remove the old value
|
lua_remove(L, -2); // remove the old value
|
||||||
// now have string (-1), struct(-2), chrtable (-3)
|
// now have string (-1), struct(-2), chrtable (-3)
|
||||||
}
|
}
|
||||||
size_t datalen;
|
data = lua_tolstring(L, -1, &datalen);
|
||||||
const char *data = lua_tolstring(L, -1, &datalen);
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
message.buffer = malloc(datalen);
|
|
||||||
if (message.buffer) {
|
|
||||||
message.length = datalen;
|
|
||||||
memcpy(message.buffer, data, datalen);
|
|
||||||
message.errcode = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lua_pop(L, 1);
|
|
||||||
message.errcode = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (task_block->ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) {
|
||||||
|
lua_getfield(L, -2, "name");
|
||||||
|
// Now we have the name (-1), struct (-2), table (-3)
|
||||||
|
data = lua_tolstring(L, -1, &datalen);
|
||||||
|
}
|
||||||
|
|
||||||
if (task_block->ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
if (task_block->ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||||
// Push the value
|
// Push the value
|
||||||
lua_pushlstring(L, task_block->buffer, task_block->length);
|
lua_pushlstring(L, task_block->buffer, task_block->length);
|
||||||
|
@ -398,10 +406,19 @@ lble_task_cb(task_param_t param, task_prio_t prio) {
|
||||||
} else {
|
} else {
|
||||||
lua_pop(L, 1); // Throw away the null write pointer
|
lua_pop(L, 1); // Throw away the null write pointer
|
||||||
}
|
}
|
||||||
lua_pop(L, 1); // Throw away the value
|
|
||||||
message.errcode = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
message.buffer = malloc(datalen);
|
||||||
|
if (message.buffer) {
|
||||||
|
message.length = datalen;
|
||||||
|
memcpy(message.buffer, data, datalen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1); // Throw away the value
|
||||||
|
message.errcode = 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
lua_settop(L, top);
|
lua_settop(L, top);
|
||||||
message.seqno = task_block->seqno;
|
message.seqno = task_block->seqno;
|
||||||
|
@ -424,6 +441,7 @@ lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp, const uint
|
||||||
|
|
||||||
// -1 is the services list
|
// -1 is the services list
|
||||||
int nc = 0;
|
int nc = 0;
|
||||||
|
int nd = 0;
|
||||||
for (int i = 1; i <= ns; i++) {
|
for (int i = 1; i <= ns; i++) {
|
||||||
MODLOG_DFLT(INFO, "Counting -- service %d (top %d)\n", i, lua_gettop(L));
|
MODLOG_DFLT(INFO, "Counting -- service %d (top %d)\n", i, lua_gettop(L));
|
||||||
lua_geti(L, -1, i);
|
lua_geti(L, -1, i);
|
||||||
|
@ -437,13 +455,23 @@ lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp, const uint
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// -1 is the service again
|
// -1 is the service again
|
||||||
lua_getfield(L, -1, "characteristics");
|
lua_getfield(L, -1, "characteristics");
|
||||||
nc += lua_rawlen(L, -1);
|
int sccnt = lua_rawlen(L, -1);
|
||||||
|
nc += sccnt;
|
||||||
|
// Now count the number of descriptors that we need
|
||||||
|
for (int j = 1; j <= sccnt; j++) {
|
||||||
|
lua_geti(L, -1, j);
|
||||||
|
if (lua_getfield(L, -1, "name") != LUA_TNIL) {
|
||||||
|
nd++;
|
||||||
|
}
|
||||||
|
lua_pop(L, 2);
|
||||||
|
}
|
||||||
|
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
MODLOG_DFLT(INFO, "Discovered %d services with %d characteristics\n", ns, nc);
|
MODLOG_DFLT(INFO, "Discovered %d services with %d characteristics with %d descriptors\n", ns, nc, nd);
|
||||||
|
|
||||||
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);
|
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) + nd * 2 * sizeof(struct ble_gatt_dsc_def);
|
||||||
|
|
||||||
|
|
||||||
struct ble_gatt_svc_def *svcs = malloc(size);
|
struct ble_gatt_svc_def *svcs = malloc(size);
|
||||||
|
@ -456,7 +484,8 @@ lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp, const uint
|
||||||
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);
|
struct ble_gatt_dsc_def *dsc = (struct ble_gatt_dsc_def *) (uuids + ns + nc);
|
||||||
|
uint16_t *handles = (uint16_t *) (dsc + nd * 2);
|
||||||
|
|
||||||
handles[0] = 0; // number of slots used
|
handles[0] = 0; // number of slots used
|
||||||
|
|
||||||
|
@ -549,6 +578,25 @@ lble_build_gatt_svcs(lua_State *L, struct ble_gatt_svc_def **resultp, const uint
|
||||||
// -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;
|
||||||
|
|
||||||
|
if (lua_getfield(L, -1, "name") != LUA_TNIL) {
|
||||||
|
if ((void *) (dsc + 2) > eom) {
|
||||||
|
free_gatt_svcs(L, result);
|
||||||
|
return luaL_error(L, "Miscalculated memory requirements");
|
||||||
|
}
|
||||||
|
|
||||||
|
chr->descriptors = dsc;
|
||||||
|
|
||||||
|
dsc->uuid = (const ble_uuid_t*)(ble_uuid16_t[]) {
|
||||||
|
BLE_UUID16_INIT(0x2901)
|
||||||
|
};
|
||||||
|
dsc->att_flags = BLE_ATT_F_READ;
|
||||||
|
dsc->access_cb = lble_access_cb;
|
||||||
|
dsc->arg = chr->arg;
|
||||||
|
|
||||||
|
dsc += 2;
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
lua_pop(L, 2);
|
lua_pop(L, 2);
|
||||||
chrs++; // terminate the list of characteristics for this service
|
chrs++; // terminate the list of characteristics for this service
|
||||||
|
|
|
@ -30,7 +30,7 @@ function read_battery_level()
|
||||||
-- This ought to do something better!
|
-- This ought to do something better!
|
||||||
return 50
|
return 50
|
||||||
end
|
end
|
||||||
battery = { uuid="180f", characteristics={ {uuid="2a19", type='B', read=read_battery_level} } }
|
battery = { uuid="180f", characteristics={ {uuid="2a19", type='B', read=read_battery_level, name="Battery percentage"} } }
|
||||||
myservice = {uuid="0123456789abcdef0123456789abcdef", characteristics={{uuid="1234", value=0, type='c'}}}
|
myservice = {uuid="0123456789abcdef0123456789abcdef", characteristics={{uuid="1234", value=0, type='c'}}}
|
||||||
config = {name="MyGadget", services={ myservice, battery } }
|
config = {name="MyGadget", services={ myservice, battery } }
|
||||||
ble.init(config)
|
ble.init(config)
|
||||||
|
@ -124,6 +124,7 @@ The characteristic table contains the following keys:
|
||||||
- `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 then notifications are supported on this characteristic. The value of the `notify` attribute is updated to be an integer which is the value to be passed into `ble.notify()`
|
- `notify` If this attribute is present then notifications are supported on this characteristic. The value of the `notify` attribute is updated to be an integer which is the value to be passed into `ble.notify()`
|
||||||
|
- `name` If this attribute is present, then an additional descriptor is added containing the name of the characteristic.
|
||||||
|
|
||||||
In the above functions, the value is that passed to/from the write/read functions is of the type specified by the `type` key. If this key is missing, then the default type is a string of bytes. For example, if `type` is `'B'` then the value is an integer (in the range 0 - 255) and the bluetooth client will see a single byte containing that value.
|
In the above functions, the value is that passed to/from the write/read functions is of the type specified by the `type` key. If this key is missing, then the default type is a string of bytes. For example, if `type` is `'B'` then the value is an integer (in the range 0 - 255) and the bluetooth client will see a single byte containing that value.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue