Quectel BG96 で AT コマンドを使って 70 文字超の SMS を送信する

# はじめに

この記事では、Quectel 製の LPWA モデムである BG96 を用いて AT コマンドを使って長文の SMS を送信する方法について解説します。長文の SMS とは、長さが 140 オクテット（文字セットが UCS-2 の場合 70 文字）を超えるために、分割して送信されて受信後に結合が行われる連結メッセージ（Concatenated message）のことです。連結 SMS (Concatenated SMS) とよばれることもあります。

連結メッセージを含む SMS の標準仕様の解説や、もう少し一般的な SMS の送信方法については[別の記事](https://qiita.com/shozoo/items/2070681c034be9829404)にも書いておりますので、本記事の前提となる知識については先にそちらを参照してご理解いただけますと幸いです！

本記事の解説に関しては、3GPP 標準仕様で定義されている AT コマンドではなく、BG96 独自の AT コマンドを使用します。Quectel 製品であれば BG96 以外のモデムでも同一のコマンドが利用可能な場合がありますが、Quectel 社以外のモデムには基本的に適用できないものとしてご承知ください（類似の機能が備わっている可能性はありますので、各デバイスの仕様書・取扱説明書を参照ください）。

:::note info
この記事では解説しませんが、Linux ベースのシステムで USB セルラーモデムを利用する場合は、AT コマンドではなく ModemManager の機能を用いて SMS 送信が行える場合もあります。ModemManager は連結メッセージに対応しているので、長文のメッセージの送受信に ModemManager を用いるのも一つの方法です。
:::

## 使用機材

この記事では、以下の SIM とセルラーモデムを用いました

* SIM: [SORACOM 特定地域向け IoT SIM (plan-D SMS/データ通信)](https://soracom.jp/services/air/cellular/)（ドコモ回線）
* セルラーモデム: Quectel BG96 ([LTE-M Shield for Arduino](https://soracom.jp/store/5303/) に搭載のものと同じ）

SORACOM の plan-D (SMS/データ通信対応) の場合、送信先として Harvest Data などは利用できないため、別の国内通信キャリアの SIM を挿したスマートフォンの電話番号を SMS の送信先とします。

## 前提条件

セルラーデバイスについて、既にネットワークへの接続ができており、かつ AT コマンドが利用できる状態になっているものとします。

# AT コマンド仕様

早速ですが、 Quectel BG96 で連結メッセージを送信するための AT コマンドの解説です。メッセージを分割するセグメント毎に `AT+QCMGS` コマンドを実行します。

### AT+QCMGS: Send Concatenated Messages

```
AT+QCMGS=<da>[,<toda>][,<uid>,<msg_seg>,<msg_total>]<CR>
text is entered
<Ctrl+Z/ESC>
```
* \<da\>
    * メッセージ送信先のアドレス (Destination address)を指定します
        * MSISDN、いわゆる電話番号です
        * ハイフンやスペースは含めず、`"` で括って文字列として指定します
        * 送信先が国際電話番号の場合は先頭の `+` を含めます（`"+8190... "` など)
* \<toda\>
    * メッセージ送信先のアドレスの種別を 10 進数値で指定します。省略可能です
    * 指定する場合、一般的な用途では `129` か `145` を指定します 
        * 送信先が `"090... "` などの国内電話番号や、SORACOM Harvest Data などの SORACOM のエンドポイントの場合は `129` を指定します
        * 送信先が `"+81... "` などの国際電話番号や、SORACOM IoT SIM の[グループ A](https://users.soracom.io/ja-jp/docs/air/send-sms/) の MSISDN の場合は `145` を指定します
* \<uid\>
    * 1通の連結メッセージを識別するためのユニークID (Reference number) を指定します
    * BG96 で指定可能な範囲は `0` - `255` (8-bit) です
        * 連結メッセージを送信する毎にインクリメントして指定すると良いでしょう
        * なお、3GPP TS 23.040 では Reference number に 16-bit を用いる仕様も規定されています
    * SMS のペイロードの UDH (User-Data-Header) 内に Concatenated short message reference number として格納されます
* \<msg_seg\>
    * 1通の連結メッセージの中における、セグメントの番号（Sequence number）を指定します
    * BG96 で指定可能値は `0` - `7` です
        * なお、3GPP TS 23.040 の定義では `0` - `255` です
    * 連結メッセージとして有効なのは `1`から開始する数値です
        * BG96 では、`0`を指定すると非連結の通常のメッセージとして処理されます
    * UDH 内に Sequence number of the current short message として格納されます
* \<msg_total\>
    * 1 通の連結メッセージを構成するセグメント数を指定します
    * BG96 で指定可能な値は `0` - `7` です
        * 連結メッセージとして有効なのは、`2` - `7` の範囲です
        * BG96 では、`0`, `1` を指定すると非連結のメッセージとして処理されます 
    * 当然、1通の連結メッセージを構成するセグメントの中では全て同じ値を指定する必要があります
    * UDH 内に Maximum number of short messages in the concatenated short message として格納されます

`<CR>` (改行文字) の後ろには当該のセグメントで送信したいテキストを入力し、最後に `Ctrl` + `Z` を送信することでセグメントが送信されます。1つのセグメントに含めることのできる文字数は、文字エンコード方式が GSM 7bit の場合は最大 153 文字、UCS-2 の場合は最大 67 文字です。

\<uid\>, \<msg_seg\>, \<msg_total\> の関係を模式的に表したのが下の図です。独立なメッセージがうっかり間違って結合されてしまわないように区別するための識別子が reference number (uid) です。1 つの連結メッセージあたりの分割数を把握するために使用するのが msg_total、連結メッセージ内のセグメントの順序を示すのが sequence number (msg_seg) です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/ff9af2ae-b7dc-b87d-f7a2-65b0d76c45d6.png" width=100%>

# 実際にやってみる

## GSM 7bit で連結メッセージを送信する

メッセージ本文を入力する手前までの準備は、[通常のSMSを送信する手順](https://qiita.com/shozoo/items/2070681c034be9829404#%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9%E3%81%8B%E3%82%89-sms-%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B)とほぼ同様です。

事前にモデムがネットワークに正常に接続されているものとします。送信モードをテキスト (`AT+CMGF=1`) にして、Data Coding Scheme (DCS) を GSM 7bit に、TE-MT 間の文字エンコード方式を IRA に設定します。

```
AT+CMGF=1
OK

AT+CSMP=17,167,0,0
OK

AT+CSCS="IRA"
OK
```

では、2 つのセグメントに分割されたテキストメッセージを送ってみることにします。
つまり、`AT+QCMGS=` コマンドを 2 回実行します。電話番号のところ（`+8190xxxxxxxx`）は伏せさせていただきました。

1セグメント目の送信。この例では改行文字を含めて 153 文字にしていますが、153 文字より少なくても構いません。

```
AT+QCMGS="+8190xxxxxxxx",145,0,1,2
All work and no play makes Jack a dull boy.
All work and no play makes Jack a dull boy.
All work and no play makes Jack a dull boy.
All work and no pl<Ctrl+Z>

+QCMGS: 169

OK
```

なお、+QCMGS: の後ろに表示される数値はメッセージの通し番号なので、実行毎にインクリメントされます。

2セグメント目の送信です

```
AT+QCMGS="+8190xxxxxxxx",145,0,2,2
ay makes Jack a dull boy.
The quick brown fox jumps over the lazy dog.
<Ctrl+Z>

+QCMGS: 170

OK
```

さてどうなったでしょうか？受信側のスマートフォンを見てみます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/21e18283-0966-74ea-22a4-9c39e7abb0e3.jpeg" width=80%>

ジャジャーン！はい、メッセージを受信したスマートフォンでは無事に結合されて表示されました。

## UCS-2 で連結メッセージを送信する

送信モードをテキスト (`AT+CMGF=1`) にして、Data Coding Scheme (DCS) を UCS-2 に設定します。

```
AT+CMGF=1
OK

AT+CSMP=17,167,0,8
OK
```

先ほどと同様に、2つのセグメントに分割して送信してみます。Reference number (\<uid\>) は先ほどとは別の数値にします。

1セグメント目の送信です。本文については、送信したいテキストを UTF-16 でエンコードしたものを hex 文字として入力します。すなわち、UTF-16 における 1 文字を `0000` - `FFFF` の範囲の 4 文字の hex 文字列として入力します。

```
AT+QCMGS="+8190xxxxxxxx",145,1,1,2
50914F5C<Ctrl+Z>

+QCMGS: 171

OK
```

2セグメント目の送信です。

```
AT+QCMGS="+8190xxxxxxxx",145,1,2,2
3060308DFF1F<Ctrl+Z>

+QCMGS: 172

OK
```

受信側のスマートフォンを見てみます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2960954/9c9e606b-b7ba-f6d2-e701-b4254c7010ef.jpeg" width=80%>

UCS-2で送信された日本語のメッセージ（2通目）も、きちんと結合されて表示されていますね！なお、送信していたのは1セグメント目の内容が『 "傑"`5091` "作"`4F5C`』、2セグメント目の内容が『 ”だ"`3060` "ろ" `308D` "？" `FF1F`』 でした。文字数がこれだけであれば分割する必要はないわけですが、そこは例ということでご容赦ください。

# おわりに

本記事では、Quectel BG96 で連結メッセージ（Concatenated messsage）を用いることで、本文の長さが 140 オクテット（文字セットが UCS-2 の場合 70 文字）を超えるショートメッセージを送信する方法について解説しました。
連結メッセージは内部的には複数の分割されたメッセージを送受信していることになるので、分割数に応じて料金が増加すること、また、送信・受信に使用するデバイスや通信事業者によっては最大数に制限があることにはご注意の上活用ください。
送信可能な文字数が増えることによって、皆様の SMS の活用の幅が広げられましたら幸いです。