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

Connection Refused, works with gatttool #15

Closed
gabrielcolson opened this issue Nov 11, 2018 · 6 comments
Closed

Connection Refused, works with gatttool #15

gabrielcolson opened this issue Nov 11, 2018 · 6 comments

Comments

@gabrielcolson
Copy link

gabrielcolson commented Nov 11, 2018

I wrote this function (mostly inspired by the example):

    pub fn search() -> Result<(), failure::Error> {
        let manager = Manager::new()?;

        let adaptaters = manager.adapters()?;
        let mut adaptater = adaptaters.into_iter().nth(0).unwrap();

        adaptater = manager.down(&adaptater)?;
        adaptater = manager.up(&adaptater)?;

        let central = adaptater.connect()?;

        println!("Scanning...");
        central.start_scan()?;

        central.on_event(Box::new(|event| {
            match event {
                rumble::api::CentralEvent::DeviceDiscovered(device_address) => {
                    println!("{:?}", device_address);
                },
                _ => println!("other"),
            };
        }));

        thread::sleep(Duration::from_secs(3));

        for p in central.peripherals() {
            println!("name: {:?} address: {:?}", p.properties().local_name, p.properties().address);
        }
        Ok(())
    }

And my output is the following:

Scanning...
35:6B:C8:09:09:3E
80:7A:BF:E0:8A:B4
other
F8:3A:59:AF:67:25
07:5A:AE:EC:10:7A
EF:A5:3C:1F:49:16
name: None address: 00:00:00:00:00:00
name: None address: 00:00:00:00:00:00
name: None address: 00:00:00:00:00:00
name: None address: 00:00:00:00:00:00
name: Some("HTC BS B454C4") address: 00:00:00:00:00:00

I don't know if I misuse the library or if this is just a bug but in the meanwhile I guess I will have to workaround by getting the addresses from the events or by using another crate.

EDIT:
Ok so my main issue is that i can't get my program to get connected with my device. For the issue above, I looked at the code and figured out that the address field has nothing to do with the fact that the connection is refused.

I did copy/past the example and replaced the name of my device (which is the OpenBCI_Ganglion board). I get the following output:

found: F2:BC:72:E9:77:FD properties: PeripheralProperties { address: 00:00:00:00:00:00, address_type: Random, local_name: Some("Ganglion-9223"), tx_power_level: None, manufacturer_data: None, discovery_count: 2, has_scan_response: true }, characteristics: {}
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Other("ECONNREFUSED: Connection refused")', libcore/result.rs:1009:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.

for the following code:

pub fn main() {
    let manager = Manager::new().unwrap();

    // get the first bluetooth adapter
    let adapters = manager.adapters().unwrap();
    let mut adapter = adapters.into_iter().nth(0).unwrap();

    // reset the adapter -- clears out any errant state
    adapter = manager.down(&adapter).unwrap();
    adapter = manager.up(&adapter).unwrap();

    // connect to the adapter
    let central = adapter.connect().unwrap();

    // start scanning for devices
    central.start_scan().unwrap();
    // instead of waiting, you can use central.on_event to be notified of
    // new devices
    thread::sleep(Duration::from_secs(2));

    // find the device we're interested in
    let light = central.peripherals().into_iter()
        .find(|p| p.properties().local_name.iter()
            .any(|name| name.contains("Ganglion"))).unwrap();
    println!("found: {:?}", light);

    // connect to the device
    light.connect().unwrap();
    println!("connected !");

    // discover characteristics
    light.discover_characteristics().unwrap();

    // find the characteristic we want
    let chars = light.characteristics();
    let cmd_char = chars.iter().find(|c| c.uuid == UUID::B16(0xFFE9)).unwrap();

    // dance party
    let mut rng = thread_rng();
    for _ in 0..20 {
        let color_cmd = vec![0x56, rng.gen(), rng.gen(), rng.gen(), 0x00, 0xF0, 0xAA];
        light.command(&cmd_char, &color_cmd).unwrap();
        thread::sleep(Duration::from_millis(200));
    }
}

Do you see any reason why I get this "Connection Refused" error ? I tried with gatttool and it works perfectly though...

@gabrielcolson gabrielcolson changed the title All addresses are 00:00:00:00:00:00 in central.peripherals but not in central.on_event Connection Refused, works with gatttool Nov 11, 2018
@bleggett
Copy link
Contributor

