#3 OpenScope MZ【softAP, I2C, SPI機能の付加】

さて、先ずはOpenScopeMZがどのように通信をしているかを説明します。

OpenScopeMZをただのオシロスコープとして使用するだけであるなら、WiFiテザリングが可能なアンドロイド携帯にWaveFormsアプリをダウンロードし、ワイヤレスオシロスコープとして使用すればいいのですが、普通の人はデータを測定し、保存・解析がしたいと思います。そのためにはPCを使う必要があり、PCでWiFiテザリング機能を持っているのはまれなため、基本的にはWiFiルーターを介してデータをやり取りする形になります。

OpenScope MZとPCがそれぞれWiFiルーターにアクセスし、PCとOpenScopeに割り当てられたIPアドレスを使いWiFiルーターを経由してデータのやり取りをします。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/359111/4644612e-ce26-8e26-a682-9b85bab3c79b.png)


これが、とても使い辛い。
例えば、何らかの原因でPCからOpenScopeMZにアクセスできなくなった場合、何が原因で切れてしまったのかがわからない。そして、再接続するたびにOpenScopeMZに割り振られるIPアドレスが変わってしまう可能性もある。（実際にはソースコードの一部分を変更することでIPアドレスを固定することは可能。）

そこで、直接PCとOpenScopeMZを接続し、通信することでその問題に対処することを考えます。
その時、OpenScopeMZをWiFiルーターの様に親機として機能させるモードがsoftAPモードになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/359111/bfb23b00-1d3b-a40c-2bc6-44dcb7871392.png)


さて、MRF24のデータシートを確認したいのですが、残念なことにどのようにプログラミングすれば、モードを変更し、データをやり取りするのかが公開されていません。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/359111/e47a1c03-dff8-2836-9077-a8a99549d7ba.png)


MRFのプログラムインターフェースはOpenScopeMZを開発しているDigilent 社の deIPcKライブラリによって提供されていて、動き方は下のようなフローチャートになります。

先ずは、WiFi機能を初期化し、接続し、ネットワークを確立するところまで行い、その後にTCPソケット通信でデータをやり取りします。(TCPの他にUDPという通信方法も考えられますが、今回のような遅延やデータの欠落が許されていない使用目的の場合には、データが相手まで届くことを確証しないUDP通信は適していません。)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/359111/8721f604-3b0e-e116-6e69-24095add40f9.png)


ここでは、WiFi Adaptorとしてクラスを宣言し、WiFiルーターに経由する方法と自分がWiFiルーターになる方法があります。しかし、残念ながら、OpenScopeMZのファームウェアのライブラリフォルダの中にあるWiFi.ccp及び、deIPcKライブラリの中にはWiFiルーターに経由する方法の関数しか記述されていない...!（ように見える。）

そこで、MRF24のライブラリコードからリバースエンジニアリングし、コードの動作を理解し、直接MRF24を動かすコードを作成することにします。（思った以上に難易度が高いなあ...汗）
MRF24のコードはOpenScopeMZのlibrariesフォルダの中に格納されています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/359111/c17087ee-2d66-cc67-05e7-4944076abf6d.png)

さて、問題となるコードはWiFi Adaptorクラスの IsInitailized関数の中にあり、そのコードが下記になります。
ふーむ、、汗

```
static bool IsInitialized(IPSTATUS * pStatus)
{
    // we ONLY DO THIS ONCE
    static bool fInitSetup = false;

    AssignStatusSafely(pStatus, wfmrf24.priv.initStatus);
    
    // Run the task because we might not be in the Adaptor yet
    WF_Task();

    if(!fInitSetup && wfmrf24.priv.initStatus == (InitMask | WF_INIT_SUCCESSFUL))
    {
        uint8_t channels[] = {};
        t_scanContext scanContext = {WF_ACTIVE_SCAN, 1, 200, 400, 20};

        WF_RegionalDomainSet(WF_DOMAIN_FCC);
        WF_NetworkTypeSet(WF_NETWORK_TYPE_INFRASTRUCTURE);
        WF_ChannelListSet(channels, sizeof(channels));
        WF_ReconnectModeSet(3, WF_ATTEMPT_TO_RECONNECT, 40, WF_ATTEMPT_TO_RECONNECT);
        WF_ScanContextSet(&scanContext);

        // fixup the MAC
        if(memcmp(&wfmrf24.adpMRF24G.mac, &MACNONE, sizeof(MACADDR)) == 0)
        {
            WF_MacAddressGet((uint8_t *) &wfmrf24.adpMRF24G.mac);
        }
        else
        {
            WF_MacAddressSet((uint8_t *) &wfmrf24.adpMRF24G.mac);
        }

        // set up the hardware filters
        //WF_SetHwMultiCastFilter(WF_MULTICAST_FILTER_1, (uint8_t *) &wfmrf24.adpMRF24G.mac);
        WF_SetHwMultiCastFilter(WF_MULTICAST_FILTER_2, (uint8_t *) &MACNONE);

        // we are done
        fInitSetup = true;
    }
    return(wfmrf24.priv.initStatus == (InitMask | WF_INIT_SUCCESSFUL));
}
```

ここでネットワークタイプが初期値はWF_NETWORK_TYPE_INFRASTRUCTUREと宣言されているので、ここを変更すればいいと思うのだけどれも、

```
// see WF_SetNetworkType()
typedef enum t_networkType
{
    WF_MIN_NETWORK_TYPE            = 1,

    WF_NETWORK_TYPE_INFRASTRUCTURE = 1,
    WF_NETWORK_TYPE_ADHOC          = 2,
    WF_NETWORK_TYPE_P2P            = 3,
            
    WF_MAX_NETWORK_TYPE            = 3
} t_networkType;
```

あれ、ここの記述にもそもそもsoftAPモードが見当たらない。

softAPモードの数値はMRF24のデータシートでは4に割り当てられているようなので、
仕方がないので、networkTypeにsoftAPモードを追記する。

```
// see WF_SetNetworkType()
typedef enum t_networkType
{
    WF_MIN_NETWORK_TYPE            = 1,

    WF_NETWORK_TYPE_INFRASTRUCTURE = 1,
    WF_NETWORK_TYPE_ADHOC          = 2,
    WF_NETWORK_TYPE_P2P            = 3,
    WF_NETTWORK_TYPE_SOFTAP        = 4,  // 20190216 modified by chino
            
    WF_MAX_NETWORK_TYPE            = 4   // 20190216 modified by chino
} t_networkType;
```

さて、あとはネットワークリージョンもFCC(アメリカ)になっているので、JAPANに変更する。
これは、ちゃんと宣言されている。

```
// See WF_SetRegionalDomain()
typedef enum t_regionalDomain
{
    WF_DOMAIN_FCC   = 0,    // Available Channels: 1 - 11
    WF_DOMAIN_ETSI  = 2,    // Available Channels: 1 - 13
    WF_DOMAIN_JAPAN = 7,    // Available Channels: 1 - 14
    WF_DOMAIN_OTHER = 7    // Available Channels: 1 - 14
} t_regionalDomain;
```

次回に状態遷移図を作って、どのように動かすかを検討する。