Как предотвратить соединение Android Bluetooth RFCOMM от смерти сразу после.connect()?
Эта проблема была решена! Большое спасибо Брэду, Денису и наркоману! Вы герои!:)
Это рабочий код. Он подключается к Zeemote и считывает данные с него.
===== Код =====
открытый класс ZeeTest расширяет активность { @Override public void onCreate(BundlevedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); пытаться { для (int i = 0; i < 3; i++) { тестовое задание(); } } catch (исключение e) { e.printStackTrace(); } } частное логическое соединение = ложь; приватный носок BluetoothSocket; private InputStream in; public void test() выдает Exception { если (подключен) { вернуть; } BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter(). getRemoteDevice("00:1C:4D:02:A6:55"); Метод m = zee.getClass(). GetMethod("createRfcommSocket", новый класс [] { int.class }); sock = (BluetoothSocket)m.invoke(zee, Integer.valueOf(1)); Log.d("ZeeTest", "++++ Connecting"); sock.connect(); Log.d("ZeeTest", "++++ Connected"); in = sock.getInputStream(); byte[] buffer = new byte[50]; int read = 0; Log.d("ZeeTest", "++++ Listening..."); пытаться { while (true) { read = in.read(буфер); подключен = правда; StringBuilder buf = new StringBuilder(); for (int i = 0; i===== Оригинальный вопрос =====
Я пытаюсь подключиться к игровому контроллеру Zeemote ( http://zeemote.com/) от Moto Droid с прошивкой 2.0.1. Тестовое приложение, приведенное ниже, подключается к устройству (светодиод мигает), но сразу после этого соединение прерывается.
Ниже я вставляю два тестовых приложения: одно, которое на самом деле пытается прочитать из входного потока, и второе, которое просто сидит там, ожидая отключения устройства через 5 секунд. И да, у меня есть третья версия:), которая сначала ждет ACL_CONNECTED, а затем открывает сокет, но в его поведении нет ничего нового.
Немного справочной информации: я могу отлично подключиться к Zeemote с моего ноутбука с помощью инструментов bluez (журнал также прилагается). Я точно знаю, что Droid также может общаться с Zeemote, потому что "Game Pro" из Маркета прекрасно с ним работает (но тогда это драйвер / сервис, так что, возможно, он использует API более низкого уровня?).
Я заметил, что 'adb bugreport' не сообщает ни о UUID, ни о канале RFCOMM для Zeemote, в то время как он делает это для всех других устройств (включая гарнитуру Moto HS815, еще одно тупое устройство, для которого 'sdp browse' ничего не сообщает). Кроме того, при загрузке устройства приоритет Zeemote равен 0 (другие имеют приоритет 100+).
Я в полном недоумении, я работал над этим так долго, что у меня кончились идеи, поэтому любая помощь будет очень признательна (даже если вы не знаете ответ:))
Спасибо Макс
Тестовое приложение № 1
Это приложение пытается на самом деле читать с устройства.
===== Код =====
открытый класс ZeeTest расширяет активность { @Override public void onCreate(BundlevedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); пытаться { тестовое задание(); } catch (IOException e) { e.printStackTrace(); } } приватный носок BluetoothSocket; private InputStream in; public void test() выдает IOException { BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter(). getRemoteDevice("00:1C:4D:02:A6:55"); sock = zee.createRfcommSocketToServiceRecord( UUID.fromString("8e1f0cf7-508f-4875-b62c-fbb67fd34812")); Log.d("ZeeTest", "++++ Connecting"); sock.connect(); Log.d("ZeeTest", "++++ Connected"); in = sock.getInputStream(); byte[] buffer = new byte[1]; int bytes = 0; int x = 0; Log.d("ZeeTest", "++++ Listening..."); while (x < 2) { х ++; пытаться { bytes = in.read(буфер); Log.d("ZeeTest", "++++ Read "+ bytes +" bytes"); } catch (IOException e) { e.printStackTrace(); попробуй { Thread.sleep(100); } catch (InterruptedException ie) {} } } Log.d("ZeeTest", "++++ Done: test()"); } @Override public void onDestroy() { пытаться { if (in! = null) { in.close (); } if (sock! = null) { sock.close (); } } catch (IOException e) { e.printStackTrace (); } super.onDestroy (); } }===== Журнал =====
04-19 22: 27: 01.147: DEBUG / ZeeTest (8619): ++++ Подключение 04-19 22:27:04.085: INFO/usbd(1062): process_usb_uevent_message(): buffer = add@/devices/virtual/bluetooth/hci0/hci0:1 04-19 22:27:04.085: INFO/usbd(1062): main(): выбор вызова (...) 04-19 22:27:04.327: ОШИБКА /BluetoothEventLoop.cpp(4029): event_filter: получен сигнал org.bluez.Device:PropertyChanged from /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55 04-19 22:27:04.491: VERBOSE/BluetoothEventRedirector(7499): получено android.bleactionUID.vice 04-19 22:27:04.905: DEBUG/ZeeTest(8619): ++++ Подключено 04-19 22:27:04.905: DEBUG/ZeeTest(8619): ++++ Прослушивание... 04-19 22:27:05.538: WARN/System.err(8619): java.io.IOException: программное обеспечение вызвало прерывание соединения 04-19 22:27:05.600: WARN/System.err(8619): at android.bluetooth.BluetoothSocket.readNative(Собственный метод) ... 04-19 22:27:05.717: WARN/System.err(8619): java.io.IOException: программное обеспечение вызвало прерывание соединения 04-19 22: 27: 05.717: WARN / System.err (8619): на android.bluetooth.Blueto othSocket.readNative (собственный метод) ... 04-19 22:27:05.819: DEBUG/ZeeTest(8619): ++++ Выполнено: test() 04-19 22:27:07.155: VERBOSE/BluetoothEventRedirector(7499): Получено android.bleutooth.device.action.UUID 04-19 22:27:09.077: INFO/usbd(1062): process_usb_uevent_message(): buffer = remove@/devices/virtual/bluetooth/hci0/hci0:1 04-19 22:27:09.085: INFO/usbd(1062): main(): выбор вызова (...) 04-19 22:27:09.139: ERROR/BluetoothEventLoop.cpp(4029): event_filter: полученный сигнал org.bluez. Устройство: PropertyChanged from / org / bluez / 4121 / hci0 / dev_00_1C_4D_02_A6_55Тестовое приложение № 2
Этот тест подключается и ждет - полезно для отображения проблемы автоматического отключения.
===== Код =====
открытый класс ZeeTest расширяет активность { @Override public void onCreate(BundlevedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); getApplicationContext().registerReceiver(приемник, новый IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)); getApplicationContext().registerReceiver(приемник, новый IntentFilter(BluetoothDevice.ACTION_ACL_DISCONNECTED)); пытаться { BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter (). getRemoteDevice ("00: 1C: 4D: 02: A6: 55"); sock = zee.createRfcommSocketToServiceRecord (UUID.fromString ("8e1f0cf7-508f-4875-b62c-fbb67fd34812")); Log.d ("ZeeTest", "++++ Connecting"); sock.connect (); Log.d ("ZeeTest", "++++ Connected"); } catch (IOException e) { e.printStackTrace(); } } приватное статическое окончание LogBroadcastReceiver receive = new LogBroadcastReceiver(); открытый статический класс LogBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Контекст контекста, Намерение намерения) { Log.d("ZeeReceiver", intent.toString()); Bundle extras = intent.getExtras(); for (строка k: extras.keySet()) { Log.d("ZeeReceiver", " Extra: "+ extras.get(k).toString()); } } } приватный носок BluetoothSocket; @Override public void onDestroy() {. GetApplicationContext () unregisterReceiver(приемник); if (sock!= null) { пытаться { sock.close (); } catch (IOException e) { e.printStackTrace (); } } super.onDestroy (); } }===== Журнал =====
04-19 22: 06: 34.944: DEBUG / ZeeTest (7986): ++++ Подключение 04-19 22:06:38.202: INFO/usbd(1062): process_usb_uevent_message(): buffer = add@/devices/virtual/bluetooth/hci0/hci0:1 04-19 22:06:38.202: INFO/usbd(1062): main(): выбор вызова (...) 04-19 22:06:38.217: ОШИБКА /BluetoothEventLoop.cpp(4029): event_filter: полученный сигнал org.bluez.Device:PropertyChanged from /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55 04-19 22:06:38.428: VERBOSE/BluetoothEventRedirector(7499): получено android.bleactionUID.vice 04-19 22:06:38.968: DEBUG/ZeeTest(7986): ++++ Подключено 04-19 22:06:39.061: DEBUG/ZeeReceiver(7986): Intent { act=android.bluetooth.device.action.ACL_CONNECTED (есть дополнения) } 04-19 22:06:39.108: DEBUG/ZeeReceiver(7986): дополнительно: 00:1C:4D:02:A6:55 04-19 22:06:39.538: INFO/ActivityManager(4029): Отображаемая активность zee.test/.ZeeTest: 5178 мс (всего 5178 мс) 04-19 22:06:41.014: VERBOSE/BluetoothEventRedirector(7499): получено android.bleutooth.device.action.UUID 04-19 22:06:43.038: INFO/usbd(1062): process_usb_uevent_message(): buffer = remove@/devices/virtual/bluetooth/hci0/hci0:1 04-19 22:06:43.038: INFO/usbd(1062): main(): вызов выбора (...) 04-19 22:06:43.069: ОШИБКА /BluetoothEventLoop.cpp(4029): event_filter: полученный сигнал org.bluez.Device:PropertyChanged from /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55 04-19 22:06:43.124: DEBUG/ZeeReceiver(7986): Intent { act=android.bluetooth.device.action.ACL_DISCONNECTED (имеет дополнения) } 04-19 22:06:43.124: DEBUG/ZeeReceiver(7986): дополнительно: 00: 1C: 4D: 02: A6: 55Системные журналы
===== Терминальный журнал =====
$ sdptool browse Спрашивая... Просмотр 00: 1C: 4D: 02: A6: 55... $ sdptool записывает 00: 1C: 4D: 02: A6: 55 Название услуги: Zeemote RecHandle службы: 0x10015 Список идентификаторов классов обслуживания: UUID 128: 8e1f0cf7-508f-4875-b62c-fbb67fd34812 Список дескрипторов протокола: "L2CAP" (0x0100) "RFCOMM" (0x0003) Канал: 1 Список базовых языков: code_ISO639: 0x656e кодировка: 0x6a base_offset: 0x100 $ rfcomm connect / dev / tty10 00: 1C: 4D: 02: A6: 55 Подключено /dev/rfcomm0 к 00: 1C: 4D: 02: A6: 55 на канале 1 Нажмите CTRL-C для зависания # rfcomm show /dev/tty10 rfcomm0: 00:1F:3A:E4:C8:40 -> 00:1C:4D:02:A6:55 подключен канал 1 [reuse-dlc release-on-hup tty-connected] # cat / dev / tty10 (здесь ничего) # hcidump HCI сниффер - анализатор пакетов Bluetooth версия 1.42 устройство: hci0 snap_len: 1028 фильтр: 0xffffffff <Команда HCI: создать соединение (0x01 | 0x0005) plen 13 > Событие HCI: статус команды (0x0f) plen 4 > Событие HCI: Connect Complete (0x03) plen 11 <Команда HCI: чтение поддерживаемых функций удаленного доступа (0x01 | 0x001b) plen 2 > Событие HCI: чтение удаленных поддерживаемых функций (0x0b) plen 11 <Данные ACL: обрабатывать 11 флагов 0x02 dlen 10 L2CAP (s): информационный запрос: тип 2 > Событие HCI: статус команды (0x0f) plen 4 > Событие HCI: изменение режима повторения сканирования страницы (0x20) plen 7 > Событие HCI: максимальное изменение слотов (0x1b) plen 3 <Команда HCI: запрос удаленного имени (0x01 | 0x0019) plen 10 > Событие HCI: статус команды (0x0f) plen 4 > Данные ACL: обрабатывать 11 флагов 0x02 dlen 16 L2CAP: Info rsp: type 2 result 0 Маска с расширенными функциями 0x0000 <Данные ACL: обрабатывать 11 флагов 0x02 и 12 дней L2CAP (s): Требуется соединение: psm 3 scid 0x0040 > Событие HCI: количество завершенных пакетов (0x13) plen 5 > Данные ACL: обрабатывать 11 флагов 0x02 dlen 16 L2CAP(s): Connect rsp: dcid 0x04fb scid 0x0040 результат 1, статус 2 Ожидание подключения - ожидание авторизации > Событие HCI: удаленный запрос имени завершен (0x07) plen 255 > Данные ACL: обрабатывать 11 флагов 0x02 dlen 16 L2CAP: Connect rsp: dcid 0x04fb scid 0x0040 результат 0 статус 0 Соединение успешно <Данные ACL: обрабатывать 11 флагов 0x02 и 16 дней L2CAP: Config req: dcid 0x04fb flags 0x00 clen 4 MTU 1013 (события правильно принимаются с использованием bluez)===== Часть отчета об ошибках adb =====
Известные устройства 00:19:A1:2D:16:EA (0) LG U830 00001105-0000-1000-8000-00805f9b34fb RFCOMM канал = 17 00:1C:4D:02:A6:55 связаны (0) Zeemote JS1 00:0B:2E:6E:6F:00 (0) Motorola HS815 00001108-0000-1000-8000-00805f9b34fb RFCOMM канал = 1 0000111e-0000-1000-8000-00805f9b34fb RFCOMM канал = 2 00:1F:3A:E4:C8:40 (0) BRCM BT4X 00001105-0000-1000-8000-00805f9b34fb RFCOMM канал = 9 00:18:42:EC:E2:99 (0) N95 00001105-0000-1000-8000-00805f9b34fb RFCOMM канал = 9===== Выдержка из журнала загрузки =====
04-18 21: 55: 10.382: VERBOSE / BluetoothEventRedirector (1985): получено android.bluetooth.adapter.action.STATE_CHANGED 04-18 21:55:10.421: DEHUG/BT HSHFP(1237): загруженный приоритет 00:19:A1:2D:16:EA = 100 04-18 21:55:10.428: DEHUG/BT HSHFP(1237): загруженный приоритет 00:1C:4D:02:A6:55 = 0 04-18 21:55:10.444: DEHUG/BT HSHFP(1237): приоритет загрузки 00:0B:2E:6E:6F:00 = 101 04-18 21:55:10.749: DEHUG/BT HSHFP(1237): загруженный приоритет 00:1F:3A:E4:C8:40 = 100 04-18 21:55:10.780: DEHUG/BT HSHFP(1237): приоритет загрузки 00:18:42:EC:E2:99 = 100
5 ответов
Попробуйте изменить код для создания RfcommSocket:
sock = zee.createRfcommSocketToServiceRecord(
UUID.fromString("8e1f0cf7-508f-4875-b62c-fbb67fd34812"));
для этого кода:
Method m = zee.getClass().getMethod("createRfcommSocket", new Class[] { int.class });
sock = (BluetoothSocket) m.invoke(device, 1);
Также попробуйте изменить значение аргумента в диапазоне 1-3 в этом m.invoke(device, 1); Когда соединение будет подключено, но прервано при попытке чтения, снова вызовите в вашем цикле ваш метод test(). Как просто:
for(int i=0;i<3;i++){ if(!testDone) test(); }
Я объединил написанный мной код и код от [android-beginners] Re: Serial over Bluetooth от XCaffeinated] 1 и выше.
Создать простейшую из возможных программ bluetooth.
Основным дополнением для этого кода является улучшенная обработка исключений, создаваемых connect()
,
Ищите "@todo", чтобы настроить его под свои нужды.
Надеюсь, это сэкономит вам время!
package com.xxx; // @todo Change to your package.
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Bundle;
import android.util.Log;
/**
* This is the simplest bluetooth program. It sends one message to one bluetooth
* device. The message and the bluetooth hardware id for the device are hard
* coded. <br>
* <br>
* It does <b>not</b> receive any data. It does not do any thread processing. <br>
* <br>
*
* This application will be useful to communicate with a bluetooth hardware
* device such as a bar code reader, Lego Mindstorm, a PC with a com port
* application, a PC with a terminal program with 'listening' to a com port, a
* second android device with a terminal program such as <a href=
* "http://www.tec-it.com/en/software/data-acquisition/getblue/android-smartphone/Default.aspx"
* >GetBlue</a>. It is not a full android bluetooth application but more a proof
* of concept that the bluetooth works.
*
* <br>
* <br>
*
* This code should cut and paste into the <a
* href="http://developer.android.com/resources/tutorials/hello-world.html>
* 'HelloAndroid' example</a>. It does not use any screen io.
*
* Add to your Android Manifest.xml file: <uses-permission
* android:name="android.permission.BLUETOOTH" /> <uses-permission
* android:name="android.permission.BLUETOOTH_ADMIN" />
*
* For a proper bluetooth example with threading and receiving data see: <a
* href=
* "http://developer.android.com/resources/samples/BluetoothChat/index.html"
* >http://developer.android.com/resources/samples/BluetoothChat/index.html</a>
*
* @see <a
* href="http://developer.android.com/guide/topics/wireless/bluetooth.html">
* http://developer.android.com/guide/topics/wireless/bluetooth.html</a>
*
*/
public class BlueToothTesterActivity extends Activity {
/** The BluetoothAdapter is the gateway to all bluetooth functions **/
protected BluetoothAdapter bluetoothAdapter = null;
/** We will write our message to the socket **/
protected BluetoothSocket socket = null;
/** The Bluetooth is an external device, which will receive our message **/
BluetoothDevice blueToothDevice = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Grab the BlueToothAdapter. The first line of most bluetooth programs.
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// if the BluetoothAdapter.getDefaultAdapter(); returns null then the
// device does not have bluetooth hardware. Currently the emulator
// does not support bluetooth so this will this condition will be true.
// i.e. This code only runs on a hardware device an not on the emulator.
if (bluetoothAdapter == null) {
Log.e(this.toString(), "Bluetooth Not Available.");
return;
}
// This will find the remote device given the bluetooth hardware
// address.
// @todo: Change the address to the your device address
blueToothDevice = bluetoothAdapter.getRemoteDevice("00:00:00:00:00:00");
for (Integer port = 1; port <= 3; port++) {
simpleComm(Integer.valueOf(port));
}
}
protected void simpleComm(Integer port) {
// byte [] inputBytes = null;
// The documents tell us to cancel the discovery process.
bluetoothAdapter.cancelDiscovery();
Log.d(this.toString(), "Port = " + port);
try {
// This is a hack to access "createRfcommSocket which is does not
// have public access in the current api.
// Note: BlueToothDevice.createRfcommSocketToServiceRecord (UUID
// uuid) does not work in this type of application. .
Method m = blueToothDevice.getClass().getMethod(
"createRfcommSocket", new Class[] { int.class });
socket = (BluetoothSocket) m.invoke(blueToothDevice, port);
// debug check to ensure socket was set.
assert (socket != null) : "Socket is Null";
// attempt to connect to device
socket.connect();
try {
Log.d(this.toString(),
"************ CONNECTION SUCCEES! *************");
// Grab the outputStream. This stream will send bytes to the
// external/second device. i.e it will sent it out.
// Note: this is a Java.io.OutputStream which is used in several
// types of Java programs such as file io, so you may be
// familiar with it.
OutputStream outputStream = socket.getOutputStream();
// Create the String to send to the second device.
// Most devices require a '\r' or '\n' or both at the end of the
// string.
// @todo set your message
String message = "Data from Android and tester program!\r";
// Convert the message to bytes and blast it through the
// bluetooth
// to the second device. You may want to use:
// public byte[] getBytes (Charset charset) for proper String to
// byte conversion.
outputStream.write(message.getBytes());
} finally {
// close the socket and we are done.
socket.close();
}
// IOExcecption is thrown if connect fails.
} catch (IOException ex) {
Log.e(this.toString(), "IOException " + ex.getMessage());
// NoSuchMethodException IllegalAccessException
// InvocationTargetException
// are reflection exceptions.
} catch (NoSuchMethodException ex) {
Log.e(this.toString(), "NoSuchMethodException " + ex.getMessage());
} catch (IllegalAccessException ex) {
Log.e(this.toString(), "IllegalAccessException " + ex.getMessage());
} catch (InvocationTargetException ex) {
Log.e(this.toString(),
"InvocationTargetException " + ex.getMessage());
}
}
}
Если я правильно понимаю, ваше приложение не может видеть какие-либо данные с устройства вообще?
Одна маленькая вещь: попробуйте свой UUID без хайфенов. В моих приложениях RFCOMM я фактически определяю UUID как длинную целочисленную константу.
Кроме того, способ написания вашего метода test() заставляет меня поверить, что test() устанавливает соединение, определяет поток, приказывает запустить и немедленно вернуться. Другими словами, ваш поток ссылается на переменную извне потока, который является частью метода test(), но когда умирает test(), то же самое происходит и с переменными.
Короче, попробуйте провести тестирование вне потока и сначала запустите его. Один из простых способов сделать это - использовать Thread.run() вместо thread.start(). .run() запускает его на переднем плане (и таким образом блокирует test(), чтобы он не возвращался до завершения потока).
Для более долгосрочного решения вы можете определить свои переменные Bluetooth как глобальные переменные / переменные-члены, чтобы они не выходили за рамки и всегда были доступны для вашего потока.
Код выше не работает на Samsung Galaxy Tab 2 с 4.0.4. BTSocket.connect всегда запускал диалоговое окно сопряжения Bluetooth, а затем вызывал ошибку, даже если был введен правильный пин-код. Переход от "createRfcommSocket" к "createInsecureRfcommSocket" решил проблему. Надеюсь, это поможет, я боролся с этой проблемой более 3 часов.
Попробуйте известный UUID:00001101-0000-1000-8000-00805F9B34FB