Afero Modulo-1とM5Stackで遊ぶ

# 前提

* M5Stack Gray
    * [製品資料](https://github.com/m5stack/m5-docs/blob/master/docs/en/core/gray.md)
    * [回路図](https://github.com/m5stack/M5-Schematic/blob/master/Core/Basic/M5-Core-Schematic(20171206).pdf)
* Afero Modulo-1
    * [データシート](https://developer.afero.io/Modulo1DataSheet)
* Arduino IDE 1.8.10


# 確認したいこと

* afLibの使い方の確認
    * Aferoデバイスのデータがどのように送受信できるのか
    * 具体的なイベントの種類


# サンプルコード

サンプルコードはafLibの `afero-clock` を使用した。
そのままではM5Stackで動かないので、UART通信 / SPI通信それぞれ用にパッチを当てて確認。


# UART編
## 結線

* M5Stackの5V出力をModulo-1のVINへ
* GNDはてきとうに
* GPIO16 / GPIO17をソフトウェアシリアルの入出力に使う
    * GPIO16 = TX
    * GPIO17 = RX

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29860/9ec17546-bdd2-e199-24ed-15409b863ee2.png)


## 差分

```patch
--- examples/afero_clock/afero_clock.ino	2019-12-31 15:20:46.000000000 +0900
+++ ../../aflib_test/afero_clock/afero_clock.ino	2019-12-31 19:30:26.000000000 +0900
@@ -98,12 +98,12 @@
 // as long as the Modulo is flashed with a profile that has MCU support enabled.
 // We have a demo profile here that you can flash to our Modulo if you need one
 //#include "profile/afero_clock_Modulo-1_SPI/device-description.h"           // For Modulo-1 SPI
-//#include "profile/afero_clock_Modulo-1_UART/device-description.h"          // For Modulo-1 UART
+#include "profile/afero_clock_Modulo-1_UART/device-description.h"          // For Modulo-1 UART
 //#include "profile/afero_clock_Modulo-1B_SPI/device-description.h"          // For Modulo-1B SPI
 //#include "profile/afero_clock_Modulo-1B_UART/device-description.h"         // For Modulo-1B UART
 //#include "profile/afero_clock_Modulo-2_SPI/device-description.h"           // For Modulo-2 SPI
 //#include "profile/afero_clock_Modulo-2_UART/device-description.h"          // For Modulo-2 UART
-#include "profile/afero_clock_Plumo-2D_UART/device-description.h"         // For Plumo-2D, UART
+//#include "profile/afero_clock_Plumo-2D_UART/device-description.h"         // For Plumo-2D, UART



@@ -152,7 +152,8 @@
 #define TX_PIN                    8

 #else
-#error "Sorry, afLib can not identify this board, define necessary pins in sketch"
+#define RX_PIN                    17
+#define TX_PIN                    16
 #endif

 // Serial monitor baud rate
@@ -215,13 +216,6 @@
           }
           break;

-        case AF_UTC_TIME:
-          asr_utc_time = *((int32_t *)value);
-          af_logger_print_buffer("ASR UTC Time: ");
-          printTimeString((time_t)asr_utc_time);
-          // TODO: If you have an RTC this would be a good place to set the clock time
-          break;
-
         case AF_SYSTEM_ASR_STATE:
           af_logger_print_buffer("ASR state=");
           switch (value[0]) {
@@ -441,10 +435,6 @@
       printAttrHex("UTC Offset Data", attributeId, valueLen, value);
       break;

-    case AF_UTC_TIME:
-      printAttr32("ASR Timestamp", attributeId, valueLen, value);
-      break;
-
     case AF_APPLICATION_VERSION:
       printAttr16("FW Version", attributeId, valueLen, value);
       break;
```


# SPI編
## 結線

* M5Stackの5V出力をModulo-1のVINへ(UARTと同じ)
* GNDはてきとうに
* M5StackのSPIインターフェースをそれぞれ接続する
    * Modulo-1 の `RESET_B` を `GPIO2` へ
    * Modulo-1 の `SPI_SCS` を `GPIO16` へ
    * Modulo-1 の `HOST_INT_B` を `GPIO17` へ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29860/36a40dc5-a240-bc46-33e6-69de8c9e9270.png)



## 差分

UART版との差分のみ。Modulo-1がリセットループしてしまうので、明示的にリセットをしてからハイに引っ張る（Modulo-1のリセット端子はアクティブロー）。

```patch
--- examples/afero_clock/afero_clock.ino	2019-12-31 15:20:46.000000000 +0900
+++ ../../aflib_test/afero_clock/afero_clock.ino	2019-12-31 20:30:28.000000000 +0900
@@ -97,13 +97,13 @@
 // system attributes exist in all profiles created with Profile Editor > 1.2.1
 // as long as the Modulo is flashed with a profile that has MCU support enabled.
 // We have a demo profile here that you can flash to our Modulo if you need one
-//#include "profile/afero_clock_Modulo-1_SPI/device-description.h"           // For Modulo-1 SPI
+#include "profile/afero_clock_Modulo-1_SPI/device-description.h"           // For Modulo-1 SPI
 //#include "profile/afero_clock_Modulo-1_UART/device-description.h"          // For Modulo-1 UART
 //#include "profile/afero_clock_Modulo-1B_SPI/device-description.h"          // For Modulo-1B SPI
 //#include "profile/afero_clock_Modulo-1B_UART/device-description.h"         // For Modulo-1B UART
 //#include "profile/afero_clock_Modulo-2_SPI/device-description.h"           // For Modulo-2 SPI
 //#include "profile/afero_clock_Modulo-2_UART/device-description.h"          // For Modulo-2 UART
-#include "profile/afero_clock_Plumo-2D_UART/device-description.h"         // For Plumo-2D, UART
+//#include "profile/afero_clock_Plumo-2D_UART/device-description.h"         // For Plumo-2D, UART



@@ -118,8 +118,8 @@
 // the physical hardware pins connecting the MCU and Modulo, and also
 // the MCU Configuration section of the profile loaded on the Modulo
 //     (in the Afero Profile Editor app "Attributes" menu, interface and UART speed)
-//#define ASR_USE_SPI                   1
-#define ASR_USE_UART                  1
+#define ASR_USE_SPI                   1
+//#define ASR_USE_UART                  1

 // For Modulo-1 UART speed is fixed at 9600
 // For Modulo-2 the UART_BAUD_RATE here must match the UART speed set in Profile Editor
@@ -152,7 +152,9 @@
 #define TX_PIN                    8

 #else
-#error "Sorry, afLib can not identify this board, define necessary pins in sketch"
+#define RESET                     2    // This pin is used to reboot the Modulo when needed
+#define INT_PIN                   17    // Modulo sends an interrupt on this pin to initiate communication
+#define CS_PIN                    16    // Standard SPI chip select line
 #endif

 // Serial monitor baud rate
@@ -278,16 +273,11 @@

   af_logger_println_buffer("afLib: Time of Day from Afero Cloud Example");

-  // The Plinto board automatically connects reset on UNO to reset on Modulo
-  // For Teensy, we need to reset manually...
-#if defined(TEENSYDUINO)
   pinMode(RESET, OUTPUT);
   digitalWrite(RESET, 0);
   delay(250);
   digitalWrite(RESET, 1);
-  // This leaves the reset pin pulled high when unused
   pinMode(RESET, INPUT_PULLUP);
-#endif


   // Start the sketch awaiting initialization
```


## 動作の流れ

* `arduino_transport_create_uart()` でUART入出力を取り扱えるようにする
* `attrEventCallback()` をコールバック関数として定義し、受信データを処理する
* イベント種別が `AF_LIB_EVENT_ASR_NOTIFICATION` であった場合、ASR-1のイベントとして処理する
    * ユーザ操作などの属性変更もここに含まれる
* AferoデバイスがAferoクラウドに接続されると `AF_SYSTEM_LINKED_TIMESTAMP` が発生する

```console
19:44:49.138 -> afLib: Time of Day from Afero Cloud Example
19:44:49.269 -> Using UART
19:45:11.407 -> Attribute Id: 65015
19:45:11.407 -> attr Linked Timestamp=1577789110
19:45:11.444 -> ASR linked at: Tue 2019-12-31 10:45:10 GMT
19:45:11.591 -> Attribute Id: 65013
19:45:11.591 -> ASR state=Linked
19:45:11.810 -> Attribute Id: 65001
19:45:11.810 -> attr UTC Offset Data=1c2b626b5e1c2
19:45:11.810 -> Current TZ: 9h
19:45:11.810 -> Next Offset: 9h at Tue 2019-12-31 10:45:10 GMT
```

# わかったこと
## ハードウェアに固有のイベントがある
Modulo-1は `AF_UTC_TIME` イベントに対応していない。
イベント名が微妙に違うけどたぶん次の箇所。

> ** Note: ASR_UTC_TIME is not supported on Modulo-1/ASR-1 but is supported on all other Afero modules.

## プロフィールによって通信バスが異なる

Modulo-1のプロフィールはSPI / UARTを明示的に選択する必要があり、サンプルも2つのプロフィールに分かれている。SPIプロフィールではUARTにデータは出力されない。