Skip to content

Instantly share code, notes, and snippets.

@IvanSanchez
Created October 18, 2017 09:03
Show Gist options
  • Save IvanSanchez/7e4d796616f4dfd85598bf0b1d627a25 to your computer and use it in GitHub Desktop.
Save IvanSanchez/7e4d796616f4dfd85598bf0b1d627a25 to your computer and use it in GitHub Desktop.
var noble = require('noble');
noble.on('stateChange', (state)=>{
console.log(state);
if (state === 'poweredOn') {
noble.startScanning();
} else {
noble.stopScanning();
}
});
noble.on('warning', function(warning) {
console.warn('Warning: ', warning);
});
noble.on('discover', function(peripheral) {
console.log(
"Found device with local name: ", peripheral.advertisement.localName,
" address ", peripheral.addressType, peripheral.address,
" service UUIDS ", peripheral.advertisement.serviceUuids,
" RSSI ", peripheral.rssi,
"\n" );
// If the device is advertising a Nordic Secure DFU (0xfe59) service...
// if (peripheral.advertisement.serviceUuids.indexOf('fe59') !== 1){
// Check if the device is advertiing a "DfuTest" name.
if (peripheral.advertisement.localName === 'DfuTest'){
noble.stopScanning();
peripheral.connect(onConnect.bind(peripheral));
}
});
function onConnect(err) {
if (err) { throw err; }
// Discover the DFU service
this.discoverServices(['fe59'], onDiscoverServices);
}
function onDiscoverServices(err, services) {
if (err) { throw err; }
var dfuService = services[0];
// Discover the two characteristics of the DFU service
dfuService.discoverCharacteristics(null, onDiscoverCharacteristics);
}
function onDiscoverCharacteristics(err, characteristics) {
if (err) { throw err; }
// console.log(characteristics);
var controlEndpoint = characteristics.filter(function(i){
return i.uuid === '8ec90001f3154f609fb8838830daea50'
})[0];
var dataEndpoint = characteristics.filter(function(i){
return i.uuid === '8ec90002f3154f609fb8838830daea50'
})[0];
// Change this value to receive notifications more/less often
var prn = 0x10;
controlEndpoint.subscribe(function() {
sendBytes(controlEndpoint, false, [
0x02, // 0x02 = "Set PRN" command. We expect a notification through the
prn, 0x00, // control characteristic every PRN (little-endian) data packets
])
.then(function(){
return waitForBytes(controlEndpoint); // Should receive 0x60 0x02 0x01.
})
.then(function(){
return sendBytes(controlEndpoint, false, [
0x01, // 0x01 = "Create object". The target should allocate ...
0x01, // ...in the command region (0x01) a buffer...
0xFF, 0x00, 0x00, 0x00 // ... of 0x000000FF (little-endian) bytes.
]);
})
.then(function(){
return waitForBytes(controlEndpoint); // Should receive 0x60 0x01 0x01.
})
.then(function(){ return sendDataBlock(controlEndpoint, dataEndpoint, prn); })
.then(function(){ return sendDataBlock(controlEndpoint, dataEndpoint, prn); })
.then(function(){ return sendDataBlock(controlEndpoint, dataEndpoint, prn); })
.then(function(){ return process.exit(0); })
});
}
// Returns a Promise
function sendBytes(endpoint, writeWithoutResponse, bytes) {
bytes = new Buffer(bytes);
// Uncomment the timeout to add a synthetic delay
return new Promise(function(res, rej){
// setTimeout(function() {
endpoint.write(bytes, writeWithoutResponse, function(err) {
if (writeWithoutResponse) {
console.log(' data --> ', bytes);
} else {
console.log(' cmnd --> ', bytes);
}
if (err) rej(err); else res();
});
// }, 250);
});
}
// Returns a Promise
function waitForBytes(endpoint) {
return new Promise(function(res, rej){
endpoint.once('data', function(bytes) {
console.log(' recv <-- ', bytes);
res(bytes);
});
});
}
// Sends a bunch of data blocks and then waits for a notification.
function sendDataBlock(controlEndpoint, dataEndpoint, prnLeft) {
if (prnLeft <= 0) {
return waitForBytes(controlEndpoint); // Should receive 0x60 0x03 [offset] [crc]
}
return sendBytes(dataEndpoint, true, [1,2,3,4,5,6,7,8])
.then(function(){
return sendDataBlock(controlEndpoint, dataEndpoint, prnLeft - 1);
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment