-
Notifications
You must be signed in to change notification settings - Fork 136
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
How to disconnect device or close adapter #247
Comments
I have the same issue. Disconnect on Windows doesn't actually seem to disconnect the device and i have to restart the software before i can connect to the same BT device again |
What is the error? What system are you on? How can I reproduce this issue? |
No errors are raised, the software next time around starts scanning fine and i can see other devices. but my OBDX Pro doesn't start announcing itself again until i close the test software. it's like even after i called Disconnect the device is not actually disconnected until i close the program. Im on Windows 11 23H2 22631.3155, Go 1.22 and using tdm-gcc as C compiler if that helps. Code is compiled as 64 bit as 32 bit panics and i've raised a issue here about it saltosystems/winrt-go#83 Here is some uggly code to trigger the problem: package main
import (
"log"
"time"
"github.com/roffe/gocan/dvi"
"tinygo.org/x/bluetooth"
)
var (
uartService = bluetooth.NewUUID([16]byte{0x6e, 0x40, 0x00, 0x01, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5, 0x0e, 0x24, 0xdc, 0xca, 0x9e})
gatUUID = map[string]string{
"00001800-0000-1000-8000-00805f9b34fb": "Generic Access",
"00001801-0000-1000-8000-00805f9b34fb": "Generic Attribute",
"6e400001-b5a3-f393-e0a9-e50e24dcca9e": "UART service",
}
characteristicUUID = map[string]string{
"6e400003-b5a3-f393-e0a9-e50e24dcca9e": "TX",
"6e400002-b5a3-f393-e0a9-e50e24dcca9e": "RX",
}
)
var adapter = bluetooth.DefaultAdapter
func init() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
func main() {
must("enable BLE stack", adapter.Enable())
for i := 0; i < 3; i++ {
main2()
time.Sleep(5 * time.Second)
}
}
func main2() {
// Enable BLE interface.
ch := make(chan bluetooth.ScanResult, 1)
// Start scanning.
println("scanning...")
err := adapter.Scan(func(adapter *bluetooth.Adapter, device bluetooth.ScanResult) {
//println("found device:", device.Address.String(), device.RSSI, device.LocalName())
log.Printf("found device: %s, %d, %s", device.Address.String(), device.RSSI, device.LocalName())
if device.LocalName() == "OBDX Pro GT" {
adapter.StopScan()
ch <- device
}
})
must("start scan", err)
var device bluetooth.Device
select {
case d := <-ch:
device, err = adapter.Connect(d.Address, bluetooth.ConnectionParams{})
if err != nil {
log.Fatal("failed to connect:", err)
}
log.Printf("connected to %s", d.Address.String())
case <-time.After(10 * time.Second):
log.Fatal("Did not find any OBDX Pro GT device")
}
svcs, err := device.DiscoverServices(nil)
if err != nil {
log.Fatal("failed to discover services:", err)
}
log.Println("services found:", len(svcs))
for _, svc := range svcs {
if name, ok := gatUUID[svc.UUID().String()]; ok {
log.Printf("service: %s (%s)", svc.String(), name)
} else {
log.Printf("service: %s", svc.String())
}
}
srvc := svcs[2]
chars, err := srvc.DiscoverCharacteristics(nil)
if err != nil {
log.Fatal("failed to discover characteristics:", err)
}
for _, char := range chars {
if name, ok := characteristicUUID[char.UUID().String()]; ok {
log.Printf("characteristic: %s (%s)", char.String(), name)
} else {
log.Printf("characteristic: %s", char.String())
}
}
rx := chars[0]
tx := chars[1]
err = rx.EnableNotifications(func(buf []byte) {
log.Printf("received: %X %q", buf, buf)
})
if err != nil {
log.Fatal("failed to enable notifications:", err)
}
for i := 0; i < 3; i++ {
tx.Write([]byte("\r\n"))
time.Sleep(50 * time.Millisecond)
}
//tx.Write([]byte("DXDP1\r"))
//time.Sleep(150 * time.Millisecond)
//tx.Write([]byte("AT@1\r"))
payload := dvi.New(0x22, []byte{0x03}).Bytes()
log.Printf("sending: %X", payload)
for i := 0; i < 3; i++ {
tx.Write(payload)
time.Sleep(2 * time.Second)
}
if err := device.Disconnect(); err != nil {
log.Fatal("failed to disconnect:", err)
}
}
func must(action string, err error) {
if err != nil {
log.Fatal("failed to " + action + ": " + err.Error())
}
} I can see during the scans in the 2 and 3rd itteration that the EnableNotifications handler still is getting data from the device so it's indeed the "disconnect" that doesn't free the adapter properly
|
Unfortunately the only Windows system I have available is a Windows ARM VM, where I can't get Bluetooth to work well (not even with an external Bluetooth USB stick). So I can't debug this myself. I looked at the code and we do correctly call
If the device doesn't actually get disconnected, my guess would be that we hold on a reference somewhere. |
it seems that in the second time around in the loop it can connect again to the BT device, but now when i DiscoverCharacteristics on the UART service it says it has 0 characteristics so i can't get a rx or tx characteristic to communicate with package main
import (
"log"
"time"
"github.com/roffe/gocan/dvi"
"tinygo.org/x/bluetooth"
)
var (
uartService = bluetooth.NewUUID([16]byte{0x6e, 0x40, 0x00, 0x01, 0xb5, 0xa3, 0xf3, 0x93, 0xe0, 0xa9, 0xe5, 0x0e, 0x24, 0xdc, 0xca, 0x9e})
gatUUID = map[string]string{
"00001800-0000-1000-8000-00805f9b34fb": "Generic Access",
"00001801-0000-1000-8000-00805f9b34fb": "Generic Attribute",
"6e400001-b5a3-f393-e0a9-e50e24dcca9e": "UART service",
}
characteristicUUID = map[string]string{
"6e400003-b5a3-f393-e0a9-e50e24dcca9e": "TX",
"6e400002-b5a3-f393-e0a9-e50e24dcca9e": "RX",
}
)
var adapter = bluetooth.DefaultAdapter
func init() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
}
func main() {
// Enable BLE interface.
must("enable BLE stack", adapter.Enable())
for i := 0; i < 3; i++ {
main2()
time.Sleep(5 * time.Second)
}
}
func main2() {
ch := make(chan bluetooth.ScanResult, 1)
addr := bluetooth.Address{}
addr.Set("64:B7:08:5F:F6:9A")
var err error
ch <- bluetooth.ScanResult{Address: addr}
var device bluetooth.Device
select {
case d := <-ch:
device, err = adapter.Connect(d.Address, bluetooth.ConnectionParams{})
if err != nil {
log.Fatal("failed to connect:", err)
}
log.Printf("connected to %s", d.Address.String())
case <-time.After(10 * time.Second):
log.Fatal("Did not find any OBDX Pro GT device")
}
svcs, err := device.DiscoverServices(nil)
if err != nil {
log.Fatal("failed to discover services:", err)
}
log.Println("services found:", len(svcs))
for _, svc := range svcs {
if name, ok := gatUUID[svc.UUID().String()]; ok {
log.Printf("service: %s (%s)", svc.String(), name)
} else {
log.Printf("service: %s", svc.String())
}
}
srvc := svcs[2]
chars, err := srvc.DiscoverCharacteristics(nil)
if err != nil {
log.Fatal("failed to discover characteristics:", err)
}
for _, char := range chars {
if name, ok := characteristicUUID[char.UUID().String()]; ok {
log.Printf("characteristic: %s (%s)", char.String(), name)
} else {
log.Printf("characteristic: %s", char.String())
}
}
if len(chars) < 2 {
log.Fatal("expected at least 2 characteristics got ", len(chars))
}
rx := chars[0]
tx := chars[1]
err = rx.EnableNotifications(func(buf []byte) {
log.Printf("received: %X %q", buf, buf)
})
if err != nil {
log.Fatal("failed to enable notifications:", err)
}
for i := 0; i < 3; i++ {
tx.Write([]byte("\r\n"))
time.Sleep(50 * time.Millisecond)
}
payload := dvi.New(0x22, []byte{0x03}).Bytes()
log.Printf("sending: %X", payload)
for i := 0; i < 3; i++ {
tx.Write(payload)
time.Sleep(2 * time.Second)
}
if err := device.Disconnect(); err != nil {
log.Fatal("failed to disconnect:", err)
}
}
func must(action string, err error) {
if err != nil {
log.Fatal("failed to " + action + ": " + err.Error())
}
}
|
I'm the same with Roffe. |
I tried. Disconnect successfully when i removing the code that scans for characteristics. So I think you can check out this code. |
I'm wildly speculating now as i don't know anything about bluetooth development but it feels like the characteristics we obtain after the scan is what's not being released, maybe there should be a .Close method on them to free them once you are done with a characteristic? |
oh well, it's one of those projects, you close issues that is not solved :D. Good thing i discovered this is not usable in my project before getting to invovled |
oh sorry, It was an operational error.I don't want to close issues. |
If that's the case, this is something the bluetooth library should do internally on disconnect. Not something the API user should have to worry about. (Again, I'd like to help but don't have the right system available). |
I think that could be one way. So what can i do if I want the function to work properly now.Can you give me some advice? Very anxious.Thank you. |
Maybe just patch the code. It's fairly simple code underneath. You probably just need to free / uninitialise something properly. Disconnection is working great for me on Windows, however it does not always truly disconnect the device immediately if it is being used for something. |
Thany you! Can you show me what to change?As far as I know,the code has not free / uninitialise method. |
I also encountered the same problem |
@hgqcode @hellosqi You could narrow it down by disabling parts of I don't have time to help at the moment (and also we internally forked this project and haven't updated in a while), but if no-one has looked at it in the next week or so I can try to see if there's some way we can convince Windows to let go of the device sooner. It may be possible or it may not, as with the WinRT Bluetooth API you don't own the device, you just own a session. It provides no guarantees that it will disconnect the physical device behind your session. But there probably is something that is making it hang around longer than it should. I have a feeling that we see a variety of side-effects from this, but we have worked around it in our higher level code. |
It doesn't work when i use disconnect device. so What am I supposed to do
The text was updated successfully, but these errors were encountered: