48

この問題は解決しました!ブラッド、デニス、ジャンキーに感謝!あなたはヒーローです!:)

これは作業コードです。Zeemote に接続し、そこからデータを読み取ります。

===== コード =====

public class ZeeTest extends Activity {
    @オーバーライド
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        試す {
            for (int i = 0; i < 3; i++) {
                テスト();
            }
        キャッチ(例外e){
            e.printStackTrace();
        }
    }

    プライベート ブール接続 = false;
    プライベート BluetoothSocket ソックス。
    プライベート InputStream で;
    public void test() は例外をスローします {
        もし (接続) {
            戻る;
        }
        BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter()。
            getRemoteDevice("00:1C:4D:02:A6:55");
        メソッド m = zee.getClass().getMethod("createRfcommSocket",
            new Class[] { int.class });
        sock = (BluetoothSocket)m.invoke(ジー、Integer.valueOf(1));
        Log.d("ZeeTest", "++++ 接続中");
        sock.connect();
        Log.d("ZeeTest", "++++ 接続済み");
        in = sock.getInputStream();
        バイト[] バッファ = 新しいバイト[50];
        int 読み取り = 0;
        Log.d("ZeeTest", "++++ リスニング...");
        試す {
            while (真) {
                読み取り = in.read(バッファ);
                接続されている = 真;
                StringBuilder buf = new StringBuilder();
                for (int i = 0; i < 読み取り; i++) {
                    int b = バッファ[i] & 0xff;
                    もし (b < 0x10) {
                        buf.append("0");
                    }
                    buf.append(Integer.toHexString(b)).append(" ");
                }
                Log.d("ZeeTest", "++++ Read "+ read +" bytes: "+ buf.toString());
            }
        } キャッチ (IOException e) {}
        Log.d("ZeeTest", "++++ 完了: test()");
    }
    @オーバーライド
    public void onDestroy() {
        試す {
            if (!= null) {
                in.close();
            }
            if (靴下 != null) {
                sock.close();
            }
        } キャッチ (IOException e) {
            e.printStackTrace();
        }
        super.onDestroy();
    }
}

===== 元の質問 =====

2.0.1 ファームウェアを実行している Moto Droid からZeemote ( http://zeemote.com/ ) ゲーム コントローラーに接続しようとしています。以下のテスト アプリケーションはデバイスに接続しますが (LED が点滅)、その直後に接続が切断されます。

以下に 2 つのテスト アプリを貼り付けています。はい、私は 3 番目のバージョンを持っています :) 最初に ACL_CONNECTED を待ってからソケットを開きますが、その動作には何も新しいものはありません。

背景情報: bluez ツールを使用して、ラップトップから Zeemote に完全に接続できます (ログも添付されています)。DroidZeemote と通信できることは確かです。なぜなら、Market の「Game Pro」はそれで問題なく動作するからです (ただし、これはドライバー/サービスであるため、低レベルの API を使用している可能性があります)。

「adb bugreport」では、Zeemote の UUID チャネルも RFCOMM チャネルも報告されていませんが、他のすべてのデバイス (Moto HS815 ヘッドセット、「sdp ブラウズ」では何も報告されない別のダム デバイスを含む) では報告されていることに気付きました。また、デバイスの起動時、Zeemote の優先度は 0 です (その他の優先度は 100+ です)。

私はここでかなり途方に暮れています。私はアイデアを使い果たしたほど長い間それに取り組んできたので、どんな助けも大歓迎です(答えがわからなくても:) )

ありがとう、マックス

テストアプリケーション No. 1

このアプリは、実際にデバイスから読み取ろうとします。

===== コード =====

