W5500-EVB-picoを使用してftpserverを構築したい。ファイルシステムはLitterFSが使いたい

最終更新日:2023/1/23

W5500-EVB-picoをFTPサーバとして構築します。

FTPserver機能が必要な理由を明確にしておく必要があるのかと思います。
  • フラッシュメモリサイズが大きくスケッチだけでは使い切れないのであれば、別用途に利用するのは良いことです。最初に思いついたのがデータのファイル保存領域です。これは、Arduino-Picoの場合LittleFSで実現出来ます。
  • このデータを外部に対して表示するだけならブラウザによる扱いも可能かと思うのですが、より一般的な方法としてFTPなのかと思います。
  • FTPクライアントの機能を搭載して、外部FTPサーバに定期的に転送する方法もあります。
  • 一方サーバ機能を用意しておき、外部からFTPソフトでデータを取り出したり、削除したり出来た方がリーズナブルでは無いかと思います。
  • 現在Webserver機能を搭載する際、グラフ表示機能を追加する場合があります。その際JAVASCRIPTで作成したファイルを読み込んでいるのですが、このファイルをマイコン内に保持することで安定した動作を期待できます。※処理速度に問題は出ますが、利用しているJAVASCRIPTファイルが突然無くなると云ったトラブル回避が可能となります。

RP2040はフラッシュメモリを2MB〜16MB搭載することが出来ます。このフラッシュメモリの内、1MBはスケッチ用として使い、残りをファイルシステムとして使う事が可能であることが判っています。このファイルシステムに対しての読み書きをFTPで実現出来るようにFTPserverを構築したいと思いました。ところが適当なExampleが見つからず結構敷居が高いと感じています。
この構築過程を記録に残したいと思います。

まずフラッシュメモリをファイルシステムとして使う事は伯爵ライブラリLittleFSを使う事で実現出来そうだという事は判っています。
W5500-EVB-picoには2MBのフラッシュが搭載されているので、ArduinoIDE1.xの環境にてツール>FlashSizeにてスケッチ1MBファイルシステム1MBの状態を選択します。これでスケッチを書き込む度にフォーマット化されるようです

一応コンパイルは通るライブラリ組み合わせは見えてきましたが、実行してみるとpingが通りません。不思議です。暫くトライアンドエラーとなりそうです。
※ArduinoIDE1.xではデバッグが難しいのが難点です、しかし、ArduinoIDE2.xではまだまだArduinoIDE1.x同等に融通が利きません。しばらくはArduinoIDE1.8.19で挑戦するしかなさそうです。
※結構シリアルドライバを壊してしまいます。初期化するためのuf2ファイルは予め準備しておく必要があります。

FTPserverのライブラリですが、SimpleFTPserver.h と SimpleFtpServer.h というよく似たものが存在します。まずはSimpleFTPserver.hを使ったのですが、

  • コンパイルは通りました。
  • 自動でファイル転送された後、シリアルモニタを開くと
    15:12:12.500 -> server is at 192.168.0.208
    15:12:12.534 -> LittleFS opened!
    ちゃんとsetupは通りました
  • PicoボードのLEDは点滅しています。Loop()には入ったことを確認しました。
  • コンソールから ping 192.168.0.208を実行すると
    192.168.0.208 に ping を送信しています 32 バイトのデータ:
    192.168.0.208 からの応答: バイト数 =32 時間 <1ms TTL=128
    192.168.0.208 からの応答: バイト数 =32 時間 <1ms TTL=128
    192.168.0.208 からの応答: バイト数 =32 時間 <1ms TTL=128
    192.168.0.208 からの応答: バイト数 =32 時間 <1ms TTL=128

    192.168.0.208 の ping 統計:
    パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
    ラウンド トリップの概算時間 (ミリ秒):
    最小 = 0ms、最大 = 0ms、平均 = 0ms

    問題なしです。
  • ftpクライアントからアクセスしてみました。ポート21に対してホームページビルダのファイル転送ツールでアクセスしてのですが、エラーが発生しうまくゆきませんでした。このツールはエラーコードが出ません。ツールを変更してみます。
  • FFFTPは履歴が残るので接続出来ない理由が判るかと思い実行して見ました。
    −−−
    通信は暗号化されていません.
    第三者にパスワードおよび内容を傍受される可能性があります.
    ホスト 192.168.0.208 (192.168.0.208:21) に接続しています.
    接続できません.
  • Windowsのエクスプローラでもアクセス可能です。
    ftp://ユーザ名:パスワード@IPアドレス/
    でアクセスします。
    実行して見ました。結果は'サーバーに接続出来ませんでした です。
  • 実行したソースは以下の通りです。

