Linux 上で Bluez に基づいた USB Bluetooth SPP サーバーを開発する

 Linux 上で実行されているため、参照されている bluez コードは Bluetooth サーバーを C 言語で実装しています。

原理も非常にシンプルで、サーバー側で以下のコマンドでSPPサービスを追加します。

前提として、まず bluez をインストールします。通常はインストールされます。インストールされていない場合は、
sudo apt-get install bluezを使用できます。

インストール後にBluetoothを設定する

Bluetoothをオフにする
sudo hciconfig hci0 down

Bluetoothをリセット
sudo hciconfig hci0 リセット

Bluetoothをオンにする
sudo hciconfig hci0 up

Bluetooth を接続可能にして検出可能にする
sudo hciconfig hci0 piscan 

設定後、hciconfig -a を使用してマシンのアドレスやその他の情報を表示できます。hciconfig はツールであり、変更は一時的なものです

構成後、SPP サービスを手動で追加する必要があります

sdptool SP を追加

この文も非常に重要です。デバイス上で SPP プロトコル サービスを確立する必要があります。つまり、UUID=0x1101 のサービスでは、この文はデフォルトでチャネル =1 にあります。
ここで、コード内でソケットがリッスンするポートも非常に重要です。

SerialPortServiceClass_UUID = '{00001101-0000-1000-8000-00805F9B34FB}'

こちら https://www.jianshu.com/p/eb85cb690e86 を参照してください。

このサービスでは、ソケットを使用して他のクライアントからの接続要求を受け付け、要求を確立した後にデータを送受信します。

これは大きな穴で、私は長い間この穴にいます。

ネット上にはこのように書かれており、この文を実行すればsdpサーバーが構築されるようです。そうではありません。


実行後、次のコマンドを使用して、このサービスが存在するかどうかを確認する必要があります。

sudo sdptool ローカルを参照 

audfly@linux:/opt/tmp$ sudo sdptool ローカルを参照
FF:FF:FF:00:00:00 で SDP サーバーに接続できませんでした: そのようなファイルまたはディレクトリはありません

残念ながら、この文の実装ではエラーが報告されました。解決策は、システムの Bluetooth サービスの起動オプションを変更することです。-C は互換性を意味し、Bluetooth サービスを互換モードで実行します。

sudo vim /lib/systemd/system/bluetooth.service

ExecStart=/usr/lib/bluez5/bluetooth/bluetoothd -C

sudo systemctl daemon-reload
sudo systemctl restart bluetooth.service

ここを参照してください

https://qa.1r1g.com/sf/ask/2317769471/

オンにすると、追加を再開すると成功のプロンプトが表示されます。

確認後、正常にサービス情報が表示されます。
sudo sdptoolBrowse local 

rowsing FF:FF:FF:00:00:00 ...
サービス RecHandle: 0x10000
サービス クラス ID リスト:
  "PnP 情報" (0x1200)
プロファイル記述子リスト:
  "PnP 情報" (0x1200)
    バージョン: 0x0103

FF:FF:FF:00:00:00 ...
サービスの検索に失敗しました: 引数が無効です
サービス名: シリアル ポート
サービスの説明: COM ポート
サービス プロバイダー: BlueZ
サービス RecHandle: 0x10001
サービス クラス ID リスト:
  "シリアル ポート" (0x1101 )
プロトコル記述子リスト:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    チャネル: 1
言語ベース属性リスト:
  code_ISO639: 0x656e
  エンコーディング: 0x6a
  Base_offset: 0x100
プロファイル記述子リスト:
  "Serial Port" (0x1101)
    バージョン: 0x0100

サービス名: メッセージ通知
サービス RecHandle: 0x10002
サービスクラス ID リスト:
  "Message Access - MNS" (0x1133)
プロトコル記述子リスト:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    チャネル: 17
  "OBEX" (0x0008)
プロファイル記述子リスト:
  「メッセージ アクセス」(0x1134)
    バージョン: 0x0102

