Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simultaneous connection with ANCS and other peripherals #3

Closed
sander opened this issue Oct 26, 2015 · 11 comments
Closed

Simultaneous connection with ANCS and other peripherals #3

sander opened this issue Oct 26, 2015 · 11 comments

Comments

@sander
Copy link
Contributor

sander commented Oct 26, 2015

I’m trying to use ble-ancs to connect to my iPhone for ANCS, to my heart rate sensor, and to an UART device (Bluefruit Micro) from one Node script. Both the sensor and the UART device are BLE peripherals. Before I spend hours trying to make it work, should this be possible in ble-ancs / able already?

[edit: removed irrelevant example, will update if I have a clearer example]

@sander
Copy link
Contributor Author

sander commented Oct 26, 2015

My code right now:

var BleAncs = require('../index');
var Able = require('../lib/able');

var ancs = new BleAncs();

ancs.on('notification', function(notification) {
  notification.readTitle(function(title) {
    notification.readMessage(function(message) {
      console.log('Notification: ' + notification); }); }); });

var SERVICE = '6e400001b5a3f393e0a9e50e24dcca9e';
var TX = '6e400002b5a3f393e0a9e50e24dcca9e';
var RX = '6e400003b5a3f393e0a9e50e24dcca9e';

var state = {peripheral: null, tx: null};

function onRead(v) {
  console.log('Read:', v.toString());};

var other = new Able()
.on('stateChange', function(state) {
  if (state == 'poweredOn') { other.startScanning(); }
  else { other.stopScanning(); }})
.on('discover', function(p) {
  console.log('peripheral', p.uuid);
  if (p.advertisement.serviceUuids.indexOf(SERVICE) != -1) {
    other.stopScanning();
    p.connect(function(err) {
      p.findService(SERVICE, function(err, services) {
        services[0].discoverCharacteristics([], function(err, cs) {
          cs.forEach(function(c) {
            if (c.uuid == TX) {
              state.tx = c; }
            else if (c.uuid == RX) {
              c.notify(true);
              c.on('read', onRead); }}); }); }); });
    state.peripheral = p; }});

When I comment out either the ANCS or UART part, the other part works as expected. When I try the full script, only ANCS works:

# node examples/test-multiple.js 
on -> stateChange: poweredOn
on -> advertisingStart: success
peripheral 68644b2f0965
peripheral 1499e21d7e71
peripheral b0349539cf8b
Bleno: Handle: 64 UUID: 6f777d0c23b0 address 6f:77:7d:0c:23:b0
on -> accept: 
able encryptChange!!!
peripheral d3c0f5a6366d
Connect - uuid: d3c0f5a6366d addres: d3:c0:f5:a6:36:6d
Notification: {"event":"added","flags":["silent","important"],"category":"other","categoryCount":2,"uid":4,"title":"TestFlight","subtitle":"","message":"iA Writer 3.0.3 (565) is now available for testing.","messageSize":51,"date":""}

The device that should connect and doesn’t succeed is d3c0f5a6366d. Any ideas on how to get this to work? Should it be easier (or possible at all) to use ble-ancs and Sandeep’s noble simultaneously?

@robotastic
Copy link
Owner

Hmm... This should be possible. Able is really just Noble and Bleno combined.

I would check out the index.js for ble-ancs. I bet it is doing something in there that is messing things up. You should be able to move most of this code into that file.

@sander
Copy link
Contributor Author

sander commented Oct 27, 2015

I’m trying a custom index.js at https://github.com/sander/ble-ancs/commit/790bdfa37f5b9e54724981ac7d5a0659a880fe7f. Noticing several things:

  1. With this._able.on('stateChange', this.onStateChange.bind(this)); in BleAncs, my UART device won’t connect, so I commented it out.
  2. My UART device disconnects after several seconds (varying per session). This didn’t happen with noble. It even happens if I comment out all ANCS code.
  3. I’ve been calling ancs.onStateChange('poweredOn') after service/characteristic discovery for my UART device, to compensate for change (1). On this call, BleAncs logs on -> advertisingStart: error Error: Unknown (12). After the UART device disconnects (automatically, unintended), BleAncs still connects to my phone and receives notifications. See the log below.

How would you recommend proceeding? It seems like advertising conflicts with scanning, and like established connections die after a while.

