LoRaLinkとは
LoRaで一番使われているプロトコルはLoRaWANである。 WANとして使用できるように周波数や拡散係数(スプレッディング・フアクター、SF値)、出力電力などをネットワークサーバが自動的に管理出来るよう様々なコマンドが組み込まれた複雑なプロトコルだ。 LoRaWAN以外のプロトコルはプライベートLoRaと総称されており、LoRa利用者が自由に定めた独自プロトコルだ。 LoRaLinkもMQTT-SNでLoRaを使用するために設計したプライベートLoRaである。
LoRa物理層のパケットは上図のようにPreamble,Header, max256BのペイロードとCRCで構成されている。 SX1276は受信周波数と拡散係数、sysncwordを設定して受信モードになるとPreambleの待ち受け状態になる。 Preambleを受信してsysncwordが設定値と一致すれば、後続データが読み込まれる。 Headerにはデータ長が入っているので可変長のペイロードを受信することが出来る。LoRaWANでは0x34をsyncwordに指定しているのでプライベートLoRaではそれ以外の値を使用するのがマナーだ。LoRaLinkでは複数のネットワークを共存させるためにネットワーク毎に異なる値を設定できるようにしている。 LoRaLinkのネットワークはPan(Personal Network)としてPanIdで識別する。 MQTT-SNゲートウェイが管理するデバイス数を考慮して、一つのPanの最大デバイス数を254台としてデバイスのアドレスを1バイトとした。 0XFFはマルチキャストアドレスで、0X01-0XFEをデバイス毎に割り付ける。LoRaLink管理用のパケットとMQTT-SNパケットを区別できるようにPayloadTypeを設けている。
アプリケーション層のプロトコル
MQTT-SNゲートウェイでLoRaLinkを使用するためには、アプリケーション層のプロトコルが必要になる。 ゲートウェイはlinuxあるいはOSX上で稼働することからUSB-UARTデバイスで接続することにした。 SX1276と異なりバケット長の制約が無いことから、機能拡張も考慮してRssiやSNRも送信するようにした。
またISMバンドで通信する場合、LBT(リッスン・ビフォア・トーク)といって送信周波数帯が空いていることを確認してから送信しなければならない。 そのため周波数帯が空かず送信できないことが有る。 送信タイムアウト時間内に送信できた場合は受信データのPayloadTypeを使ってACKを返すことにした。
MQTT-SNゲートウェイにはアプリケーション層のデータを送受信する新たなSensorNetworkクラスを作成して追加した。
https://github.com/eclipse/paho.mqtt-sn.embedded-c/tree/experiment/MQTTSNGateway/src/linux/loralink
ネットワーク層のAPI実装
LoRaLinkを使用するためのAPIは以下のとおりとした。
/*!
* Initialize LoRaLink
*/
void LoRaLinkInitialize(void);
/*!
* Setup Device Parameters
*
* \param [IN] key Encription key
* \param [IN] panId Pan ID
* \param [IN] devTxCh Uplink channel
* \param [IN] devRxCh Downlink channel
* \param [IN] sfValue Spreading Factor
* \param [IN] power Output power in dBm
* \retval value LoRaLinkStatus
*/
LoRaLinkStatus_t LoRaLinkDeviceInit( uint8_t* key, uint16_t panId, uint8_t devAddr, uint8_t syncWord, uint8_t uplinkCh, uint8_t dwnlinkCh, LoRaLinkSf_t sfValue, int8_t power );
/*!
* Gateway Modem Process
*
* \param [IN] key Encription key
* \param [IN] panId Pan ID
* \param [IN] devTxCh Uplink channel
* \param [IN] devRxCh Downlink channel
* \param [IN] sfValue Spreading Factor
* \param [IN] power Output power in dBm
* \retval value LoRaLinkStatus
*/
LoRaLinkStatus_t LoRaLinkUart( uint8_t* key, uint16_t panId, uint8_t devAddr, LoRaLinkUartType_t devType, uint8_t syncWord, uint8_t devTxCh, uint8_t devRxCh, LoRaLinkSf_t sfValue, int8_t power );
/*!
* Receive LoRaLink Packet
*
* \param [OUT] pkt Received packet pointer
* \param [IN] timeout Receive time out value in ms
* \retval value LoRaLinkStatus
*/
LoRaLinkStatus_t LoRaLinkRecvPacket(LoRaLinkPacket_t* pkt, uint32_t timeout);
/*!
* Send Payload
*
* \param [IN] destAddr Destination address
* \param [IN] payloadType Payload Type
* \param [IN] buffer Payload data pointer
* \param [IN] buffLen Payload length
* \param [IN] timeout Send time out value in ms
* \retval value LoRaLinkStatus
*/
LoRaLinkStatus_t LoRaLinkSend( uint8_t destAddr, uint8_t payloadType, uint8_t* buffer, uint8_t buffLen, uint32_t timeout );
LoRaLinkのペイロードをAES128で暗号化するので、同一Panに属するデバイスは一つの暗号キーを共有する必要がある。LoRaLinkDeviceInit( ), LoRaLinkUart( ) でPanで共有する暗号化キー、送受信周波数、拡散係数やデバイスアドレス、送信出力を設定する。
詳しいコードはhttps://github.com/ty4tw/LoRaMQTT-SN/tree/master/LoRaLink
に公開した。