SOCK_DGRAM

UDP通信をする場合は、socketの第2引数にSOCK_DGRAMを指定する。

Man page of SOCKET
3-3 単純なUDP受信プログラム:Geekなぺーじ

SOCK_DGRAM.cで、

SOCK_DGRAMを指定して、UDPソケットを作る。

$ vi SOCK_DGRAM.c
$ gcc SOCK_DGRAM.c -o SOCK_DGRAM
$ ./SOCK_DGRAM
soc = 3
$

できた。

Sample/unixsyscall/SOCK_DGRAM/SOCK_DGRAM/src/SOCK_DGRAM at master · bg1bgst333/Sample · GitHub

GetWindowLong

GetWindowLongは、ウィンドウに関する様々なLong値を取得できる。

GetWindowLongA function (winuser.h) - Win32 apps | Microsoft Docs

たとえば、アプリケーションインスタンスハンドルhInstanceは、WinMain(_tWinMain)の引数として渡されるが、それが渡されない他の関数から使いたい場合は、GetWindowLongにGWL_HINSTANCEを指定して取得する。
GetWindowLong.cppで、

引数のほうのhInstanceの値を序盤でメッセージボックスで表示。

WM_PAINTで、GetWindowLongにGWL_HINSTANCEを渡して取得したhInstanceの値はTextOutで描画。

引数のhInstanceは0x00400000
引数のhInstanceは0x00400000

引数のhInstanceは0x00400000。

GetWindowLongで取得したhInstanceも0x00400000
GetWindowLongで取得したhInstanceも0x00400000

GetWindowLongで取得したhInstanceも0x00400000。

Sample/winapi/GetWindowLong/GetWindowLong/src/GetWindowLong at master · bg1bgst333/Sample · GitHub

$this

$thisは、呼び出し元オブジェクトを指す。

PHP: クラスの基礎 - Manual

まあ、C++と同じ。

クラス外の変数、クラス内のメンバ変数、引数を全部同じ$aにしてみる。
メンバと引数を区別するのに$thisはよく使う。

こうなる
こうなる

こうなる。
1回目のfunc呼び出しで、引数は20、メンバは30。引数の値をメンバに代入。
2回目のfuncでは、引数は50、メンバは前回の引数20を代入されてるので20。
クラス外は影響受けないので10。

Sample/php/class/this/src/class at master · bg1bgst333/Sample · GitHub

BluetoothAdapter.isDiscovering

BluetoothAdapter.isDiscoveringで、Bluetooth機器の探索中かどうかをチェック出来る。

BluetoothAdapter  |  Android Developers

strings.xmlで、

Button2を追加。
activity_main.xmlで、

こちらも"Button2"と表示されるbutton2が追加。
MainActivity.javaで、

button2が押されたら、mBluetoothAdapter.isDiscoveringで探索中かそうでないかをチェックする。

起動時
起動時

起動時。
この状態でButton2を押した場合、

探索されていない
探索されていない

探索されていない。
Button1を押すと、

今回OFFの状態にしてたので許可を押す
今回OFFの状態にしてたので許可を押す

今回OFFの状態にしてたので許可を押す。
そしてButton1を押して探索しているところでButton2を押すと、

探索中となる
探索中となる

探索中となる。
でしばらく経ってから、Button2を押すと、

既に探索は終わっているので、こうなる。
既に探索は終わっているので、こうなる。

既に探索は終わっているので、こうなる。

Sample/android/BluetoothAdapter/isDiscovering/src/BluetoothAdapter at master · bg1bgst333/Sample · GitHub

BluetoothSocket.getInputStream

BluetoothSocket.getInputStreamで、InputStreamオブジェクトを取得して、あとはそれを使って読み込む。

BluetoothSocket  |  Android Developers

MainActivity.javaで、

package com.bgstation0.android.sample.bluetoothsocket_;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.UUID;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

//メインアクティビティ
public class MainActivity extends Activity implements OnClickListener, OnItemClickListener{

