Nordic nRF52840で802.15.4通信の実験

Nordic nRF52840 は

Raitac MDBT50Q は 技適として
BLE 5.0(!) と IEEE 802.15.4 で認証を受けています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/7f8b9811-e27a-b03b-7c61-08db8d03fc73.png)


IEEE802.15.4 通信としては ZigbeeやThreadが使えますが、単なる802.15.4のだけの通信を試してみました。


環境

- Raitac MDBT50Q DB
- アオノドン2019
- nRF5_SDK_16.0.0_98a08e2
- Segger Embeddid Studio 
- 開発母艦 Ubuntu 18.04
- CP2102 USB シリアルアダプタ

# ドキュメント
https://infocenter.nordicsemi.com/topic/sdk_nrf5_v16.0.0/wireless_uart_15_4.html

# first

(SDKディレクトリ)/examples/802_15_4/wireless_uart/raw/first/pca10056/blank/ses/wireless_uart_raw_first_pca10056.emProject

を開き、MDBT50Q DBに書き込みます。

# second


(SDKディレクトリ)/examples/802_15_4/wireless_uart/raw/second/pca10056/blank/ses/wireless_uart_raw_second_pca10056.emProject

を開き、アオノドン2019に書き込みます。

# 配線

uart.c において以下のようにハードウェアフローが設定されているので、RTS/CTS線の配線が必要です。

```

static hal_uart_config_t m_uart_config =
{
    .module         = CONFIG_UART_MODULE,
    .tx_pin         = CONFIG_UART_TX_PIN,
    .rx_pin         = CONFIG_UART_RX_PIN,
    .cts_pin        = CONFIG_UART_CTS_PIN,
    .rts_pin        = CONFIG_UART_RTS_PIN,
    .baudrate       = CONFIG_UART_BAUDRATE,
    .parity         = CONFIG_UART_PARITY,
    .char_size      = HAL_UART_EIGHT_BITS_CHAR,
    .flow_control   = HAL_UART_FLOW_CONTROL_ENABLED,
};

```

RTS/CTS線を含めて、以下のように配線をします。

![IMG_20200218_120209.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/8f62a963-f44d-13e6-ff97-883507328b5c.jpeg)

詳細は以下を参照。
「nRF52840 ボードの UART ポートの配線」
https://qiita.com/nanbuwks/items/0a9151f693c346a681cf

# 実行

picocomで以下のようにして起動。

First用

```

picocom --flow h -b 38400 -r -l  --imap crcrlf /dev/ttyUSB0
```
Second用

```

picocom --flow h -b 38400 -r -l  --imap crcrlf /dev/ttyUSB1
```

picocom の起動パラメータは以下の通り。

- --flow h   ハードウェアフロー制御(RTS/CTS線を使う)
- -b 38400 ボーレート 38400bps
- -r 終了時にポートリセットを行わない
- -l 起動時にポートロックしない (排他専有しない)
- --imap crcrlf  USBシリアルアダプタから受信した CR コードを CR+LF コードに変換
- /dev/ttyUSB0 または /dev/ttyUSB1 USBシリアルアダプタポート

実行すると、2ターミナル間で通信ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139524/e366bdad-9f7d-964d-3ab3-0296b6b513c3.png)


# First と Second の違い

両方共、main.c は同じものを使用している。
設定ファイル sdk_config.h でFirstとSecondの違いを作っている。

## First側

該当箇所

```
// <h> Application 

//==========================================================
// <o> CONFIG_DEVICE_SHORT_ADDRESS - Device short address 
#ifndef CONFIG_DEVICE_SHORT_ADDRESS
#define CONFIG_DEVICE_SHORT_ADDRESS 10
#endif

// <o> CONFIG_OTHER_ADDRESS - Peer device short address 
#ifndef CONFIG_OTHER_ADDRESS
#define CONFIG_OTHER_ADDRESS 11
#endif

// </h> 
//==========================================================
```
## Second側

該当箇所

