[メモ] BLE カスタムサービスを作成 ~  BLENano(nRF51822) + BDS(Bluetooth Developer Studio)


## 目標
- BLEカスタムサービスを さくっと 作る
- READされたときに(それをトリガーとして)、カウントアップして、値を返す。

## 宿題
- 命名規則とか？
- アプリ層へは、どうかかわったらよい?
<br>main.c/service_if.c/ble_ble_rdcntsvr.c の切り分け。どこに何を書くべきか。
- スマホ側のアプリ... これは、ま、ええか...

## 環境

- Windows7 64bit + MDK-Lite (5.18)
- BLE Nano (V1.5) + MK20 USB Board
- Bluetooth Developer Studio
  <br>https://www.bluetooth.com/download-developer-studio
- Nordic nRF5 Bluetooth Development Studio plugin
  <br>https://developer.nordicsemi.com/nRF51_bluetooth_development_studio_plugin/
- nRF51 SDK v10 (nRF51_SDK_10.0.0_dc26b5e)
 <br>https://developer.nordicsemi.com/nRF5_SDK/nRF51_SDK_v10.x.x/
 <br>nRF51_SDK_10.0.0_dc26b5e/examples/ble_peripheral/*experimental_bluetoothds_template* のサンプルを使用
- スマホアプリ nRF MCP(Master Control Panel) - Nordic社提供


## Bluetooth Developer Studio

1. プロジェクト
    1. NEWで、新しいプロジェクト作成
    2. うまく埋める
<br> ![BDS1.png](https://qiita-image-store.s3.amazonaws.com/0/75594/97c331c1-8142-4075-d244-6f954eaa495c.png)
2. プロファイル
    1. "New Profile"って出てると個をクリック
    2. うまい名前を入れて
    3.  SAVE.
    4. `CUSTOM SERVICE`をクリック。
<br>![BDS2.png](https://qiita-image-store.s3.amazonaws.com/0/75594/6bbceac4-9813-e519-90ff-4efff93ebdb1.png)
3. サービス
    1. ~~~~ new serviceと黄色のような字で書かれたとこをクリック
    2. うまい名前をいれて、
    3. LOW ENERGYにチェック入れて
    4. SAVE
<br>![BDS3.png](https://qiita-image-store.s3.amazonaws.com/0/75594/6e6c86da-7227-eb04-d0d5-cdb7dbac6452.png)
4. キャラクタリスティクス
    1. (+)をおす。サービス名の下
    2. NAMEをいれて
    3. READとかをMANDATORYへして
    4. ADD FIELDSをおす
<br>![BDS4.png](https://qiita-image-store.s3.amazonaws.com/0/75594/ca223bb4-f35d-935c-2ad1-6b338cf53850.png)
5. フィールド
    1. FIELDSのウィンドウが開いたら、左下のADDを押す
    2. NAMEをいれて
    3. FORMATをきめて
    4. DONE
<br>![BDS5.png](https://qiita-image-store.s3.amazonaws.com/0/75594/7012b06f-ae6d-dda3-350f-beab0ff04c51.png)
6. コード生成
    1. (キャラクタリスティクスのとこにもどってくる)
    2. SAVE
    3. 上のメニューから、TOOLS=> CODE GENERATE
    4. Server, NORDIC~~~, で、セーブ先を確認したら、
    5. `GENERATE`をおす
<br>![BDS6.png](https://qiita-image-store.s3.amazonaws.com/0/75594/1782ca9f-3e84-3b10-34a4-14354ae34e0f.png)
    6. 今回の場合、5つのファイルが生成される。
    <br>=> Readme.txt、service_if.cと.h、ble_rdcntsvr.cと.h
 

## ビルド MDK-ARM
1. 上で、生成されあたコードの \*.h, \*.cを↓にコピーする<br>nRF51_SDK_10.0.0_dc26b5e/examples/ble_peripheral/*experimental_bluetoothds_template*
2. bluetoothds_template_s110_pca10028.uvprojx をダブルクリック。<br>nRF51_SDK_10.0.0_dc26b5e/examples/ble_peripheral/experimental_bluetoothds_template/pca10028/s110/arm5_no_packs/の中
3. [F7]おしてとりあえずビルド。
4. 焼くとサービスとか、キャラクタリスティクスとかみれるはず。
5. カウンターのコードを追加
    1. READ時に認証を通るようにする.<br>キャラクタリスティクス追加のとこで、is_defered_read=1とパラメータを入れる<br>とREAD時にも `on_rw_authorize_request()`まで飛んでくるラシイ

        ```c:ble_rdcntsvr.c
uint32_t ble_rdcntsvr_init(ble_rdcntsvr_t * p_rdcntsvr, const ble_rdcntsvr_init_t * p_rdcntsvr_init)
{
...
    // Add READ_COUNTER characteristic
..
    add_read_counter_params.is_var_len          = 1; 
    add_read_counter_params.is_defered_read     = 1;  // この一行を追加
    err_code = characteristic_add(p_rdcntsvr->service_handle, &add_read_counter_params, &(p_rdcntsvr->read_counter_handles));
...
```
    2. カウントアップの処理<br>現在の値を読み出して(`ble_rdcntsvr_read_counter_get`)、+1 して、値を戻す(`ble_rdcntsvr_read_counter_set`)、、と。

        ```c:ble_rdcntsvr.c
static void on_rw_authorize_request(ble_rdcntsvr_t * p_rdcntsvr, ble_gatts_evt_t * p_gatts_evt)
{
    ble_gatts_evt_rw_authorize_request_t * p_auth_req = &p_gatts_evt->params.authorize_request;
    if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
    {
... WRITE時関係の処理 ...もともと生成されるやつ 
    } //ここから追加
    else if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_READ)
    {
			uint32_t err_code;
			ble_gatts_rw_authorize_reply_params_t read_authorize_reply;
			read_authorize_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
			read_authorize_reply.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS; 
			
			if (p_auth_req->request.read.handle == p_rdcntsvr->read_counter_handles.value_handle)
			{ //Counter++
				ble_rdcntsvr_read_counter_t _rdcounter;
				ble_gatts_value_t gatts_value;
				uint8_t encoded_value[MAX_READ_COUNTER_LEN];
				memset(&gatts_value, 0, sizeof(gatts_value));

				gatts_value.len = MAX_READ_COUNTER_LEN;
				gatts_value.offset  = 0;
				gatts_value.p_value = encoded_value;
				sd_ble_gatts_value_get(p_rdcntsvr->conn_handle, p_rdcntsvr->read_counter_handles.value_handle, &gatts_value);
				read_counter_decode(gatts_value.len, gatts_value.p_value, &_rdcounter);

				_rdcounter.field_rd_cnt++;

				ble_rdcntsvr_read_counter_set(p_rdcntsvr, &_rdcounter);
			}

			sd_ble_gatts_rw_authorize_reply(p_rdcntsvr->conn_handle, &read_authorize_reply);
}
}
```
6. ビルドして、焼く。

## テスト
1. スマホで、nRF MCPを起動
2. Nordic_BDSってのが見つかるので、CONNECTを押す。
3. Unknown Service UUIDなんちゃらかんちゃらを押す
4. ↓がREAD 押すたびにカウントアップ。 (LittleEndianなので、0x01000000 => 0x02000000 =>  .... => 0xFF000000 => 0x00010000となるはず)
5. ↑がWRITE(16進数で数値を入れてSEND)、READをおすと変更されたデータ +1が読み出されるハズ。<br>桁が足りないとごみが入る？