 // メンバフィールドの定義
 Context mContext = null;	// mContextをnullで初期化.
 ListView mListView1 = null;	// mListView1をnullで初期化.
 ArrayList<BluetoothDevice> mBluetoothDeviceList = null;	// mBluetoothDeviceListをnullで初期化.
 CustomAdapter mCustomAdapter = null;	// mCustomAdapterをnullで初期化.
 BroadcastReceiver mCustomReceiver = null;	// ブロードキャストレシーバはnullで初期化.
 BluetoothAdapter mBluetoothAdapter = null;	// nullで初期化.
 public static final int REQUEST_CODE_BLUETOOTH_ENABLE = 1;	// REQUEST_CODE_BLUETOOTH_ENABLEを1で初期化.
 
 // アクティビティ生成時
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 	
 	// 既定の処理
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     
     // mContextに自身をセット.
     mContext = this;	// mContextにthisを格納.
     
     // リストビューの取得とアイテム選択ハンドラのセット.
     mListView1 = (ListView)findViewById(R.id.listview1);	// mListView1を取得.
     mListView1.setOnItemClickListener(this);	// thisをセット.
     
     // カスタムアダプタの生成とセット..
     mBluetoothDeviceList = new ArrayList<BluetoothDevice>();	// mBluetoothDeviceListを生成.
     mCustomAdapter = new CustomAdapter(this, R.layout.list_item, mBluetoothDeviceList);	// CustomAdapterの生成.
     mListView1.setAdapter(mCustomAdapter);	// mListView1.setAdapterでmCustomAdapterをセット.
     
     // カスタムレシーバ生成.
     mCustomReceiver = new CustomReceiver(this);	// CustomReceiverを生成.(thisを渡す.)
     