# node test-issue3.js 
uart init
uart discovered
uart discovered
Connect - uuid: d3c0f5a6366d addres: d3:c0:f5:a6:36:6d
uart connected
uart starting ancs
on -> stateChange: poweredOn
on -> advertisingStart: error Error: Unknown (12)
uart read: L586;
uart read: L566;L552;
uart read: L536;L521;L467;
uart read: L480;
uart read: L457;L486;L550;L561;
uart read: L579;
uart read: L591;
        Hande:64    uuid: d3c0f5a6366d
Got a disconnect
uart disconnected
Got a disconnect
Able: unknown peripheral d3:c0:f5:a6:36:6d disconnected!
Bleno: Handle: 64 UUID: 7e122588a5ee address 7e:12:25:88:a5:ee
on -> accept: 
        Hande:64    uuid: 7e122588a5ee
Got a disconnect
Got a disconnect
Got a disconnect
Able: unknown peripheral 7e:12:25:88:a5:ee disconnected!
Bleno: Handle: 64 UUID: 7e122588a5ee address 7e:12:25:88:a5:ee
on -> accept: 
Recieved a Pairing Request
able encryptChange!!!
Notification: {"event":"added","flags":["silent","important"],"category":"location","categoryCount":1,"uid":0,"title":"Reisplanner","subtitle":"","message":"Uw volgende trein vertrekt om 14:36 van spoor 3b\nVertrektijd zoals gepland","messageSize":74,"date":""}

@robotastic
Copy link
Owner

One thing I would check is if the Bluetooth device you are using supports Advertising and Scanning at the same time. Try doing sudo hciconfig hci0 lestates and look for something like: YES Connectable Advertising State and Active Scanning State combination

I am not sure what the difference is to be honest. I think it could be a good idea to try using hcidump to look for the differences. It could be that there is something in there that is stopping the advertisements, which cause the peripheral to disconnect...

@sander
Copy link
Contributor Author

sander commented Oct 28, 2015

The lestates seem positive:

# hciconfig hci0 lestates
Supported link layer states:
        YES Non-connectable Advertising State
        YES Scannable Advertising State
        YES Connectable Advertising State
        YES Directed Advertising State
        YES Passive Scanning State
        YES Active Scanning State
        YES Initiating State/Connection State in Master Role
        YES Connection State in the Slave Role
        YES Non-connectable Advertising State and Passive Scanning State combination
        YES Scannable Advertising State and Passive Scanning State combination
        YES Connectable Advertising State and Passive Scanning State combination
        YES Directed Advertising State and Passive Scanning State combination
        YES Non-connectable Advertising State and Active Scanning State combination
        YES Scannable Advertising State and Active Scanning State combination
        YES Connectable Advertising State and Active Scanning State combination
        YES Directed Advertising State and Active Scanning State combination
        YES Non-connectable Advertising State and Initiating State combination
        YES Scannable Advertising State and Initiating State combination
        YES Non-connectable Advertising State and Master Role combination
        YES Scannable Advertising State and Master Role combination
        YES Non-connectable Advertising State and Slave Role combination
        YES Scannable Advertising State and Slave Role combination
        YES Passive Scanning State and Initiating State combination
        YES Active Scanning State and Initiating State combination
        YES Passive Scanning State and Master Role combination
        YES Active Scanning State and Master Role combination
        YES Passive Scanning State and Slave Role combination
        YES Active Scanning State and Slave Role combination
        YES Initiating State and Master Role combination/Master Role and Master Role combination

Good idea to compare the hcidump output between noble and able, I’ll try that later today.

@sander
Copy link
Contributor Author

sander commented Oct 29, 2015

I can’t reproduce the disconnection issue anymore so I assume that was an issue with my UART device. Still, I can’t have both the UART device and iOS/ANCS connected at the same time. This is my simplified test script now:

var Able = require('./lib/able');
var BleAncs = require('./index');

var TRY_WITH_ANCS = false;
var UART = '6e400001b5a3f393e0a9e50e24dcca9e';

function TestIssue3() {
  this._able = new Able()
  .on('stateChange', this.onStateChange.bind(this))
  .on('discover', this.onDiscover.bind(this));
  if (TRY_WITH_ANCS) this._able.on('advertisingStart', BleAncs.prototype.onAdvertisingStart.bind(this));
};
TestIssue3.prototype.onStateChange = function(state) {
  console.log('state', state);
  if (TRY_WITH_ANCS) BleAncs.prototype.onStateChange.call(this, 'poweredOn');
  if (state == 'poweredOn') this._able.startScanning();
  else this._able.stopScanning();
};
TestIssue3.prototype.onDiscover = function(peripheral) {
  console.log('discovered', peripheral.uuid);
  if (this._uart || peripheral.advertisement.serviceUuids.indexOf(UART) == -1) return;
  console.log('found uart device');
  this._able.stopScanning();
  this._uart = peripheral;
  peripheral.connect(function(e) { console.log('connected', e); });
};