```

// <h> Application 

//==========================================================
// <o> CONFIG_DEVICE_SHORT_ADDRESS - Device short address 
#ifndef CONFIG_DEVICE_SHORT_ADDRESS
#define CONFIG_DEVICE_SHORT_ADDRESS 11
#endif

// <o> CONFIG_OTHER_ADDRESS - Peer device short address 
#ifndef CONFIG_OTHER_ADDRESS
#define CONFIG_OTHER_ADDRESS 10
#endif

// </h> 
```


これらがどこから参照されているかというと、(SDKディレクトリ)/examples/802_15_4/wireless_uart/fsm.c で使用している。

## CONFIG_DEVICE_SHORT_ADDRESS


```
static void a_short_addr_set(void * p_data)
{
    const pib_id_t pib_id =
    {
        .mlme_id = MAC_SHORT_ADDRESS,
    };
    mp_set_req = (mlme_set_req_t *)sys_mm_alloc(sizeof(mlme_set_req_t));
    ASSERT(mp_set_req != NULL);
    mp_set_req->value = (uint8_t *)sys_mm_alloc(mlme_pib_attr_size_calc(pib_id, 0));
    ASSERT(mp_set_req->value != NULL);

    mp_set_req->pib_attribute.mlme_id = MAC_SHORT_ADDRESS;
    uint16_t address = CONFIG_DEVICE_SHORT_ADDRESS;
    memcpy(mp_set_req->value, &address, sizeof(uint16_t));
    mp_set_req->pib_attribute_idx = 0;
    mlme_set_req(mp_set_req, mlme_set_conf);
}
```


## CONFIG_OTHER_ADDRESS


```


static mcps_data_req_t m_data_req;

・・・

static void a_radio_tx_start(void * p_data)
{
    m_radio_tx_idle = false;

    const hal_uart_descriptor_t * p_descr = uart_descr_get();
    size_t sz = hal_uart_read_buffer_size_get(p_descr);

    LEDS_OFF(BIT(CONFIG_UPSTREAM_PIN));

    if (sz > MAX_MSDU_SIZE)
    {
        sz = MAX_MSDU_SIZE;
    }

    if (sz > 0)
    {
        hal_uart_read(p_descr, &m_radio_tx_buffer[PAYLOAD_START_POSITION], sz);
        memcpy(&m_radio_tx_buffer[COUNTER_POSITION], &tx_sequence_number, MAX_APP_SEQUENCE_NUMBER_SIZE);
#if (CONFIG_SECURE == 1)
        memcpy(m_radio_tx_buffer_shadow, &m_radio_tx_buffer[COUNTER_POSITION],
                                            sz + MAX_APP_SEQUENCE_NUMBER_SIZE);
#endif

        m_data_req.dst_addr_mode = MAC_ADDR_SHORT;
        m_data_req.dst_addr.short_address = CONFIG_OTHER_ADDRESS;
        m_data_req.dst_pan_id = CONFIG_PAN_ID;
        m_data_req.src_addr_mode = MAC_ADDR_SHORT;
        m_data_req.msdu = (uint8_t *)&m_radio_tx_buffer[MAC_MAX_MHR_SIZE];
        m_data_req.msdu_length = sz + MAX_APP_SEQUENCE_NUMBER_SIZE;
        m_data_req.msdu_handle++;
        m_data_req.tx_options.ack = true;
        m_data_req.tx_options.gts = false;
        m_data_req.tx_options.indirect = false;
#if (CONFIG_SECURE == 1)
        m_data_req.security_level = CONFIG_DATA_SECURITY_LEVEL;
        m_data_req.key_id_mode = 0;
#endif
        mcps_data_req(&m_data_req, mcps_data_conf);

        LEDS_ON(BIT(CONFIG_UPSTREAM_PIN));
    }
    else
    {
        m_radio_tx_idle = true;
    }
}

```



mlme_set_req_t は、(SDKディレクトリ)/components/802_15_4/api/MAC/mac_mlme_pib.h 
で定義されている。