     // button1の初期化.
     Button button1 = (Button)findViewById(R.id.button1);	// button1を取得.
     button1.setOnClickListener(this);	// thisをセット.
     
 }
 
 // クリック時
 @Override
 public void onClick(View v) {
 	
     // TODO Auto-generated method stub
     // BluetoothAdapterの取得.
     mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();	// mBluetoothAdapterの取得.
     if (mBluetoothAdapter != null){	// nullでない.
     	
     	// 利用可能でなかったら, Bluetooth設定画面に遷移し, 利用可能なら探索.
			if (!mBluetoothAdapter.isEnabled()){	// 利用可能でない.
				Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);	// 利用可能リクエスト.
				startActivityForResult(intent, REQUEST_CODE_BLUETOOTH_ENABLE);	// startActivityForResultでintent発行, REQUEST_CODE_BLUETOOTH_ENABLEを渡す.
			}
			else{	// 利用可能.
				
				// インテントフィルターをカスタムレシーバに登録.
				IntentFilter filter = new IntentFilter();	// filterの生成.
				filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);	// 開始
				filter.addAction(BluetoothDevice.ACTION_FOUND);	// 発見
				filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);	// 終了
				registerReceiver(mCustomReceiver, filter);	// mCustomReceiverにfilterを登録.
				
				// 探索.
				mBluetoothAdapter.startDiscovery();	// mBluetoothAdapter.startDiscoveryで探索開始.
				
			}
			
		}
		
 }

	// Bluetooth許可ダイアログから返ってきた時.
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent intent){
		
		// リクエストがBluetooth許可の場合.
		if (requestCode == REQUEST_CODE_BLUETOOTH_ENABLE){
			if (resultCode == Activity.RESULT_OK){	// ユーザが許可を押した時.
				
				// インテントフィルターをカスタムレシーバに登録.
				IntentFilter filter = new IntentFilter();	// filterの生成.
				filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);	// 開始
				filter.addAction(BluetoothDevice.ACTION_FOUND);	// 発見
				filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);	// 終了
				registerReceiver(mCustomReceiver, filter);	// mCustomReceiverにfilterを登録.
				
				// 探索.
				mBluetoothAdapter.startDiscovery();	// mBluetoothAdapter.startDiscoveryで探索開始.
				
			}
		}
		
	}
	
	// アイテムが選択された時.
	@Override
	public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
		
		// デバイスの取得.
		BluetoothDevice bluetoothDevice = mBluetoothDeviceList.get(position);	// mBluetoothDeviceList.getでbluetoothDeviceを取得.
		
		// SPPのUUID準備.
		UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");	// SPPのUUIDはこれ.
		
		// Bluetoothソケットで接続.
		BluetoothSocket soc = null;	// Bluetoothソケットsocをnullで初期化.
		try {
			
			// ソケット作成.
            soc = bluetoothDevice.createRfcommSocketToServiceRecord(uuid);
            Toast.makeText(mContext, "soc = " + soc.toString(), Toast.LENGTH_LONG).show();	// soc.toString()を表示.
            
            // ソケット接続.
            soc.connect();	// soc.connectで接続.
            Toast.makeText(mContext, "soc.connect", Toast.LENGTH_LONG).show();	// "soc.connect"と表示.
            
            // 書き込み.
            OutputStream outputStream = soc.getOutputStream();	// soc.getOutputStreamで出力ストリーム取得.
            String str = "ABCDE";	// strに"ABCDE"をセット.
            outputStream.write(str.getBytes(Charset.forName("UTF-8")));	// strを書き込み.
            
            // 読み込み.
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(soc.getInputStream(), Charset.forName("UTF-8")));	// bufferedReaderを生成.
            String res = bufferedReader.readLine();	// bufferedReader.readLineで読み込み, resに格納.
            Toast.makeText(mContext, "res = " + res, Toast.LENGTH_LONG).show();	// resを表示.
            
            // ソケットを閉じる.
            soc.close();	// soc.closeで閉じる.
            soc = null;	// 閉じたらsocをnullにする.
            Toast.makeText(mContext, "soc.close", Toast.LENGTH_LONG).show();	// "soc.close"と表示.
            
		}
		catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
			Toast.makeText(mContext, "e1 = " + e1.getMessage(), Toast.LENGTH_LONG).show();	// 例外メッセージ表示.
			if (soc != null){	// socが残ってたら閉じておく.
				try {
					// ソケットを閉じる.
		            soc.close();	// soc.closeで閉じる.
		            soc = null;	// 閉じたらsocをnullにする.
		            Toast.makeText(mContext, "soc.close", Toast.LENGTH_LONG).show();	// "soc.close"と表示.
				} catch (Exception e2) {
					// TODO Auto-generated catch block
					e2.printStackTrace();
					Toast.makeText(mContext, "e2 = " + e2.getMessage(), Toast.LENGTH_LONG).show();	// 例外メッセージ表示.
				}
			}
		}
		
	}
	
}

こんな感じ。
server.cは、

/* ヘッダファイルのインクルード */
#include <stdio.h> /* 標準入出力 */
#include <unistd.h> /* UNIX標準 */
#include <sys/types.h> /* 派生型 */
#include <sys/socket.h> /* ソケット */
#include <bluetooth/bluetooth.h> /* Bluetooth */
#include <bluetooth/rfcomm.h> /* RFCOMM */