var test = new TestIssue3();

When TRY_WITH_ANCS = true, this is the output:

# node issue3.js
state poweredOn
on -> stateChange: poweredOn
on -> advertisingStart: success
discovered 563dd861449b
discovered 4d7f669638eb
discovered e2d5284cdde4
found uart device
Connect - uuid: e2d5284cdde4 addres: e2:d5:28:4c:dd:e4
Bleno: Handle: 64 UUID: 46c41c027aee address 46:c4:1c:02:7a:ee

hcidump shows this about the attempted connection:

< HCI Command: LE Create Connection (0x08|0x000d) plen 25
    bdaddr E2:D5:28:4C:DD:E4 type 1
    interval 96 window 48 initiator_filter 0
    own_bdaddr_type 0 min_interval 6 max_interval 12
    latency 0 supervision_to 200 min_ce 4 max_ce 6
> HCI Event: Command Status (0x0f) plen 4
    LE Create Connection (0x08|0x000d) status 0x0c ncmd 1
    Error: Command Disallowed

The full log with TRY_WITH_ANCS = true is here.

When TRY_WITH_ANCS = false, this is the output:

# node issue3.js
state poweredOn
discovered 4d7f669638eb
discovered 563dd861449b
discovered db12bef4fee8
discovered e2d5284cdde4
found uart device
Connect - uuid: e2d5284cdde4 addres: e2:d5:28:4c:dd:e4
connected null

hcidump shows this about the attempted connection:

< HCI Command: LE Create Connection (0x08|0x000d) plen 25
    bdaddr E2:D5:28:4C:DD:E4 type 1
    interval 96 window 48 initiator_filter 0
    own_bdaddr_type 0 min_interval 6 max_interval 12
    latency 0 supervision_to 200 min_ce 4 max_ce 6
> HCI Event: Command Status (0x0f) plen 4
    LE Create Connection (0x08|0x000d) status 0x00 ncmd 1

The full log with TRY_WITH_ANCS = false is here.

So it seems that we can’t connect to a peripheral while advertising as a peripheral. I’ll try connecting to the UART peripheral once the role-switching for ANCS has finished. Better ideas welcome :-)

@sander
Copy link
Contributor Author

sander commented Oct 29, 2015

Trying to connect to the UART peripheral after encryptChange doesn’t help. The code:

var Able = require('./lib/able');
var BleAncs = require('./index');

var util = require('util');
var events = require('events');

var UART = '6e400001b5a3f393e0a9e50e24dcca9e';

function TestIssue3b() {
  this._able = new Able()
  .on('encryptChange', this.startUart.bind(this))
  .on('discover', this.onDiscover.bind(this))
  .on('stateChange', this.onStateChange.bind(this))
  .on('accept', this.onAccept.bind(this))
  .on('mtuChange', this.onMtuChange.bind(this))
  .on('advertisingStart', this.onAdvertisingStart.bind(this))
  .on('encryptChange', this.onEncryptChange.bind(this))
  .on('encryptFail', this.onEncryptFail.bind(this))
  .on('connect', this.onConnect.bind(this))
  this._characteristics = {};
  this._notifications = {};
  this._lastUid = null;
};
util.inherits(TestIssue3b, BleAncs);
TestIssue3b.prototype.startUart = function() {
  console.log('scanning for uart');
  this._able.startScanning();
};
TestIssue3b.prototype.onDiscover = function(peripheral) {
  console.log('discovered', peripheral.uuid);
  if (this._uart || peripheral.advertisement.serviceUuids.indexOf(UART) == -1) return;
  console.log('found uart device');
  this._able.stopScanning();
  this._uart = peripheral;
  peripheral.connect(function(e) { console.log('connected', e); });
};

var test = new TestIssue3b();

The error (same as above):

< HCI Command: LE Create Connection (0x08|0x000d) plen 25
    bdaddr E2:D5:28:4C:DD:E4 type 1
    interval 96 window 48 initiator_filter 0
    own_bdaddr_type 0 min_interval 6 max_interval 12
    latency 0 supervision_to 200 min_ce 4 max_ce 6
> HCI Event: Command Status (0x0f) plen 4
    LE Create Connection (0x08|0x000d) status 0x0c ncmd 1
    Error: Command Disallowed

