ESP-IDFを使ってみる

esp32_nat_router


こちら
にESP-IDFを使ったRouterアプリが公開されています。
少し古いプロジェクトなので、ESP-IDF V5.4でビルドすると、以下のエラーになります。
Compilation failed because cmd_router.c (in "cmd_router" component) includes spi_flash_mmap.h, provided by spi_flash component(s).
However, spi_flash component(s) is not in the requirements list of "cmd_router".
To fix this, add spi_flash to PRIV_REQUIRES list of idf_component_register call in /home/nop/esp32_nat_router/components/cmd_router/CMakeLists.txt.

components/cmd_router/CMakeLists.txtを以下の様に変更すると、ESP-IDF V5.4でもビルドすることができます。
【変更前】
idf_component_register(SRCS "cmd_router.c"
                    INCLUDE_DIRS .
                    REQUIRES console nvs_flash esp_wifi driver)

【変更後】
idf_component_register(SRCS "cmd_router.c"
                    INCLUDE_DIRS .
                    REQUIRES console nvs_flash esp_wifi driver spi_flash)

Console Componentを使って、コマンドラインで設定を行うことができます。
ファームを書き込むと、シリアルポートに以下が表示されます。
ESP32 NAT ROUTER
Type 'help' to get the list of commands.
Use UP/DOWN arrows to navigate through command history.
Press TAB when typing command name to auto-complete.

Unconfigured WiFi
Configure using 'set_sta' and 'set_ap' and restart.
esp32>

showコマンドで現在の設定を確認することができます。
esp32> show
STA SSID: <undef> Password: <undef> Enterprise: <not active>
AP SSID: <undef> Password: <undef>
AP IP address: 192.168.4.1
Uplink AP not connected
0 Stations connected

helpコマンドで使用できるコマンドの一覧を表示します。
esp32> help
help  [<string>] [-v <0|1>]
  Print the summary of all registered commands if no arguments are given,
  otherwise print summary of given command.
      <string>  Name of command
  -v, --verbose=<0|1>  If specified, list console commands with given verbose level

free
  Get the current size of free heap memory

heap
  Get minimum size of free heap memory that was available during program
  execution

version
  Get version of chip and SDK

restart
  Software reset of the chip

deep_sleep  [-t <t>] [--io=<n>] [--io_level=<0|1>]
  Enter deep sleep mode. Two wakeup modes are supported: timer and GPIO. If no
  wakeup option is specified, will sleep indefinitely.
  -t, --time=<t>  Wake up time, ms
      --io=<n>  If specified, wakeup using GPIO with given number
  --io_level=<0|1>  GPIO level to trigger wakeup

light_sleep  [-t <t>] [--io=<n>]... [--io_level=<0|1>]...
  Enter light sleep mode. Two wakeup modes are supported: timer and GPIO.
  Multiple GPIO pins can be specified using pairs of 'io' and 'io_level'
  arguments. Will also wake up on UART input.
  -t, --time=<t>  Wake up time, ms
      --io=<n>  If specified, wakeup using GPIO with given number
  --io_level=<0|1>  GPIO level to trigger wakeup

tasks
  Get information about running tasks

nvs_set  <key> <type> -v <value>
  Set key-value pair in selected namespace.
  Examples:
  nvs_set VarName i32 -v 123
  nvs_set VarName str -v YourString
  nvs_set VarName blob -v 0123456789abcdef
         <key>  key of the value to be set
        <type>  type can be: i8, u8, i16, u16 i32, u32 i64, u64, str, blob
  -v, --value=<value>  value to be stored

nvs_get  <key> <type>
  Get key-value pair from selected namespace.
Example: nvs_get VarName i32
         <key>  key of the value to be read
        <type>  type can be: i8, u8, i16, u16 i32, u32 i64, u64, str, blob

nvs_erase  <key>
  Erase key-value pair from current namespace
         <key>  key of the value to be erased

nvs_namespace  <namespace>
  Set current namespace
   <namespace>  namespace of the partition to be selected

nvs_list  <partition> [-n <namespace>] [-t <type>]
  List stored key-value pairs stored in NVS.Namespace and type can be specified
  to print only those key-value pairs.
  Following command list variables stored inside 'nvs' partition, under
  namespace 'storage' with type uint32_tExample: nvs_list nvs -n storage -t u32

   <partition>  partition name
  -n, --namespace=<namespace>  namespace name
  -t, --type=<type>  type can be: i8, u8, i16, u16 i32, u32 i64, u64, str, blob

nvs_erase_namespace  <namespace>
  Erases specified namespace
   <namespace>  namespace to be erased

set_sta  <ssid> <passwd> [-- <ent_username>] [-- <ent_identity>]
  Set SSID and password of the STA interface
        <ssid>  SSID
      <passwd>  Password
  --, -u, ----username=<ent_username>  Enterprise username
  --, -a, ----anan=<ent_identity>  Enterprise identity

set_sta_static  <ip> <subnet> <gw>
  Set Static IP for the STA interface
          <ip>  IP
      <subnet>  Subnet Mask
          <gw>  Gateway Address