```

/**
 * @brief   MLME-SET.request
 *
 * @details structure for setting a PIB attribute.
 *
 * In accordance with IEEE Std 802.15.4-2006, section 7.1.13.1
 */
typedef struct
{
    /** Do not edit this field. */
    mac_abstract_req_t service;

    /** Confirm to this request. */
    mlme_set_conf_t    confirm;

    pib_id_t           pib_attribute;      /**< PIB Attribute. */
    uint8_t            pib_attribute_idx;  /**< PIB Attribute index. */
    uint8_t          * value;              /**< Attribute value. The value size is calculated
                                                with mlme_pib_attr_size_calc. */
} mlme_set_req_t;

```



この mlme_set_conf_t は同様に、mac_mlme_pib.h 中で定義されている。

```

/**
 * @brief   MLME-SET.confirm
 *
 * @details structure for reporting the results of an attempt to write a value
 * to a PIB attribute.
 *
 * In accordance with IEEE Std 802.15.4-2006, section 7.1.13.2
 */
typedef struct
{
    mac_status_t       status;             /**< Status of operation. */
    pib_id_t           pib_attribute;      /**< PIB Attribute. */
    uint8_t            pib_attribute_idx;  /**< PIB Attribute index. */
} mlme_set_conf_t;

```

ここで指定するパラメータは 802.14.4 MAC層情報ベース管理サービスの MLME-SETによるもの。
このうちの macShortAddress に CONFIG_DEVICE_SHORT_ADDRESS 11 が入る。


また、 CONFIG_OTHER_ADDRESS で使っている mcps_data_req_t は、(SDKディレクトリ)/components/802_15_4/api/MAC/mac_mcps_data.h 
で定義されている。

```

/**
 * @brief   MCPS-DATA.request.
 *
 * @details The MCPS-DATA.request primitive requests the transfer of
 * a data SPDU (i.e., MSDU) from a local SSCS entity to a single peer SSCS entity.
 *
 * In accordance with IEEE Std 802.15.4-2006, section 7.1.1.1.
 */
typedef struct
{
    /** Do not edit this field. */
    mac_abstract_req_t      service;

    /** Confirm to this request. */
    mcps_data_conf_t        confirm;

    /**
     * The source addressing mode for this primitive and
     * subsequent MPDU. This value can take one of the following values:
     * @ref mac_addr_mode_t
     * 0x00 = no address (addressing fields omitted, see 7.2.1.1.8).
     * 0x01 = reserved.
     * 0x02 = 16-bit short address.
     * 0x03 = 64-bit extended address.
     */
    mac_addr_mode_t         src_addr_mode;

    /**
     * The destination addressing mode for this primitive
     * and subsequent MPDU.
     * According to 7.1.1.1.1, Table 41.
     */
    mac_addr_mode_t         dst_addr_mode;

    /** The 16-bit PAN identifier of the entity to which the MSDU is being transferred. */
    uint16_t                dst_pan_id;

    /** The individual device address of the entity to which the MSDU is being transferred. */
    mac_addr_t              dst_addr;

    /** The number of octets contained in the MSDU to be transmitted by
     * the MAC sublayer entity.
     */
    uint8_t                 msdu_length;

    /**
     * The pointer to the set of octets forming the MSDU
     * to be transmitted by the MAC sublayer entity.
     *
     * Caller must provide enough space for MAC and PHY header before this pointer.
     */
    uint8_t               * msdu;

    /** The handle associated with the MSDU to be transmitted by the MAC sublayer entity. */
    uint8_t                 msdu_handle;

    /**
     * The  bits (b0, b1, b2) indicate the transmission options for this MSDU.
     * For b0, 1 = acknowledged transmission, 0 = unacknowledged transmission.
     * For b1, 1 = GTS transmission, 0 = CAP transmission for a beacon-enabled PAN.
     * For b2, 1 = indirect transmission, 0 = direct transmission.
     * For a nonbeacon-enabled PAN, bit b1 should always be set to 0.
     */
    mac_tx_options_t        tx_options;
#if (CONFIG_SECURE == 1)
    uint8_t                 security_level;            /**< Security level. */
    uint8_t                 key_id_mode;               /**< Key ID node. */
    uint64_t                key_source;                /**< Key source. */
    uint8_t                 key_index;                 /**< Key index. */
#endif
} mcps_data_req_t;

```