/* main関数 */
int main(void){

  /* 変数の初期化. */
  int soc = -1; /* Bluetoothソケットを-1で初期化. */
  struct sockaddr_rc local_addr = {0}; /* local_addrを{0}で初期化. */
  struct sockaddr_rc remote_addr = {0}; /* remote_addrを{0}で初期化. */
  int remote_addr_len = 0; /* remote_addr_lenを0で初期化. */
  int acc = -1; /* 待ち受けソケットを-1で初期化. */
  char remote_addr_str[1024] = {0}; /* リモートアドレス文字列を{0}で初期化. */
  int read_len = -1; /* 読み込んだ長さread_lenを-1で初期化. */
  char read_buf[1024] = {0}; /* 読み込みバッファread_buf(長さ1024)を{0}で初期化. */
  char write_str[] = "VWXYZ"; /* write_strを"VWXYZ"で初期化. */

  /* Bluetooth(RFCOMM)のソケット作成 */
  soc = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); /* socketにAF_BLUETOOTHとBTPROTO_RFCOMMをセットしてsocを作成. */
  if (soc == -1){ /* socが-1の時はエラー. */

    /* エラー処理 */
    printf("socket error!\n"); /* "socket error!"と出力. */
    return -1; /* -1を返す. */

  }

  /* ソケットの値を出力. */
  printf("soc = %d\n", soc); /* socを出力. */

  /* バインドするアドレス情報の設定. */
  local_addr.rc_family = AF_BLUETOOTH; /* Bluetoothアドレスファミリー */
  local_addr.rc_bdaddr = *BDADDR_ANY; /* BDADDR_ANY */
  local_addr.rc_channel = (uint8_t)22; /* チャンネルは22とする. */

  /* socにlocal_addrをバインドする. */
  if (bind(soc, (struct sockaddr *)&local_addr, sizeof(local_addr)) == -1){ /* bindが-1ならエラー. */

    /* エラー処理 */
    printf("bind error!\n"); /* "bind error!"と出力. */
    close(soc); /* closeでsocを閉じる. */
    return -1; /* -1を返す. */

  }

  /* 成功したら"bind success." */
  printf("bind success.\n"); /* "bind success."と出力. */

  /* リッスン開始. */
  if (listen(soc, 1) == -1){ /* listenで1つだけ待ち受ける. */

    /* エラー処理 */
    printf("listen error!\n"); /* "listen error!"と出力. */
    close(soc); /* closeでsocを閉じる. */
    return -1; /* -1を返す. */

  }

  /* 成功したら"listen success." */
  printf("listen success.\n"); /* "listen success."と出力. */

  /* remote_addr_lenのセット. */
  remote_addr_len = sizeof(remote_addr); /* sizeof(remote_addr)をセット. */

  /* アクセプト開始. */
  acc = accept(soc, (struct sockaddr *)&remote_addr, &remote_addr_len); /* acceptでアクセプトしたら, アクセプトソケットをaccに格納. */
  if (acc == -1){ /* accが-1ならエラー. */

    /* エラー処理 */
    printf("accept error!\n"); /* "accept error!"と出力. */
    close(soc); /* closeでsocを閉じる. */
    return -1; /* -1を返す. */

  }

  /* リモートアドレスの出力. */
  ba2str(&remote_addr.rc_bdaddr, remote_addr_str); /* ba2strで文字列に変換. */
  printf("accept!(Bluetooth Address = %s)\n", remote_addr_str); /* remote_addr_strを出力. */

  /* 読み込み. */
  read_len = read(acc, read_buf, sizeof(char) * 1024); /* readで読み込んだ内容をread_bufに格納. */
  if (read_len > 0){ /* 長さが1以上. */
    printf("read_buf = %s\n", read_buf); /* read_bufを出力. */
    write(acc, write_str, strlen(write_str) + 1); /* write_strを書き込み. */
  }

  /* ソケットを閉じる. */
  close(acc); /* closeでaccを閉じる. */
  close(soc); /* closeでsocを閉じる. */

  /* プログラムの終了 */
  return 0;

}

こうする。

上手く読み込めない
上手く読み込めない

上手く読み込めない。

bufferedReader.readLineじゃなくてinputStream.readしてから文字列にしよ。

一応server.cで10秒待ってみる。
いらないかもだけど。

今度はちゃんと読み込めた
今度はちゃんと読み込めた

今度はちゃんと読み込めた。

10秒ぐらいしてからサーバも終わった
10秒ぐらいしてからサーバも終わった

10秒ぐらいしてからサーバも終わった。

Sample/android/BluetoothSocket/getInputStream/src at master · bg1bgst333/Sample · GitHub

BluetoothSocket.getOutputStream

BluetoothSocket.getOutputStreamでOutputStreamオブジェクトを取得して、OutputStream.writeでデータを書き込む。

BluetoothSocket  |  Android Developers

MainActivity.javaで、