Full log on Gist

I’m out of ideas. Do you think this is a bug in able, a limitation of my Edison chipset or BlueZ, or something else? Do you have alternative ideas for combining ble-ancs with an UART connection, for example, would it be possible to control a second BLE dongle using the same library?

@robotastic
Copy link
Owner

Hmm… my guess is that the Edison Chipset or Bluez may not like acting as a Central and Peripheral at the same time. Is the BLE built in? You could probably add a second dongle, but then you might as well just have 2 separate programs running.

There error below is coming from Bluez or the HW. It might be worth tracking down in the Bluez source to figure out what triggers the Command Disallowed error.

HCI Event: Command Status (0x0f) plen 4
LE Create Connection (0x08|0x000d) status 0x0c ncmd 1
Error: Command Disallowed

It is really weird that it works separately, but not when combined!

On Oct 29, 2015, at 7:24 AM, Sander Dijkhuis notifications@github.com wrote:

Trying to connect to the UART peripheral after encryptChange doesn’t help. The code:

var Able = require('./lib/able');
var BleAncs = require('./index');

var util = require('util');
var events = require('events');

var UART = '6e400001b5a3f393e0a9e50e24dcca9e';

function TestIssue3b() {
this._able = new Able()
.on('encryptChange', this.startUart.bind(this))
.on('discover', this.onDiscover.bind(this))
.on('stateChange', this.onStateChange.bind(this))
.on('accept', this.onAccept.bind(this))
.on('mtuChange', this.onMtuChange.bind(this))
.on('advertisingStart', this.onAdvertisingStart.bind(this))
.on('encryptChange', this.onEncryptChange.bind(this))
.on('encryptFail', this.onEncryptFail.bind(this))
.on('connect', this.onConnect.bind(this))
this._characteristics = {};
this._notifications = {};
this._lastUid = null;
};
util.inherits(TestIssue3b, BleAncs);
TestIssue3b.prototype.startUart = function() {
console.log('scanning for uart');
this._able.startScanning();
};
TestIssue3b.prototype.onDiscover = function(peripheral) {
console.log('discovered', peripheral.uuid);
if (this._uart || peripheral.advertisement.serviceUuids.indexOf(UART) == -1) return;
console.log('found uart device');
this._able.stopScanning();
this._uart = peripheral;
peripheral.connect(function(e) { console.log('connected', e); });
};

var test = new TestIssue3b();
The error (same as above):

< HCI Command: LE Create Connection (0x08|0x000d) plen 25
bdaddr E2:D5:28:4C:DD:E4 type 1
interval 96 window 48 initiator_filter 0
own_bdaddr_type 0 min_interval 6 max_interval 12
latency 0 supervision_to 200 min_ce 4 max_ce 6

HCI Event: Command Status (0x0f) plen 4
LE Create Connection (0x08|0x000d) status 0x0c ncmd 1
Error: Command Disallowed
Full log on Gist https://gist.githubusercontent.com/sander/45d1f1740abf6612e121/raw/574289d0a3c3bf27afa38ad87e32021c9d9991c0/other-order.txt
I’m out of ideas. Do you think this is a bug in able, a limitation of my Edison chipset or BlueZ, or something else? Do you have alternative ideas for combining ble-ancs with an UART connection, for example, would it be possible to control a second BLE dongle using the same library?


Reply to this email directly or view it on GitHub #3 (comment).

@sander
Copy link
Contributor Author

sander commented Oct 30, 2015

Yes, there’s a Broadcom BCM43340 chip integrated in the Edison. Is there a way to instruct the second Bluetooth program (Node script) to use the second dongle, and not try the same one as the first Bluetooth program?

@robotastic
Copy link
Owner

Noble, Bleno, and Able all have language to specify which dongle to use. Checkout hci.js :
https://github.com/robotastic/ble-ancs/blob/master/lib/hci-socket/hci.js#L121
If you specify it as an environment variable it should use that dongle. It might be better to just hard code it since there would be 2 different instances.

@sander
Copy link
Contributor Author

sander commented Nov 2, 2015

Works well when I run one with ABLE_HCI_DEVICE_ID=0 and the other with ABLE_HCI_DEVICE_ID=1. I’m going to experiment with Node’s require('child_process').fork() to get all the data still in one process. Thanks for the help, amazing to finally get full iOS notifications reliably on my Edison!

Closing this bug since it seems a driver/hardware issue, not something in ble-ancs or able.

@sander sander closed this as completed Nov 2, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants