-
Yeah - your other comment about bonding from the neighbor thread did the trick.
This is working now:
var gatt; function onInit() { NRF.requestDevice({ filters: [{namePrefix: "AB"}] }).then((device)=> { console.log("FOUND", device.id, device.name); return device.gatt.connect(); }).then((device)=>{ gatt = device; console.log("CONNECTED", device); return gatt.startBonding(); }).then(function() { console.log("BONDED", gatt.getSecurityStatus()); return gatt.getPrimaryService(0x1812); }).then((service)=>{ console.log("SERVICE", service); return service.getCharacteristic(0x2a4d); }).then((char)=>{ console.log("CHAR", char); char.on("characteristicvaluechanged",(e)=>{ console.log("EVENT", e.target.value); }); return char.startNotifications(); }).then(()=>{ console.log("DONE"); return true; }).catch((err)=>{ console.log("ERROR", err); }); } onInit();
For a button press I get:
EVENT DataView: { "buffer": new Uint8Array([2, 0]).buffer, "byteOffset": 0, "byteLength": 2 }
and for a release:
EVENT DataView: { "buffer": new ArrayBuffer(2), "byteOffset": 0, "byteLength": 2 }
The only thing is that when I pull the power from Espruino the bonding seems to be lost and the blue LED on the remote begins flashing again.
This does not happen when bonded to Laptop/Phone. Maybe it's about the whitelisting.
But I could live with that.
Thanks @Gordon for the hint! -
Thanks @Gordon.
Do I really need this bonding call on the peripheral side?
This thread here is a test to gain some insight how HID works as a peripheral to use it on the "other side" when Espruino is the Host/Central.No Code in iOS needed btw., just a confirmation (Yes/No).
How do I setup Espruino as HID device?
I thought thatNRF.setServices(undefined, { hid : kb.report });
would do the trick.
Is there more that is not given in the example code? -
Just digging into this issue and found this HOGP specification here.
Chapter 5 explains details about bonding and how to establish a connection.
I could not find much of that in the Espruino API yet, maybe this is the missing part?At some point the Host (normally computer/phone; here: Espruino) writes his address into the HID device (peripheral; here: the remote button) causing a bonding.
-
For investigating in the other HID project I tried to get a MDBT42Q set up as a BLE keyboard or volume control using this example from here
Strangely, it didn't work.
Here is my final code (mostly copied, but wrapped in an
onInit()
so it gets called after PowerUp):function onInit() { var kb = require("ble_hid_keyboard"); NRF.setServices(undefined, { hid : kb.report }); function btnPressed() { // Send 'a' kb.tap(kb.KEY.A, 0, function() { // Followed by capital 'A' kb.tap(kb.KEY.A, kb.MODIFY.SHIFT); }); } // trigger btnPressed whenever the button is pressed setWatch(btnPressed, BTN, {edge:"rising",repeat:true,debounce:50}); }
Could someone try and confirm my results please?
I tried both examples: The one with the keyboard and the one with thevolumeUp
control.
None worked.Some more findings:
- when I connect a commercial HID remote (remote selfie camera button which sends a
volumeUp()
) my phone (iOS) shows a confirmation dialog. - with Espruino this dialog is missing.
- also the commercial remote shows up in iOS settings an (i) where I can select to "forget" (disconnect) this device
- the Espruino does not show up with this option. The only way to disconnect is to pull off the battery.
- when I pull the battery Espruino is gone from the list and I have to pair it again afterwards
- the commercial remote stays in the list when switched off and is coming online again right after switching it on again.
Is this expected behaviour or a bug?
Thanks in advance.
- when I connect a commercial HID remote (remote selfie camera button which sends a
-
Thanks @Gordon for the hints.
NRF Connect only shows the Service, no peeking or poking possible (iOS here).
By the way, this is my code so far:
var notify = 0; var hidService; var modeChar, reportChar; function onInit() { NRF.requestDevice({ filters: [{namePrefix: "AB"}] }).then((device)=>{ console.log("FOUND"); return device.gatt.connect(); }).then((gatt)=>{ console.log("CONNECTED", gatt); return gatt.getPrimaryService("1812"); }).then((service)=>{ hidService = service; console.log("SERVICE", hidService); return hidService.getCharacteristic(0x2a4e); // 2a4e - protocol mode (R-W) // 2a4d - report (R-N) // 2a4b - report map (R) // 2a4a - hid information (R) // 2a4c - hid control point (W) }).then((char)=>{ console.log("MODE", char); modeChar = char; return char.readValue(); }).then((d)=>{ console.log("READ", d.buffer); console.log("WRITING 1"); return modeChar.writeValue(1); }).then((d)=>{ console.log("WRITTEN, GET REPORT"); return hidService.getCharacteristic(0x2a4d); }).then((char)=>{ console.log("REPORT", char); reportChar = char; char.on("characteristicvaluechanged",(e)=>{ console.log("EVENT", e.targete.value); }); return char.startNotifications(); }).then((d)=>{ console.log("DONE"); return true; }).catch((err)=>{ console.log("ERROR", err); }); } onInit();
And this is the output:
FOUND CONNECTED BluetoothRemoteGATTServer: { "device": BluetoothDevice: { "id": "2a:07:98:10:35:fb public", "rssi": -59, "data": new Uint8Array([2, 1, 5, 3, 2, 18, 24, 3, 25, 193, 3, 12, 9, 65, 66, 32, 83, 104, 117, 116, 116, 101, 114, 51]).buffer, "name": "AB Shutter3", "services": [ "1812" ], "gatt": ... }, "connected": true, "handle": 1 } SERVICE BluetoothRemoteGATTService: { "device": BluetoothDevice: { "id": "2a:07:98:10:35:fb public", "rssi": -59, "data": new Uint8Array([2, 1, 5, 3, 2, 18, 24, 3, 25, 193, 3, 12, 9, 65, 66, 32, 83, 104, 117, 116, 116, 101, 114, 51]).buffer, "name": "AB Shutter3", "services": [ "1812" ], "gatt": BluetoothRemoteGATTServer: { "device": ... , "connected": true, "handle": 1 } }, "uuid": "0x1812", "isPrimary": true, "start_handle": 15, "end_handle": 31 } MODE BluetoothRemoteGATTCharacteristic: { "service": BluetoothRemoteGATTService: { "device": BluetoothDevice: { "id": "2a:07:98:10:35:fb public", "rssi": -59, "data": new Uint8Array([2, 1, 5, 3, 2, 18, 24, 3, 25, 193, 3, 12, 9, 65, 66, 32, 83, 104, 117, 116, 116, 101, 114, 51]).buffer, "name": "AB Shutter3", "services": [ "1812" ], "gatt": BluetoothRemoteGATTServer: { "device": ... , "connected": true, "handle": 1 } }, "uuid": "0x1812", "isPrimary": true, "start_handle": 15, "end_handle": 31 }, "uuid": "0x2a4e", "handle_value": 17, "handle_decl": 16, "properties": { "broadcast": false, "read": true, "writeWithoutResponse": true, "write": false, "notify": false, "indicate": false, "authenticatedSignedWrites": false } } READ new Uint8Array([1]).buffer WRITING 1 WRITTEN, GET REPORT REPORT BluetoothRemoteGATTCharacteristic: { "service": BluetoothRemoteGATTService: { "device": BluetoothDevice: { "id": "2a:07:98:10:35:fb public", "rssi": -59, "data": new Uint8Array([2, 1, 5, 3, 2, 18, 24, 3, 25, 193, 3, 12, 9, 65, 66, 32, 83, 104, 117, 116, 116, 101, 114, 51]).buffer, "name": "AB Shutter3", "services": [ "1812" ], "gatt": BluetoothRemoteGATTServer: { "device": ... , "connected": true, "handle": 1 } }, "uuid": "0x1812", "isPrimary": true, "start_handle": 15, "end_handle": 31 }, "uuid": "0x2a4d", "handle_value": 19, "handle_decl": 18, "properties": { "broadcast": false, "read": true, "writeWithoutResponse": false, "write": false, "notify": true, "indicate": false, "authenticatedSignedWrites": false } } DONE
Maybe you see something I don't.
As far as I can seePROTOCOL_MODE
already is set to1
:READ new Uint8Array([1]).buffer
What about this BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST?
I will have to look at the sourcecode more in-depth though.
Any way to log what is going on when Espruino is in the HID role against a phone or computer? -
Thanks @Gordon for clarifying - I almost have suspected something like that.
And meanwhile I wired back to just run the Button LED betweengnd
and the port.
It is a bit dimly still, but it is enough for me at the moment.Not easy to pull the button apart though since the back is pressed in.
It one of these cheap china ones here: https://www.amazon.de/Gebildet-Momentanen-wasserdichte-Drucktaste-LED-Kontrollleuchte/dp/B088CNW12P/ -
There is a HID module for BLE that helps Espruino to emulate a HID device (like keyboard or media controller) itself.
What I want to do is exactly the opposite:
I bought a cheap 1-button camera trigger for smartphones (that sends a "volume up" button command)
want to use it on my Espruino project as a remote switch, but how?
I can:
find and connect it it via
NRF.requestDevice
(named "AB Shutter3" - prefix "AB" works)connected BluetoothRemoteGATTServer: { "device": BluetoothDevice: { "id": "2a:07:98:10:35:fb public", "rssi": -67, "data": new Uint8Array([2, 1, 5, 3, 2, 18, 24, 3, 25, 193, 3, 12, 9, 65, 66, 32, 83, 104, 117, 116, 116, 101, 114, 51]).buffer, "name": "AB Shutter3", "services": [ "1812" ], "gatt": ... }, "connected": true, "handle": 1 }
find a a single service (
1812
) and fetch itservice BluetoothRemoteGATTService: { "device": BluetoothDevice: { "id": "2a:07:98:10:35:fb public", "rssi": -67, "data": new Uint8Array([2, 1, 5, 3, 2, 18, 24, 3, 25, 193, 3, 12, 9, 65, 66, 32, 83, 104, 117, 116, 116, 101, 114, 51]).buffer, "name": "AB Shutter3", "services": [ "1812" ], "gatt": BluetoothRemoteGATTServer: { "device": ... , "connected": true, "handle": 1 } }, "uuid": "0x1812", "isPrimary": true, "start_handle": 15, "end_handle": 31 }
find a bunch of characteristics:
{ "uuid": "0x2a4e", "properties": { "broadcast": false, "read": true, "writeWithoutResponse": true, "write": false, "notify": false, "indicate": false, "authenticatedSignedWrites": false } } { "uuid": "0x2a4d", "properties": { "broadcast": false, "read": true, "writeWithoutResponse": false, "write": false, "notify": true, "indicate": false, "authenticatedSignedWrites": false } } { "uuid": "0x2a4d", "properties": { "broadcast": false, "read": true, "writeWithoutResponse": false, "write": false, "notify": true, "indicate": false, "authenticatedSignedWrites": false } } { "uuid": "0x2a4b", "properties": { "broadcast": false, "read": true, "writeWithoutResponse": false, "write": false, "notify": false, "indicate": false, "authenticatedSignedWrites": false } } { "uuid": "0x2a4a", "properties": { "broadcast": false, "read": true, "writeWithoutResponse": false, "write": false, "notify": false, "indicate": false, "authenticatedSignedWrites": false } } { "uuid": "0x2a4c", "properties": { "broadcast": false, "read": false, "writeWithoutResponse": true, "write": false, "notify": false, "indicate": false, "authenticatedSignedWrites": false } }
The odd thing is:
0x2a4d
exists twice and is the only characteristic that willnotify
, so this is probably the one I'm looking for, butc..on("characteristicvaluechanged",…
andc.startNotifications()
doesn't work- meaning it works, but the button does not notify anything
When I pair it with my smartphone there is a dialog popping up first.
Will there be something to happen first before both are connected?
Like writing back to one of the other characteristics to say that we'd like to connect?Any hints or links appreciated.
-
Short question:
I have a MDBT42Q breakout board, driven by 7,2 V (Li-Ion 2S) and a Chinese button with builtin LED + resistor(?) that is rated for 12 V and below 2 mA at my voltage.So I thought the simplest way to run this LED from a port is:
- connect
LED+
toVin
- connect
LED-
to my port (D15
in this case)
and usepinMode(D15, "opendrain")
and inverse logic (0 to light, 1 to clear the LED).
But the LED is lit always (a bit dimly) and only changes brightness when I do
D15.set()
orD15.reset()
.
I have tried any other pinMode too and it always lights up, never goes completely dark.I would try to avoid any additional components like transistors if possible since I have gotten away without so far in this project and have just to wire up the board somehow to buton and a servo motor.
However, 3,3 V seems not to be enough to light the LED and that's why I came up with theopendrain
thing to run it of the (higher) battery voltage.What am I doing wrong?
- connect
-
Thanks @Gordon, there was not much time left before the race and I had to hack everything together to get a semi-working setup.
It actually worked to a point, but unfortunately the race was called off during warmup because of the wet weather conditions making the track slippery.
Maybe there is another date in the next weeks, that may give me some time for improvements... -
Yes, it's reproducable.
This is/was the actual line:Flash.s.write(Flash.NAME, [CONST.LAP_DATA_SIZE], 0, 1 + CONST.LAP_DATA_SIZE * CONST.LAPS_STORAGE)
Being
Flash.NAME = 'laps'
,LAP_DATA_SIZE=8
,LAPS_STORAGE=2000
which would be:write('laps', [8], 0, 16001)
which worked perfectly fine in the console, but not when called via a
setWatch()
callback when a button was pressed.
I even changed all thethis.
references to absolute ones in case the context got lost inside the method. -
Maybe I'll just switch back to RAM and just use binary, reserved data for now.
Is there a way to safely acquire memory without crashing the system?
Something like:- determine how much memory we have left
process.memory().free
- subtract some margin of memory left unallocated (how much would you suggest?)
- calculate how big my
ArrayBuffer
can get (any clues here?)
Or I'll just do it via trial + error and put the hardcoded numbers in...
- determine how much memory we have left
-
Another issue:
If I keep my storage file in flash and try to upload new code (minified + direct to flash), it gives me this:No errors. Minified 23072 bytes to 14425 bytes. > ____ _ | __|___ ___ ___ _ _|_|___ ___ | __|_ -| . | _| | | | | . | |____|___| _|_| |___|_|_|_|___| |_| espruino.com 2v09 (c) 2021 G.Williams Espruino is Open Source. Our work is supported only by sales of official boards and donations: http://espruino.com/Donate >fficial boards and donations: http://espruino.comds and do$>DgGAMABgAOD4AAAwwEgBgAwAkBhgAAYACAAgAPAIAIAYAAAEGCFBEgkQUIMEAAH/yAJAEAAYADAAYADAAYAAQBIAn/wAAGAMAYADAAYAAAAIAEACABAAgAQAIAAQAEAAAADAKQFICkA+AAD/gIQEICEA8AAAPAIQEICEAkAAAPAIQEICEP+AAAPAKQFICkA0AAAQA/wkASAIAAAAPAISEJCEh/gAD/gIAEACAA+AAAQBPwAAABAAggSfwAA/4AQAYASAQgAAgAf8AAA/AQAIAD4CABAAfAAAPwEACABAAfAAAHgEICEBCAeAAAP+EICEBCAeAAAHgEICEBCA/4AAPwCACABAAQAAAEQFICkBKAiAAAIAfwCEBCABAAAPgAIAEACA/AAAMABgAMAYAwAAAPAAYAYAwAGABgPAAACEAkAMAJAIQAAD5ACQBIAkP8AACEBGAlAUgMQAAAgAQD3iAJAEAAf/AAEASAI94BAAgAAAIAIAEADAAgAQAQAAAFAHwFUCqBBARAAAACAOAAAAQQI/4kASAAAADgAAA4AAAEAAABAAAAQAAEACAH/AgAQAAAFACgH/AoAUAAAEAEAEABAAQAAAGMAYAwBjAAAAwAADEKRDIiiQRIEYAAAIAKAIgAAH4ECCBA/AkQSIIEAACDFChiRSIKEGCAADAAQAAAEAMAAADAAQAwAEAAABADAAQAwAAAAQAcAfAHABAAAAQAIAEACABAAAAQAIAEACABAAgAQAAAgAgAIAIAAACAB4AgAAAPAGADwAAAEQlIKkJKAiAAAIgCgAgAAAeAQgIQDwCkBSAaAAAIQkYKUJSAxAAAYACAQgAOEIAIAYAAAL8AAAeAQgf4EIBIAAATA+gkQSIAEAABBAfAIgEQCIB8BBAAAwAEgBQAeAUASAwAAAffAADCCYhKQjIIYAAEAAABAAAAH4ECCZBSgpQQIH4AAAQBUAqAPAAAAQAUAVAFAEQAAAQAIAEADwAAH4ECC9BU",1024);
The only way to get new code flashed is removing the storage file first it seems.
>require('Storage').getFree() =12116 >require('Storage').list() =[ "laps", ".bootcde" ]
-
@Gordon I'd like to have a method to do a reset "in the field", meaning starting everything new when I have to.
What is working is calling my
reset()
method via commandline.
What does not work is calling it through a handler after a button was pressed.The method does this:
reset: function() { console.log('reset'); if(!Flash.s.write(Flash.NAME, [CONST.LAP_DATA_SIZE], 0, 1 + CONST.LAP_DATA_SIZE * CONST.LAPS_STORAGE)) { throw new Error('could not reserve storage'); } Flash.pos = 0; },
manual call:
>Flash.reset() reset =undefined
through handler:
reset Uncaught Error: Unable to find or create file at line 1 col 114 ...ATA_SIZE*CONST.LAPS_STORAGE))throw new Error('could not reserve stor... ^ in function "reset" called from line 1 col 15 a&&Flash.reset(),Object.keys(this.macs).forEach(c=>{const d=this.macs[c];... ^ in function "init" called from line 1 col 122 ...tons.BTN_MID]&&(Race.init(!0),ErrorLog.log=[]),this.objects.forE... ^ in function "wakeup" called from line 1 col 16 a?Power.wakeup():Power.sleep() ^ in function "onOff" called from line 1 col 37 ...N?Buttons.onOff(a,b.state==0):Buttons.event(a,b.state==0) ^ in function called from system
-
OK - something works. I can somehow create a storage and fill it up with data.
What does not work is removing it at runtime.So how to erase and recreate a Storage file on runtime?
I can
storage.eraseAll()
but that would remove my code too.I can
storage.write('name', [data], 0, large_value)
but that gives me
Uncaught Error: Unable to find or create file
even if I 'overwrite' my current file.
So I'll try to
storage.erase('name'); storage.compact(); // this seems to be necessary to actually free up the space storage.write('name', [data], 0, large_value):
but run into errors too.
Is
Storage
buggy or am I doing something wrong here? -
Thanks @allObjects, but since the day of the track race is already next Sunday there is not much time left to try something with external hardware.
@Gordon I tried to implemented
Storage
yesterday, but it gave me headaches.EDIT: another error found. Don't put something like
require('Storage').eraseAll()
as first line in your code on upload... oh my. -
-
Hmmm. Blocking even if I use the
async
methods?
I would keep things small and simple. Just create one directory when starting.
And write a small file for one lap.
That would still cause issues you think?About
require("Storage")
I am not sure actually how this could work.
Maybe create an "empty" file first that fills up all available space.>require('Storage').getFree() =18440
with my current code.
And then use it as binary ring buffer writing on
pos = i * REC_SIZE
or something like that.With my current set of datapoints (I ended up at 10 bytes) this would be something like 1800 laps which would give me 225 laps for 8 transponders meaning about 56 km distance on a 250 m track which can easily be reached with a fast velomobile in one hour.
Tight fit, but an improvement. I'll consider that - thanks.What about this cut-down thing? This would mean disabling every compile-time module I don't need for this board I suppose?
Sounds interesting.EDIT:
At some point I thought since my code is in Flash and RAM is about the same size as Flash there would be more space in RAM instead (and RAM doesn't wear and is easier to access...).
Was that a wrong assumption? -
@allObjects thanks about the idea with the Advertiser.
However communicating back to the Pucks would mean the Pucks would have to scan as well.
I was worried about battery consumption here, so that's why I wanted to keep it simple on the transponder side. -
Thanks @Gordon, having the scan handler super short was also something I had in mind.
Good that you confirm this, I will try to optimize it.There are currently 8 pucks available for me, so that is the maximum I should handle - would be nice if there were more.
However "in the field" not all should be in range at the same time - only when starting the race.But it would be good if conditions like these would not break the whole setup.
My main issue was the memory though I think. Limiting the log to 100 laps made it stable for now.
I am considering pushing the lap data to an external SD card.
Is that something you can advise or does it make things slower/worse?I would create a new directory for every one (timestamp of start time as directory name to make it simple).
And then create just one short file for every lap event like (00001.csv) for the first lap, (00002.csv) for the second.
No longish CSV file, short open and writes.But I would like to be able to "serve" this file data via BLE as well so it can be pulled via a Laptop at race time - I would have to be able to scan a directory on request and push out record (file) by record.
Do you see issues here doing that in parallel?
I'm about to hook up a SD card to the rig now and see how it works... -
Let's say I have a Puck/Pixl/MDBT42Q collecting data in a queue.
Before any overflow happens this data should be polled via BLE by another system as BLE central.So as BLE peripheral I use
NRF.setServices()
to create someService
/Characteristics
for pushing out data.The thing is: How can I know if the central actually read the data so I can remove it from my queue?
For the other direction
onWrite
is a synchronous API for writing data back, but for reading there is only:notify: true
and/orindicate: true
which is documented as notify + ACK.
But how does it work?
As peripheral I am supposed to callNRF.updateServices()
and set a newvalue
.
But how can I detect if this value was successfully read by the connected central?
How often should I callupdateService()
in case the queue got filled up a bit and there areN
items waiting?My current idea is a multipart API:
- use
onWrite
so the central can request the next item - in return the requested item is presented via
updateServices()
If the queue entries have some kind of timestamp or sequence number I can assume that all previous entries are read already and safely remove them.
What do you think?
-
Having started a new test and just pressing buttons very quickly gives me this:
Running onInit()... WARNING: jsble_exec_pending: Unknown enum type 216 36 12 3 WARNING: jsble_exec_pending: Unknown enum type 56 7 89 80 WARNING: jsble_exec_pending: Unknown enum type 56 19 89 80 WARNING: jsble_exec_pending: Unknown enum type 56 11 62 53 WARNING: jsble_exec_pending: Unknown enum type 120 0 22 13 New interpreter error: FIFO_FULL WARNING: jsble_exec_pending: Unknown enum type 152 10 61 52 WARNING: jsble_exec_pending: Unknown enum type 56 2 177 168
But everything seems to keep working after that. Nothing got stuck.
What is this about? -
OK - some updates:
I blew up my
MDBT42s
somehow. It still works, but days ago I overloaded one of the LED pins and was curious about the bad battery runtime and the high amps (> 40 mA) even with everything switched off.
Pulled everything apart to sort it out, put it back together (minus LED, don't need it) - yesD27
is gone.
So I replaced it with a spare device, unfortunately not with external antenna (just ordered replacements yesterday)I run tests again and ran into issues again after ~30 minutes runtime and ~160 - 200 simulated laps with two Pucks:
- the lap array is limited to 200 entries, so
process.memory().free
stays way above 400 mostly - at some point everything freezes. No display updates, no button reponses, amps at ~15 mA (also with Backlight on which is only a few mA) all the time, no BLE connection possible, no advertising either
doing it a second time I tried to stay connected via Web Console, after ~ 10 minutes I lost connection, reconnected and monitored memory a few times.
This is the final output before and after reconnect and before the freeze:={ free: 900, usage: 1600, total: 2500, history: 10, gc: 0, gctime: 6.43920898437, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } >process.memory() ={ free: 891, usage: 1609, total: 2500, history: 10, gc: 0, gctime: 6.50024414062, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } >process.memory() ={ free: 888, usage: 1612, total: 2500, history: 10, gc: 0, gctime: 6.65283203125, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } >process.memory() ={ free: 873, usage: 1627, total: 2500, history: 10, gc: 0, gctime: 6.53076171875, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } >process.memory() ={ free: 873, usage: 1627, total: 2500, history: 10, gc: 0, gctime: 6.53076171875, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } Disconnected from Web Bluetooth, MDBT42Q cd4f > <- Serial1 Found MDBT42Q, 2v08 > Connected to Web Bluetooth, MDBT42Q cd4f >process.memory() ={ free: 603, usage: 1897, total: 2500, history: 10, gc: 0, gctime: 7.2021484375, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } >process.memory() ={ free: 510, usage: 1990, total: 2500, history: 10, gc: 0, gctime: 7.4462890625, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } >process.memory() ={ free: 447, usage: 2053, total: 2500, history: 10, gc: 0, gctime: 7.87353515625, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } >process.memory() ={ free: 511, usage: 1989, total: 2500, history: 10, gc: 0, gctime: 7.41577148437, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } >process.memory() ={ free: 510, usage: 1990, total: 2500, history: 10, gc: 0, gctime: 7.41577148437, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } >process.memory() ={ free: 468, usage: 2032, total: 2500, history: 10, gc: 0, gctime: 7.53784179687, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } >process.memory() ={ free: 502, usage: 1998, total: 2500, history: 10, gc: 0, gctime: 7.4462890625, blocksize: 16, stackEndAddress: 536928912, flash_start: 0, flash_binary_end: 430980, flash_code_start: 442368, flash_length: 524288 } ERROR: Ctrl-C while processing interval - removing it. Execution Interrupted during event processing. New interpreter error: CALLBACK,LOW_MEMORY,MEMORY ERROR: Ctrl-C while processing interval - removing it. Execution Interrupted during event processing. Execution Interrupted Execution Interrupted Execution Interrupted New interpreter error: Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted > Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted Execution Interrupted
The errors happened just when calling
process.memory()
Any ideas someone?
I'll remove the logging into RAM completely now and see if that helps. -
@allObjects you are absolutely right.
I used PHP for most of the time, and a bit of MySQL too. I did some Web/Frontend stuff too. JQuery mostly, but maybe lacked a deeper understanding of the Javascript language which was slightly changing over the years too.I also like it because it is so easy to try. And pretty fast too...
I will update my other Puck.js today to run the lap-simulation code and then run a thorough test again.
One last question:
Does it matter that the console still stays attached to the BLE service, even if there is no active connection?
Can this cause issues?
I would expect that any output or error occurring will be queued somewhere in RAM and flushed to the console once you reconnect to the BLE service some time later.
That's why I added theErrorLog
mechanism, but it lacks a proper stack trace.
Are there better ways? -
Aaah - thanks for the brief explanation.
I was aware of the scope ofthis
and the technique of usingthat
but did not expect it to be an issue with just referencing a callback function likesetTimeout(this.log, …)
expecting it to be resolved just before the timeout is started.
However, thebind()
function was new to me, thanks for the suggestion.
And thatfunction() {}
is different from() => {}
regarding the scope ofthis
did not occur to me.
Javascript is easy and nice in some aspects, but has a lot of oddities when digging deeper...
Strange. I tested also with Puck and even the newest release to rule out some Board-specific issue. No luck.
It gets paired, but no key or volume change gets recognized by either iPhone nor MacBook.
However, this is not the project I'm working on, just a way to debug things "from the other side".
My original issue was just solved thanks to a hint by @Gordon :)