public class ZeeTest extends Activity {
    @オーバーライド
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        試す {
            テスト();
        } キャッチ (IOException e) {
            e.printStackTrace();
        }
    }

    プライベート BluetoothSocket ソックス。
    プライベート InputStream で;
    public void test() は IOException をスローします {
        BluetoothDevice zee = BluetoothAdapter.getDefaultAdapter()。
                      getRemoteDevice("00:1C:4D:02:A6:55");
        靴下 = zee.createRfcommSocketToServiceRecord(
                      UUID.fromString("8e1f0cf7-508f-4875-b62c-fbb67fd34812"));
        Log.d("ZeeTest", "++++ 接続中");
        sock.connect();
        Log.d("ZeeTest", "++++ 接続済み");
        in = sock.getInputStream();
        バイト[] バッファ = 新しいバイト[1];
        int バイト = 0;
        整数 x = 0;
        Log.d("ZeeTest", "++++ リスニング...");
        ながら (x < 2) {
            x++;
            試す {
                バイト = in.read(バッファ);
                Log.d("ZeeTest", "++++ Read "+ bytes +" bytes");
            } キャッチ (IOException e) {
                e.printStackTrace();
                { Thread.sleep(100); を試してください。} catch (InterruptedException ie) {}
            }
        }
        Log.d("ZeeTest", "++++ 完了: test()");
    }
    @オーバーライド
    public void onDestroy() {
        試す {
            if (!= null) {
                in.close();
            }
            if (靴下 != null) {
                sock.close();
            }
        } キャッチ (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(): バッファ = add@/devices/virtual/bluetooth/hci0/hci0:1
04-19 22:27:04.085: INFO/usbd(1062): main(): コール select(...)
04-19 22:27:04.327: エラー/BluetoothEventLoop.cpp(4029): event_filter: 受信信号 org.bluez.Device:PropertyChanged から /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55
04-19 22:27:04.491: VERBOSE/BluetoothEventRedirector(7499): android.bleutooth.device.action.UUID を受信しました
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): 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.BluetoothSocket.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(): バッファ = remove@/devices/virtual/bluetooth/hci0/hci0:1
04-19 22:27:09.085: INFO/usbd(1062): main(): 呼び出し select(...)
04-19 22:27:09.139: エラー/BluetoothEventLoop.cpp(4029): event_filter: 受信信号 org.bluez.Device:PropertyChanged から /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55

テストアプリケーション No. 2

このテストは接続して待機します。自動切断の問題を表示するのに役立ちます。

===== コード =====

public class ZeeTest extends Activity {
    @オーバーライド
    public void onCreate(Bundle savedInstanceState) {
        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");
            靴下 = zee.createRfcommSocketToServiceRecord(
                            UUID.fromString("8e1f0cf7-508f-4875-b62c-fbb67fd34812"));

            Log.d("ZeeTest", "++++ 接続中");
            sock.connect();
            Log.d("ZeeTest", "++++ 接続済み");
        } キャッチ (IOException e) {
            e.printStackTrace();
        }
    }

    プライベート静的最終 LogBroadcastReceiver レシーバー = 新しい LogBroadcastReceiver();
    public static class LogBroadcastReceiver extends BroadcastReceiver {
        @オーバーライド
        public void onReceive(コンテキスト コンテキスト、インテント インテント) {
            Log.d("ZeeReceiver", インテント.toString());
            バンドル エクストラ = インテント.getExtras();
            for (文字列 k : extras.keySet()) {
                Log.d("ZeeReceiver", " Extra: "+ extras.get(k).toString());
            }
        }
    }

    プライベート BluetoothSocket ソックス。
    @オーバーライド
    public void onDestroy() {
        getApplicationContext().unregisterReceiver(レシーバー);
        if (靴下 != null) {
            試す {
                sock.close();
            } キャッチ (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(): バッファ = add@/devices/virtual/bluetooth/hci0/hci0:1
04-19 22:06:38.202: INFO/usbd(1062): main(): コール select(...)
04-19 22:06:38.217: エラー/BluetoothEventLoop.cpp(4029): event_filter: 受信信号 org.bluez.Device:PropertyChanged から /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55
04-19 22:06:38.428: VERBOSE/BluetoothEventRedirector(7499): android.bleutooth.device.action.UUID を受信しました
04-19 22:06:38.968: DEBUG/ZeeTest(7986): ++++ 接続
04-19 22:06:39.061: DEBUG/ZeeReceiver(7986): 意図 { 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(): バッファ = remove@/devices/virtual/bluetooth/hci0/hci0:1
04-19 22:06:43.038: INFO/usbd(1062): main(): 呼び出し select(...)
04-19 22:06:43.069: エラー/BluetoothEventLoop.cpp(4029): event_filter: 受信信号 org.bluez.Device:PropertyChanged から /org/bluez/4121/hci0/dev_00_1C_4D_02_A6_55
04-19 22:06:43.124: DEBUG/ZeeReceiver(7986): 意図 { act=android.bluetooth.device.action.ACL_DISCONNECTED (エキストラあり) }
04-19 22:06:43.124: DEBUG/ZeeReceiver(7986): エクストラ: 00:1C:4D:02:A6:55

システムログ

===== 端末ログ =====

$ sdptool ブラウズ
問い合わせ中...
00:1C:4D:02:A6:55 を参照しています ...

$ sdptool レコード 00:1C:4D:02:A6:55
サービス名:Zeemote
サービス RecHandle: 0x10015
サービス クラス ID リスト:
  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 をチャネル 1 の 00:1C:4D:02:A6:55 に接続
ハングアップするには 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-attached]

# 猫/dev/tty10
(ここには何もない)

# hcidump
HCI sniffer - Bluetooth パケット アナライザー バージョン 1.42
デバイス: hci0 snap_len: 1028 フィルター: 0xffffffff
< HCI コマンド: 接続の作成 (0x01|0x0005) plen 13
> HCI イベント: コマンド ステータス (0x0f) plen 4
> HCI イベント: 接続完了 (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(s): 情報 rsp: タイプ 2 結果 0
      拡張機能マスク 0x0000
< ACL データ: ハンドル 11 フラグ 0x02 dlen 12
    L2CAP: 接続要求: psm 3 scid 0x0040
> HCI イベント: 完了したパケット数 (0x13) plen 5
> ACL データ: 11 個のフラグを処理 0x02 dlen 16
    L2CAP: 接続 rsp: dcid 0x04fb scid 0x0040 結果 1 ステータス 2
      接続保留中 - 認証保留中
> HCI イベント: リモート名要求完了 (0x07) plen 255
> ACL データ: 11 個のフラグを処理 0x02 dlen 16
    L2CAP: 接続 rsp: dcid 0x04fb scid 0x0040 結果 0 ステータス 0
      接続成功
< ACL データ: ハンドル 11 フラグ 0x02 dlen 16
    L2CAP: 構成要件: dcid 0x04fb フラグ 0x00 clen 4
      MTU1013
(イベントは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) モトローラ 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: DEBUG/BT HSHFP(1237): ロードされた優先度 00:19:A1:2D:16:EA = 100
04-18 21:55:10.428: DEBUG/BT HSHFP(1237): ロードされた優先度 00:1C:4D:02:A6:55 = 0
04-18 21:55:10.444: DEBUG/BT HSHFP(1237): ロードされた優先度 00:0B:2E:6E:6F:00 = 101
04-18 21:55:10.749: DEBUG/BT HSHFP(1237): ロードされた優先度 00:1F:3A:E4:C8:40 = 100
04-18 21:55:10.780: DEBUG/BT HSHFP(1237): ロードされた優先度 00:18:42:EC:E2:99 = 100
4

5 に答える 5

26

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);

また、この m.invoke(device, 1); で引数の値を 1 ~ 3 の範囲で変更してみてください。接続が接続されているが、読み取りを試みたときに中止された場合は、何らかのループでメソッド test() を再度呼び出します。簡単に:

for(int i=0;i<3;i++){  if(!testDone) test(); }
于 2010-04-21T09:45:38.967 に答える
8

私が書いたコードと [android-beginners] Re: Serial over Bluetooth by 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());
        }
    }

}
于 2010-12-27T23:02:18.183 に答える
5

私の理解が正しければ、あなたのアプリはデバイスからのデータをまったく見ることができませんか?

ちょっとしたことですが、ハイフンなしで UUID を試してください。私の RFCOMM アプリでは、実際に UUID を long integer 定数として定義しています。

また、あなたの test() メソッドが書かれている方法は、 test() が接続を確立し、スレッドを定義し、開始するように指示し、すぐに戻ると私に信じさせます。つまり、スレッドは、test() メソッドの一部であるスレッドの外部から変数を参照していますが、test() が終了すると、その変数も終了します。

要するに、スレッドの外でテストを試み、最初にそこで動作するようにします。これを行う簡単な方法の 1 つは、thread.start() の代わりに Thread.run() を使用することです。.run() はそれをフォアグラウンドで実行します (したがって、test() をブロックするため、スレッドが終了する前に戻りません)。

長期的な解決策として、Bluetooth 変数をグローバル/メンバー変数として定義して、スコープ外に出ず、常にスレッドで使用できるようにすることをお勧めします。

于 2010-04-19T14:20:52.677 に答える
0

よく知られている UUID:00001101-0000-1000-8000-00805F9B34FB を試してください。

于 2010-04-20T23:38:02.410 に答える