soc.connectで例外が起きなければ、soc.getOutputStreamでoutputStreamを取得し、outputStream.writeで"ABCDE"を書き込む。
で、サーバ側の準備。

サーバ側のプログラムを書く
サーバ側のプログラムを書く

サーバ側のプログラムを書く。

acceptが成功して、リモートアドレスが出力されたら、readで読み込んだ内容をread_bufに格納し、printfで出力。

出来たらコンパイル
出来たらコンパイル

出来たらコンパイル

hciconfigは前回piscanしたのでこれでいいとして
hciconfigは前回piscanしたのでこれでいいとして

hciconfigは前回piscanしたのでこれでいいとして。

sdptool browse local
sdptool browse local

sdptool browse localを実行。

Channel: 22はなさそう
Channel: 22はなさそう

Channel: 22はなさそう。

やっぱないわ
やっぱないわ

やっぱないわ。

channel=22でSP追加
channel=22でSP追加

channel=22でSP追加。

今度は22があるみたい
今度は22があるみたい

今度は22があるみたい。

あった
あった

あった。

Fedoraなので一応ここも見ておく
Fedoraなので一応ここも見ておく

Fedoraなので一応ここも見ておく。

ちゃんと--compatはついてる
ちゃんと--compatはついてる

ちゃんと--compatはついてる。

パーミッション戻ってる
パーミッション戻ってる

パーミッション戻ってる。

一応777にする
一応777にする

一応777にする。
ここで、GUIの設定で、

Essential Phoneがいるのを確認
Essential Phoneがいるのを確認

Essential Phoneがいるのを確認。
これをクリックすると、

スマホ側に番号が出る
スマホ側に番号が出る

スマホ側に番号が出る。

PC側も同じ番号が出る
PC側も同じ番号が出る

PC側も同じ番号が出る。
これをどちらも了承してペアリングとなる。
スマホ側から、"localhost.localdomain"を押しても、両方出て同じ流れ。

正確にはペアリングと接続は別だけど接続しちゃってる
正確にはペアリングと接続は別だけど接続しちゃってる

正確にはペアリングと接続は別だけど接続しちゃってる。
クリックすると、

今の状態が見える。トグルを押すと切断にもなるし、削除を押すとペアリングが解除される。
今の状態が見える。トグルを押すと切断にもなるし、削除を押すとペアリングが解除される。

今の状態が見える。
トグルを押すと切断にもなるし、削除を押すとペアリングが解除される。

スマホ側も接続状態
スマホ側も接続状態

スマホ側も接続状態。

CUIでやる場合はbluetoothctlを使う
CUIでやる場合はbluetoothctlを使う

CUIでやる場合はbluetoothctlを使う。
今回は使わないけど。

infoのあとにBluetoothアドレス(先頭何文字か入力してあとはタブ補完が効く)で状態が見れる
infoのあとにBluetoothアドレス(先頭何文字か入力してあとはタブ補完が効く)で状態が見れる

infoのあとにBluetoothアドレス(先頭何文字か入力してあとはタブ補完が効く)で状態が見れる。

rfcommコマンドで/dev/rfcomm0とBluetoothアドレスを紐づける
rfcommコマンドで/dev/rfcomm0とBluetoothアドレスを紐づける

rfcommコマンドで/dev/rfcomm0とBluetoothアドレスを紐づける。
-aで一覧を確認できる。
作ってすぐclosedになってるのを確認したら、基本はこれでacceptできるはず。

この状態から
この状態から

この状態から、

アプリのlocalhost.localdomainを押す
アプリのlocalhost.localdomainを押す

アプリのlocalhost.localdomainを押す。

これが出て
これが出て

これが出て、

connectできて
connectできて

connectできて、

closeできた
closeできた

closeできた。
PC側は、

&quot;ABCDE&quot;を受け取れた
"ABCDE"を受け取れた

"ABCDE"を受け取れた。
ただし、このままもう1回やろうとすると、

こうなってしまって
こうなってしまって

こうなってしまって、

acceptを抜けないのでlistenを強制終了しないといけない
acceptを抜けないのでlistenを強制終了しないといけない