/*
 * 2023/01/18 T.Wanibe
 * FtpServer Raspberry Pi Pico W with LittleFS
 *
 * 著者:  Renzo Mischianti を参考にしています。
 * https://www.mischianti.org/2020/02/08/ftp-server-on-esp8266-and-esp32
 * 最大1044480バイトのフラッシュメモリのうち、スケッチが120792バイト(11%)を使っています。
 * 最大262144バイトのRAMのうち、グローバル変数が51340バイト(19%)を使っていて、ローカル変数で210804バイト使うことができます。
 */
#include        "arduino_secrets.h"                                     //機密データを「Secret」タブ/arduino_secrets.hに入力してください
#include        <SPI.h>
#include        <Ethernet.h>
#include        <EthernetUdp.h>
//EthernetServer  webServer(HttpPort);
#include        <LittleFS.h>
//#include        <SimpleFtpServer.h>
#include        <SimpleFTPServer.h>
#define         NICReset        20
#define         NICInit         21
#define         SPI_SCK         2
#define         SPI_RX          4
#define         SPI_TX          3
#define         SPI_CS          5
const char      FVirsion[]      = "1.0.0";
byte            mac[]           = {0x00,0x08,0xDC,0x54,0x4D,0xDD};      //Wiznet
byte            ip[]            = {192, 168, 0, 208};
byte            dns_server[]    = {192, 168, 0, 1};
byte            gateway[]       = {0, 0, 0, 0};
byte            subnet[]        = {255, 255, 255, 0};
byte            NTPip[]         = {192,168,0,199};
char            ftpUser[16]     = SECRET_FTPUSERNAME;                   //ネットワークFTPユーザ名
char            ftpPass[16]     = SECRET_FTPPASSWORD;                   //ネットワークFTPパスワード
byte            fTogle1         = LOW;
byte            fTogle2         = LOW;
FtpServer       ftpSrv;   //set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial
void _callback(FtpOperation ftpOperation, unsigned int freeSpace, unsigned int totalSpace){
        switch (ftpOperation) {
                case FTP_CONNECT:
                Serial.println(F("FTP: Connected!"));
                break;
        case FTP_DISCONNECT:
                Serial.println(F("FTP: Disconnected!"));
                break;
        case FTP_FREE_SPACE_CHANGE:
                Serial.printf("FTP: Free space change, free %u of %u!\n", freeSpace, totalSpace);
                break;
        default:
                break;
        }
};
//
void _transferCallback(FtpTransferOperation ftpOperation, const char* name, unsigned int transferredSize){
        switch (ftpOperation) {
                case FTP_UPLOAD_START:
                        Serial.println(F("FTP: Upload start!"));
                        break;
                case FTP_UPLOAD:
                        Serial.printf("FTP: Upload of file %s byte %u\n", name, transferredSize);
                        break;
                case FTP_TRANSFER_STOP:
                        Serial.println(F("FTP: Finish transfer!"));
                        break;
                case FTP_TRANSFER_ERROR:
                        Serial.println(F("FTP: Transfer error!"));
                        break;
                default:
                        break;
        }
        /* FTP_UPLOAD_START = 0,
         * FTP_UPLOAD = 1,
         *
         * FTP_DOWNLOAD_START = 2,
         * FTP_DOWNLOAD = 3,
         *
         * FTP_TRANSFER_STOP = 4,
         * FTP_DOWNLOAD_STOP = 4,
         * FTP_UPLOAD_STOP = 4,
         *
         * FTP_TRANSFER_ERROR = 5,
         * FTP_DOWNLOAD_ERROR = 5,
         * FTP_UPLOAD_ERROR = 5
         */
};
//
void setup(void){
        pinMode(LED_BUILTIN, OUTPUT);
        pinMode(NICReset, OUTPUT);
        //pinMode(NICInit, INPUT);
        digitalWrite(LED_BUILTIN, fTogle2);
        pinMode(NICReset, LOW);
        //SPI0のpinアサインを設定
        SPI.setSCK(SPI_SCK);
        SPI.setRX(SPI_RX);
        SPI.setTX(SPI_TX);
        SPI.setCS(SPI_CS);
        Ethernet.init(SPI_CS);      
        Serial.begin(115200);
        while (!Serial) {delay(100);};
        // イーサネット接続とサーバーを起動します。
        Ethernet.begin(mac, ip);
        //
        // イーサネットハードウェアが存在するかどうかを確認します
        if (Ethernet.hardwareStatus() == EthernetNoHardware) {
                Serial.println(F("Ethernet shield was not found.  Sorry, can't run without hardware. :("));
                while (true) {
                        delay(1);       // 何もしない、イーサネットハードウェアなしで実行しても意味がない
                }
        }
        if (Ethernet.linkStatus() == LinkOFF) {
                Serial.println(F("Ethernet cable is not connected."));
        }
        delay(500);
        Serial.print(F("server is at "));       Serial.println(Ethernet.localIP());
        /////FTP Setup, ensure SPIFFS is started before ftp;  /////////
        if (LittleFS.begin()) {
                ftpSrv.setCallback(_callback);
                ftpSrv.setTransferCallback(_transferCallback);
                Serial.println("LittleFS opened!");
                ftpSrv.begin("user","pass");                  //username, password for ftp.   (default 21, 50009 for PASV)
        }
}
//
void loop(void){
        ftpSrv.handleFTP();        //make sure in loop you call handleFTP()!!
        fTogle2  = !fTogle2;
        digitalWrite(LED_BUILTIN, fTogle2);
        delay(500);
}

