Skip to content

Commit db470b6

Browse files
committed
Merge branch 'master' of github.com:espruino/Espruino
2 parents 6ca54db + 41e2d36 commit db470b6

File tree

3 files changed

+198
-2
lines changed

3 files changed

+198
-2
lines changed

libs/bluetooth/jswrap_bluetooth.c

Lines changed: 193 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ typedef enum {
8686
static volatile BLEStatus bleStatus;
8787

8888
#define BLE_SCAN_EVENT JS_EVENT_PREFIX"blescan"
89+
#define BLE_WRITE_EVENT JS_EVENT_PREFIX"blew"
8990

9091
/**@brief Error handlers.
9192
*
@@ -273,6 +274,12 @@ void jswrap_nrf_bluetooth_startAdvertise(void) {
273274
APP_ERROR_CHECK(err_code);
274275
}
275276

277+
/// Get the correct event name for a BLE write event to a characteristic (eventName should be 12 chars long)
278+
void ble_handle_to_write_event_name(char *eventName, uint16_t handle) {
279+
strcpy(eventName, BLE_WRITE_EVENT);
280+
itostr(handle, &eventName[strlen(eventName)], 16);
281+
}
282+
276283
/**@brief Function for the application's SoftDevice event handler.
277284
*
278285
* @param[in] p_ble_evt SoftDevice event.
@@ -334,7 +341,7 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
334341
p_adv->peer_addr.addr[0]));
335342
JsVar *data = jsvNewStringOfLength(p_adv->dlen);
336343
if (data) {
337-
jsvSetString(data, p_adv->data, p_adv->dlen);
344+
jsvSetString(data, (char*)p_adv->data, p_adv->dlen);
338345
JsVar *ab = jsvNewArrayBufferFromString(data, p_adv->dlen);
339346
jsvUnLock(data);
340347
jsvObjectSetChildAndUnLock(evt, "data", ab);
@@ -345,6 +352,26 @@ static void on_ble_evt(ble_evt_t * p_ble_evt)
345352
break;
346353
}
347354

355+
case BLE_GATTS_EVT_WRITE: {
356+
ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
357+
// We got a param write event - add this to the object callback queue
358+
JsVar *evt = jsvNewObject();
359+
if (evt) {
360+
JsVar *data = jsvNewStringOfLength(p_evt_write->len);
361+
if (data) {
362+
jsvSetString(data, (char*)p_evt_write->data, p_evt_write->len);
363+
JsVar *ab = jsvNewArrayBufferFromString(data, p_evt_write->len);
364+
jsvUnLock(data);
365+
jsvObjectSetChildAndUnLock(evt, "data", ab);
366+
}
367+
char eventName[12];
368+
ble_handle_to_write_event_name(eventName, p_evt_write->handle);
369+
jsiQueueObjectCallbacks(execInfo.root, eventName, &evt, 1);
370+
jsvUnLock(evt);
371+
}
372+
break;
373+
}
374+
348375
default:
349376
// No implementation needed.
350377
break;
@@ -604,6 +631,171 @@ void jswrap_nrf_bluetooth_setAdvertising(JsVar *data) {
604631
jsExceptionHere(JSET_ERROR, "Got BLE error code %d", err_code);
605632
}
606633

634+
635+
/*JSON{
636+
"type" : "staticmethod",
637+
"class" : "NRF",
638+
"name" : "setServices",
639+
"generate" : "jswrap_nrf_bluetooth_setServices",
640+
"params" : [
641+
["data","JsVar","The service (and characteristics) to advertise"]
642+
]
643+
}
644+
BETA: This only partially works at the moment
645+
646+
Change the services and characteristics Espruino advertises.
647+
648+
```
649+
NRF.setServices({
650+
0xBCDE : {
651+
0xABCD : {
652+
value : "Hello", // optional
653+
maxLen : 5, // optional (otherwise is length of initial value)
654+
broadcast : false, // optional, default is false
655+
readable : true, // optional, default is false
656+
writable : true, // optional, default is false
657+
onWrite : function(evt) { // optional
658+
console.log("Got ", evt.data);
659+
}
660+
}
661+
// more characteristics allowed
662+
}
663+
// more services allowed
664+
});
665+
```
666+
*/
667+
void jswrap_nrf_bluetooth_setServices(JsVar *data) {
668+
uint32_t err_code;
669+
670+
// TODO: Reset services
671+
672+
if (jsvIsObject(data)) {
673+
JsvObjectIterator it;
674+
jsvObjectIteratorNew(&it, data);
675+
while (jsvObjectIteratorHasValue(&it)) {
676+
ble_uuid_t ble_uuid;
677+
uint16_t service_handle;
678+
679+
// Add the service
680+
BLE_UUID_BLE_ASSIGN(ble_uuid, jsvGetIntegerAndUnLock(jsvObjectIteratorGetKey(&it)));
681+
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
682+
&ble_uuid,
683+
&service_handle);
684+
if (err_code) {
685+
jsExceptionHere(JSET_ERROR, "Got BLE error code %d in gatts_service_add", err_code);
686+
break;
687+
}
688+
// sd_ble_gatts_include_add ?
689+
690+
// Now add characteristics
691+
JsVar *serviceVar = jsvObjectIteratorGetValue(&it);
692+
JsvObjectIterator serviceit;
693+
jsvObjectIteratorNew(&serviceit, serviceVar);
694+
while (jsvObjectIteratorHasValue(&serviceit)) {
695+
ble_uuid_t char_uuid;
696+
ble_gatts_char_md_t char_md;
697+
ble_gatts_attr_t attr_char_value;
698+
ble_gatts_attr_md_t attr_md;
699+
ble_gatts_char_handles_t characteristic_handles;
700+
701+
BLE_UUID_BLE_ASSIGN(char_uuid, jsvGetIntegerAndUnLock(jsvObjectIteratorGetKey(&serviceit)));
702+
JsVar *charVar = jsvObjectIteratorGetValue(&serviceit);
703+
704+
memset(&char_md, 0, sizeof(char_md));
705+
if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "broadcast", 0)))
706+
char_md.char_props.broadcast = 1;
707+
if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "readable", 0)))
708+
char_md.char_props.read = 1;
709+
if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "writable", 0))) {
710+
char_md.char_props.write = 1;
711+
char_md.char_props.write_wo_resp = 1;
712+
}
713+
char_md.p_char_user_desc = NULL;
714+
char_md.p_char_pf = NULL;
715+
char_md.p_user_desc_md = NULL;
716+
char_md.p_cccd_md = NULL;
717+
char_md.p_sccd_md = NULL;
718+
719+
memset(&attr_md, 0, sizeof(attr_md));
720+
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
721+
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
722+
attr_md.vloc = BLE_GATTS_VLOC_STACK;
723+
attr_md.rd_auth = 0;
724+
attr_md.wr_auth = 0;
725+
attr_md.vlen = 1; // TODO: variable length?
726+
727+
memset(&attr_char_value, 0, sizeof(attr_char_value));
728+
attr_char_value.p_uuid = &char_uuid;
729+
attr_char_value.p_attr_md = &attr_md;
730+
attr_char_value.init_len = 0;
731+
attr_char_value.init_offs = 0;
732+
attr_char_value.p_value = 0;
733+
attr_char_value.max_len = (uint16_t)jsvGetIntegerAndUnLock(jsvObjectGetChild(charVar, "maxLen", 0));
734+
if (attr_char_value.max_len==0) attr_char_value.max_len=1;
735+
736+
// get initial data
737+
JsVar *charValue = jsvObjectGetChild(charVar, "value", 0);
738+
if (charValue) {
739+
JSV_GET_AS_CHAR_ARRAY(vPtr, vLen, charValue);
740+
if (vPtr && vLen) {
741+
attr_char_value.p_value = (uint8_t*)vPtr;
742+
attr_char_value.init_len = vLen;
743+
if (attr_char_value.init_len > attr_char_value.max_len)
744+
attr_char_value.max_len = attr_char_value.init_len;
745+
}
746+
}
747+
748+
err_code = sd_ble_gatts_characteristic_add(service_handle,
749+
&char_md,
750+
&attr_char_value,
751+
&characteristic_handles);
752+
753+
jsvUnLock(charValue); // unlock here in case we were storing data in a flat string
754+
if (err_code) {
755+
jsExceptionHere(JSET_ERROR, "Got BLE error code %d in gatts_characteristic_add", err_code);
756+
break;
757+
}
758+
759+
// Add Write callback
760+
JsVar *writeCb = jsvObjectGetChild(charVar, "onWrite", 0);
761+
if (writeCb) {
762+
char eventName[12];
763+
ble_handle_to_write_event_name(eventName, characteristic_handles.value_handle);
764+
jsvObjectSetChildAndUnLock(execInfo.root, eventName, writeCb);
765+
}
766+
767+
jsvUnLock(charVar);
768+
/* We'd update the characteristic with:
769+
770+
memset(&hvx_params, 0, sizeof(hvx_params));
771+
hvx_params.handle = characteristic_handle.value_handle;
772+
hvx_params.p_data = p_string;
773+
hvx_params.p_len = &length;
774+
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
775+
return sd_ble_gatts_hvx(p_nus->conn_handle, &hvx_params);
776+
777+
Maybe we could find the handle out based on characteristic UUID, rather than having
778+
to store it?
779+
780+
*/
781+
782+
jsvObjectIteratorNext(&serviceit);
783+
}
784+
jsvObjectIteratorFree(&serviceit);
785+
jsvUnLock(serviceVar);
786+
787+
jsvObjectIteratorNext(&it);
788+
}
789+
jsvObjectIteratorFree(&it);
790+
791+
792+
793+
} else if (!jsvIsUndefined(data)) {
794+
jsExceptionHere(JSET_TYPEERROR, "Expecting object or undefined, got %t", data);
795+
}
796+
}
797+
798+
607799
/*JSON{
608800
"type" : "staticmethod",
609801
"class" : "NRF",

libs/bluetooth/jswrap_bluetooth.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ void jswrap_nrf_bluetooth_wake(void);
2121

2222
JsVarFloat jswrap_nrf_bluetooth_getBattery(void);
2323
void jswrap_nrf_bluetooth_setAdvertising(JsVar *data);
24+
void jswrap_nrf_bluetooth_setServices(JsVar *data);
2425
void jswrap_nrf_bluetooth_setScan(JsVar *callback);
2526
void jswrap_nrf_bluetooth_setTxPower(JsVarInt pwr);
2627

misc/45-espruino.rules

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# To go in /etc/udev/rules.d/
22
# Makes Espruino's serial port accessible to non-SU users, and stops the Modem Manager trying to enumerate it
33
ATTRS{idProduct}=="5740", ATTRS{idVendor}=="0483", ENV{ID_MM_DEVICE_IGNORE}="1", MODE="0666", GROUP="plugdev"
4-
4+
# Nordic kits
5+
ATTRS{idProduct}=="1015", ATTRS{idVendor}=="1366", ENV{ID_MM_DEVICE_IGNORE}="1"
6+
# Microbit
7+
ATTRS{idProduct}=="0204", ATTRS{idVendor}=="0d28", ENV{ID_MM_DEVICE_IGNORE}="1"

0 commit comments

Comments
 (0)