FF:FF:FF:00:00:00 ...
サービスの検索に失敗しました: 引数が無効です
サービス名: 同期
サービス RecHandle: 0x10009
サービス クラス ID リスト:
  "IrMC Sync" (0x1104)
プロトコル記述子リスト:
  "L2CAP" (0x0100) )
  "RFCOMM" (0x0003)
    チャネル: 14
  "OBEX" (0x0008)
プロファイル記述子リスト:
  "IrMC Sync" (0x1104)
    バージョン: 0x0100

まだサービスが追加されていない可能性があります。

テスト後、上限に達する可能性があるため、SP を正常に追加するにはいくつかのサービスを手動で削除する必要があります。

成功しない場合は、いくつかの不要なものを手動で削除する必要があり、次の削除コマンドを実行します。

sudo sdptool del 0x10004 


del の後の ID は、この情報Service RecHandle: 0x10009の後の ID を参照します。

削除後、再度実行してください

sdptool SP を追加


この時点で、次のような成功を示すプロンプトが表示されるはずです。

niuben@niuben-VirtualBox:/media/sf_qt_bluetooth$ sudo sdptool add SP
Serial Port サービスの登録
ここまでで SPP サービスの登録が完了し、ソケットを使用してデータを送受信できるようになります。

sudo sdptool ここにSPを追加します 

デフォルトでは、このサービスは、ソケットのポート番号に似たチャネル =1 のチャネルに配置されます。ここが重要です。

テストのサーバーコードで使用する必要があります。コードは次のとおりです。

 
 
    struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
    char buf[1024] = { 0 };
    int s, client, bytes_read;
    int opt = sizeof(rem_addr);
    // allocate socket
    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
    // bind socket to port 1 of the first available
    // local bluetooth adapter
    loc_addr.rc_family = AF_BLUETOOTH;
    loc_addr.rc_bdaddr = *BDADDR_ANY;
    loc_addr.rc_channel = (uint8_t) 1;//这里的通道就是SPP的通道
    bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
    // put socket into listening mode
    listen(s, 1);
    printf("orther_server listen success\n");
    // accept one connection

    //这里accept没有做并发处理,只能连接要给设,后续可自行扩展
    client = accept(s, (struct sockaddr *)&rem_addr, &opt);


    ba2str( &rem_addr.rc_bdaddr, buf );
    printf("client connected success\n");
    fprintf(stderr, "accepted connection from %s\n", buf);

    //这里循环读数据也没有做线程处理,一直在读,应该放到线程种,同样的写数据一样的道理
    for(;;)
    {
        memset(buf, 0, sizeof(buf));
        // read data from the client
        bytes_read = read(client, buf, sizeof(buf));
        if( bytes_read > 0 ) {
            printf("received [%s]\n", buf);
        }
    }
    // close connection
    close(client);
    
    
    close(s);
    return 0;
 

クライアントが接続するときは、チャネルを 1 に設定する必要もありますが、アドレスを入力する必要があります。
最初はクライアントが接続できず、とてもイライラしました。を使用してクライアントのデバイスを使用するという考えはほぼ諦めていました。

dmesg | grep -i 青 

彼の接続アドレスが私のコードと矛盾しているというプロンプトを見つけ、正しく書いたのですが、インターネットから str2ba をダウンロードして修正してしまいました。

問題は、順序が逆であることです。同様に、正しいアドレスを使用できるように、初期化アドレスでも逆順序を使用する必要があります。

または、正のシーケンスのアドレスを渡し、str2ba 関数を変更してシーケンスを逆にします。

もちろん、クライアントの設定はより簡単で、面倒な設定をする必要はありません。このコードは Linux 上でも動作し、Linux システムの arm バージョンです。

テスト後、大量のデータが一度に送信され、テスト クライアントは 16M のデータを送信しました。