W5500-EVB-picoを使用してftpserverを構築したい。 現時点では実現出来ていません。頭を冷やして別解の検討をしようと思います。


※2023年1月23日 dplasa/FTPClientServer が利用できないか?

ESP32にFTP機能を搭載したという記事を以前書きました。このライブラリはLittleFSを使用したFTPサーバ機能を提供しますので、これが利用できればいいと思いました。
ただ、このライブラリは既にArduinoIDEにインストール済みだったので、サンプルスケッチが「互換性無し」のカテゴリに入ってしまっていることは確認済みでした。
このライブラリは https://github.com/dplasa/FTPClientServer から取得出来るのですが、最近Updateされたような記述はありませんでした。ダメ元で、サンプルスケッチ「LittleFSSample」をビルドしてみましたが、

警告:ライブラリFTPClientServer-masterはアーキテクチャesp8266, esp32, arduino-esp32に対応したものであり、
アーキテクチャrp2040で動作するこのボードとは互換性がないかもしれません。

と表示され、結局ビルド出来ないことが判りました。ちょっとレタッチして改善できないか確認しましたが、難しそうです。
ただ、このExampleを使う事でLittleFSによる1MBのストレージ領域のアクセス自体は確認出来ました。
このExampleではコンソールから“F”キャラクタを入力するとフォーマット処理、“L”キャラクタを入力するとリスト表示処理が出来ます。ファイルのアップロードはスケッチと同じディレクトリに“data”フォルダを作成し、その中に適当なファイルを入れておき、IDEのツール>>Pico LittleFS Data Uploadでファイルがシリアル経由でアップロードされます。