set_sta_mac  <octet> <octet> <octet> <octet> <octet> <octet>
  Set MAC address of the STA interface
       <octet>  First octet
       <octet>  Second octet
       <octet>  Third octet
       <octet>  Fourth octet
       <octet>  Fifth octet
       <octet>  Sixth octet

set_ap_mac  <octet> <octet> <octet> <octet> <octet> <octet>
  Set MAC address of the AP interface
       <octet>  First octet
       <octet>  Second octet
       <octet>  Third octet
       <octet>  Fourth octet
       <octet>  Fifth octet
       <octet>  Sixth octet

set_ap  <ssid> <passwd>
  Set SSID and password of the SoftAP
        <ssid>  SSID of AP
      <passwd>  Password of AP

set_ap_ip  <ip>
  Set IP for the AP interface
          <ip>  IP

portmap  [add|del] [TCP|UDP] <ext_portno> <int_ip> <int_portno>
  Add or delete a portmapping to the router
     [add|del]  add or delete portmapping
     [TCP|UDP]  TCP or UDP port
  <ext_portno>  external port number
      <int_ip>  internal IP
  <int_portno>  internal port number

show
  Get status and config of the router




最初に以下のコマンドでAPのSSIDとパスワードを設定します。
パスワードが8文字未満の時はオープン(パスワード無し)ルーターの設定となります。
コマンドで指定した内容は、NVS領域に記録されます。
restartコマンドで最新の設定が有効になります。
esp32> set_ap ESP32 ESP32
AP will be open (no passwd needed).
I (24305) cmd_router: AP settings ESP32/ESP32 stored.

esp32> set_ap ESP32 ESP32PASS
I (111554) cmd_router: AP settings ESP32/ESP32PASS stored.

esp32> restart

esp32> show
I (16000) cmd_router: ap_ssid ESP32
I (16010) cmd_router: ap_passwd ESP32PASS
STA SSID: <undef> Password: <undef> Enterprise: <not active>
AP SSID: ESP32 Password: ESP32PASS
AP IP address: 192.168.4.1
Uplink AP not connected
0 Stations connected

このアクセスポイントに接続すると、192.168.4.xのアドレスが払い出されます。
esp32> I (19566) wifi:new:<1,0>, old:<1,1>, ap:<1,1>, sta:<255,255>, prof:1
I (19576) wifi:station: 60:01:94:3a:79:dd join, AID=1, bgn, 20
I (19586) ESP32 NAT router: 1. station connected
I (19606) esp_netif_lwip: DHCP server assigned IP to a station, IP is: 192.168.4.2

DHCPで払い出されるアドレスを変更するコマンドは用意されていません。
直接ソース(esp32_nat_router.c)の以下の部分を変更する必要が有ります。
    //IP4_ADDR(&ipInfo.ip, 192,168,4,1);
    //IP4_ADDR(&ipInfo.gw, 192,168,4,1);
    IP4_ADDR(&ipInfo.ip, 192,168,11,1);
    IP4_ADDR(&ipInfo.gw, 192,168,11,1);



外部のサイトに接続するためには、以下のコマンドでUplink側のルーター(外部と接続しているルータ)を登録する必要が有ります。
Uplink側のルーターを登録するとESP32は中継機として動作します。
esp32> set_sta UplinkルータのSSID Uplinkルータのパスワード
I (5346545) cmd_router: STA settings aterm-d5a4ee-g/xxxxxxxxxx stored.

esp32> restart

esp32> show
I (5740) cmd_router: ssid aterm-d5a4ee-g
I (5750) cmd_router: ent_username
I (5750) cmd_router: ent_identity
I (5750) cmd_router: passwd xxxxxxxxxx
I (5750) cmd_router: ap_ssid ESP32
I (5760) cmd_router: ap_passwd ESP32PASS
STA SSID: aterm-d5a4ee-g Password: xxxxxxxxxx Enterprise: <not active>
AP SSID: ESP32 Password: ESP32PASS
AP IP address: 192.168.4.1
Uplink AP connected
IP: 192.168.10.115
0 Stations connected

Linuxマシンを使用してWiFiのパフォーマンスを調べてみました。
使用したLinuxマシンはOrangePi-PCで、MT7601UのUSB-WiFiとspeedtestツールを使いました。
どちらも親機にはAterm PA-WG2600HSを使っています。
こちらがNECのAterm WR8165N(300Mbps)経由で、親機に接続している状態でのパフォーマンスです。
orangepi@orangepipc:~$ speedtest --simple
Ping: 57.313 ms
Download: 13.38 Mbit/s
Upload: 6.26 Mbit/s
orangepi@orangepipc:~$ speedtest --simple
Ping: 55.69 ms
Download: 13.85 Mbit/s
Upload: 6.55 Mbit/s
orangepi@orangepipc:~$ speedtest --simple
Ping: 67.225 ms
Download: 13.87 Mbit/s
Upload: 5.69 Mbit/s