int main(int argc, char **argv)
{
    struct sockaddr_rc addr = { 0 };
    int s, status;
    //char dest[18] = "8C:88:2B:01:6E:17";
    char dest[18] = "17:6E:01:2B:88:8C"; //我在这里直接把地址逆序了,实际地址与此相反
    // allocate a socket
    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

    // set the connection parameters (who to connect to)
    addr.rc_family = AF_BLUETOOTH;
    addr.rc_channel = (uint8_t) 1;
     
    str2ba( dest, &addr.rc_bdaddr );
    // addr.rc_bdaddr.b[0]=0x00;
    // addr.rc_bdaddr.b[1]=0x13;
    // addr.rc_bdaddr.b[2]=0xEF;
    // addr.rc_bdaddr.b[3]=0xF8;
    // addr.rc_bdaddr.b[4]=0x70;
    // addr.rc_bdaddr.b[5]=0xE0;
    printf( "connect device\n" );
    // connect to server
    status = connect(s, (struct sockaddr *)&addr, sizeof(addr));

    // send a message
    static char data[16*1024*1024]={1};
    for(int i=0;i!=16*1024*1024;++i){
        data[i]=i;
    }
    if( status == 0 ) {
        printf("connected success\n");
        status = write(s, data,16*1024*1024);
    }

    if( status < 0 ) {
        printf("connected 00:13:EF:F8:70:E0 failed,status = %d\n",status);
    }

    close(s);
    return 0;
}


フォローアップ:
Bluetooth サービスは上記のファイルではなく、Bluetooth モジュールのデーモン プロセスであるため、一部の Linux デバイスに -C を追加しても機能しません。

最終的には arm デバイス上でサーバーを実行する必要があるため、問題のトラブルシューティングを続ける必要があります。

Linuxで作成されたarmのバージョンを解決する必要がある

SPサービスの問題

これが問題です。FF:FF:FF:00:00:00 で SDP サーバーに接続できませんでした: そのようなファイルまたはディレクトリはありません


NvidiaのNXTX2開発ボードを使用しているので、

ここの設定は、NX TX2 開発ボード上で変更する必要があります。同様の理由で、-C を追加します。

gedit /lib/systemd/system/bluetooth.service.d/nv-bluetooth-service.conf&

[サービス]

#--noplugin=audio,a2dp,avrcp
ExecStart=
ExecStart=/usr/lib/bluetooth/bluetoothd -d -C
ExecStartPost=/usr/bin/sdptool add --channel=1 SP


USB Bluetooth の操作中にドライバー ファイル エラーが発生した場合

この解決策を参照してください

https://huaweicloud.csdn.net/635637e7d3efff3090b5aeaf.html?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~activity-2-122438204-blog-521 22447.pc_relevant_vip_default& Depth_1- utm_source=distribute.pc_relevant.none-task-blog-2~default~Baidu からのブログコメント~activity-2-122438204-blog-52122447.pc_relevant_vip_default&utm_relevant_index=3

rtl8723b_config と rtl8761b_fw を取得します 

wget https://raw.githubusercontent.com/Realtek-OpenSource/android_hardware_realtek/rtk1395/bt/rtkbt/Firmware/BT/rtl8723b_config
wget https://raw.githubusercontent.com/Realtek-OpenSource/android_hardware_realtek/rtk1395/bt/rtkbt /Firmware/BT/rtl8723b_fw
sudo mv rtl8723b_config /lib/firmware/rtl_bt/rtl8723b_config.bin
sudo mv rtl8723b_fw /lib/firmware/rtl_bt/rtl8723b_fw.bin
sudo modprobe btusb
sudo systemctl restart bluetooth.service
hciconfig -a # は Bluetooth が- デバイスは起動しています

最後の非常に役立つドキュメントは、BlueZ 開発といくつかの簡単なデモを説明するマニュアルです。この記事の例はすべてこのドキュメントからのものです。この記事ではhciconfigの使い方を解説しているのでとても便利です!

Bluetooth for Programmers.pdf、これはBluetoothforProgrammers.zip_BluetoothEssentialsforProgrammers-Linux Documentation Resources-CSDN Download C の友人によってアップロードされました

おすすめ

転載: blog.csdn.net/zanglengyu/article/details/128116927