acceptを抜けないのでlistenを強制終了しないといけない。
closedってなってるけど、いったんrfcomm0をリリースしないといけない。

releaseして、一覧に残っていない状態で、またrfcommでアドレス登録してからなら、またacceptできるとおもう。
releaseして、一覧に残っていない状態で、またrfcommでアドレス登録してからなら、またacceptできるとおもう。

releaseして、一覧に残っていない状態で、またrfcommでアドレス登録してからなら、またacceptできるとおもう。

またできた
またできた

またできた。

Sample/android/BluetoothSocket/getOutputStream/src at master · bg1bgst333/Sample · GitHub

sockaddr_rc構造体

struct sockaddr_rcに値をセットしてbindに渡して、listenして、acceptするのを待つ。

./bluetooth/rfcomm.txt

acceptを抜けたら、acceptにも渡しておいたstruct sockaddr_rcにリモート側の情報が入っている。
struct_sockaddr_rc.cで、

acceptを抜けたら、リモート側のBluetoothアドレスremote_addr.rc_bdaddrを文字列に変換して出力する。
クライアントは、AndroidカテゴリのBluetoothSocket.connectで作ったやつを使う。
サーバはプログラム以外にもいろいろ準備が必要。

【備忘録】BluetoothでAndroidからLinuxにメッセージを送る|Azukish

まず、この辺をやる。
まず、この辺をやる。

まず、この辺をやる。
hci0でpiscan追加。
spdtoolでchannelが22のSPを追加。

sudoで開く
sudoで開く

Fedoraの場合はsudoでここを開いて、

こうなっているのを
こうなっているのを

こうなっているのを、

こうして
こうして

こうして、

daemon-reloadとrestart bluetooth
daemon-reloadとrestart bluetooth

daemon-reloadとrestart bluetooth

これもやっといたほうがいいか
これもやっといたほうがいいか

これもやっといたほうがいいか。
で、Fedora側でGUIBluetooth設定でEssential Phoneとペアリングして接続して、Essential Phoneもペアリングと接続済み状態で、

こうなっちゃって
こうなっちゃって

こうなっちゃって、

accept抜けないから強制終了させて
accept抜けないから強制終了させて

accept抜けないから強制終了させて。
ここまでやっても失敗するし、何が原因か全然わからない状態に。
結果的には、

【ESP32】UbuntuとBluetooth ClassicでSPP通信する方法【Arduino】 | みゆともり

で見つけた、

$ sudo rfcomm -r -M -L 0 bind 0 E0:63:xx:xx:xx:9F

"E0:63:xx:xx:xx:9F"は、XperiaBluetoothアドレスなのだが、rfcommで相手のアドレスとbindするこれが必要だった。
(Essential Phoneでダメ、Desire 626でダメ、なのでXperia SPで試してた。)

これでなんとかacceptできた。
これでなんとかacceptできた。

これでなんとかacceptできた。
ただし、

2回目はaccept出来ないし、いったんrfcommをreleaseしないといけない。
2回目はaccept出来ないし、いったんrfcommをreleaseしないといけない。

2回目はaccept出来ないし、いったんrfcommをreleaseしないといけない。
それと、1回目はペアリングかつ切断の状態、2回目はペアリングかつ接続の状態、でacceptした気がして、どっちなのかわからない。
ペアリングで接続状態じゃないとそもそもrfcomm0 <リモート側Bluetoothアドレス>が出来ないかも。
acceptするには、rfcomm -aで"closed"になってる事。("clean"だと上手くいかない。)
そして、実はAndroid側もconnect前にcancelDiscoveryでスキャンを止めるようにコードいじった。(これはAndroid側にも原因有るかとおもっていじったのだが、これは関係ないかも。)

これで丸々1日潰したけど、とりあえずacceptできた。
ただ、改めてちゃんと整理したい。

Sample/bluez/struct_sockaddr_rc/struct_sockaddr_rc/src/struct_sockaddr_rc at master · bg1bgst333/Sample · GitHub