bleggett commented Nov 15, 2018

There's a PR (#14) to fix the empty address issue.

As to why the connection is refused, are you sure the peripheral is not already connected to something else? Maybe reset the device being connected to? The library is working for me outside of a few bugs, connections and all.

@gabrielcolson
Copy link
Author

Thanks for responding @bleggett .
Yes I am very sure that the device is not already connected (the blue LED is blinking as usual when it is waiting for connection). Moreover, it is working perfectly with gatttool or the other softwares that I am used to work with. Do you see anything in my code that would trigger this error? The device seems to work fine though.

@bleggett
Copy link
Contributor

bleggett commented Nov 16, 2018

Nope, I'm doing almost exactly the same thing you are.

extern crate rumble;
extern crate rand;

use std::thread;
use std::env;
use std::time::Duration;
use rand::{Rng, thread_rng};
use rumble::bluez::manager::Manager;
use rumble::bluez::adapter::ConnectedAdapter;
use rumble::api::{UUID, Central, Peripheral, Characteristic};

pub fn main() {
    let args: Vec<String> = env::args().skip(1).collect();
    let manager = Manager::new().unwrap();

    // get the first bluetooth adapter
    let adapters = manager.adapters().unwrap();
    let mut adapter = adapters.into_iter().nth(0).unwrap();

    // reset the adapter -- clears out any errant state
    adapter = manager.down(&adapter).unwrap();
    adapter = manager.up(&adapter).unwrap();

    // connect to the adapter
    let central = adapter.connect().unwrap();

    // start scanning for devices
    println!("Beginning scan...");

    central.start_scan().unwrap();
    // instead of waiting, you can use central.on_event to be notified of
    // new devices
    thread::sleep(Duration::from_secs(1));

    let mut peripheral_calls: Vec<Box<Fn() -> Vec<u8>>> = Vec::new();

    let mut rng = thread_rng();

    for dev in args.iter() {
        // Some amount of wait is required here between connects or you get EDEVICEBUSY
        // TODO figure out how and why to handle that better
        thread::sleep(Duration::from_secs(1));

        let peripheral = query_and_connect(&central, dev);

        // peripherals.push(peripheral);

        println!("Connected, discovering characteristics...");
        peripheral.discover_characteristics().unwrap();


        // // find the characteristic we want
        // let chars = peripheral.characteristics();
        let cmd_char = get_characteristic_command(UUID::B16(0xEC0E), &peripheral);

        let color_cmd = vec![0x56, rng.gen(), rng.gen(), rng.gen(), 0x00, 0xF0, 0xAA];

        peripheral_calls.push(Box::new(move || peripheral.request(&cmd_char, &color_cmd).unwrap()));

    }
    for _ in 0..20 {
        for call in peripheral_calls.iter() {
            let result = call();
            println!("Command result! {:?}", result);
        }
        thread::sleep(Duration::from_millis(200));
    }
}

fn query_and_connect(adapter: &ConnectedAdapter, device_name: &str) -> Box<dyn Peripheral> {
    println!("Finding device...{}", device_name);
    let peripheral = adapter.peripherals().into_iter()
        .find(|p| p.properties().local_name.iter()
              .any(|name| name.contains(device_name))).unwrap();

    println!("Peripheral Properties found: {:#?}", peripheral.properties());

    println!("Connecting to...{}", device_name);
    peripheral.connect().unwrap();

    Box::new(peripheral)
}

fn get_characteristic_command(hexcode: UUID, peripheral: &Box<Peripheral>) -> Characteristic {
    println!("Getting characteristics...");
    let cmd_char = peripheral.characteristics().iter().find(|c| c.uuid == hexcode).unwrap().clone();

    println!("Command char found: {:#?}", cmd_char);
    cmd_char
}

@gabrielcolson
Copy link
Author

Okay so where do you think my error can come from ? My device is working fine and i can get connected with other tools before and after my tests with rumble

@bleggett
Copy link
Contributor

You might try RUST_LOG=debug executablename to see what output you get.

@mwylde
Copy link
Owner

mwylde commented Nov 25, 2018

I've merged #14, so hopefully the first problem is fixed (also, it's easier to access the address using peripheral.address(), not through the properties).

To help debug the second issue, can you send me a pcap trace of your bluetooth traffic while running the example? The easiest way to capture one is through wireshark. You can send it to micah@micahw.com.

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

3 participants