こちらがesp32_nat_router経由で、親機に接続したときのパフォーマンスです。
orangepi@orangepipc:~$ speedtest --simple
Ping: 54.381 ms
Download: 3.99 Mbit/s
Upload: 6.20 Mbit/s
orangepi@orangepipc:~$ speedtest --simple
Ping: 38.856 ms
Download: 5.88 Mbit/s
Upload: 6.07 Mbit/s
orangepi@orangepipc:~$ speedtest --simple
Ping: 52.458 ms
Download: 5.72 Mbit/s
Upload: 6.24 Mbit/s

こちらがesp_wifi_repeater(ESP8266のルーター)経由で、親機に接続したときのパフォーマンスです。
ESP32(240MHz 2Core)とESP8266(160MHz 1Core)では、CPU周波数は1.5倍の差ですが、Downloadスピードはそれ以上の差が出ています。
orangepi@orangepipc:~$ speedtest --simple
Ping: 55.979 ms
Download: 1.52 Mbit/s
Upload: 4.77 Mbit/s
orangepi@orangepipc:~$ speedtest --simple
Ping: 54.665 ms
Download: 1.20 Mbit/s
Upload: 4.20 Mbit/s
orangepi@orangepipc:~$ speedtest --simple
Ping: 48.133 ms
Download: 1.19 Mbit/s
Upload: 4.14 Mbit/s



ESP32はEthernet、WiFi-Station、WiFi-SoftAPの3つのInterfaceを持っているので、これらを使った ブリッジアプリケーションがいくつか公開されています。

esp32_nat_routerはWiFi-Stationを外部へのInterface、WiFi-SoftAPを内部への Interfaceとして使いますが、
こ ちらに複数の組み合わせが可能なブリッジアプリケーションが公開されています。
このサンプルはESP-IoT-Bridgeコンポーネントを使用しています

こ ちらにはEthernetを外部へのInterface、WiFi-SoftAPを内部へのInterfaceとして使うアプリケー ションが公開されています。
このサンプルは自前のコードでEthernet<-->WiFiのパケット転送を行っています。


こ ちらにはEthernetを外部へのInterface、USB/SPI/SDIOを内部へのInterfaceとして使うアプリ ケーションが公開されています。
内部InterfaceにSPIを使う場合、ESP32はSPI周辺機器(SPI-Slave)として動作します。
RaspberryPiをSPI-Masterとしたアプリケーションの作り方がこ ちらに公開されています。
内部InterfaceにSDIOを使う場合、ESP32はSDIO周辺機器(SDIO-Slave)として動作します。
RaspberryPiをSDIO-Masterとしたアプリケーションの作り方がこ ちらに公開されています。
Ethernet/WiFi機能のないMCUに対して、Ethenetの機能を提供することができます。
このサンプルはESP-IoT-Bridgeコンポーネントを使用しています。

ESP-IoT-Bridgeコンポーネントでは、外部Interfaceとして4Gモデムを使うことができます。





ESP-IoT-Bridgeコンポーネントの詳細はこ ちらに公開されています。
試しに、WiFi-Stationを外部へのInterface、WiFi-SoftAPを内部への Interfaceとして使って見ました。


ここで外部Interfaceとして使うInterfaceを選択します。


ここで内部Interfaceとして使うInterfaceを選択します。


内部InterfaceとしてWiFi-SoftAPを選択した場合、これがAPの情報になります。


ファームウェアをビルドしてESP32に書き込むとESP_Bridge_XXXXXのAPが出現します。
XXXXXXの部分はESP32のMACアドレスの一部が使われます。
また、WebServerが起動していることが分かります。


このAPに接続して、ブラウザのアドレスに192.168.5.1を指定すると、WebServerは以下の画面を表示します。


WiFiルータへの接続情報を指定します、


WiFiルーターへの接続が完了すると、ルーターから払い出されたIPアドレスを表示し、外部との接続が完了します。


もう一台、ESP32を用意し接続先にESP_Bridge_XXXXXを指定します。
今回は、こ ちらのSNTPサンプルを使いました、


ビルドするとESP-IoT-Bridgeを経由して、SNTPサーバーへ接続し、サーバーからの応答を表示します。


外部へのInterfaceをWiFi-StationからW5500 SPI Ethernetに変えてみました。


ここでSPIで使用するGPIOの設定を行います。


但し、このままビルドして実行するとエラーが多数表示されます。
ESP-IDFで利用可能なSPI PHYが全て有効になっているのが理由です。
#
# Ethernet
#
CONFIG_ETH_ENABLED=y
CONFIG_ETH_USE_SPI_ETHERNET=y
CONFIG_ETH_SPI_ETHERNET_DM9051=y
CONFIG_ETH_SPI_ETHERNET_W5500=y
CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL=y

今回使用するのはW5500なので、これ以外は無効にします。
これでエラーは無くなります。
#
# Ethernet
#
CONFIG_ETH_ENABLED=y
CONFIG_ETH_USE_SPI_ETHERNET=y
CONFIG_ETH_SPI_ETHERNET_DM9051=n
CONFIG_ETH_SPI_ETHERNET_W5500=y
CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL=n



これがESP-IoT-Bridgeの基本形です。


STAインタフェースとSoftAPインタフェースを使ってESP-IoT-Bridgeを多段連結して、
接続先APの検知機能と、ノードの管理機能を追加したものが、こちらのESP- Mesh-Liteになります。



続く...