13:03:18.707 -> FS format done, took 105 ms!
13:03:18.809 -> hFTP
13:03:18.809 -> Enter 'F' to format, 'L' to list the contents of the FS
・・・・
13:03:28.009 -> Listing contents...
13:03:28.043 -> 0 files/dirs total
13:03:28.111 -> hFTP
13:03:28.111 -> Enter 'F' to format, 'L' to list the contents of the FS
・・・・
13:06:18.404 -> Listing contents...
13:06:18.404 -> Chart.bundle.js  (455297 Bytes)
13:06:18.404 -> favicon.ico      (2238 Bytes)
13:06:18.404 -> utils.js         (3443 Bytes)
13:06:18.404 -> 3 files/dirs total
13:06:18.506 -> hFTP
13:06:18.506 -> Enter 'F' to format, 'L' to list the contents of the FS

これでftpツールからアクセスしてリスト取得が出来ればひとまず成功なのですが、ftpツールの接続が認められません。

Anonymusならうまく接続出来るのか?スケッチで ftpSrv.begin("","");  でビルドするとAnonymusServerにするとあります。
FFFTPはAnonymusの扱いが明確に出来ます。アクセスしてみました。

通信は暗号化されていません.
第三者にパスワードおよび内容を傍受される可能性があります.
ホスト 192.168.0.208 (192.168.0.208:21) に接続しています.
接続できません

結局接続出来ませんでした。デバッグ文字列を追加して接続ミスがどうして起きるのか、深掘りしているのですが、、、

※リビルドし、バイナリコードのUpdateしたらファイルシステム領域が初期化されてしまうと考えていました。しかし、リビルド後UF2ファイルが更新された後に “L”を実行したら、ファイルが残っていることを確認出来ました。


※2023年1月24日 ftpサーバが機能しない理由

PicoにFTPサーバを構築したくともうまくゆかない件、ライブラリ内にプリント文をいれて調査を始めました。

まず判ったこととして、FtpServer.h内でデバイスパラメータを元にインクルードファイルの再設定をしている部分でそもそもPico+NICのケースが存在しない様に思われ、PicoWに割付いてしまっているようです。このためftpserverの初期化がそもそも出来ていないと考えます。

Pico+NICを割り当てても良いケースがどれに相当するのか検討中です。


戯言(nonsense)に戻る


問い合わせ頁の表示


免責事項

本ソフトウエアは、あなたに対して何も保証しません。本ソフトウエアの関係者(他の利用者も含む)は、あなたに対して一切責任を負いません。
あなたが、本ソフトウエアを利用(コンパイル後の再利用など全てを含む)する場合は、自己責任で行う必要があります。

本ソフトウエアの著作権はToolsBoxに帰属します。
本ソフトウエアをご利用の結果生じた損害について、ToolsBoxは一切責任を負いません。
ToolsBoxはコンテンツとして提供する全ての文章、画像等について、内容の合法性・正確性・安全性等、において最善の注意をし、作成していますが、保証するものではありません。
ToolsBoxはリンクをしている外部サイトについては、何ら保証しません。
ToolsBoxは事前の予告無く、本ソフトウエアの開発・提供を中止する可能性があります。

商標・登録商標

Microsoft、Windows、WindowsNTは米国Microsoft Corporationの米国およびその他の国における登録商標です。
Windows Vista、Windows XPは、米国Microsoft Corporation.の商品名称です。
LabVIEW、National Instruments、NI、ni.comはNational Instrumentsの登録商標です。
I2Cは、NXP Semiconductors社の登録商標です。
その他の企業名ならびに製品名は、それぞれの会社の商標もしくは登録商標です。
すべての商標および登録商標は、それぞれの所有者に帰属します。