RP2040にW5500とTM1637及びGPSを接続する(GPSNTPサーバ)

最終更新日:2022/5/30

※2022年12月26日 GPSモジュールをM5Stack用GPSユニットに置き換えして見ました。
            また、WebPageの改善を行う

2022年5月30日 EthernetHardwareStatus()でのヘルスチェックはうまく機能するのですが。

2022年5月27日 EthernetHardwareStatus()が有効みたいです

2022年5月20日 対策方法が確立しません。

2022年5月12日 NICがpingに反応しなくなる点の対策

Pico版NTPサーバが構築出来たので、NTPクライアントの部分をGPSに置き換えます。

GPS時刻のRTCに対する更新は1時間間隔程度で良いかなと思います。
自身がNTPサーバであり、他にNTPサーバがあるとは考えにくいので起動時はRTCから取得し、GPSから有効なセンテンスを取得出来たら更新、以後1時間毎に校正する様な方針で作成します。

以下のスケッチはきちんと動作し、PCからNTPでアクセスして時刻同期出来る事を確認しました。
まだ、WebSerser機能を追加していないためIPの確認変更登録等は出来ませんが、GPS同期は掛かっています。

/*
 * 2022年4月20日 T.Wanibe
 * 2.5.2 GPS機能を追加する GPSのパースはライブラリを使わに実施する GxRMCを採用する
 * 2.5.1 ではNTPサーバー機能を追加する 内部RTCはLocalTimeとし 問い合わせに対してはUTCに変換する必要がある
 * 2.5.0.1起動時にNTP(192.168.0.199)にアクセスして内部RTCにセットして、その後TM1637LEDに表示しています。
 * 
 * 実行環境はPiPicoをGroveShieldに接続した状態で、SPIポートにW5500を接続して使います。CS=GPIO5です。
 * 固定IPとします。192.168.0.207 MACアドレスはダブらないように注意します。
 * アクセスするNTPサーバはLocalにある192.168.0.199です。
 * 最大2093056バイトのフラッシュメモリのうち、スケッチが79896バイト(3%)を使っています。
 * 最大262144バイトのRAMのうち、グローバル変数が12332バイト(4%)を使っていて、ローカル変数で249812バイト使うことができます。
 */
#define          TIMER_INTERRUPT_DEBUG          1
#define         _TIMERINTERRUPT_LOGLEVEL_       4
#include        <stdio.h>
#include        <TimeLib.h>
#include        "TM1637.h"
#include        "RPi_Pico_TimerInterrupt.h"
#include        <SPI.h>
#include        <Ethernet.h>
#include        <EthernetUdp.h>
#include        <EEPROM.h>
extern "C" {
#include        <hardware/watchdog.h>
};
#define         CLK             18
#define         DIO             19
#define         TIMER0_INTERVAL_MS      1000
#define         HttpPort        80
#define         DELIMITER       ","
#define         vers    "NTP PiPicoShield 2.5.1"
uint32_t        delay_ms        = 8000;                                 //8秒 最大8.3秒
const char      FVirsion[]      = "2.5.1";
byte            mac[]           = {0x00,0x08,0xDC,0x54,0x4D,0xD7};      //Wiznet
byte            ip[]            = {192, 168, 0, 207};
byte            dns_server[]    = {192, 168, 0, 1};
byte            gateway[]       = {0, 0, 0, 0};
byte            subnet[]        = {255, 255, 255, 0};
unsigned int    localPort       = 8888;                                 // local port to listen for UDP packets
//const char    timeServer[]    = "time.nist.gov";                      // time.nist.gov NTP server
const char      timeServer[]    = "192.168.0.199";
const int       NTPport         = 123;
const int       NTP_PACKET_SIZE = 48;                                   // NTP time stamp is in the first 48 bytes of the message
byte            packetBuffer[NTP_PACKET_SIZE];                          //buffer to hold incoming and outgoing packets
byte            fTogle1         = LOW;
byte            fTogle2         = LOW;
float           timezone        = 9.0;
time_t          TimeZoneSec     = long(timezone * 3600);
float           unit            = 2.33E-7;
unsigned long   baseMilis       = millis();
unsigned long   miliTime;
struct          tm              *local;                                 //STM32dinoとRP2040の構造体が異なる
time_t          currentTime,recieveTime,gpsTime;
unsigned long   currentHour,currentMin,currentSec;
int8_t          TimeDisp[]      = {0x00,0x00,0x00,0x00};
const unsigned long seventyYears = 2208988800UL;
char            buff[80];
char            buf1[32];
char            MacAddressStr[20];
char            IPAddressStr[20];
char            SubnetMaskStr[20];
char            GatewayStr[20];
char            NTPserverStr[20];
char            DateTimeStr[20];
String          nmea;
const uint8_t   daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };//const or compiler complains
uint32_t        timestamp, tempval,microVal,fractions;
int             preH,nowH;
int             chYear;
//GPS
char            chkHader[]      = "RMC";                                //このバージョンから3文字に変更
//内部カウンタ
unsigned long   gNTPqueryCount  = 0;
long            gLoopCount      = 3;                                    //1時間毎に更新予定 最初は1分後に更新したくて初期値を調整
//
const byte      ID = 0x97;
//オブジェクトコンストラクタ
EthernetServer  webServer(HttpPort);
EthernetClient  client;
TM1637          tm1637(CLK,DIO);
EthernetUDP     Udp;                                                    // A UDP instance to let us send and receive packets over UDP
RPI_PICO_Timer  ITimer0(0);
//----------------------------------
void LANSetup(){
        int idcheck = EEPROM.read(0);
        Serial.print(F("LocalID = 0x"));Serial.println(idcheck,HEX);
        if (idcheck == ID){
                //idがIDと同じ値の場合、
                //これは、このスケッチがシールドを設定するために使用されたことを意味します。
                //EERPOMの値を読み取ってシールドを設定します。
                for (int i = 0; i < 6; i++){
                        mac[i] = EEPROM.read(i+1);
                }
                for (int i = 0; i < 4; i++){
                        ip[i] = EEPROM.read(i+7);
                }
                for (int i = 0; i < 4; i++){
                        subnet[i] = EEPROM.read(i+11);
                }
                for (int i = 0; i < 4; i++){
                        gateway[i] = EEPROM.read(i+15);
                }
                timezone = float(EEPROM.read(19)) / 10.0;
        }else{
                //idが一致しない場合、初期値を書き込む事にします。
                for (int i = 0 ; i < 6; i++){
                        EEPROM.write(i + 1,mac[i]);
                }
                for (int i = 0 ; i < 4; i++){
                        EEPROM.write(i + 7, ip[i]);
                }
                for (int i = 0 ; i < 4; i++){
                        EEPROM.write(i + 11, subnet[i]);
                }
                for (int i = 0 ; i < 4; i++){
                        EEPROM.write(i + 15, gateway[i]);
                }
                EEPROM.write(19,char(timezone * 10));
                // IDを既知のビットに設定します。したがって、Arduinoをリセットすると、EEPROM値が使用されます。
                EEPROM.write(0, ID); 
        }
        sprintf(MacAddressStr,"%02x.%02x.%02x.%02x.%02x.%02x",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
        sprintf(IPAddressStr,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
        sprintf(SubnetMaskStr,"%d.%d.%d.%d",subnet[0],subnet[1],subnet[2],subnet[3]);
        sprintf(GatewayStr,"%d.%d.%d.%d",gateway[0],gateway[1],gateway[2],gateway[3]);
        Ethernet.begin(mac, ip);
//      Ethernet.begin(mac);                                            //DHCPの場合
//      Ethernet.begin(mac, ip, subnet);                                //SubnetMaskを意識した場合。
//      Ethernet.begin(mac, ip, subnet, gateway);                       //gatewayを意識した場合。
}
//-------------タイマ割込で呼ばれるルーチン クロック表示
bool    TimerHandler0(struct repeating_timer *t){
        currentTime     =       now();
        //local           = localtime(&currentTime);
        //sprintf(buff,"\n%04d/%02d/%02d %02d:%02d:%02d", local->tm_year,local->tm_mon+1,local->tm_mday,local->tm_hour,local->tm_min,local->tm_sec);
        if(Serial)      Serial.println(currentTime);
        currentTime     %=  86400;
        currentHour     = currentTime / 3600;
        currentMin      = (currentTime % 3600)/60;
        TimeDisp[0]     = currentHour/ 10;
        TimeDisp[1]     = currentHour % 10;
        TimeDisp[2]     = currentMin / 10;
        TimeDisp[3]     = currentMin % 10;
        if(fTogle1)      tm1637.point(POINT_OFF);
        else            tm1637.point(POINT_ON);
        tm1637.display(TimeDisp);
        fTogle1         = !fTogle1;
        return true;
}
//---------------------
bool processNTP() {
        //利用可能なデータがある場合は、パケットを読み取ります
        //https://blog.goo.ne.jp/hiro239415/e/c426a545863921a13a9d6a70b7ae4484
        //NTP_Packet (48Byte)
        bool    req             =       false;
        int     packetSize      =       Udp.parsePacket();
        if(packetSize){
                digitalWrite(LED_BUILTIN,HIGH);                         //要求があったときにBuiltInLEDを点灯
                miliTime                = millis() - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                sprintf(buf1,"■%d\t%d\n",packetSize,fractions);
                if(Serial)     Serial.print(buf1);
                Udp.read(packetBuffer,NTP_PACKET_SIZE);
                IPAddress       Remote  = Udp.remoteIP();
                int             PortNum = Udp.remotePort();
                //受信タイムスタンプ = サーバが受け取った時刻を予めセットしておく JSTなのでGMTに変換
                timestamp               = now()         - TimeZoneSec;
                miliTime                = millis()      - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                tempval                 = timestamp;
                packetBuffer[32]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[33]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[34]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[35]        = (tempval) & 0xFF;
                //
                microVal                = fractions;
                packetBuffer[36]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[37]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[38]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[39]        = microVal & 0xFF;
                 //ヘッダーセット
                packetBuffer[0]         = 0b00100100;                           // 閏秒警告なしLI, 4:SNTPサーバ(Version), 4:サーバ(Mode)
                packetBuffer[1]         = 1 ;                                   // 1:一次基準源(GPS等)(stratum
                packetBuffer[2]         = 5 ;                                   // ポーリング64秒デフォルト値 6(64秒)->5(32秒)
                packetBuffer[3]         = 0xF6;                                 // 精度 -3(0xFD)->-10(0xF6)に変更 msec
                packetBuffer[4]         = 0;                                    // ルート遅延
                packetBuffer[5]         = 0;
                packetBuffer[6]         = 8;
                packetBuffer[7]         = 0;
                packetBuffer[8]         = 0;                                    // ルート分散
                packetBuffer[9]         = 0;
                packetBuffer[10]        = 0xC;
                packetBuffer[11]        = 0;
                //
                packetBuffer[12]        = 71;                                   //"G";   ReferenceID
                packetBuffer[13]        = 80;                                   //"P";   ReferenceID
                packetBuffer[14]        = 83;                                   //"S";   ReferenceID
                packetBuffer[15]        = 0;                                    //"0";   ReferenceID
                // リファレンス時刻をセット(現在時間)
                timestamp               = now()         - TimeZoneSec;          //UTC
                if(Serial){
                        Serial.print(timestamp);Serial.print(F(":Time synchronization Request received\n"));
                }
                tempval                 = timestamp;
                microVal                = fractions;
                packetBuffer[16]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[17]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[18]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[19]        = (tempval) & 0xFF;
                packetBuffer[20]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[21]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[22]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[23]        = microVal & 0xFF;
                //オリジナル時間をコピー(サーバに要求が届いた時間)
                packetBuffer[24]        = packetBuffer[40];
                packetBuffer[25]        = packetBuffer[41];
                packetBuffer[26]        = packetBuffer[42];
                packetBuffer[27]        = packetBuffer[43];
                packetBuffer[28]        = packetBuffer[44];
                packetBuffer[29]        = packetBuffer[45];
                packetBuffer[30]        = packetBuffer[46];
                packetBuffer[31]        = packetBuffer[47];
                //送信時刻をセット
                timestamp               = now()         - TimeZoneSec;                  //UTC
                miliTime                = millis()      - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                tempval                 = timestamp;
                packetBuffer[40]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[41]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[42]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[43]        = (tempval) & 0xFF;
                //transmit_timestamp_fractions
                microVal                = fractions; 
                packetBuffer[44]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[45]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[46]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[47]        = microVal & 0xFF;
                //NTP要求を送信したIPアドレスとポートに応答します
                Udp.beginPacket(Remote, PortNum);
                Udp.write(packetBuffer,NTP_PACKET_SIZE);
                Udp.endPacket();
                digitalWrite(LED_BUILTIN,LOW);                                  //処理完了で消灯
                sprintf(buf1,"●%d\t%d\t%d\t%d\n",packetBuffer[20],packetBuffer[21],packetBuffer[22],packetBuffer[23]);
                if(Serial)      Serial.print(buf1);
                req     = true;
                gNTPqueryCount++;
        }
        return req;
}
//-----------------指定されたアドレスのタイムサーバーにNTP要求を送信します
void sendNTPpacket(const char * address) {
        // バッファ内のすべてのバイトを0に設定します
        memset(packetBuffer, 0, NTP_PACKET_SIZE);
        // NTP要求を形成するために必要な値を初期化します(パケットの詳細については、上記のURLを参照してください)
        packetBuffer[0]         = 0b11100011;                                   // LI, Version, Mode
        packetBuffer[1]         = 0;                                            // Stratum, or type of clock
        packetBuffer[2]         = 6;                                            // ポーリング64秒デフォルト値
        packetBuffer[3]         = 0xEC;                                         // 精度
        // ルート遅延とルート分散の場合は8バイトのゼロ
        packetBuffer[12]        = 0x31;                                         // '1'
        packetBuffer[13]        = 0x4E;                                         // 'N'
        packetBuffer[14]        = 0x31;                                         // '1'
        packetBuffer[15]        = 0x34;                                         // '4'
        //すべてのNTPフィールドに値が指定されているため、タイムスタンプを要求するパケットを送信できます。
        Udp.beginPacket(address, NTPport);                                      // NTP要求はポート123に送信されます
        Udp.write(packetBuffer, NTP_PACKET_SIZE);
        Udp.endPacket();
}
//-----------------受信したNTPパケットを解析してRTCにセットします
bool parseNTPpacket(){
        // 返信が利用可能かどうかを確認するのを待ちます
        if (Udp.parsePacket()) {
                // パケットを受信しました。そこからデータを読み取ります
                Udp.read(packetBuffer, NTP_PACKET_SIZE);                        // パケットをバッファに読み込みます
                // タイムスタンプは、受信したパケットのバイト40から始まり、4バイトです。
                unsigned long secsSince1900;
                // 位置40から始まる4バイトを長整数に変換します
                secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
                secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
                secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
                secsSince1900 |= (unsigned long)packetBuffer[43];
                Serial.print("Seconds since Jan 1 1900 = ");
                Serial.println(secsSince1900);
                // エピックタイムに変換します。(local)
                unsigned long epoch = secsSince1900 - seventyYears + TimeZoneSec;
                Serial.print("Unix time = ");
                Serial.println(epoch);
                setTime(epoch);                                                 //RTC登録(LocalTime)
        }
        return true;
}
//---------------NTP since 1900/01/01 retouch2020/12/25
static unsigned long int numberOfSecondsSince1900Epoch(uint16_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t mm, uint8_t s,float timezone) {
        //2036年問題が存在する。unsigned long intの桁溢れが発生
        //桁溢れが発生したら受信側が対応する必要がある。サーバ側では64bit化するべきだが動かなくなる。
        //timezoneをfloat扱いにした
        int leapAdjustment = 0;
        if (y >= 1970) {
                y -= 1970;
                leapAdjustment  = 2;                            // LM: 1970 was NOT a leap year!
        }
        uint16_t days = d;
        for (uint8_t i = 1; i < m; ++i)         days += pgm_read_byte(daysInMonth + i);
/*
        if (m > 2 && y % 4 == 0)                ++days;
*/
        if (m > 2 && (y + leapAdjustment) % 4 == 0)     ++days; // LM: Weak but okay for the present
        days += 365 * y + (y + 3) / 4 - 1;
        long offsetTime = long((float(h)+ timezone) * 3600.0);
        return days*24L*3600L + offsetTime + mm*60L + s + seventyYears;
}
//------------------
bool readSensor(void){
        if (Serial1.available()) {
                Serial1.readStringUntil('\n');                                  //読み捨てて先頭から読めるようにする
                nmea = Serial1.readStringUntil('\n');
                if(Serial)      Serial.println(nmea);
                //$GNRMC,022757.000,A,3430.62587,N,13316.66175,E,0.63,144.24,231220,,,A,V*02
                String  nmeames = nmea.substring(3,6);                          // $GP***
                int     count   = 0;
                while(!nmeames.equals(chkHader)){
                       nmea     = Serial1.readStringUntil('\n');
                       nmeames  = nmea.substring(3,6);                          // $GP***
                       if(Serial){
                                Serial.print(nmea);Serial.print(F("\t"));Serial.println(nmeames);
                       }
                        if(count++ > 30)    break;
                }
                int     nextPos = 0;
                if ( nmeames.equals(chkHader)){                                 // get UTC
                        nextPos         = nmea.indexOf(DELIMITER);              //int indexOf(char ch, unsigned int fromIndex) const;
                        String shh      = nmea.substring(nextPos+1,nextPos+3);
                        String smm      = nmea.substring(nextPos+3,nextPos+5);
                        String sss      = nmea.substring(nextPos+5,nextPos+7);
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip UTC
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip Status
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 緯度
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 北緯か南緯か
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 経度
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 東経か西経か
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 地表における移動の速度[knot]
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 地表における移動の真方位[deg]
                        String sdd      = nmea.substring(nextPos+1,nextPos+3);
                        String smn      = nmea.substring(nextPos+3,nextPos+5);
                        String syy      = nmea.substring(nextPos+5,nextPos+7);
                        if(Serial)      Serial.println("20" + syy + smn + sdd + shh + smm + sss);
                        chYear          = syy.toInt() + 2000 - 1970;
                        if ((chYear < 31) || (chYear > 100)){                   //2001~2079をサポート
                                return false;
                        }else{
                                gpsTime =       numberOfSecondsSince1900Epoch(chYear,smn.toInt(),sdd.toInt(),shh.toInt(),smm.toInt(),sss.toInt(),timezone);
                                return true;
                        }
                }else{
                        return false;
                }
        }
        return false;
}
//------------------GPSにアクセスし、取得に成功したら内部時間を更新
bool ReadGPS(){
        bool valid      = false;
        if(readSensor()) {
                nowH    = now() / 3600;                         //内部時計はLocalTime
                if(nowH > preH){                                //1時間毎にRTCを更新する
                        preH    = nowH;
                        setTime(gpsTime);
                }
                valid      = true;
        }else{
                delay(100); 
                if(gLoopCount%60)       Serial.print(F("."));
                else                    Serial.println(F("."));
        }
        return valid;
}
//-----------------
void setup() {
        pinMode(LED_BUILTIN, OUTPUT);
        digitalWrite(LED_BUILTIN, fTogle2);
        //SPI0のpinアサインを設定
        SPI.setSCK(2);
        SPI.setRX(4);
        SPI.setTX(3);
        SPI.setCS(5);
        // Ethernet.init(pin)を使用してCSピンを設定できます
        //Ethernet.init(10);                                                    // Most Arduino shields
        Ethernet.init(5);                                                       // MKR ETH shield
        //Ethernet.init(0);                                                     // Teensy 2.0
        //Ethernet.init(20);                                                    // Teensy++ 2.0
        //Ethernet.init(15);                                                    // ESP8266 with Adafruit Featherwing Ethernet
        //Ethernet.init(33);                                                    // ESP32 with Adafruit Featherwing Ethernet
        //シリアル通信を開き、ポートが開くのを待ちます。
        Serial.begin(115200);
        //GPS用にUART0 を使用
        Serial1.setRX(1);
        Serial1.setTX(0);
        Serial1.begin(9600);
        /*
        while (!Serial) {
                ; // シリアルポートが接続するのを待ちます。 ネイティブUSBポートにのみ必要
                //シリアルモニタを開かないと先に進まないので注意が必要
        }
        */
        // start Ethernet and UDP
        LANSetup();
        if(Serial){
                Serial.print(F("server is at "));Serial.println(Ethernet.localIP());
        }
        Udp.begin(NTPport);
        webServer.begin();
        //最初にNTPサーバから時刻を取得する
        sendNTPpacket(timeServer);                                      // NTPパケットをタイムサーバーに送信します
        delay(1000); 
        parseNTPpacket();
        tm1637.init();
        tm1637.set(BRIGHT_TYPICAL);                                     //BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
        //マイクロ秒単位の間隔
        if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 500, TimerHandler0)){
                if(Serial){
                        Serial.print(F("Starting ITimer0 OK, millis() = ")); Serial.println(millis());
                }
        }else{
                if(Serial){
                        Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
                }
        }
        watchdog_reboot(0,0,delay_ms);
        if(Serial){
                Serial.println(F("EndSetup"));
        }
}
//-----------------
void loop() {
        //1秒のループ WDT8秒
        if (watchdog_caused_reboot()){
                if(Serial)    Serial.print("Rebooted by Watchdog!\n");
        }else{
                if(Serial)    Serial.print("Clean boot\n");
        }
        watchdog_update();        
        bool valid      = ReadGPS();                                    //GPSセンテンス読込
        bool req        = processNTP();                                 //NTP要求確認
        Ethernet.maintain();
        digitalWrite(LED_BUILTIN, fTogle2);
        fTogle2  = !fTogle2;
        gLoopCount++;
        if(Serial)      Serial.println(gLoopCount);
}


機能追加し、STM32miniShieldで実現している機能を満たすように改造します。
ほぼ同等の機能を有し安定動作する様になりました。まだちょっとバグがあるかもしれませんが。

/*
 * 2022年4月27日 T.Wanibe
 * 2.5.4 UtilPage等々追加する
 * 2.5.3 WebSerserを追加しユーティリティ機能を追加する フラッシュサイズについては余裕がある。
 *      HTMLコードは極力String型で一度に扱えるようにする。実行中のメモリの余裕も可成り有るので。
 *      Arduino-PicoではTextFinder.hのコンパイルが通らない。TextFinderを使わないパース方法を使用する必要がある
 * 2.5.2 GPS機能を追加する GPSのパースはライブラリを使わに実施する GxRMCを採用する
 * 2.5.1 ではNTPサーバー機能を追加する 内部RTCはLocalTimeとし 問い合わせに対してはUTCに変換する必要がある
 * 2.5.0.1起動時にNTP(192.168.0.199)にアクセスして内部RTCにセットして、その後TM1637LEDに表示しています。
 * 
 * 実行環境はPiPicoをGroveShieldに接続した状態で、SPIポートにW5500を接続して使います。CS=GPIO5です。
 * 固定IPとします。192.168.0.207 MACアドレスはダブらないように注意します。
 * アクセスするNTPサーバはLocalにある192.168.0.199です。
 * 最大2093056バイトのフラッシュメモリのうち、スケッチが105056バイト(5%)を使っています。
 * 最大262144バイトのRAMのうち、グローバル変数が13720バイト(5%)を使っていて、ローカル変数で248424バイト使うことができます。
 */
#define          TIMER_INTERRUPT_DEBUG          1
#define         _TIMERINTERRUPT_LOGLEVEL_       4
#include        <TimeLib.h>
#include        "TM1637.h"
#include        "RPi_Pico_TimerInterrupt.h"
#include        <SPI.h>
#include        <Ethernet.h>
#include        <EthernetUdp.h>
#include        <EEPROM.h>
extern "C" {
#include        <hardware/watchdog.h>
};
#define         CLK             18
#define         DIO             19
#define         TIMER0_INTERVAL_MS      1000
#define         HttpPort        80
#define         DELIMITER       ","
#define         vers    "GPSNTP RPiPicoShield 2.5.4"
uint32_t        delay_ms        = 8000;                                 //8秒 最大8.3秒
const char      FVirsion[]      = "2.5.4";
byte            mac[]           = {0x00,0x08,0xDC,0x54,0x4D,0xD7};      //Wiznet
byte            ip[]            = {192, 168, 0, 207};
byte            dns_server[]    = {192, 168, 0, 1};
byte            gateway[]       = {0, 0, 0, 0};
byte            subnet[]        = {255, 255, 255, 0};
String          HTTP_req; 
unsigned int    localPort       = 8888;                                 // local port to listen for UDP packets
//const char    timeServer[]    = "time.nist.gov";                      // time.nist.gov NTP server
const char      timeServer[]    = "192.168.0.199";
const int       NTPport         = 123;
const int       NTP_PACKET_SIZE = 48;                                   // NTP time stamp is in the first 48 bytes of the message
byte            packetBuffer[NTP_PACKET_SIZE];                          //buffer to hold incoming and outgoing packets
byte            fTogle1         = LOW;
byte            fTogle2         = LOW;
float           timezone        = 9.0;
time_t          TimeZoneSec     = long(timezone * 3600);
float           unit            = 2.33E-7;
unsigned long   baseMilis       = millis();
unsigned long   miliTime;
struct          time_tm         *tm;                                    //STM32dinoとRP2040の構造体が異なる
time_t          currentTime,recieveTime,gpsTime;
unsigned long   currentHour,currentMin,currentSec;
int8_t          TimeDisp[]      = {0x00,0x00,0x00,0x00};
const unsigned long seventyYears = 2208988800UL;
char            buff[80];
char            buf1[32];
char            MacAddressStr[20];
char            IPAddressStr[20];
char            SubnetMaskStr[20];
char            GatewayStr[20];
char            NTPserverStr[20];
char            DateTimeStr[20];
char            Status          = 'V';
String          nmea;
String          bufIP                  = "192.168.0.200";
const uint8_t   daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };//const or compiler complains
uint32_t        timestamp, tempval,microVal,fractions;
int             preH,nowH;
int             chYear;
String          setenceStr              = "$GPRMC";
String          StatusStr               = "V = 警告";
String          DateTime2Str            = "2020年12月24日 8時25分59秒.000";
String          DateStr;
String          TimeStr;
String          latitudeStr             = "北緯 35度41.1493分";
String          latitudeNSStr;
String          longitudeStr            = "東経 139度45.3994分";
String          longitudeEWStr;
String          VeloStr                 = "00.0";
String          DirStr                  = "0.0度";
String          ModeStr                 = "A = 自律方式";
String          MagDegStr;
String          MagDevStr;
String          NavStr;
double          latitude;
double          longitude;
float           gDayBuf[24][5];                                         //24時間分5要素データに変更
float           gTemp(NAN);
typedef struct{
        uint32_t        UTC;
        long            LAT;                                            //10000倍した緯度
        long            LON;                                            //10000倍した経度
        int             DIR;                                            //100倍した値0〜3600
        int             SPD;                                            //速度(ノット単位)を100倍したもの
}RMC;
RMC             gRmc;
//GPS
char            chkHader[]      = "RMC";                                //このバージョンから3文字に変更
//内部カウンタ
unsigned long   gNTPqueryCount  = 0;
long            gLoopCount      = 3;                                    //1時間毎に更新予定 最初は1分後に更新したくて初期値を調整
unsigned long   OperatingTime   = 0;                                    //稼働時間 Count2で1秒
//
const byte      ID = 0x97;
//オブジェクトコンストラクタ
EthernetServer  webServer(HttpPort);
EthernetClient  client;
TM1637          tm1637(CLK,DIO);
EthernetUDP     Udp;                                                    // A UDP instance to let us send and receive packets over UDP
RPI_PICO_Timer  ITimer0(0);
//------------EEPROM.read
void ReadID(){
        for (int i = 0; i < 6; i++){
                mac[i]          = EEPROM.read(i+1);
        }
        for (int i = 0; i < 4; i++){
                ip[i]           = EEPROM.read(i+7);
        }
        for (int i = 0; i < 4; i++){
                subnet[i]       = EEPROM.read(i+11);
        }
        for (int i = 0; i < 4; i++){
                gateway[i]      = EEPROM.read(i+15);
        }
        timezone = float(EEPROM.read(19)) / 10.0;
}
//------------EEPROM.write
void WriteID(){
        for (int i = 0 ; i < 6; i++){
                EEPROM.write(i + 1,mac[i]);
        }
        for (int i = 0 ; i < 4; i++){
                EEPROM.write(i + 7, ip[i]);
        }
        for (int i = 0 ; i < 4; i++){
                EEPROM.write(i + 11, subnet[i]);
        }
        for (int i = 0 ; i < 4; i++){
                EEPROM.write(i + 15, gateway[i]);
        }
        EEPROM.write(19,char(timezone * 10));
        // IDを既知のビットに設定します。したがって、Arduinoをリセットすると、EEPROM値が使用されます。
        EEPROM.write(0, ID); 
}
//----------------------------------
void LANSetup(){
        int idcheck = EEPROM.read(0);
        Serial.print(F("LocalID = 0x"));Serial.println(idcheck,HEX);
        if (idcheck == ID){
                //idがIDと同じ値の場合、
                //これは、このスケッチがシールドを設定するために使用されたことを意味します。
                //EERPOMの値を読み取ってシールドを設定します。
                ReadID();
        }else{
                //idが一致しない場合、初期値を書き込む事にします。
                WriteID();
        }
        sprintf(MacAddressStr,"%02x.%02x.%02x.%02x.%02x.%02x",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
        sprintf(IPAddressStr,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
        sprintf(SubnetMaskStr,"%d.%d.%d.%d",subnet[0],subnet[1],subnet[2],subnet[3]);
        sprintf(GatewayStr,"%d.%d.%d.%d",gateway[0],gateway[1],gateway[2],gateway[3]);
        Ethernet.begin(mac, ip);
//      Ethernet.begin(mac);                                            //DHCPの場合
//      Ethernet.begin(mac, ip, subnet);                                //SubnetMaskを意識した場合。
//      Ethernet.begin(mac, ip, subnet, gateway);                       //gatewayを意識した場合。
}
//--------------------------
void paramParse(String reqStr){
        int Code;
        int len         = reqStr.length();
        char* HTTP_c    = (char*)malloc(len+1);
        reqStr.toCharArray(HTTP_c, len);
        char bufff[10];
        //DT1 mac[0]            HEX
        int indexS      = reqStr.indexOf("DT1=");
        int indexE      = reqStr.indexOf("&",indexS);
        int k = 0;
        char c;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[0]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT2 mac[1]            HEX
        indexS = reqStr.indexOf("DT2=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[1]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT3 mac[2]            HEX
        indexS = reqStr.indexOf("DT3=");                                        //Serial.print("Pos=");Serial.println(indexS);
        indexE = reqStr.indexOf("&",indexS);                                    //Serial.print("Pos=");Serial.println(indexE);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);                                           //Serial.println(c);
                if (c == '='){
                        int m = indexE - indexS;                                //Serial.print("m=");Serial.println(m);
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[2]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                 }
        }
        //DT4 mac[3]            HEX
        indexS = reqStr.indexOf("DT4=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[3]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT5 mac[4]            HEX
        indexS = reqStr.indexOf("DT5=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[4]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[4]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT6 mac[5]            HEX
        indexS = reqStr.indexOf("DT6=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[5]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[5]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT7 ip[0]             DEC
        indexS = reqStr.indexOf("DT7=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[0]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT8 ip[1]             DEC
        indexS = reqStr.indexOf("DT8=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[1]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT9 ip[2]             DEC
        indexS = reqStr.indexOf("DT9=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[2]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT10 ip[3]            DEC
        indexS = reqStr.indexOf("DT10=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[3]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT11 subnet[0]        DEC
        indexS = reqStr.indexOf("DT11=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[0]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT12 subnet[1]        DEC
        indexS = reqStr.indexOf("DT12=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[1]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT13 subnet[2]        DEC
        indexS = reqStr.indexOf("DT13=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j); //Serial.println(bufff);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[2]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT14 subnet[3]        DEC
        indexS = reqStr.indexOf("DT14=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = HTTP_req.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[3]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT15 gateway[0]       DEC
        indexS = reqStr.indexOf("DT15=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[0]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT16 gateway[1]       DEC
        indexS = reqStr.indexOf("DT16=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[1]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT17 gateway[2]       DEC
        indexS = reqStr.indexOf("DT17=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[2]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT18 gateway[3]       DEC
        indexS = reqStr.indexOf("DT18=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[3]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT19 timezone       float
        indexS = reqStr.indexOf("DT19=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        timezone =int((strtof(bufff, NULL)*10));
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
}
//--------------------------
void checkWebPage( EthernetClient client){
        if(Serial)      Serial.println(F("new webClient"));
        boolean restart = false;
        if (client) {
                // HTTPリクエスト空行(\r\n\r\n)で終わる。ので、空行を探す。
                boolean currentLineIsBlank = true;
                while (client.connected()) {
                        if( !client.available() ){
                                if(Serial)    Serial.print(F("."));
                                continue;
                        }
                        char c = client.read();
                        HTTP_req += c;
                        if(Serial)    Serial.print(c);
                        if( c == '\n'  && currentLineIsBlank ){                 // 空行発見。HTTPリクエスト終了。レスポンスを返す。
                                //Serial.print("RecieveLength=");Serial.println(HTTP_req.length());
                                if (HTTP_req.indexOf("/?")>0) {                 //setup?と/?を区別する必要がある
                                        if(Serial)    Serial.print(F("CASE1:"));Serial.print(gLoopCount);
                                        if(gLoopCount % 2){
                                                digitalWrite(LED_BUILTIN,HIGH); //Serial.println(F(" H"));
                                        }else{
                                                digitalWrite(LED_BUILTIN,LOW);  //Serial.println(F(" L"));
                                        }
                                        delay(100);
                                        HTTP_req = "";
                                        break;
                                }else if(HTTP_req.indexOf("setup")>0){
                                        //setup頁の場合 SBMが含まれていればEEPROMに書込、そうで無ければ表示のみ
                                        //setup?SBM=1&DT1=0&DT2=8&DT3=DC&DT4=54&DT5=4D&DT6=D0&DT1=0&DT2=8&DT3=220&DT4=84&DT5=77&DT6=208&DT7=192&DT8=168&DT9=0&DT10=200&DT11=255&DT12=255&DT13=255&DT14=0&DT15=192&DT16=168&DT17=0&DT18=1
                                        //TextFinderを使うとHTMLの切り出しは比較的容易これをSTRING型のままどう扱うか?
                                        if(Serial)    Serial.print(F("CASE2:"));Serial.print(gLoopCount);
                                        if (HTTP_req.indexOf("SBM")>0){
                                                //Serial.println(F("Found_SBM"));
                                                if(Serial)    Serial.print(F("CASE3:"));Serial.print(gLoopCount);
                                                paramParse(HTTP_req);
                                                // すべてのデータを取得したので、EEPROMに保存します。
                                                WriteID();
                                                //データがEEPROMに書き込まれている場合は、arduinoをリセットする必要があります。
                                                //読込直す
                                                int idcheck = EEPROM.read(0);
                                                if (idcheck == ID){
                                                        //idがIDと同じ値の場合、
                                                        //これは、このスケッチがシールドを設定するために使用されたことを意味します。
                                                        //EERPOMの値を読み取ってシールドを設定します。
                                                        ReadID();
                                                }
                                                //ハードウェアリセットボタンを使用する必要があります
                                                HTTP_req = "";
                                        }else if(HTTP_req.indexOf("setup1")>0){
                                                if(Serial)      Serial.println(F("setup1"));
                                                PrintSetUpPage(client);
                                                HTTP_req = "";
                                        }else if(HTTP_req.indexOf("setup2")>0){
                                                if(Serial)      Serial.println(F("setup2"));
                                                PrintUtilPage(client);
                                                HTTP_req = "";
                                        }else if(HTTP_req.indexOf("setup3")>0){
                                                if(Serial)      Serial.println(F("setup3"));
                                                pageLoadUtilsJS(client);
                                                HTTP_req = "";
                                        }else{
                                                if(Serial)      Serial.print(F("CASE404-1"));
                                                PrintResponse404(client);
                                                HTTP_req = "";
                                                break;
                                        }
                                }else if(HTTP_req.indexOf("\n")>0) {
                                        if(Serial)      Serial.println(F("CASE4"));
                                        pageIntroduction(client);
                                        HTTP_req = "";
                                        break;
                                }else if(HTTP_req.indexOf("/index")>0) {
                                        if(Serial)      Serial.println(F("CASE5"));
                                        pageIntroduction(client);
                                        HTTP_req = "";
                                        break;
                                }else{
                                        if(Serial)      Serial.print(F("CASE404-2"));
                                        PrintResponse404(client);
                                        HTTP_req = "";
                                        break;
                                }
                                HTTP_req = "";
                                break;                          // ループを抜ける
                        }
                        if(c ==  '\n'){                         // 新しい行の始まり。
                                currentLineIsBlank = true;
                        } else if(c !=  '\r' ){                 // この行は空行ではなかった。
                                currentLineIsBlank = false;
                        }
                }
                delay(1);
                client.stop();
        }     
}
//--------OK_200
String OK_200           =
"HTTP/1.1 200 OK\n"
"Content-Type: text/html\n";
//--------NG_404
String NG_404           =
"HTTP/1.1 404 Not Found\n"
"Content-Type: text/html\n"
"Connnection: close\n";
//--------LoadUtilsJS
String LoadUtilsJS1     =
"'use strict';\n"
"window.chartColors = {\n"
        "\tred: 'rgb(255, 99, 132)',\n"
        "\torange: 'rgb(255, 159, 64)',\n"
        "\tyellow: 'rgb(255, 205, 86)',\n"
        "\tgreen: 'rgb(75, 192, 192)',\n"
        "\tblue: 'rgb(54, 162, 235)',\n"
        "\tpurple: 'rgb(153, 102, 255)',\n"
        "\tgrey: 'rgb(201, 203, 207)'\n"
"};\n"
"(function(global) {\n"
        "\tvar MONTHS = [\n"
                "\t\t'January',\n"
                "\t\t'February',\n"
                "\t\t'March',\n"
                "\t\t'April',\n"
                "\t\t'May',\n"
                "\t\t'June',\n"
                "\t\t'July',\n"
                "\t\t'August',\n"
                "\t\t'September',\n"
                "\t\t'October',\n"
                "\t\t'November',\n"
                "\t\t'December'\n"
        "\t];\n"
        "\tvar COLORS = [\n"
                "\t\t'#4dc9f6',\n"
                "\t\t'#f67019',\n"
                "\t\t'#f53794',\n"
                "\t\t'#537bc4',\n"
                "\t\t'#acc236',\n"
                "\t\t'#166a8f',\n"
                "\t\t'#00a950',\n"
                "\t\t'#58595b',\n"
                "\t\t'#8549ba'\n"
        "\t];\n"
        "\tvar Samples = global.Samples || (global.Samples = {});\n"
        "\tvar Color = Chart.helpers.color;\n"
        "\tfunction applyDefaultNumbers(config) {\n"
                "\t\tvar cfg = config || {};\n"
                "\t\tcfg.min = cfg.min || 0;\n"
                "\t\tcfg.max = cfg.max || 1;\n"
                "\t\tcfg.from = cfg.from || [];\n"
                "\t\tcfg.count = cfg.count || 8;\n"
                "\t\tcfg.decimals = cfg.decimals || 8;\n"
                "\t\tcfg.continuity = cfg.continuity || 1;\n"
                "\t\treturn cfg;\n"
        "\t}\n";
String LoadUtilsJS2     =
        "\tSamples.utils = {\n"
                "\t\t// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/\n"
                "\t\tsrand: function(seed) {\n"
                "\t\t\tthis._seed = seed;\n"
                "\t\t},\n"
                "\t\trand: function(min, max) {\n"
                "\t\t\tvar seed = this._seed;\n"
                "\t\t\tmin = min === undefined ? 0 : min;\n"
                "\t\t\tmax = max === undefined ? 1 : max;\n"
                "\t\t\tthis._seed = (seed * 9301 + 49297) % 233280;\n"
                "\t\t\treturn min + (this._seed / 233280) * (max - min);\n"
                "\t\t},\n"
                "\t\tnumbers: function(config) {\n"
                        "\t\t\tvar cfg = applyDefaultNumbers(config);\n"
                        "\t\t\tvar dfactor = Math.pow(10, cfg.decimals) || 0;\n"
                        "\t\t\tvar data = [];\n"
                        "\t\t\tvar i, value;\n"
                        "\t\t\tfor (i = 0; i < cfg.count; ++i) {\n"
                                "\t\t\t\tvalue = (cfg.from[i] || 0) + this.rand(cfg.min, cfg.max);\n"
                                "\t\t\t\tif (this.rand() <= cfg.continuity) {\n"
                                "\t\t\t\t\tdata.push(Math.round(dfactor * value) / dfactor);\n"
                                "\t\t\t\t} else {\n"
                                "\t\t\t\t\tdata.push(null);\n"
                                "\t\t\t\t}\n"
                        "\t\t\t}\n"
                        "\t\t\treturn data;\n"
                "\t\t},\n"
                "\t\tlabels: function(config) {\n"
                        "\t\t\tvar cfg = config || {};\n"
                        "\t\t\tvar min = cfg.min || 0;\n"
                        "\t\t\tvar max = cfg.max || 100;\n"
                        "\t\t\tvar count = cfg.count || 8;\n"
                        "\t\t\tvar step = (max - min) / count;\n"
                        "\t\t\tvar decimals = cfg.decimals || 8;\n"
                        "\t\t\tvar dfactor = Math.pow(10, decimals) || 0;\n"
                        "\t\t\tvar prefix = cfg.prefix || '';\n"
                        "\t\t\tvar values = [];\n"
                        "\t\t\tvar i;\n"
                        "\t\t\tfor (i = min; i < max; i += step) {\n"
                        "\t\t\t\tvalues.push(prefix + Math.round(dfactor * i) / dfactor);\n"
                        "\t\t\t}\n"
                        "\t\t\treturn values;\n"
                "\t\t},\n"
                "\t\tmonths: function(config) {\n"
                        "\t\t\tvar cfg = config || {};\n"
                        "\t\t\tvar count = cfg.count || 12;\n"
                        "\t\t\tvar section = cfg.section;\n"
                        "\t\t\tvar values = [];\n"
                        "\t\t\tvar i, value;\n"
                        "\t\t\tfor (i = 0; i < count; ++i) {\n"
                                "\t\t\t\tvalue = MONTHS[Math.ceil(i) % 12];\n"
                                "\t\t\t\tvalues.push(value.substring(0, section));\n"
                        "\t\t\t}\n"
                        "\t\t\treturn values;\n"
                "\t\t},\n"
                "\t\tcolor: function(index) {\n"
                        "\t\t\treturn COLORS[index % COLORS.length];\n"
                "\t\t},\n"
                "\t\ttransparentize: function(color, opacity) {\n"
                        "\t\t\tvar alpha = opacity === undefined ? 0.5 : 1 - opacity;\n"
                        "\t\t\treturn Color(color).alpha(alpha).rgbString();\n"
                "\t\t}\n"
        "\t};\n";
String LoadUtilsJS3     =
        "\t// DEPRECATED\n"
        "\twindow.randomScalingFactor = function() {\n"
                "\t\treturn Math.round(Samples.utils.rand(-100, 100));\n"
        "\t};\n"
        "\t// INITIALIZATION\n"
        "\tSamples.utils.srand(Date.now());\n"
        "\t// Google Analytics\n"
        "\t/* eslint-disable */\n"
        "\tif (document.location.hostname.match(/^(www\\.)?chartjs\\.org$/)) {\n"
                "\t\t(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n"
                "\t\t(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n"
                "\t\tm=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n"
                "\t\t})(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n"
                "\t\tga('create', 'UA-28909194-3', 'auto');\n"
                "\t\tga('send', 'pageview');\n"
        "\t}\n"
        "\t/* eslint-enable */\n"
"}(this));\n";
//--------WebTopPage
String WebTopPage1      =
"<HTML>\n"
"<HEAD>\n"
        "\t<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;CHARSET=UTF-8\">\n"
"</HEAD>\n"
"<BODY BGCOLOR='#ffffff'>\n"
"<H2><CENTER><FONT COLOR='#00ff00'>RP2040版 GPSNTP メニュー</FONT></CENTER></H2>\n"
"<P><CENTER><TABLE WIDTH='300' BORDER='0' CELLSPACING='0' CELLPADDING='0'>\n"
        "\t<TR>\n"
                "\t\t<TD WIDTH='100%'>\n"
                "\t\t<OL>\n"
                "\t\t\t<LI><FONT SIZE='+1'><A HREF=\"http://";
String WebTopPage2       =
                "/setup1\">設定メニュー</A>\n"
                "\t\t\t<LI><A HREF=\"http://";
String WebTopPage3       =
                "/setup2\">GPSセンテンス表示</A></FONT>\n"
                "\t\t</OL>\n"
                "\t\t</TD>\n"
        "\t</TR>\n"
"</TABLE></CENTER>\n"
"</BODY>\n"
"</HTML>\n";
//-------------SetPage
String SetPage1         =
"<!DOCTYPE HTML PUBLIC \"\">\n<html>\n<HEAD>\n\t<META http-equiv=\"Content-Type\" charset=Shift_JIS\">\n"
        "\t<META http-equiv=\"Content-Style-Type\">\n\t<TITLE>";
String SetPage2         =
        " Setup Page</TITLE>\n</HEAD>\n"
        "<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\">\n<BLOCKQUOTE><BLOCKQUOTE>\n"
        "<table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\">\n"
        "<tr><td>";
String SetPage3         =
        " Setup Page</td></tr></table><br>\n"
        "<script>\n\tfunction hex2num (s_hex) {\n\t\teval(\"var n_num=0X\" + s_hex);\n\t\treturn n_num;\n\t}\n</script>\n"
        "<tbody>\n<FORM><input type=\"hidden\" name=\"SBM\" value=\"1\">\n<table>\n<tr><td>MAC:</td><td>"
        "<input id=\"T1\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT1\" value=\"";
String SetPage4         =
        "\">.<input id=\"T3\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT2\" value=\"";
String SetPage5         =
        "\">.<input id=\"T5\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT3\" value=\"";
String SetPage6         =
        "\">.<input id=\"T7\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT4\" value=\"";
String SetPage7         =
        "\">.<input id=\"T9\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT5\" value=\"";
String SetPage8         =
        "\">.<input id=\"T11\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT6\" value=\"";
String SetPage9         =
        "\"><input id=\"T2\" type=\"hidden\" name=\"DT1\"><input id=\"T4\" type=\"hidden\" name=\"DT2\n"
        "\"><input id=\"T6\" type=\"hidden\" name=\"DT3\"><input id=\"T8\" type=\"hidden\" name=\"DT4\n"
        "\"><input id=\"T10\" type=\"hidden\" name=\"DT5\"><input id=\"T12\" type=\"hidden\" name=\"DT6\n"
        "\"></td></tr>\n<tr><td>IP:</td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT7\" value=\"";
String SetPage10        =
       "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT8\" value=\"";
String SetPage11        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT9\" value=\"";
String SetPage12        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT10\" value=\"";
String SetPage13        =
        "\"></td></tr>\n<tr><td>MASK: </td><td><input type= \"text\" size=\"3\" maxlength=\"3\" name=\"DT11\" value=\"";
String SetPage14        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT12\" value=\"";
String SetPage15        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT13\" value=\"";
String SetPage16        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT14\" value=\"";
String SetPage17        =
        "\"></td></tr>\n<tr><td>GW: </td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT15\" value=\"";
String SetPage18        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT16\" value=\"";
String SetPage19        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT17\" value=\"";
String SetPage20        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT18\" value=\"";
String SetPage21        =
        "\"></td></tr><tr><td COLSPAN='2'>\n<HR ALIGN=CENTER></td></tr>\n"
        "<tr><td>TimeZone:</td><td><input type=\"text\" size=\"3\" maxlength=\"5\" name=\"DT19\" value=\"";
String SetPage22        =
        "\"></td></tr>\n<tr><td><br></td></tr><tr><td COLSPAN='2'><P ALIGN=RIGHT><input id=\"button1\"type=\"submit\" value=\"SUBMIT\" \n"
        "Onclick=\""
        "document.getElementById('T2').value = hex2num(document.getElementById('T1').value);\n"
        "\t\tdocument.getElementById('T4').value = hex2num(document.getElementById('T3').value);\n"
        "\t\tdocument.getElementById('T6').value = hex2num(document.getElementById('T5').value);\n"
        "\t\tdocument.getElementById('T8').value = hex2num(document.getElementById('T7').value);\n"
        "\t\tdocument.getElementById('T10').value = hex2num(document.getElementById('T9').value);\n"
        "\t\tdocument.getElementById('T12').value = hex2num(document.getElementById('T11').value);\""
        "></td></tr></tbody>\n</table>\n</BLOCKQUOTE></BLOCKQUOTE>\n</form>\n</BODY>\n</html>\n";
//------------------PrintSetUpPage
void PrintSetUpPage( EthernetClient client){
        client.println(OK_200);
        client.print(SetPage1);
        client.print(vers);
        client.print(SetPage2);
        client.print(vers);
        client.print(SetPage3);
        client.print(mac[0],HEX);
        client.print(SetPage4);
        client.print(mac[1],HEX);
        client.print(SetPage5);
        client.print(mac[2],HEX);
        client.print(SetPage6);
        client.print(mac[3],HEX);
        client.print(SetPage7);
        client.print(mac[4],HEX);
        client.print(SetPage8);
        client.print(mac[5],HEX);
        client.print(SetPage9);
        client.print(ip[0],DEC);
        client.print(SetPage10);
        client.print(ip[1],DEC);
        client.print(SetPage11);
        client.print(ip[2],DEC);
        client.print(SetPage12);
        client.print(ip[3],DEC);
        client.print(SetPage13);
        client.print(subnet[0],DEC);
        client.print(SetPage14);
        client.print(subnet[1],DEC);
        client.print(SetPage15);
        client.print(subnet[2],DEC);
        client.print(SetPage16);
        client.print(subnet[3],DEC);
        client.print(SetPage17);
        client.print(gateway[0],DEC);
        client.print(SetPage18);
        client.print(gateway[1],DEC);
        client.print(SetPage19);
        client.print(gateway[2],DEC);
        client.print(SetPage20);
        client.print(gateway[3],DEC);
        client.print(SetPage21);
        client.print(timezone,2);
        client.print(SetPage22);
}
//-------------UtilPage
String UtilPage1        =
        "<!DOCTYPE HTML PUBLIC \"\">\n"
        "<html>\n"
        "<HEAD>\n"
                "\t<META http-equiv=\"Content-Type\" charset=\"UTF-8\">\n"
                "\t<META http-equiv=\"Content-Style-Type\">\n"
                "\t<TITLE>";
String UtilPage2        =
                " Utility Page</TITLE>\n"
                "\t<script type='application/javascript' SRC='http://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.js'></script>\n"
                "\t<script type='application/javascript' SRC='http://192.168.0.199/setup3'></script>\n"
                "\t<style>\n"
                        "\t\tcanvas{\n"
                                "\t\t\t-moz-user-select: none;\n"
                                "\t\t\t-webkit-user-select: none;\n"
                                "\t\t\t-ms-user-select: none;\n"
                        "\t\t}\n"
                        "\t\thtml { font-family: Helvetica; display: inline-block; margin: 0px auto;}\n"
                        "\t\tbody{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n"
                        "\t\tp {font-size: 24px;color: #444444;margin-bottom: 10px;}\n"
                "\t</style>\n"
        "</HEAD>\n"
        "<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\" BGCOLOR=\"#ffffff\">\n"
        "<FORM>\n"
        "<BLOCKQUOTE><BLOCKQUOTE>\n"
        "<P><table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\" CELLSPACING=\"2\">\n"
        "<tr><td>";
String UtilPage3        =
        " Utility Page</td></tr></table><br>\n";
String UtilPage4        =
        "<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">FirmwareVirsion:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage5        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">MacAddress:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage6        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">IPAddress:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage7        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">SubnetMask:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage8        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">BoardTemperature:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage9        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">NTP受信回数:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage10       =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\" NOWRAP>Data acquisition time(Local):</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage11       =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\" NOWRAP>Operating Time:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage12       =
        "</TD>\n"
        "</TR></TABLE></P>\n"
        "<P><center><TABLE WIDTH=\"750\" BORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"0\" HEIGHT=\"101\">\n"
                "\t<CAPTION ALIGN=\"TOP\"><P ALIGN=LEFT>GPS センテンス</CAPTION>"
                "\t<TR>\n"
                        "\t\t<TD COLSPAN=\"2\" BGCOLOR=\"#000000\">\n"
                        "\t\t<BLOCKQUOTE>\n"
                                "\t\t\t<PRE><FONT COLOR=\"#ffffff\" SIZE=\"+1\">";
String UtilPage13       =
                "</FONT></PRE>\n"
                        "\t\t</BLOCKQUOTE>"
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">ステータス:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage14       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">日時(UTC):</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage15       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">位置情報:緯度</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage16       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">位置情報:経度</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage17       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">移動の速度:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage18       =
                "[knot]</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">移動の真方位:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage19       =
                "[度]</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">モード:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage20       =
                "</TD>\n"
                "\t</TR>\n"
        "</TABLE></center>\n"
        "<CENTER>\n"
                "\t<div style='width:75%;'><canvas id='canvas' width='750' height='400' style='display: block; width: 750px; height: 400px;'></canvas></div>\n"
        "</CENTER></BLOCKQUOTE></BLOCKQUOTE>\n"
        "</form>\n"
        "<script>\n"
                "\tvar randomScalingFactor = function() {\n"
                        "\t\t\treturn 18 + Math.random() * 10;\n"
                        "\t\t};\n";
String UtilPage21       =
                        "\t\tvar config = {\n"
                                "\t\t\ttype: 'line',\n\t\t\tdata: {\n"
                                        "\t\t\t\tlabels: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12' , '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'],\n"
                                        "\t\t\t\tdatasets: [{\n"
                                                "\t\t\t\t\tlabel: '緯度[度]',\n"
                                                "\t\t\t\t\tdata: data_00,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.red,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tcubicInterpolationMode: 'monotone',\n"
                                                "\t\t\t\t\tyAxisID: 'y1'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '経度[度]',\n"
                                                "\t\t\t\t\tdata: data_01,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.blue,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y2'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '速度[knot]',\n"
                                                "\t\t\t\t\tdata: data_02,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.orange,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y3'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '真方位[度]',\n"
                                                "\t\t\t\t\tdata: data_03,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.yellow,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y4'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '温度[℃]',\n"
                                                "\t\t\t\t\tdata: data_04,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.grey,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y5'\n"
                                        "\t\t\t\t}]\n"
                                "\t\t\t},\n"
                                "\t\t\toptions: {\n"
                                        "\t\t\t\tresponsive: true,\n"
                                        "\t\t\t\ttitle: {\n";
String UtilPage22       =
                                                "\t\t\t\t\tdisplay: true,\n"
                                                "\t\t\t\t\ttext: '今日のGPS位置情報'\n"
                                        "\t\t\t\t},\n"
                                        "\t\t\t\tlegend: {\n"
                                                "\t\t\t\t\tdisplay: true\n"
                                                "\t\t\t\t},\n"
                                                "\t\t\t\ttooltips: {\n"
                                                        "\t\t\t\t\tenabled: true,\n"
                                                        "\t\t\t\t\tmode: 'index'\n"
                                                "\t\t\t\t},\n"
                                                "\t\t\t\tscales: {\n"
                                                        "\t\t\t\t\txAxes: [{\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '時刻 [時]'\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t}],\n"
                                                        "\t\t\t\t\tyAxes: [{\n"
                                                                "\t\t\t\t\t\tid:'y1',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.red,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '緯度[度]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.red,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: -200,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  200\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y2',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.blue,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '経度[度]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.blue,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: -200,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  200\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y3',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.orange,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '速度[knot]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.orange,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: 0,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  40\n"
                                                                "\t\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y4',\n"
                                                                "\t\t\t\t\t\tposition: 'right',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.yellow,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '真方位[度]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.yellow,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: 0,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  400\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y5',\n"
                                                                "\t\t\t\t\t\tposition: 'right',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.grey,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '気温[℃]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.grey,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: 10,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  50\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t}]\n"
                                                "\t\t\t\t}\n"
                                        "\t\t\t}\n"
                                "\t\t};\n" 
                                "\t\twindow.onload = function() {\n"
                                        "\t\t\tvar ctx = document.getElementById('canvas').getContext('2d');\n"
                                        "\t\t\twindow.myLine = new Chart(ctx, config);\n"
                                "\t\t};\n"
        "</script>\n"
        "</BODY></html>";
//-------------PrintUtilPage
void PrintUtilPage( EthernetClient client){
        client.println(OK_200);
        client.print(UtilPage1);
        client.print(vers);
        client.print(UtilPage2);
        client.print(vers);
        client.print(UtilPage3);
        client.print(UtilPage4);
        client.print(FVirsion);
        client.print(UtilPage5);
        client.print(MacAddressStr);
        client.print(UtilPage6);
        client.print(IPAddressStr);
        client.print(UtilPage7);
        client.print(SubnetMaskStr);
        client.print(UtilPage8);
        sprintf(buf1,"%.2f[℃]",analogReadTemp());
        client.print(buf1);
        client.print(UtilPage9);
        sprintf(buf1,"%d[回]",gNTPqueryCount);
        client.print(buf1);
        client.print(UtilPage10);
        currentTime     = now() - seventyYears;
        sprintf(DateTimeStr,"%04u/%02u/%02u %02u:%02u:%02u",year(currentTime),month(currentTime),day(currentTime),hour(currentTime),minute(currentTime),second(currentTime));
        client.print(DateTimeStr);
        client.print(UtilPage11);
        sprintf(buf1,"%d[sec]",(OperatingTime / 2));
        client.print(buf1);
        client.print(UtilPage12);
        client.print(nmea);
        if(Serial)      Serial.println(nmea);
        analsysRMC();           //RMCの要素切り出し
        client.print(UtilPage13);
        client.print(StatusStr);
        client.print(UtilPage14);
        client.print(DateTime2Str);
        client.print(UtilPage15);
        client.print(latitudeNSStr);
        client.print(latitudeStr);
        client.print(F("\t("));client.print(latitude,8);client.print(F(")"));
        client.print(UtilPage16);
        client.print(longitudeEWStr);
        client.print(longitudeStr);
        client.print(F("\t("));client.print(longitude,8);client.print(F(")"));
        client.print(UtilPage17);
        client.print(VeloStr);
        client.print(UtilPage18);
        client.print(DirStr);
        client.print(UtilPage19);
        client.print(ModeStr);
        client.print(UtilPage20);
        client.print(F("\t\tvar data_00 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][0]) ? String('\0') : String(gDayBuf[i][0],6));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_01 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][1]) ? String('\0') : String(gDayBuf[i][1],6));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_02 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][2]) ? String('\0') : String(gDayBuf[i][2],2));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_03 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][3]) ? String('\0') : String(gDayBuf[i][3],2));
                client.print(F(","));
        }
        client.print(F("];\n"));        
        client.print(F("\t\tvar data_04 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][4]) ? String('\0') : String(gDayBuf[i][4],2));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(UtilPage21);
        client.print(UtilPage22);
}
//-------------WebPageTop
void pageIntroduction( EthernetClient client){
        client.println(OK_200);
        client.print(WebTopPage1);
        client.print(bufIP);
        client.print(WebTopPage2);
        client.print(bufIP);
        client.println(WebTopPage3);
        client.stop();
}
//-------------LoadUtilsJS
void pageLoadUtilsJS( EthernetClient client){
        client.println(OK_200);
        client.println(LoadUtilsJS1);                                     //バッファサイズを考慮して3分割しています。
        client.println(LoadUtilsJS2);
        client.println(LoadUtilsJS3);
        client.stop();
}
//------------PrintResponse404
void PrintResponse404( EthernetClient client ){
        client.println(NG_404);
        client.stop();
}
//-------------タイマ割込で呼ばれるルーチン クロック表示 500msec毎
bool    TimerHandler0(struct repeating_timer *t){
        OperatingTime++;
        currentTime     =       now();
        if(Serial)      Serial.println(currentTime);
        currentTime     %=  86400;
        currentHour     = currentTime / 3600;
        currentMin      = (currentTime % 3600)/60;
        TimeDisp[0]     = currentHour/ 10;
        TimeDisp[1]     = currentHour % 10;
        TimeDisp[2]     = currentMin / 10;
        TimeDisp[3]     = currentMin % 10;
        if(fTogle1)     tm1637.point(POINT_OFF);
        else            tm1637.point(POINT_ON);
        tm1637.display(TimeDisp);
        fTogle1         = !fTogle1;
        return true;
}
//---------------------
bool processNTP() {
        //利用可能なデータがある場合は、パケットを読み取ります
        //https://blog.goo.ne.jp/hiro239415/e/c426a545863921a13a9d6a70b7ae4484
        //NTP_Packet (48Byte)
        bool    req             =       false;
        int     packetSize      =       Udp.parsePacket();
        if(packetSize){
                digitalWrite(LED_BUILTIN,HIGH);                         //要求があったときにBuiltInLEDを点灯
                miliTime                = millis() - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                sprintf(buf1,"■%d\t%d\n",packetSize,fractions);
                if(Serial)     Serial.print(buf1);
                Udp.read(packetBuffer,NTP_PACKET_SIZE);
                IPAddress       Remote  = Udp.remoteIP();
                int             PortNum = Udp.remotePort();
                //受信タイムスタンプ = サーバが受け取った時刻を予めセットしておく JSTなのでGMTに変換
                timestamp               = now()         - TimeZoneSec;
                miliTime                = millis()      - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                tempval                 = timestamp;
                packetBuffer[32]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[33]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[34]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[35]        = (tempval) & 0xFF;
                //
                microVal                = fractions;
                packetBuffer[36]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[37]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[38]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[39]        = microVal & 0xFF;
                 //ヘッダーセット
                packetBuffer[0]         = 0b00100100;                           // 閏秒警告なしLI, 4:SNTPサーバ(Version), 4:サーバ(Mode)
                packetBuffer[1]         = 1 ;                                   // 1:一次基準源(GPS等)(stratum
                packetBuffer[2]         = 5 ;                                   // ポーリング64秒デフォルト値 6(64秒)->5(32秒)
                packetBuffer[3]         = 0xF6;                                 // 精度 -3(0xFD)->-10(0xF6)に変更 msec
                packetBuffer[4]         = 0;                                    // ルート遅延
                packetBuffer[5]         = 0;
                packetBuffer[6]         = 8;
                packetBuffer[7]         = 0;
                packetBuffer[8]         = 0;                                    // ルート分散
                packetBuffer[9]         = 0;
                packetBuffer[10]        = 0xC;
                packetBuffer[11]        = 0;
                //
                packetBuffer[12]        = 71;                                   //"G";   ReferenceID
                packetBuffer[13]        = 80;                                   //"P";   ReferenceID
                packetBuffer[14]        = 83;                                   //"S";   ReferenceID
                packetBuffer[15]        = 0;                                    //"0";   ReferenceID
                // リファレンス時刻をセット(現在時間)
                timestamp               = now()         - TimeZoneSec;          //UTC
                if(Serial){
                        Serial.print(timestamp);Serial.print(F(":Time synchronization Request received\n"));
                }
                tempval                 = timestamp;
                microVal                = fractions;
                packetBuffer[16]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[17]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[18]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[19]        = (tempval) & 0xFF;
                packetBuffer[20]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[21]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[22]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[23]        = microVal & 0xFF;
                //オリジナル時間をコピー(サーバに要求が届いた時間)
                packetBuffer[24]        = packetBuffer[40];
                packetBuffer[25]        = packetBuffer[41];
                packetBuffer[26]        = packetBuffer[42];
                packetBuffer[27]        = packetBuffer[43];
                packetBuffer[28]        = packetBuffer[44];
                packetBuffer[29]        = packetBuffer[45];
                packetBuffer[30]        = packetBuffer[46];
                packetBuffer[31]        = packetBuffer[47];
                //送信時刻をセット
                timestamp               = now()         - TimeZoneSec;                  //UTC
                miliTime                = millis()      - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                tempval                 = timestamp;
                packetBuffer[40]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[41]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[42]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[43]        = (tempval) & 0xFF;
                //transmit_timestamp_fractions
                microVal                = fractions; 
                packetBuffer[44]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[45]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[46]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[47]        = microVal & 0xFF;
                //NTP要求を送信したIPアドレスとポートに応答します
                Udp.beginPacket(Remote, PortNum);
                Udp.write(packetBuffer,NTP_PACKET_SIZE);
                Udp.endPacket();
                digitalWrite(LED_BUILTIN,LOW);                                  //処理完了で消灯
                sprintf(buf1,"●%d\t%d\t%d\t%d\n",packetBuffer[20],packetBuffer[21],packetBuffer[22],packetBuffer[23]);
                if(Serial)      Serial.print(buf1);
                req     = true;
                gNTPqueryCount++;
        }
        return req;
}
//-----------------指定されたアドレスのタイムサーバーにNTP要求を送信します
void sendNTPpacket(const char * address) {
        // バッファ内のすべてのバイトを0に設定します
        memset(packetBuffer, 0, NTP_PACKET_SIZE);
        // NTP要求を形成するために必要な値を初期化します(パケットの詳細については、上記のURLを参照してください)
        packetBuffer[0]         = 0b11100011;                                   // LI, Version, Mode
        packetBuffer[1]         = 0;                                            // Stratum, or type of clock
        packetBuffer[2]         = 6;                                            // ポーリング64秒デフォルト値
        packetBuffer[3]         = 0xEC;                                         // 精度
        // ルート遅延とルート分散の場合は8バイトのゼロ
        packetBuffer[12]        = 0x31;                                         // '1'
        packetBuffer[13]        = 0x4E;                                         // 'N'
        packetBuffer[14]        = 0x31;                                         // '1'
        packetBuffer[15]        = 0x34;                                         // '4'
        //すべてのNTPフィールドに値が指定されているため、タイムスタンプを要求するパケットを送信できます。
        Udp.beginPacket(address, NTPport);                                      // NTP要求はポート123に送信されます
        Udp.write(packetBuffer, NTP_PACKET_SIZE);
        Udp.endPacket();
}
//-----------------受信したNTPパケットを解析してRTCにセットします
bool parseNTPpacket(){
        // 返信が利用可能かどうかを確認するのを待ちます
        if (Udp.parsePacket()) {
                // パケットを受信しました。そこからデータを読み取ります
                Udp.read(packetBuffer, NTP_PACKET_SIZE);                        // パケットをバッファに読み込みます
                // タイムスタンプは、受信したパケットのバイト40から始まり、4バイトです。
                unsigned long secsSince1900;
                // 位置40から始まる4バイトを長整数に変換します
                secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
                secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
                secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
                secsSince1900 |= (unsigned long)packetBuffer[43];
                Serial.print("Seconds since Jan 1 1900 = ");
                Serial.println(secsSince1900);
                // エピックタイムに変換します。(local)
                unsigned long epoch = secsSince1900 - seventyYears + TimeZoneSec;
                Serial.print("Unix time = ");
                Serial.println(epoch);
                setTime(epoch);                                                 //RTC登録(LocalTime)
        }
        return true;
}
//---------------NTP since 1900/01/01 retouch2020/12/25
static unsigned long int numberOfSecondsSince1900Epoch(uint16_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t mm, uint8_t s,float timezone) {
        //2036年問題が存在する。unsigned long intの桁溢れが発生
        //桁溢れが発生したら受信側が対応する必要がある。サーバ側では64bit化するべきだが動かなくなる。
        //timezoneをfloat扱いにした
        int leapAdjustment = 0;
        if (y >= 1970) {
                y -= 1970;
                leapAdjustment  = 2;                            // LM: 1970 was NOT a leap year!
        }
        uint16_t days = d;
        for (uint8_t i = 1; i < m; ++i)         days += pgm_read_byte(daysInMonth + i);
/*
        if (m > 2 && y % 4 == 0)                ++days;
*/
        if (m > 2 && (y + leapAdjustment) % 4 == 0)     ++days; // LM: Weak but okay for the present
        days += 365 * y + (y + 3) / 4 - 1;
        long offsetTime = long((float(h)+ timezone) * 3600.0);
        return days*24L*3600L + offsetTime + mm*60L + s + seventyYears;
}
//------------------
bool readSensor(void){
        if (Serial1.available()) {
                Serial1.readStringUntil('\n');                                  //読み捨てて先頭から読めるようにする
                nmea = Serial1.readStringUntil('\n');
                if(Serial)      Serial.println(nmea);
                //$GNRMC,022757.000,A,3430.62587,N,13316.66175,E,0.63,144.24,231220,,,A,V*02
                String  nmeames = nmea.substring(3,6);                          // $GP***
                int     count   = 0;
                while(!nmeames.equals(chkHader)){
                       nmea     = Serial1.readStringUntil('\n');
                       nmeames  = nmea.substring(3,6);                          // $GP***
                       if(Serial){
                                //Serial.print(nmea);Serial.print(F("\t"));Serial.println(nmeames);
                       }
                        if(count++ > 30)    break;
                }
                int     nextPos = 0;
                if ( nmeames.equals(chkHader)){                                 // get UTC
                        nextPos         = nmea.indexOf(DELIMITER);              //int indexOf(char ch, unsigned int fromIndex) const;
                        String shh      = nmea.substring(nextPos+1,nextPos+3);
                        String smm      = nmea.substring(nextPos+3,nextPos+5);
                        String sss      = nmea.substring(nextPos+5,nextPos+7);
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip UTC
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip Status
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 緯度
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 北緯か南緯か
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 経度
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 東経か西経か
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 地表における移動の速度[knot]
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 地表における移動の真方位[deg]
                        String sdd      = nmea.substring(nextPos+1,nextPos+3);
                        String smn      = nmea.substring(nextPos+3,nextPos+5);
                        String syy      = nmea.substring(nextPos+5,nextPos+7);
                        if(Serial)      Serial.println("20" + syy + smn + sdd + shh + smm + sss);
                        chYear          = syy.toInt() + 2000 - 1970;
                        if ((chYear < 31) || (chYear > 100)){                   //2001~2079をサポート
                                return false;
                        }else{
                                gpsTime =       numberOfSecondsSince1900Epoch(chYear,smn.toInt(),sdd.toInt(),shh.toInt(),smm.toInt(),sss.toInt(),timezone);
                                return true;
                        }
                }else{
                        return false;
                }
        }
        return false;
}
//------------------GPSにアクセスし、取得に成功したら内部時間を更新
bool ReadGPS(){
        bool valid      = false;
        if(readSensor()) {
                nowH    = now() / 3600;                         //内部時計はLocalTime
                if(nowH > preH){                                //1時間毎にRTCを更新する
                        preH    = nowH;
                        setTime(gpsTime);
                }
                valid      = true;
        }else{
                delay(100); 
                if(gLoopCount%60)       Serial.print(F("."));
                else                    Serial.println(F("."));
        }
        return valid;
}
//----------------- RMC文字列を解析してクラスタRMCにセットする
void    analsysRMC(void){
        //$GPRMC,021227.000,A,3459.9060,N,13652.6560,E,0.09,344.80,241220,,,A*6D
        //$GNRMC,072815.000,V,         , ,          , ,    ,      ,241220,,,N,V*27
        //RMCは要素数が固定されていないようなので注意が必要
        int     stPosi = 0;
        int     endPosi;
        char    State;
        //センテンス
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                setenceStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("setenceStr="));Serial.println(setenceStr);
        }
        stPosi  =       endPosi+1;
        //測位時刻(UTC時分秒)        UTC時刻:09時24分03秒307
        endPosi =       nmea.indexOf(',',stPosi);
        Serial.print(F("endPosi="));Serial.println(endPosi);
        if(!(endPosi<0)){
                TimeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("TimeStr="));Serial.println(TimeStr);
        }
        stPosi  =       endPosi+1;
        //測位状態 A:単独測位中またはDGPS測位中 V:未測位    単独測位中/DGPS測位中
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                StatusStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("StatusStr="));Serial.println(StatusStr);
        }
        stPosi  =       endPosi+1;
        //緯度。dddmm.mmmm (10進)     緯度 43.07328
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                latitudeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("latitudeStr="));Serial.println(latitudeStr);
        }
        stPosi  =       endPosi+1;
        //N:北緯、S:南緯       北緯
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                latitudeNSStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("latitudeNSStr="));Serial.println(latitudeNSStr);
        }
        stPosi  =       endPosi+1;
        //経度。dddmm.mmmm (10進)     経度 141.270980
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                longitudeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("longitudeStr="));Serial.println(longitudeStr);
        }
        stPosi  =       endPosi+1;
        //E:東経、W:西経       東経
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                longitudeEWStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("longitudeEWStr="));Serial.println(longitudeEWStr);
        }
        stPosi  =       endPosi+1;
        //速度(000.0〜270.0、単位:ノット)  速度 0 Knot
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                VeloStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("VeloStr="));Serial.println(VeloStr);
        }
        stPosi  =       endPosi+1;
        //真方位による進行方向(000.0〜359.9、単位:度)    240.3度
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                DirStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("DirStr="));Serial.println(DirStr);
        }
        stPosi  =       endPosi+1;
        //ddmmyy 日付(日、月、年)        日付 2017年7月15日
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                DateStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("DateStr="));Serial.println(DateStr);
        }
        stPosi  =       endPosi+1;
        //磁気偏差(000.0〜180.0、単位:度)  0(なし)
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                MagDegStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("MagDegStr="));Serial.println(MagDegStr);
        }
        stPosi  =       endPosi+1;
        //磁気偏差 E:磁気偏差が東より W:磁気偏差が西より      なし
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                MagDevStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("MagDevStr="));Serial.println(MagDevStr);
        }
        stPosi  =       endPosi+1;
        //測位mode N:未測位 A:単独測位 D:DGPS測位
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                ModeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("ModeStr="));Serial.println(ModeStr);
        }else{
                ModeStr = nmea.substring(stPosi,stPosi+1);
                Serial.print(F("ModeStr="));Serial.println(ModeStr);
        }
        stPosi  =       endPosi+1;
        //ナビゲーション状態 S:Safe C:Caution U:Unsafe V:無効(RAIM 機能 OFF)
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                NavStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("NavStr="));Serial.println(NavStr);
        }else{
                NavStr = nmea.substring(stPosi,stPosi+1);
                Serial.print(F("NavStr="));Serial.println(NavStr);
        }
        Status = StatusStr.charAt(0);
        switch(Status){
                case 'A':
                        StatusStr = "A = 有効";
                        //digitalWrite(LED1, LOW);
                        break;
                case 'V':
                        StatusStr = "V = 警告";
                        //digitalWrite(LED1, HIGH);
                        break;
                default:
                        StatusStr = "";
                        //digitalWrite(LED1, HIGH);
                        break;        
        }
        DateTime2Str = "20" + DateStr.substring(4,6) + "年" + DateStr.substring(2,4) + "月" + DateStr.substring(0,2) + "日 " + TimeStr.substring(0,2) + "時" + TimeStr.substring(2,4) + "分" + TimeStr.substring(4,6) + "秒" + TimeStr.substring(7,10);
        State = latitudeNSStr.charAt(0);
        switch(State){
                case 'N':
                        latitudeNSStr = "北緯 ";
                        break;
                case 'S':
                        latitudeNSStr = "南緯 ";
                        break;
                default:
                        latitudeNSStr = "";
                        break;        
        }
        stPosi  = 0;
        endPosi = latitudeStr.indexOf('.',stPosi);
        if(endPosi>0){
                String latitudeStr1     = latitudeStr.substring(stPosi,endPosi-2);
                String latitudeStr2     = latitudeStr.substring(endPosi-2,endPosi);
                String latitudeStr3     = "." + latitudeStr.substring(endPosi+1);
                latitude        = latitudeStr1.toFloat() + (latitudeStr2.toFloat()/60.0) + (latitudeStr3.toFloat()/60.0);
                if(State == 'S')        latitude = -latitude;
                latitudeStr     = latitudeStr1 + "度" + latitudeStr2 + "分" + latitudeStr3;
        }
        State = longitudeEWStr.charAt(0);
        switch(State){
                case 'E':
                        longitudeEWStr = "東経 ";
                        break;
                case 'W':
                        longitudeEWStr = "西経 ";
                        break;
                default:
                        longitudeEWStr = "";
                        break;        
        }
        stPosi  = 0;
        endPosi = longitudeStr.indexOf('.',stPosi);
        if(endPosi>0){
                String longitudeStr1     = longitudeStr.substring(stPosi,endPosi-2);
                String longitudeStr2     = longitudeStr.substring(endPosi-2,endPosi);
                String longitudeStr3     = "." + longitudeStr.substring(endPosi+1);
                longitude        = longitudeStr1.toFloat() + (longitudeStr2.toFloat()/60.0) + (longitudeStr3.toFloat()/60.0);
                if(State == 'W')        longitude = -longitude;
                longitudeStr     = longitudeStr1 + "度" + longitudeStr2 + "分" + longitudeStr3;
        }        
        State = ModeStr.charAt(0);
        switch(State){
                case 'N':
                        ModeStr = "N = データなし";
                        break;
                case 'A':
                        ModeStr = "A = Autonomous(自律方式)";
                        break;
                case 'D':
                        ModeStr = "D = Differential(干渉測位方式)";
                        break;
                case 'E':
                        ModeStr = "E = Estimated(推定)";
                        break;
                case 'M':
                        ModeStr = "M = マニュアル入力";
                        break;
                case 'S':
                        ModeStr = "S = シミュレーター入力";
                        break;
                default:
                        ModeStr = State;
                        break;        
        }
        gRmc.UTC        =       timestamp;
        gRmc.LAT        =       long(latitude         * 10000.0);
        gRmc.LON        =       long(longitude        * 10000.0);
        gRmc.SPD        =       int(VeloStr.toFloat() * 100.0);
        gRmc.DIR        =       int(DirStr.toFloat()  * 100.0);
}
//-----------------
int     getHourTime(void){
        return (now() % 86400) / 3600;
}
//-----------------
void setup() {
        pinMode(LED_BUILTIN, OUTPUT);
        digitalWrite(LED_BUILTIN, fTogle2);
        //SPI0のpinアサインを設定
        SPI.setSCK(2);
        SPI.setRX(4);
        SPI.setTX(3);
        SPI.setCS(5);
        // Ethernet.init(pin)を使用してCSピンを設定できます
        //Ethernet.init(10);                                                    // Most Arduino shields
        Ethernet.init(5);                                                       // MKR ETH shield
        //Ethernet.init(0);                                                     // Teensy 2.0
        //Ethernet.init(20);                                                    // Teensy++ 2.0
        //Ethernet.init(15);                                                    // ESP8266 with Adafruit Featherwing Ethernet
        //Ethernet.init(33);                                                    // ESP32 with Adafruit Featherwing Ethernet
        //シリアル通信を開き、ポートが開くのを待ちます。
        Serial.begin(115200);
        //GPS用にUART0 を使用
        Serial1.setRX(1);
        Serial1.setTX(0);
        Serial1.begin(9600);
        /*
        while (!Serial) {
                ; // シリアルポートが接続するのを待ちます。 ネイティブUSBポートにのみ必要
                //シリアルモニタを開かないと先に進まないので注意が必要
        }
        */
        // start Ethernet and UDP
        LANSetup();
        Ethernet.begin(mac,ip);                                         //FIXIP サンプルスケッチはDHCPでした
        sprintf(buf1,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
        bufIP = buf1;
        if(Serial){
                Serial.print(F("server is at "));Serial.println(Ethernet.localIP());
        }
        Udp.begin(NTPport);
        webServer.begin();
        //最初にNTPサーバから時刻を取得する
        sendNTPpacket(timeServer);                                      // NTPパケットをタイムサーバーに送信します
        delay(1000); 
        parseNTPpacket();
        tm1637.init();
        tm1637.set(BRIGHT_TYPICAL);                                     //BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
        for(int i = 0;i<24;i++){
                for(int j = 0;j<5;j++){
                        gDayBuf[i][j] = NAN;
                }
        }
        //マイクロ秒単位の間隔
        if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 500, TimerHandler0)){
                if(Serial){
                        Serial.print(F("Starting ITimer0 OK, millis() = ")); Serial.println(millis());
                }
        }else{
                if(Serial){
                        Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
                }
        }
        watchdog_reboot(0,0,delay_ms);
        if(Serial)      Serial.println(F("EndSetup"));
}
//-----------------
int     preSet      = -1;
void loop() {
        //1秒のループ WDT8秒
        if (watchdog_caused_reboot()){
                if(Serial)    Serial.print("Rebooted by Watchdog!\n");
        }else{
                if(Serial)    Serial.print("Clean boot\n");
        }
        watchdog_update();        
        bool valid      = ReadGPS();                                    //GPSセンテンス読込
        bool req        = processNTP();                                 //NTP要求確認
        client          = webServer.available();                        //HTTP要求確認
        if(client)      checkWebPage(client);
        client.stop();
        Ethernet.maintain();
        digitalWrite(LED_BUILTIN, fTogle2);
        fTogle2  = !fTogle2;
        int h = getHourTime();                                          //返値0-23
        if(Serial){
                Serial.print("preH=");Serial.println(preSet);
                Serial.print("h=");Serial.println(h);
                Serial.print("Status=");Serial.println(Status);
        }
        if((Status == 'A') && (preSet != h)){
                //1時間おきに時刻を確認し、データをメモリに確保
                analsysRMC();
                preSet  = h;
                gDayBuf[h][0]   =       float(gRmc.LAT) / 10000.0;
                gDayBuf[h][1]   =       float(gRmc.LON) / 10000.0;
                gDayBuf[h][2]   =       float(gRmc.SPD) / 100.0;
                gDayBuf[h][3]   =       float(gRmc.DIR) / 100.0;
                gDayBuf[h][4]   =       analogReadTemp();
                //次回分のデータをNULL化
                h = (h+1) % 24;
                gDayBuf[h][0]   =       NAN;
                gDayBuf[h][1]   =       NAN;
                gDayBuf[h][2]   =       NAN;
                gDayBuf[h][3]   =       NAN;
                gDayBuf[h][4]   =       NAN;
        }       
        gLoopCount++;
        if(Serial)      Serial.println(gLoopCount);
}


2022年5月12日 NICがpingに反応しなくなる点の対策

RP2040版GPSNTPサーバを運用デバッグ中です。時刻表示や、BuildInLEDの点滅はしているのにNTPアクセスやWebServerアクセスが出来なくなる現象を確認しました。pingさえ通らないです。
WDT=8秒をセットしてあるのですが、これが実行されません。Loop()は定期的に動作しているからだと考えます。RPiPicoのリセットで解決するのですが、NICのみリセットする様な手立てを検討するした方がよい考えました。

W5500とRPiPico間はreset信号の配線がされています。普段LOWにしておき、リセットしたいときにHIGHのパルスを送れば良いようです。
後はNICがデッドロックした事をどのように判断するかです。
Ethernet.hを見ると、linkStatus()というAPIがある事が判りました。
https://www.arduino.cc/reference/en/libraries/ethernet/ethernet.linkstatus/
W5500だから使える機能のようですが、このStatusがLinkOFFだとケーブル未接続乃至は欠陥とあります。
今回、pingが通らないという現象がStatus=LinkOFFと云う解釈になるのでは無いかと考えてLoop()内でチェックする事にしました。
もしStatus=LinkOFFの場合はNICに対してResetPinをONにすることにしました。

結果は暫く運用した上で確認出来るのかと思います。

2022年5月20日 linkStatus()ではダメです。

この件、時間が掛かっています。

linkStatus()はRJ45を引っこ抜くとStatus=LinkOFFになります。しかし、今回の問題であるNICが外部PCからpingを受け付けないような状態でもStatus=LinkONなのです。
また、Status=LinkOFF時の復活方法ですが、rebootしないとうまく回復しません。
rebootの手法自体はwatchdog_reboot(0,0,1)で実現出来る事は確認しました。

こんな状態を確認出来るのもPico自体のLoop()は健全に稼働しています。シリアルモニタにて状態確認出来、NICがpingを受け付けない状態になってもLoop()は状態モニタを吐き出しています。
また、時刻表示のためにTimer割込を使用していますが、こちらも健全に動いています。

NICが健全なのかどうかを如何にチェックするか?Selfsendのチェックも在処と思うのですが、ping 127.0.0.1の実現方法が判りません。もう少し検討します。


2022年5月27日 EthernetHardwareStatus()が有効みたいです。

Ethernet.hを眺めていて、enumでenum EthernetHardwareStatus {}を見つけました。EthernetHardwareStatus()で現環境の場合、EthernetW5500が返ってくるのですが、リンクが途絶えるとEthernetNoHardwareが返ってくるようです。実際にソースに組み込んで見たところ、何らかのタイミングでrebootが掛かることが確認出来ました。期待通りに動いているようです。

本来ならNICが安定して動作するのが理想です。W5500-EVB-Picoが入手可能になったら、再度動作確認したいところです。rebootが発生したかどうかは内部の連続実行時間で把握出来ます。 

2022年5月30日 EthernetHardwareStatus()でのヘルスチェックはうまく機能します。

ただ、reboot後にNTPdにアクセスして取得する時刻同期に失敗するケースがあり、この場合ずっと時刻表示が期待通りにならないようです。GPSの取得時間が有効になっているのであれば、RTCの更新をすべきです。この点の問題があることが判り、修正することにしました。

/*
 * 2022年5月17日 T.Wanibe
 * 2.5.5.2 EEPROMの書込でEEPROM.commit()を追加
 * 2.5.5.1 NTP受信したときのパケットをシリアルプリントする様にした
 * 2.5.5 MainLoopがちゃんと動いているかどうかを判断する為にLEDの点滅をさせる
 *      Timer割込が動いている事を確認するために7segLEDの更新を実施する。
 * 2.5.4 UtilPage等々追加する
 * 2.5.3 WebSerserを追加しユーティリティ機能を追加する フラッシュサイズについては余裕がある。
 *      HTMLコードは極力String型で一度に扱えるようにする。実行中のメモリの余裕も可成り有るので。
 *      Arduino-PicoではTextFinder.hのコンパイルが通らない。TextFinderを使わないパース方法を使用する必要がある
 * 2.5.2 GPS機能を追加する GPSのパースはライブラリを使わに実施する GxRMCを採用する
 * 2.5.1 ではNTPサーバー機能を追加する 内部RTCはLocalTimeとし 問い合わせに対してはUTCに変換する必要がある
 * 2.5.0.1起動時にNTP(192.168.0.199)にアクセスして内部RTCにセットして、その後TM1637LEDに表示しています。
 * 
 * 実行環境はPiPicoをGroveShieldに接続した状態で、SPIポートにW5500を接続して使います。CS=GPIO5です。
 * 固定IPとします。192.168.0.207 MACアドレスはダブらないように注意します。
 * アクセスするNTPサーバはLocalにある192.168.0.199です。
 * 最大2093056バイトのフラッシュメモリのうち、スケッチが106600バイト(5%)を使っています。
 * 最大262144バイトのRAMのうち、グローバル変数が14068バイト(5%)を使っていて、ローカル変数で248076バイト使うことができます。
 */
#define          TIMER_INTERRUPT_DEBUG          1
#define         _TIMERINTERRUPT_LOGLEVEL_       4
#include        <TimeLib.h>
#include        "TM1637.h"
#include        "RPi_Pico_TimerInterrupt.h"
#include        <SPI.h>
#include        <Ethernet.h>
#include        <EthernetUdp.h>
#include        <EEPROM.h>
extern "C" {
#include        <hardware/watchdog.h>
};
#define         CLK             18
#define         DIO             19
#define         NICReset        20
#define         NICInit         21
#define         SPI_SCK         2
#define         SPI_RX          4
#define         SPI_TX          3
#define         SPI_CS          5
#define         TIMER0_INTERVAL_MS      1000
#define         HttpPort        80
#define         DELIMITER       ","
#define         vers    "GPSNTP RPiPicoShield 2.5.5.3"
uint32_t        delay_ms        = 8000;                                 //8秒 最大8.3秒
const char      FVirsion[]      = "2.5.5.3";
byte            mac[]           = {0x00,0x08,0xDC,0x54,0x4D,0xD8};      //Wiznet
byte            ip[]            = {192, 168, 0, 207};
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};
String          HTTP_req; 
unsigned int    localPort       = 8888;                                 // local port to listen for UDP packets
//const char    timeServer[]    = "time.nist.gov";                      // time.nist.gov NTP server
char            timeServer[]    = "192.168.0.199";
const int       NTPport         = 123;
const int       NTP_PACKET_SIZE = 48;                                   // NTP time stamp is in the first 48 bytes of the message
byte            packetBuffer[NTP_PACKET_SIZE];                          //buffer to hold incoming and outgoing packets
byte            fTogle1         = LOW;
byte            fTogle2         = LOW;
float           timezone        = 9.0;
time_t          TimeZoneSec     = long(timezone * 3600);
float           unit            = 2.33E-7;
unsigned long   baseMilis       = millis();
unsigned long   miliTime;
struct          time_tm         *tm;                                    //STM32dinoとRP2040の構造体が異なる
time_t          currentTime,recieveTime,gpsTime;
unsigned long   currentHour,currentMin,currentSec;
int8_t          TimeDisp[]      = {0x00,0x00,0x00,0x00};
const unsigned long seventyYears = 2208988800UL;
char            buff[80];
char            buf1[32];
char            MacAddressStr[20];
char            IPAddressStr[20];
char            SubnetMaskStr[20];
char            GatewayStr[20];
char            NTPserverStr[20];
char            DateTimeStr[20];
char            Status          = 'V';
String          nmea;
String          bufIP                  = "192.168.0.200";
const uint8_t   daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };//const or compiler complains
uint32_t        timestamp, tempval,microVal,fractions;
int             preH,nowH;
int             chYear;
String          setenceStr              = "$GPRMC";
String          StatusStr               = "V = 警告";
String          DateTime2Str            = "2020年12月24日 8時25分59秒.000";
String          DateStr;
String          TimeStr;
String          latitudeStr             = "北緯 35度41.1493分";
String          latitudeNSStr;
String          longitudeStr            = "東経 139度45.3994分";
String          longitudeEWStr;
String          VeloStr                 = "00.0";
String          DirStr                  = "0.0度";
String          ModeStr                 = "A = 自律方式";
String          MagDegStr;
String          MagDevStr;
String          NavStr;
double          latitude;
double          longitude;
float           gDayBuf[24][5];                                         //24時間分5要素データに変更
float           gTemp(NAN);
typedef struct{
        uint32_t        UTC;
        long            LAT;                                            //10000倍した緯度
        long            LON;                                            //10000倍した経度
        int             DIR;                                            //100倍した値0〜3600
        int             SPD;                                            //速度(ノット単位)を100倍したもの
}RMC;
RMC             gRmc;
//GPS
char            chkHader[]      = "RMC";                                //このバージョンから3文字に変更
//内部カウンタ
unsigned long   gNTPqueryCount  = 0;
long            gLoopCount      = 3;                                    //1時間毎に更新予定 最初は1分後に更新したくて初期値を調整
long            gLoopTime       = 0;                                    //Loop()の実行時間を求める
long            gResetCount     = 0;
long            gPreTime,gNowTime; 
unsigned long   OperatingTime   = 0;                                    //稼働時間 Count2で1秒
int             LinkStatus;
//
const byte      ID = 0x99;
//オブジェクトコンストラクタ
EthernetServer  webServer(HttpPort);
EthernetClient  client;
TM1637          tm1637(CLK,DIO);
EthernetUDP     Udp;                                                    // A UDP instance to let us send and receive packets over UDP
RPI_PICO_Timer  ITimer0(0);
//------------EEPROM.read
void ReadID(){
        for (int i = 0; i < 6; i++){
                //mac[i]        = EEPROM.read(i+1);
                mac[i]          = EEPROM[i+1];
                if(Serial)      Serial.print("R_mac=");Serial.println(mac[i]);
        }
        for (int i = 0; i < 4; i++){
                //ip[i]         = EEPROM.read(i+7);
                ip[i]           = EEPROM[i+7];
                if(Serial)      Serial.print("R_ip=");Serial.println(ip[i]);
        }
        for (int i = 0; i < 4; i++){
                //subnet[i]     = EEPROM.read(i+11);
                subnet[i]       = EEPROM[i+11];
                if(Serial)      Serial.print("R_subnet=");Serial.println(subnet[i]);
        }
        for (int i = 0; i < 4; i++){
                //gateway[i]    = EEPROM.read(i+15);
                gateway[i]      = EEPROM[i+15];
                if(Serial)      Serial.print("R_gateway=");Serial.println(gateway[i]);
        }
        for (int i = 0; i < 4; i++){
                //NTPip[i]      = EEPROM.read(i+19);
                NTPip[i]        = EEPROM[i+19];
                if(Serial)      Serial.print("R_NTPip=");Serial.println(NTPip[i]);
        }
        //timezone = float(EEPROM.read(23)) / 10.0;
        timezone = float(EEPROM[23]) / 10.0;
        if(Serial)      Serial.print("R_timezone=");Serial.println(timezone);
}
//------------EEPROM.write
void WriteID(){
        for (int i = 0 ; i < 6; i++){
                //EEPROM.write(i + 1,mac[i]);
                EEPROM[i + 1]   = mac[i];
                if(Serial)      Serial.print("W_mac=");Serial.println(mac[i]);
        }
        for (int i = 0 ; i < 4; i++){
                //EEPROM.write(i + 7, ip[i]);
                EEPROM[i + 7]   = ip[i];
                if(Serial)      Serial.print("W_ip=");Serial.println(ip[i]);
        }
        for (int i = 0 ; i < 4; i++){
                //EEPROM.write(i + 11, subnet[i]);
                EEPROM[i + 11]  = subnet[i];
                if(Serial)      Serial.print("W_subnet=");Serial.println(subnet[i]);
        }
        for (int i = 0 ; i < 4; i++){
                //EEPROM.write(i + 15, gateway[i]);
                EEPROM[i + 15]  = gateway[i];
                if(Serial)      Serial.print("W_gateway=");Serial.println(gateway[i]);
        }
        for (int i = 0; i < 4; i++){
                //EEPROM.write(i + 19, NTPip[i]);
                EEPROM[i + 19]  = NTPip[i];
                if(Serial)      Serial.print("W_NTPip=");Serial.println(NTPip[i]);
        }
        //EEPROM.write(23,char(timezone * 10));
        EEPROM[23]      = char(timezone * 10);
        if(Serial)      Serial.print("W_timezone=");Serial.println(timezone);
        // IDを既知のビットに設定します。したがって、Arduinoをリセットすると、EEPROM値が使用されます。
        //EEPROM.write(256, ID);
        EEPROM[256]     =       ID;
        EEPROM.commit();                        //2.5.5.2で追加
        
        if(Serial)      Serial.print("W_ID=");Serial.println(ID,HEX);
}
//----------------------------------
void LANSetup(){
        EEPROM.begin(512);
        //int idcheck = EEPROM.read(256);
        int idcheck     =       EEPROM[256];
        if(Serial)      Serial.print("R_ID=");Serial.println(idcheck,HEX);
        Serial.print(F("LocalID = 0x"));Serial.println(idcheck,HEX);
        if (idcheck == ID){
                //idがIDと同じ値の場合、
                //これは、このスケッチがシールドを設定するために使用されたことを意味します。
                //EERPOMの値を読み取ってシールドを設定します。
                ReadID();
        }else{
                //idが一致しない場合、初期値を書き込む事にします。
                WriteID();
        }
        EEPROM.end();
        sprintf(MacAddressStr,"%02x.%02x.%02x.%02x.%02x.%02x",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
        sprintf(IPAddressStr,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
        sprintf(SubnetMaskStr,"%d.%d.%d.%d",subnet[0],subnet[1],subnet[2],subnet[3]);
        sprintf(GatewayStr,"%d.%d.%d.%d",gateway[0],gateway[1],gateway[2],gateway[3]);
        //Ethernet.begin(mac, ip);
//      Ethernet.begin(mac);                                            //DHCPの場合
//      Ethernet.begin(mac, ip, subnet);                                //SubnetMaskを意識した場合。
//      Ethernet.begin(mac, ip, subnet, gateway);                       //gatewayを意識した場合。
}
//--------------------------
void paramParse(String reqStr){
        int Code;
        int len         = reqStr.length();
        char* HTTP_c    = (char*)malloc(len+1);
        reqStr.toCharArray(HTTP_c, len);
        char bufff[10];
        //DT1 mac[0]            HEX
        int indexS      = reqStr.indexOf("DT1=");
        int indexE      = reqStr.indexOf("&",indexS);
        int k = 0;
        char c;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[0]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT2 mac[1]            HEX
        indexS = reqStr.indexOf("DT2=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[1]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT3 mac[2]            HEX
        indexS = reqStr.indexOf("DT3=");                                        //Serial.print("Pos=");Serial.println(indexS);
        indexE = reqStr.indexOf("&",indexS);                                    //Serial.print("Pos=");Serial.println(indexE);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);                                           //Serial.println(c);
                if (c == '='){
                        int m = indexE - indexS;                                //Serial.print("m=");Serial.println(m);
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[2]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                 }
        }
        //DT4 mac[3]            HEX
        indexS = reqStr.indexOf("DT4=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[3]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT5 mac[4]            HEX
        indexS = reqStr.indexOf("DT5=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[4]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[4]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT6 mac[5]            HEX
        indexS = reqStr.indexOf("DT6=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[5]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[5]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT7 ip[0]             DEC
        indexS = reqStr.indexOf("DT7=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[0]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT8 ip[1]             DEC
        indexS = reqStr.indexOf("DT8=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[1]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT9 ip[2]             DEC
        indexS = reqStr.indexOf("DT9=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[2]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT10 ip[3]            DEC
        indexS = reqStr.indexOf("DT10=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[3]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT11 subnet[0]        DEC
        indexS = reqStr.indexOf("DT11=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[0]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT12 subnet[1]        DEC
        indexS = reqStr.indexOf("DT12=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[1]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT13 subnet[2]        DEC
        indexS = reqStr.indexOf("DT13=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j); //Serial.println(bufff);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[2]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT14 subnet[3]        DEC
        indexS = reqStr.indexOf("DT14=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = HTTP_req.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[3]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT15 gateway[0]       DEC
        indexS = reqStr.indexOf("DT15=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[0]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT16 gateway[1]       DEC
        indexS = reqStr.indexOf("DT16=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[1]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT17 gateway[2]       DEC
        indexS = reqStr.indexOf("DT17=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[2]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT18 gateway[3]       DEC
        indexS = reqStr.indexOf("DT18=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[3]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT19 NTPip[0]       DEC
        indexS = reqStr.indexOf("DT19=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        NTPip[0]=int(strtol(bufff, NULL, 10));  //Serial.print(bufff);Serial.println(NTPip[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT120 NTPip[1]       DEC
        indexS = reqStr.indexOf("DT20=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        NTPip[1]=int(strtol(bufff, NULL, 10));  //Serial.print(bufff);Serial.println(NTPip[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT21 NTPip[2]       DEC
        indexS = reqStr.indexOf("DT21=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        NTPip[2]=int(strtol(bufff, NULL, 10));  //Serial.print(bufff);Serial.println(NTPip[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT22 NTPip[3]       DEC
        indexS = reqStr.indexOf("DT22=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        NTPip[3]=int(strtol(bufff, NULL, 10));  //Serial.print(bufff);Serial.println(NTPip[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT23 timezone       float
        indexS = reqStr.indexOf("DT23=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        timezone =int((strtof(bufff, NULL)*10));
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
}
//--------------------------
void checkWebPage( EthernetClient client){
        if(Serial)      Serial.println(F("new webClient"));
        boolean restart = false;
        if (client) {
                // HTTPリクエスト空行(\r\n\r\n)で終わる。ので、空行を探す。
                boolean currentLineIsBlank = true;
                while (client.connected()) {
                        if( !client.available() ){
                                if(Serial)    Serial.print(F("."));
                                continue;
                        }
                        char c = client.read();
                        HTTP_req += c;
                        if(Serial)    Serial.print(c);
                        if( c == '\n'  && currentLineIsBlank ){                 // 空行発見。HTTPリクエスト終了。レスポンスを返す。
                                //Serial.print("RecieveLength=");Serial.println(HTTP_req.length());
                                if (HTTP_req.indexOf("/?")>0) {                 //setup?と/?を区別する必要がある
                                        if(Serial)    Serial.print(F("CASE1:"));Serial.print(gLoopCount);
                                        /*if(gLoopCount % 2){
                                                digitalWrite(LED_BUILTIN,HIGH); //Serial.println(F(" H"));
                                        }else{
                                                digitalWrite(LED_BUILTIN,LOW);  //Serial.println(F(" L"));
                                        }*/
                                        delay(100);
                                        HTTP_req = "";
                                        break;
                                }else if(HTTP_req.indexOf("setup")>0){
                                        //setup頁の場合 SBMが含まれていればEEPROMに書込、そうで無ければ表示のみ
                                        //setup?SBM=1&DT1=0&DT2=8&DT3=DC&DT4=54&DT5=4D&DT6=D0&DT1=0&DT2=8&DT3=220&DT4=84&DT5=77&DT6=208&DT7=192&DT8=168&DT9=0&DT10=200&DT11=255&DT12=255&DT13=255&DT14=0&DT15=192&DT16=168&DT17=0&DT18=1
                                        //TextFinderを使うとHTMLの切り出しは比較的容易これをSTRING型のままどう扱うか?
                                        if(Serial)    Serial.print(F("CASE2:"));Serial.println(gLoopCount);
                                        if (HTTP_req.indexOf("SBM")>0){
                                                //Serial.println(F("Found_SBM"));
                                                if(Serial)    Serial.print(F("CASE3:"));Serial.println(gLoopCount);
                                                paramParse(HTTP_req);
                                                // すべてのデータを取得したので、EEPROMに保存します。
                                                EEPROM.begin(512);
                                                WriteID();
                                                //データがEEPROMに書き込まれている場合は、arduinoをリセットする必要があります。
                                                //読込直す
                                                //int idcheck = EEPROM.read(256);
                                                int idcheck     =       EEPROM[256];
                                                if(Serial)    Serial.print(F("R_ID="));Serial.println(idcheck,HEX);
                                                if (idcheck == ID){
                                                        //idがIDと同じ値の場合、
                                                        //これは、このスケッチがシールドを設定するために使用されたことを意味します。
                                                        //EERPOMの値を読み取ってシールドを設定します。
                                                        ReadID();
                                                }
                                                EEPROM.end();
                                                //ハードウェアリセットボタンを使用する必要があります
                                                HTTP_req = "";
                                                client.stop();
                                                delay(1000);
                                                watchdog_reboot(0,0,1);
                                                break;
                                        }else if(HTTP_req.indexOf("setup1")>0){
                                                if(Serial)      Serial.println(F("setup1"));
                                                PrintSetUpPage(client);
                                                HTTP_req = "";
                                                break;
                                        }else if(HTTP_req.indexOf("setup2")>0){
                                                if(Serial)      Serial.println(F("setup2"));
                                                PrintUtilPage(client);
                                                HTTP_req = "";
                                                break;
                                        }else if(HTTP_req.indexOf("setup3")>0){
                                                if(Serial)      Serial.println(F("setup3"));
                                                pageLoadUtilsJS(client);
                                                HTTP_req = "";
                                                break;
                                        }else{
                                                if(Serial)      Serial.print(F("CASE404-1"));
                                                PrintResponse404(client);
                                                HTTP_req = "";
                                                break;
                                        }
                                }else if(HTTP_req.indexOf("\n")>0) {
                                        if(Serial)      Serial.println(F("CASE4"));
                                        pageIntroduction(client);
                                        HTTP_req = "";
                                        break;
                                }else if(HTTP_req.indexOf("/index")>0) {
                                        if(Serial)      Serial.println(F("CASE5"));
                                        pageIntroduction(client);
                                        HTTP_req = "";
                                        break;
                                }else{
                                        if(Serial)      Serial.print(F("CASE404-2"));
                                        PrintResponse404(client);
                                        HTTP_req = "";
                                        break;
                                }
                                HTTP_req = "";
                                break;                          // ループを抜ける
                        }
                        if(c ==  '\n'){                         // 新しい行の始まり。
                                currentLineIsBlank = true;
                        } else if(c !=  '\r' ){                 // この行は空行ではなかった。
                                currentLineIsBlank = false;
                        }
                }
                delay(1);
                client.stop();
        }     
}
//--------OK_200
String OK_200           =
        "HTTP/1.1 200 OK\n"
        "Content-Type: text/html\n";
//--------NG_404
String NG_404           =
        "HTTP/1.1 404 Not Found\n"
        "Content-Type: text/html\n"
        "Connnection: close\n";
//--------LoadUtilsJS
String LoadUtilsJS1     =
        "'use strict';\n"
"window.chartColors = {\n"
        "\tred: 'rgb(255, 99, 132)',\n"
        "\torange: 'rgb(255, 159, 64)',\n"
        "\tyellow: 'rgb(255, 205, 86)',\n"
        "\tgreen: 'rgb(75, 192, 192)',\n"
        "\tblue: 'rgb(54, 162, 235)',\n"
        "\tpurple: 'rgb(153, 102, 255)',\n"
        "\tgrey: 'rgb(201, 203, 207)'\n"
"};\n"
"(function(global) {\n"
        "\tvar MONTHS = [\n"
                "\t\t'January',\n"
                "\t\t'February',\n"
                "\t\t'March',\n"
                "\t\t'April',\n"
                "\t\t'May',\n"
                "\t\t'June',\n"
                "\t\t'July',\n"
                "\t\t'August',\n"
                "\t\t'September',\n"
                "\t\t'October',\n"
                "\t\t'November',\n"
                "\t\t'December'\n"
        "\t];\n"
        "\tvar COLORS = [\n"
                "\t\t'#4dc9f6',\n"
                "\t\t'#f67019',\n"
                "\t\t'#f53794',\n"
                "\t\t'#537bc4',\n"
                "\t\t'#acc236',\n"
                "\t\t'#166a8f',\n"
                "\t\t'#00a950',\n"
                "\t\t'#58595b',\n"
                "\t\t'#8549ba'\n"
        "\t];\n"
        "\tvar Samples = global.Samples || (global.Samples = {});\n"
        "\tvar Color = Chart.helpers.color;\n"
        "\tfunction applyDefaultNumbers(config) {\n"
                "\t\tvar cfg = config || {};\n"
                "\t\tcfg.min = cfg.min || 0;\n"
                "\t\tcfg.max = cfg.max || 1;\n"
                "\t\tcfg.from = cfg.from || [];\n"
                "\t\tcfg.count = cfg.count || 8;\n"
                "\t\tcfg.decimals = cfg.decimals || 8;\n"
                "\t\tcfg.continuity = cfg.continuity || 1;\n"
                "\t\treturn cfg;\n"
        "\t}\n";
String LoadUtilsJS2     =
        "\tSamples.utils = {\n"
                "\t\t// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/\n"
                "\t\tsrand: function(seed) {\n"
                "\t\t\tthis._seed = seed;\n"
                "\t\t},\n"
                "\t\trand: function(min, max) {\n"
                "\t\t\tvar seed = this._seed;\n"
                "\t\t\tmin = min === undefined ? 0 : min;\n"
                "\t\t\tmax = max === undefined ? 1 : max;\n"
                "\t\t\tthis._seed = (seed * 9301 + 49297) % 233280;\n"
                "\t\t\treturn min + (this._seed / 233280) * (max - min);\n"
                "\t\t},\n"
                "\t\tnumbers: function(config) {\n"
                        "\t\t\tvar cfg = applyDefaultNumbers(config);\n"
                        "\t\t\tvar dfactor = Math.pow(10, cfg.decimals) || 0;\n"
                        "\t\t\tvar data = [];\n"
                        "\t\t\tvar i, value;\n"
                        "\t\t\tfor (i = 0; i < cfg.count; ++i) {\n"
                                "\t\t\t\tvalue = (cfg.from[i] || 0) + this.rand(cfg.min, cfg.max);\n"
                                "\t\t\t\tif (this.rand() <= cfg.continuity) {\n"
                                "\t\t\t\t\tdata.push(Math.round(dfactor * value) / dfactor);\n"
                                "\t\t\t\t} else {\n"
                                "\t\t\t\t\tdata.push(null);\n"
                                "\t\t\t\t}\n"
                        "\t\t\t}\n"
                        "\t\t\treturn data;\n"
                "\t\t},\n"
                "\t\tlabels: function(config) {\n"
                        "\t\t\tvar cfg = config || {};\n"
                        "\t\t\tvar min = cfg.min || 0;\n"
                        "\t\t\tvar max = cfg.max || 100;\n"
                        "\t\t\tvar count = cfg.count || 8;\n"
                        "\t\t\tvar step = (max - min) / count;\n"
                        "\t\t\tvar decimals = cfg.decimals || 8;\n"
                        "\t\t\tvar dfactor = Math.pow(10, decimals) || 0;\n"
                        "\t\t\tvar prefix = cfg.prefix || '';\n"
                        "\t\t\tvar values = [];\n"
                        "\t\t\tvar i;\n"
                        "\t\t\tfor (i = min; i < max; i += step) {\n"
                        "\t\t\t\tvalues.push(prefix + Math.round(dfactor * i) / dfactor);\n"
                        "\t\t\t}\n"
                        "\t\t\treturn values;\n"
                "\t\t},\n"
                "\t\tmonths: function(config) {\n"
                        "\t\t\tvar cfg = config || {};\n"
                        "\t\t\tvar count = cfg.count || 12;\n"
                        "\t\t\tvar section = cfg.section;\n"
                        "\t\t\tvar values = [];\n"
                        "\t\t\tvar i, value;\n"
                        "\t\t\tfor (i = 0; i < count; ++i) {\n"
                                "\t\t\t\tvalue = MONTHS[Math.ceil(i) % 12];\n"
                                "\t\t\t\tvalues.push(value.substring(0, section));\n"
                        "\t\t\t}\n"
                        "\t\t\treturn values;\n"
                "\t\t},\n"
                "\t\tcolor: function(index) {\n"
                        "\t\t\treturn COLORS[index % COLORS.length];\n"
                "\t\t},\n"
                "\t\ttransparentize: function(color, opacity) {\n"
                        "\t\t\tvar alpha = opacity === undefined ? 0.5 : 1 - opacity;\n"
                        "\t\t\treturn Color(color).alpha(alpha).rgbString();\n"
                "\t\t}\n"
        "\t};\n";
String LoadUtilsJS3     =
        "\t// DEPRECATED\n"
        "\twindow.randomScalingFactor = function() {\n"
                "\t\treturn Math.round(Samples.utils.rand(-100, 100));\n"
        "\t};\n"
        "\t// INITIALIZATION\n"
        "\tSamples.utils.srand(Date.now());\n"
        "\t// Google Analytics\n"
        "\t/* eslint-disable */\n"
        "\tif (document.location.hostname.match(/^(www\\.)?chartjs\\.org$/)) {\n"
                "\t\t(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n"
                "\t\t(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n"
                "\t\tm=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n"
                "\t\t})(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n"
                "\t\tga('create', 'UA-28909194-3', 'auto');\n"
                "\t\tga('send', 'pageview');\n"
        "\t}\n"
        "\t/* eslint-enable */\n"
"}(this));\n";
//--------WebTopPage
String WebTopPage1      =
"<HTML>\n"
"<HEAD>\n"
        "\t<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;CHARSET=UTF-8\">\n"
"</HEAD>\n"
"<BODY BGCOLOR='#ffffff'>\n"
"<H2><CENTER><FONT COLOR='#00ff00'>RP2040版 GPSNTP メニュー</FONT></CENTER></H2>\n"
"<P><CENTER><TABLE WIDTH='300' BORDER='0' CELLSPACING='0' CELLPADDING='0'>\n"
        "\t<TR>\n"
                "\t\t<TD WIDTH='100%'>\n"
                "\t\t<OL>\n"
                "\t\t\t<LI><FONT SIZE='+1'><A HREF=\"http://";
String WebTopPage2       =
                "/setup1\">設定メニュー</A>\n"
                "\t\t\t<LI><A HREF=\"http://";
String WebTopPage3       =
                "/setup2\">GPSセンテンス表示</A></FONT>\n"
                "\t\t</OL>\n"
                "\t\t</TD>\n"
        "\t</TR>\n"
"</TABLE></CENTER>\n"
"</BODY>\n"
"</HTML>\n";
//-------------SetPage
String SetPage1         =
"<!DOCTYPE HTML PUBLIC \"\">\n<html>\n<HEAD>\n\t<META http-equiv=\"Content-Type\" charset=Shift_JIS\">\n"
        "\t<META http-equiv=\"Content-Style-Type\">\n\t<TITLE>";
String SetPage2         =
        " Setup Page</TITLE>\n</HEAD>\n"
        "<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\">\n<BLOCKQUOTE><BLOCKQUOTE>\n"
        "<table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\">\n"
        "<tr><td>";
String SetPage3         =
        " Setup Page</td></tr></table><br>\n"
        "<script>\n\tfunction hex2num (s_hex) {\n\t\teval(\"var n_num=0X\" + s_hex);\n\t\treturn n_num;\n\t}\n</script>\n"
        "<tbody>\n<FORM><input type=\"hidden\" name=\"SBM\" value=\"1\">\n<table>\n<tr><td>MAC:</td><td>"
        "<input id=\"T1\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT1\" value=\"";
String SetPage4         =
        "\">.<input id=\"T3\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT2\" value=\"";
String SetPage5         =
        "\">.<input id=\"T5\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT3\" value=\"";
String SetPage6         =
        "\">.<input id=\"T7\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT4\" value=\"";
String SetPage7         =
        "\">.<input id=\"T9\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT5\" value=\"";
String SetPage8         =
        "\">.<input id=\"T11\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT6\" value=\"";
String SetPage9         =
        "\"><input id=\"T2\" type=\"hidden\" name=\"DT1\"><input id=\"T4\" type=\"hidden\" name=\"DT2\n"
        "\"><input id=\"T6\" type=\"hidden\" name=\"DT3\"><input id=\"T8\" type=\"hidden\" name=\"DT4\n"
        "\"><input id=\"T10\" type=\"hidden\" name=\"DT5\"><input id=\"T12\" type=\"hidden\" name=\"DT6\n"
        "\"></td></tr>\n<tr><td>IP:</td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT7\" value=\"";
String SetPage10        =
       "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT8\" value=\"";
String SetPage11        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT9\" value=\"";
String SetPage12        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT10\" value=\"";
String SetPage13        =
        "\"></td></tr>\n<tr><td>MASK: </td><td><input type= \"text\" size=\"3\" maxlength=\"3\" name=\"DT11\" value=\"";
String SetPage14        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT12\" value=\"";
String SetPage15        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT13\" value=\"";
String SetPage16        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT14\" value=\"";
String SetPage17        =
        "\"></td></tr>\n<tr><td>GW: </td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT15\" value=\"";
String SetPage18        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT16\" value=\"";
String SetPage19        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT17\" value=\"";
String SetPage20        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT18\" value=\"";
String SetPage21        =
        "\"></td></tr><tr><td COLSPAN='2'>\n<HR ALIGN=CENTER></td></tr>\n"
        "<tr><td>NTPip: </td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT19\" value=\"";
String SetPage22        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT20\" value=\"";
String SetPage23        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT21\" value=\"";
String SetPage24        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT22\" value=\"";
String SetPage25        =
        "\"></td></tr>\n"
        "<tr><td>TimeZone:</td><td><input type=\"text\" size=\"3\" maxlength=\"5\" name=\"DT23\" value=\"";
String SetPage26        =
        "\"></td></tr>\n<tr><td><br></td></tr><tr><td COLSPAN='2'><P ALIGN=RIGHT><input id=\"button1\"type=\"submit\" value=\"SUBMIT\" "
        "Onclick=\""
        "document.getElementById('T2').value = hex2num(document.getElementById('T1').value);\n"
        "\t\tdocument.getElementById('T4').value = hex2num(document.getElementById('T3').value);\n"
        "\t\tdocument.getElementById('T6').value = hex2num(document.getElementById('T5').value);\n"
        "\t\tdocument.getElementById('T8').value = hex2num(document.getElementById('T7').value);\n"
        "\t\tdocument.getElementById('T10').value = hex2num(document.getElementById('T9').value);\n"
        "\t\tdocument.getElementById('T12').value = hex2num(document.getElementById('T11').value);\""
        "></td></tr></tbody>\n</table>\n</BLOCKQUOTE></BLOCKQUOTE>\n</form>\n</BODY>\n</html>\n";
//------------------PrintSetUpPage
void PrintSetUpPage( EthernetClient client){
        client.println(OK_200);
        client.print(SetPage1);
        client.print(vers);
        client.print(SetPage2);
        client.print(vers);
        client.print(SetPage3);
        client.print(mac[0],HEX);
        client.print(SetPage4);
        client.print(mac[1],HEX);
        client.print(SetPage5);
        client.print(mac[2],HEX);
        client.print(SetPage6);
        client.print(mac[3],HEX);
        client.print(SetPage7);
        client.print(mac[4],HEX);
        client.print(SetPage8);
        client.print(mac[5],HEX);
        client.print(SetPage9);
        client.print(ip[0],DEC);
        client.print(SetPage10);
        client.print(ip[1],DEC);
        client.print(SetPage11);
        client.print(ip[2],DEC);
        client.print(SetPage12);
        client.print(ip[3],DEC);
        client.print(SetPage13);
        client.print(subnet[0],DEC);
        client.print(SetPage14);
        client.print(subnet[1],DEC);
        client.print(SetPage15);
        client.print(subnet[2],DEC);
        client.print(SetPage16);
        client.print(subnet[3],DEC);
        client.print(SetPage17);
        client.print(gateway[0],DEC);
        client.print(SetPage18);
        client.print(gateway[1],DEC);
        client.print(SetPage19);
        client.print(gateway[2],DEC);
        client.print(SetPage20);
        client.print(gateway[3],DEC);
        client.print(SetPage21);
        client.print(NTPip[0],DEC);
        client.print(SetPage22);
        client.print(NTPip[1],DEC);
        client.print(SetPage23);
        client.print(NTPip[2],DEC);
        client.print(SetPage24);
        client.print(NTPip[3],DEC);
        client.print(SetPage25);
        client.print(timezone,2);
        client.print(SetPage26);
}
//-------------UtilPage
String UtilPage1        =
        "<!DOCTYPE HTML PUBLIC \"\">\n"
        "<html>\n"
        "<HEAD>\n"
                "\t<META http-equiv=\"Content-Type\" charset=\"UTF-8\">\n"
                "\t<META http-equiv=\"Content-Style-Type\">\n"
                "\t<TITLE>";
String UtilPage2        =
                " Utility Page</TITLE>\n"
                "\t<script type='application/javascript' SRC='http://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.js'></script>\n"
                "\t<script type='application/javascript' SRC='http://192.168.0.199/setup3'></script>\n"
                "\t<style>\n"
                        "\t\tcanvas{\n"
                                "\t\t\t-moz-user-select: none;\n"
                                "\t\t\t-webkit-user-select: none;\n"
                                "\t\t\t-ms-user-select: none;\n"
                        "\t\t}\n"
                        "\t\thtml { font-family: Helvetica; display: inline-block; margin: 0px auto;}\n"
                        "\t\tbody{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n"
                        "\t\tp {font-size: 24px;color: #444444;margin-bottom: 10px;}\n"
                "\t</style>\n"
        "</HEAD>\n"
        "<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\" BGCOLOR=\"#ffffff\">\n"
        "<FORM>\n"
        "<BLOCKQUOTE><BLOCKQUOTE>\n"
        "<P><table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\" CELLSPACING=\"2\">\n"
        "<tr><td>";
String UtilPage3        =
        " Utility Page</td></tr></table><br>\n";
String UtilPage4        =
        "<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">FirmwareVirsion:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage5        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">MacAddress:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage6        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">IPAddress:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage7        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">SubnetMask:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage8        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">BoardTemperature:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage9        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">NTP受信回数:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage10       =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\" NOWRAP>Data acquisition time(Local):</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage11       =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\" NOWRAP>Operating Time:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage111     =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\" NOWRAP>Loop Time:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage112     =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\" NOWRAP>Reset実行回数:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage12       =
        "</TD>\n"
        "</TR></TABLE></P>\n"
        "<P><center><TABLE WIDTH=\"750\" BORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"0\" HEIGHT=\"101\">\n"
                "\t<CAPTION ALIGN=\"TOP\"><P ALIGN=LEFT>GPS センテンス</CAPTION>"
                "\t<TR>\n"
                        "\t\t<TD COLSPAN=\"2\" BGCOLOR=\"#000000\">\n"
                        "\t\t<BLOCKQUOTE>\n"
                                "\t\t\t<PRE><FONT COLOR=\"#ffffff\" SIZE=\"+1\">";
String UtilPage13       =
                "</FONT></PRE>\n"
                        "\t\t</BLOCKQUOTE>"
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">ステータス:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage14       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">日時(UTC):</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage15       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">位置情報:緯度</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage16       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">位置情報:経度</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage17       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">移動の速度:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage18       =
                "[knot]</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">移動の真方位:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage19       =
                "[度]</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">モード:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage20       =
                "</TD>\n"
                "\t</TR>\n"
        "</TABLE></center>\n"
        "<CENTER>\n"
                "\t<div style='width:75%;'><canvas id='canvas' width='750' height='400' style='display: block; width: 750px; height: 400px;'></canvas></div>\n"
        "</CENTER></BLOCKQUOTE></BLOCKQUOTE>\n"
        "</form>\n"
        "<script>\n"
                "\tvar randomScalingFactor = function() {\n"
                        "\t\t\treturn 18 + Math.random() * 10;\n"
                        "\t\t};\n";
String UtilPage21       =
                        "\t\tvar config = {\n"
                                "\t\t\ttype: 'line',\n\t\t\tdata: {\n"
                                        "\t\t\t\tlabels: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12' , '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'],\n"
                                        "\t\t\t\tdatasets: [{\n"
                                                "\t\t\t\t\tlabel: '緯度[度]',\n"
                                                "\t\t\t\t\tdata: data_00,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.red,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tcubicInterpolationMode: 'monotone',\n"
                                                "\t\t\t\t\tyAxisID: 'y1'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '経度[度]',\n"
                                                "\t\t\t\t\tdata: data_01,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.blue,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y2'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '速度[knot]',\n"
                                                "\t\t\t\t\tdata: data_02,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.orange,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y3'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '真方位[度]',\n"
                                                "\t\t\t\t\tdata: data_03,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.yellow,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y4'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '温度[℃]',\n"
                                                "\t\t\t\t\tdata: data_04,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.grey,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y5'\n"
                                        "\t\t\t\t}]\n"
                                "\t\t\t},\n"
                                "\t\t\toptions: {\n"
                                        "\t\t\t\tresponsive: true,\n"
                                        "\t\t\t\ttitle: {\n";
String UtilPage22       =
                                                "\t\t\t\t\tdisplay: true,\n"
                                                "\t\t\t\t\ttext: '今日のGPS位置情報'\n"
                                        "\t\t\t\t},\n"
                                        "\t\t\t\tlegend: {\n"
                                                "\t\t\t\t\tdisplay: true\n"
                                                "\t\t\t\t},\n"
                                                "\t\t\t\ttooltips: {\n"
                                                        "\t\t\t\t\tenabled: true,\n"
                                                        "\t\t\t\t\tmode: 'index'\n"
                                                "\t\t\t\t},\n"
                                                "\t\t\t\tscales: {\n"
                                                        "\t\t\t\t\txAxes: [{\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '時刻 [時]'\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t}],\n"
                                                        "\t\t\t\t\tyAxes: [{\n"
                                                                "\t\t\t\t\t\tid:'y1',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.red,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '緯度[度]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                &quot;\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.red,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: -200,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  200\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y2',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.blue,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '経度[度]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.blue,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: -200,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  200\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y3',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.orange,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '速度[knot]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.orange,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: 0,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  40\n"
                                                                "\t\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y4',\n"
                                                                "\t\t\t\t\t\tposition: 'right',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.yellow,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '真方位[度]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.yellow,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: 0,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  400\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y5',\n"
                                                                "\t\t\t\t\t\tposition: 'right',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.grey,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '気温[℃]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.grey,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: 10,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  50\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t}]\n"
                                                "\t\t\t\t}\n"
                                        "\t\t\t}\n"
                                "\t\t};\n" 
                                "\t\twindow.onload = function() {\n"
                                        "\t\t\tvar ctx = document.getElementById('canvas').getContext('2d');\n"
                                        "\t\t\twindow.myLine = new Chart(ctx, config);\n"
                                "\t\t};\n"
        "</script>\n"
        "</BODY></html>";
//-------------PrintUtilPage
void PrintUtilPage( EthernetClient client){
        client.println(OK_200);
        client.print(UtilPage1);
        client.print(vers);
        client.print(UtilPage2);
        client.print(vers);
        client.print(UtilPage3);
        client.print(UtilPage4);
        client.print(FVirsion);
        client.print(UtilPage5);
        client.print(MacAddressStr);
        client.print(UtilPage6);
        client.print(IPAddressStr);
        client.print(UtilPage7);
        client.print(SubnetMaskStr);
        client.print(UtilPage8);
        sprintf(buf1,"%.2f[℃]",analogReadTemp());
        client.print(buf1);
        client.print(UtilPage9);
        sprintf(buf1,"%d[回]",gNTPqueryCount);
        client.print(buf1);
        client.print(UtilPage10);
        currentTime     = now() - seventyYears;
        sprintf(DateTimeStr,"%04u/%02u/%02u %02u:%02u:%02u",year(currentTime),month(currentTime),day(currentTime),hour(currentTime),minute(currentTime),second(currentTime));
        client.print(DateTimeStr);
        client.print(UtilPage11);
        sprintf(buf1,"%d[sec]",(OperatingTime / 2));
        client.print(buf1);
        client.print(UtilPage111);
        sprintf(buf1,"%d[ミリ秒]",gLoopTime);
        client.print(buf1);
        client.print(UtilPage112);
        sprintf(buf1,"%d[回]",gResetCount);
        client.print(buf1);
        client.print(UtilPage12);
        client.print(nmea);
        if(Serial)      Serial.println(nmea);
        analsysRMC();           //RMCの要素切り出し
        client.print(UtilPage13);
        client.print(StatusStr);
        client.print(UtilPage14);
        client.print(DateTime2Str);
        client.print(UtilPage15);
        client.print(latitudeNSStr);
        client.print(latitudeStr);
        client.print(F("\t("));client.print(latitude,8);client.print(F(")"));
        client.print(UtilPage16);
        client.print(longitudeEWStr);
        client.print(longitudeStr);
        client.print(F("\t("));client.print(longitude,8);client.print(F(")"));
        client.print(UtilPage17);
        client.print(VeloStr);
        client.print(UtilPage18);
        client.print(DirStr);
        client.print(UtilPage19);
        client.print(ModeStr);
        client.print(UtilPage20);
        client.print(F("\t\tvar data_00 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][0]) ? String('\0') : String(gDayBuf[i][0],6));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_01 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][1]) ? String('\0') : String(gDayBuf[i][1],6));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_02 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][2]) ? String('\0') : String(gDayBuf[i][2],2));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_03 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][3]) ? String('\0') : String(gDayBuf[i][3],2));
                client.print(F(","));
        }
        client.print(F("];\n"));        
        client.print(F("\t\tvar data_04 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][4]) ? String('\0') : String(gDayBuf[i][4],2));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(UtilPage21);
        client.print(UtilPage22);
}
//-------------WebPageTop
void pageIntroduction( EthernetClient client){
        client.println(OK_200);
        client.print(WebTopPage1);
        client.print(bufIP);
        client.print(WebTopPage2);
        client.print(bufIP);
        client.println(WebTopPage3);
        client.stop();
}
//-------------LoadUtilsJS
void pageLoadUtilsJS( EthernetClient client){
        client.println(OK_200);
        client.println(LoadUtilsJS1);                                     //バッファサイズを考慮して3分割しています。
        client.println(LoadUtilsJS2);
        client.println(LoadUtilsJS3);
        client.stop();
}
//------------PrintResponse404
void PrintResponse404( EthernetClient client ){
        client.println(NG_404);
        client.stop();
}
//-------------タイマ割込で呼ばれるルーチン クロック表示 500msec毎
bool    TimerHandler0(struct repeating_timer *t){
        OperatingTime++;
        currentTime     =       now();
        if(Serial)      Serial.println(currentTime);
        currentTime     %=  86400;
        currentHour     = currentTime / 3600;
        currentMin      = (currentTime % 3600)/60;
        TimeDisp[0]     = currentHour/ 10;
        TimeDisp[1]     = currentHour % 10;
        TimeDisp[2]     = currentMin / 10;
        TimeDisp[3]     = currentMin % 10;
        if(fTogle1)     tm1637.point(POINT_OFF);
        else            tm1637.point(POINT_ON);
        tm1637.display(TimeDisp);
        fTogle1         = !fTogle1;
        return true;
}
//---------------------
bool processNTP() {
        //利用可能なデータがある場合は、パケットを読み取ります
        //https://blog.goo.ne.jp/hiro239415/e/c426a545863921a13a9d6a70b7ae4484
        //NTP_Packet (48Byte)
        bool    req             =       false;
        int     packetSize      =       Udp.parsePacket();
        if(packetSize){
                digitalWrite(LED_BUILTIN,HIGH);                         //要求があったときにBuiltInLEDを点灯
                miliTime                = millis() - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                sprintf(buf1,"■%d\t%d\n",packetSize,fractions);
                if(Serial)     Serial.print(buf1);
                Udp.read(packetBuffer,NTP_PACKET_SIZE);
                if(Serial){
                        for (int i =0;i<48;i++){
                                Serial.print(packetBuffer[i],HEX);
                        }
                        Serial.println();
                }
                IPAddress       Remote  = Udp.remoteIP();
                int             PortNum = Udp.remotePort();
                //受信タイムスタンプ = サーバが受け取った時刻を予めセットしておく JSTなのでGMTに変換
                timestamp               = now()         - TimeZoneSec;
                miliTime                = millis()      - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                tempval                 = timestamp;
                packetBuffer[32]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[33]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[34]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[35]        = (tempval) & 0xFF;
                //
                microVal                = fractions;
                packetBuffer[36]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[37]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[38]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[39]        = microVal & 0xFF;
                 //ヘッダーセット
                packetBuffer[0]         = 0b00100100;                           // 閏秒警告なしLI, 4:SNTPサーバ(Version), 4:サーバ(Mode)
                packetBuffer[1]         = 1 ;                                   // 1:一次基準源(GPS等)(stratum
                packetBuffer[2]         = 5 ;                                   // ポーリング64秒デフォルト値 6(64秒)->5(32秒)
                packetBuffer[3]         = 0xF6;                                 // 精度 -3(0xFD)->-10(0xF6)に変更 msec
                packetBuffer[4]         = 0;                                    // ルート遅延
                packetBuffer[5]         = 0;
                packetBuffer[6]         = 8;
                packetBuffer[7]         = 0;
                packetBuffer[8]         = 0;                                    // ルート分散
                packetBuffer[9]         = 0;
                packetBuffer[10]        = 0xC;
                packetBuffer[11]        = 0;
                //
                packetBuffer[12]        = 71;                                   //"G";   ReferenceID
                packetBuffer[13]        = 80;                                   //"P";   ReferenceID
                packetBuffer[14]        = 83;                                   //"S";   ReferenceID
                packetBuffer[15]        = 0;                                    //"0";   ReferenceID
                // リファレンス時刻をセット(現在時間)
                timestamp               = now()         - TimeZoneSec;          //UTC
                if(Serial){
                        Serial.print(timestamp);Serial.print(F(":Time synchronization Request received\n"));
                }
                tempval                 = timestamp;
                microVal                = fractions;
                packetBuffer[16]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[17]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[18]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[19]        = (tempval) & 0xFF;
                packetBuffer[20]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[21]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[22]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[23]        = microVal & 0xFF;
                //オリジナル時間をコピー(サーバに要求が届いた時間)
                packetBuffer[24]        = packetBuffer[40];
                packetBuffer[25]        = packetBuffer[41];
                packetBuffer[26]        = packetBuffer[42];
                packetBuffer[27]        = packetBuffer[43];
                packetBuffer[28]        = packetBuffer[44];
                packetBuffer[29]        = packetBuffer[45];
                packetBuffer[30]        = packetBuffer[46];
                packetBuffer[31]        = packetBuffer[47];
                //送信時刻をセット
                timestamp               = now()         - TimeZoneSec;                  //UTC
                miliTime                = millis()      - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                tempval                 = timestamp;
                packetBuffer[40]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[41]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[42]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[43]        = (tempval) & 0xFF;
                //transmit_timestamp_fractions
                microVal                = fractions; 
                packetBuffer[44]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[45]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[46]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[47]        = microVal & 0xFF;
                //NTP要求を送信したIPアドレスとポートに応答します
                Udp.beginPacket(Remote, PortNum);
                Udp.write(packetBuffer,NTP_PACKET_SIZE);
                Udp.endPacket();
                digitalWrite(LED_BUILTIN,LOW);                                  //処理完了で消灯
                sprintf(buf1,"●%d\t%d\t%d\t%d\n",packetBuffer[20],packetBuffer[21],packetBuffer[22],packetBuffer[23]);
                if(Serial)      Serial.print(buf1);
                req     = true;
                gNTPqueryCount++;
        }
        return req;
}
//-----------------指定されたアドレスのタイムサーバーにNTP要求を送信します
void sendNTPpacket(const char * address) {
        // バッファ内のすべてのバイトを0に設定します
        memset(packetBuffer, 0, NTP_PACKET_SIZE);
        // NTP要求を形成するために必要な値を初期化します(パケットの詳細については、上記のURLを参照してください)
        packetBuffer[0]         = 0b11100011;                                   // LI, Version, Mode
        packetBuffer[1]         = 0;                                            // Stratum, or type of clock
        packetBuffer[2]         = 6;                                            // ポーリング64秒デフォルト値
        packetBuffer[3]         = 0xEC;                                         // 精度
        // ルート遅延とルート分散の場合は8バイトのゼロ
        packetBuffer[12]        = 0x31;                                         // '1'
        packetBuffer[13]        = 0x4E;                                         // 'N'
        packetBuffer[14]        = 0x31;                                         // '1'
        packetBuffer[15]        = 0x34;                                         // '4'
        //すべてのNTPフィールドに値が指定されているため、タイムスタンプを要求するパケットを送信できます。
        Udp.beginPacket(address, NTPport);                                      // NTP要求はポート123に送信されます
        Udp.write(packetBuffer, NTP_PACKET_SIZE);
        Udp.endPacket();
}
//-----------------受信したNTPパケットを解析してRTCにセットします
bool parseNTPpacket(){
        // 返信が利用可能かどうかを確認するのを待ちます
        if (Udp.parsePacket()) {
                // パケットを受信しました。そこからデータを読み取ります
                Udp.read(packetBuffer, NTP_PACKET_SIZE);                        // パケットをバッファに読み込みます
                // タイムスタンプは、受信したパケットのバイト40から始まり、4バイトです。
                unsigned long secsSince1900;
                // 位置40から始まる4バイトを長整数に変換します
                secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
                secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
                secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
                secsSince1900 |= (unsigned long)packetBuffer[43];
                Serial.print("Seconds since Jan 1 1900 = ");
                Serial.println(secsSince1900);
                // エピックタイムに変換します。(local)
                unsigned long epoch = secsSince1900 - seventyYears + TimeZoneSec;
                Serial.print("Unix time = ");
                Serial.println(epoch);
                setTime(epoch);                                                 //RTC登録(LocalTime)
        }
        return true;
}
//---------------NTP since 1900/01/01 retouch2020/12/25
static unsigned long int numberOfSecondsSince1900Epoch(uint16_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t mm, uint8_t s,float timezone) {
        //2036年問題が存在する。unsigned long intの桁溢れが発生
        //桁溢れが発生したら受信側が対応する必要がある。サーバ側では64bit化するべきだが動かなくなる。
        //timezoneをfloat扱いにした
        int leapAdjustment = 0;
        if (y >= 1970) {
                y -= 1970;
                leapAdjustment  = 2;                            // LM:1970年はうるう年ではありませんでした!
        }
        uint16_t days = d;
        for (uint8_t i = 1; i < m; ++i)         days += pgm_read_byte(daysInMonth + i -1);
/*
        if (m > 2 && y % 4 == 0)                ++days;
*/
        if (m > 2 && (y + leapAdjustment) % 4 == 0)     ++days; // LM: Weak but okay for the present
        days += 365 * y + (y + 3) / 4 - 1;
        long offsetTime = long((float(h)+ timezone) * 3600.0);
        return days*24L*3600L + offsetTime + mm*60L + s + seventyYears;
}
//------------------
bool readSensor(void){
        if (Serial1.available()) {
                Serial1.readStringUntil('\n');                                  //読み捨てて先頭から読めるようにする
                nmea = Serial1.readStringUntil('\n');
                if(Serial)      Serial.println(nmea);
                //$GNRMC,022757.000,A,3430.62587,N,13316.66175,E,0.63,144.24,231220,,,A,V*02
                String  nmeames = nmea.substring(3,6);                          // $GP***
                int     count   = 0;
                while(!nmeames.equals(chkHader)){
                       nmea     = Serial1.readStringUntil('\n');
                       nmeames  = nmea.substring(3,6);                          // $GP***
                       if(Serial){
                                //Serial.print(nmea);Serial.print(F("\t"));Serial.println(nmeames);
                       }
                        if(count++ > 30)    break;
                }
                int     nextPos = 0;
                if ( nmeames.equals(chkHader)){                                 // get UTC
                        nextPos         = nmea.indexOf(DELIMITER);              //int indexOf(char ch, unsigned int fromIndex) const;
                        String shh      = nmea.substring(nextPos+1,nextPos+3);
                        String smm      = nmea.substring(nextPos+3,nextPos+5);
                        String sss      = nmea.substring(nextPos+5,nextPos+7);
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip UTC
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip Status
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 緯度
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 北緯か南緯か
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 経度
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 東経か西経か
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 地表における移動の速度[knot]
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 地表における移動の真方位[deg]
                        String sdd      = nmea.substring(nextPos+1,nextPos+3);
                        String smn      = nmea.substring(nextPos+3,nextPos+5);
                        String syy      = nmea.substring(nextPos+5,nextPos+7);
                        if(Serial)      Serial.println("20" + syy + smn + sdd + shh + smm + sss);
                        chYear          = syy.toInt() + 2000;
                        if ((chYear < 2001) || (chYear > 2079)){                //2001~2079をサポート
                                return false;
                        }else{
                                gpsTime =       numberOfSecondsSince1900Epoch(chYear,smn.toInt(),sdd.toInt(),shh.toInt(),smm.toInt(),sss.toInt(),timezone);
                                return true;
                        }
                }else{
                        return false;
                }
        }
        return false;
}
//------------------GPSにアクセスし、取得に成功したら内部時間を更新
bool ReadGPS(){
        bool valid      = false;
        if(readSensor()) {
                nowH    = now() / 3600;                         //内部時計はLocalTime
                if(nowH > preH){                                //1時間毎にRTCを更新する
                        preH    = nowH;
                        setTime(gpsTime);
                }
                valid      = true;
        }else{
                delay(100); 
                if(gLoopCount%60)       Serial.print(F("."));
                else                    Serial.println(F("."));
        }
        return valid;
}
//----------------- RMC文字列を解析してクラスタRMCにセットする
void    analsysRMC(void){
        //$GPRMC,021227.000,A,3459.9060,N,13652.6560,E,0.09,344.80,241220,,,A*6D
        //$GNRMC,072815.000,V,         , ,          , ,    ,      ,241220,,,N,V*27
        //RMCは要素数が固定されていないようなので注意が必要
        int     stPosi = 0;
        int     endPosi;
        char    State;
        //センテンス
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                setenceStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("setenceStr="));Serial.println(setenceStr);
        }
        stPosi  =       endPosi+1;
        //測位時刻(UTC時分秒)        UTC時刻:09時24分03秒307
        endPosi =       nmea.indexOf(',',stPosi);
        Serial.print(F("endPosi="));Serial.println(endPosi);
        if(!(endPosi<0)){
                TimeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("TimeStr="));Serial.println(TimeStr);
        }
        stPosi  =       endPosi+1;
        //測位状態 A:単独測位中またはDGPS測位中 V:未測位    単独測位中/DGPS測位中
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                StatusStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("StatusStr="));Serial.println(StatusStr);
        }
        stPosi  =       endPosi+1;
        //緯度。dddmm.mmmm (10進)     緯度 43.07328
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                latitudeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("latitudeStr="));Serial.println(latitudeStr);
        }
        stPosi  =       endPosi+1;
        //N:北緯、S:南緯       北緯
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                latitudeNSStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("latitudeNSStr="));Serial.println(latitudeNSStr);
        }
        stPosi  =       endPosi+1;
        //経度。dddmm.mmmm (10進)     経度 141.270980
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                longitudeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("longitudeStr="));Serial.println(longitudeStr);
        }
        stPosi  =       endPosi+1;
        //E:東経、W:西経       東経
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                longitudeEWStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("longitudeEWStr="));Serial.println(longitudeEWStr);
        }
        stPosi  =       endPosi+1;
        //速度(000.0〜270.0、単位:ノット)  速度 0 Knot
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                VeloStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("VeloStr="));Serial.println(VeloStr);
        }
        stPosi  =       endPosi+1;
        //真方位による進行方向(000.0〜359.9、単位:度)    240.3度
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                DirStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("DirStr="));Serial.println(DirStr);
        }
        stPosi  =       endPosi+1;
        //ddmmyy 日付(日、月、年)        日付 2017年7月15日
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                DateStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("DateStr="));Serial.println(DateStr);
        }
        stPosi  =       endPosi+1;
        //磁気偏差(000.0〜180.0、単位:度)  0(なし)
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                MagDegStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("MagDegStr="));Serial.println(MagDegStr);
        }
        stPosi  =       endPosi+1;
        //磁気偏差 E:磁気偏差が東より W:磁気偏差が西より      なし
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                MagDevStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("MagDevStr="));Serial.println(MagDevStr);
        }
        stPosi  =       endPosi+1;
        //測位mode N:未測位 A:単独測位 D:DGPS測位
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                ModeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("ModeStr="));Serial.println(ModeStr);
        }else{
                ModeStr = nmea.substring(stPosi,stPosi+1);
                Serial.print(F("ModeStr="));Serial.println(ModeStr);
        }
        stPosi  =       endPosi+1;
        //ナビゲーション状態 S:Safe C:Caution U:Unsafe V:無効(RAIM 機能 OFF)
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                NavStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("NavStr="));Serial.println(NavStr);
        }else{
                NavStr = nmea.substring(stPosi,stPosi+1);
                Serial.print(F("NavStr="));Serial.println(NavStr);
        }
        Status = StatusStr.charAt(0);
        switch(Status){
                case 'A':
                        StatusStr = "A = 有効";
                        //digitalWrite(LED1, LOW);
                        break;
                case 'V':
                        StatusStr = "V = 警告";
                        //digitalWrite(LED1, HIGH);
                        break;
                default:
                        StatusStr = "";
                        //digitalWrite(LED1, HIGH);
                        break;        
        }
        DateTime2Str = "20" + DateStr.substring(4,6) + "年" + DateStr.substring(2,4) + "月" + DateStr.substring(0,2) + "日 " + TimeStr.substring(0,2) + "時" + TimeStr.substring(2,4) + "分" + TimeStr.substring(4,6) + "秒" + TimeStr.substring(7,10);
        State = latitudeNSStr.charAt(0);
        switch(State){
                case 'N':
                        latitudeNSStr = "北緯 ";
                        break;
                case 'S':
                        latitudeNSStr = "南緯 ";
                        break;
                default:
                        latitudeNSStr = "";
                        break;        
        }
        stPosi  = 0;
        endPosi = latitudeStr.indexOf('.',stPosi);
        if(endPosi>0){
                String latitudeStr1     = latitudeStr.substring(stPosi,endPosi-2);
                String latitudeStr2     = latitudeStr.substring(endPosi-2,endPosi);
                String latitudeStr3     = "." + latitudeStr.substring(endPosi+1);
                latitude        = latitudeStr1.toFloat() + (latitudeStr2.toFloat()/60.0) + (latitudeStr3.toFloat()/60.0);
                if(State == 'S')        latitude = -latitude;
                latitudeStr     = latitudeStr1 + "度" + latitudeStr2 + "分" + latitudeStr3;
        }
        State = longitudeEWStr.charAt(0);
        switch(State){
                case 'E':
                        longitudeEWStr = "東経 ";
                        break;
                case 'W':
                        longitudeEWStr = "西経 ";
                        break;
                default:
                        longitudeEWStr = "";
                        break;        
        }
        stPosi  = 0;
        endPosi = longitudeStr.indexOf('.',stPosi);
        if(endPosi>0){
                String longitudeStr1     = longitudeStr.substring(stPosi,endPosi-2);
                String longitudeStr2     = longitudeStr.substring(endPosi-2,endPosi);
                String longitudeStr3     = "." + longitudeStr.substring(endPosi+1);
                longitude        = longitudeStr1.toFloat() + (longitudeStr2.toFloat()/60.0) + (longitudeStr3.toFloat()/60.0);
                if(State == 'W')        longitude = -longitude;
                longitudeStr     = longitudeStr1 + "度" + longitudeStr2 + "分" + longitudeStr3;
        }        
        State = ModeStr.charAt(0);
        switch(State){
                case 'N':
                        ModeStr = "N = データなし";
                        break;
                case 'A':
                        ModeStr = "A = Autonomous(自律方式)";
                        break;
                case 'D':
                        ModeStr = "D = Differential(干渉測位方式)";
                        break;
                case 'E':
                        ModeStr = "E = Estimated(推定)";
                        break;
                case 'M':
                        ModeStr = "M = マニュアル入力";
                        break;
                case 'S':
                        ModeStr = "S = シミュレーター入力";
                        break;
                default:
                        ModeStr = State;
                        break;        
        }
        gRmc.UTC        =       timestamp;
        gRmc.LAT        =       long(latitude         * 10000.0);
        gRmc.LON        =       long(longitude        * 10000.0);
        gRmc.SPD        =       int(VeloStr.toFloat() * 100.0);
        gRmc.DIR        =       int(DirStr.toFloat()  * 100.0);
}
//-----------------
int     getHourTime(void){
        return (now() % 86400) / 3600;
}
//-----------------
void setup() {
        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(pin)を使用してCSピンを設定できます
        //Ethernet.init(10);                                                    // Most Arduino shields
        Ethernet.init(SPI_CS);                                                  //
        //Ethernet.init(0);                                                     // Teensy 2.0
        //Ethernet.init(20);                                                    // Teensy++ 2.0
        //Ethernet.init(15);                                                    // ESP8266 with Adafruit Featherwing Ethernet
        //Ethernet.init(33);                                                    // ESP32 with Adafruit Featherwing Ethernet
        //シリアル通信を開き、ポートが開くのを待ちます。
        Serial.begin(115200);
        //while(!Serial);
        //GPS用にUART0 を使用
        Serial1.setRX(1);
        Serial1.setTX(0);
        Serial1.begin(9600);
        /*
        while (!Serial) {
                ; // シリアルポートが接続するのを待ちます。 ネイティブUSBポートにのみ必要
                //シリアルモニタを開かないと先に進まないので注意が必要
        }
        */
        // start Ethernet and UDP
        LANSetup();
        Ethernet.begin(mac,ip);                                         //FIXIP サンプルスケッチはDHCPでした
        sprintf(buf1,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
        bufIP = buf1;
        if(Serial){
                Serial.print(F("server is at "));Serial.println(Ethernet.localIP());
        }
        Udp.begin(NTPport);
        webServer.begin();
        //最初にNTPサーバから時刻を取得する
        sendNTPpacket(timeServer);                                      // NTPパケットをタイムサーバーに送信します
        delay(1000); 
        parseNTPpacket();
        tm1637.init();
        tm1637.set(BRIGHT_TYPICAL);                                     //BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
        for(int i = 0;i<24;i++){
                for(int j = 0;j<5;j++){
                        gDayBuf[i][j] = NAN;
                }
        }
        //マイクロ秒単位の間隔
        if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 500, TimerHandler0)){
                if(Serial){
                        Serial.print(F("Starting ITimer0 OK, millis() = ")); Serial.println(millis());
                }
        }else{
                if(Serial){
                        Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
                }
        }
        watchdog_reboot(0,0,delay_ms);
        gPreTime        =       millis();
        if(Serial)      Serial.println(F("EndSetup"));
}
//-----------------
int     preSet      = -1;
void loop() {
        //1秒のループ WDT8秒
        if (watchdog_caused_reboot()){
                if(Serial)    Serial.print("Rebooted by Watchdog!\n");
        }else{
                if(Serial)    Serial.print("Clean boot\n");
        }
        watchdog_update();
        bool    valid   = ReadGPS();                                            //GPSセンテンス読込
        int     h       = getHourTime();                                        //返値0-23
        if(Serial){
                Serial.print("preH=");Serial.println(preSet);
                Serial.print("h=");Serial.println(h);
                Serial.print("Status=");Serial.println(Status);
        }
        if((Status == 'A') && (preSet != h)){
                //1時間おきに時刻を確認し、データをメモリに確保
                analsysRMC();
                preSet  = h;
                gDayBuf[h][0]   =       float(gRmc.LAT) / 10000.0;
                gDayBuf[h][1]   =       float(gRmc.LON) / 10000.0;
                gDayBuf[h][2]   =       float(gRmc.SPD) / 100.0;
                gDayBuf[h][3]   =       float(gRmc.DIR) / 100.0;
                gDayBuf[h][4]   =       analogReadTemp();
                //次回分のデータをNULL化
                h = (h+1) % 24;
                gDayBuf[h][0]   =       NAN;
                gDayBuf[h][1]   =       NAN;
                gDayBuf[h][2]   =       NAN;
                gDayBuf[h][3]   =       NAN;
                gDayBuf[h][4]   =       NAN;
                if(Serial)      Serial.print("DataSet");
        }
        LinkStatus      = Ethernet.linkStatus();
        if(Serial){
                Serial.print("linkStatus:");
                switch (LinkStatus){
                        case LinkON:
                                Serial.println("LinkON");
                                break;
                        case LinkOFF:
                                Serial.println("LinkOFF");
                                if(Serial)      Serial.print("Reboot");
                                delay(1000);
                                watchdog_reboot(0,0,1);
                                break;
                        case Unknown:
                        default:
                                Serial.println("Unknown");
                                break;
                }
        }
        bool req        = processNTP();                                 //NTP要求確認
        client          = webServer.available();                        //HTTP要求確認
        if(client)      checkWebPage(client);
        client.stop();
        
        digitalWrite(LED_BUILTIN, fTogle2);
        fTogle2  = !fTogle2;
        gLoopCount++;
        if(Serial)      Serial.println(gLoopCount);
        gNowTime        = millis();
        gLoopTime       = gNowTime - gPreTime;
        gPreTime        = gNowTime;
}


2022年12月26日 GPSモジュールをM5Stack用GPSユニットに置き換えして見ました。また、WebPageの改善を行う。

M5Stack用GPSユニットを入手しました。2000円前後で購入できました。チップはAT6558で、MAX2659というGPS専用のアンプが組み込まれています。そこそこ安定したモジュールで、デフォルトのまま電源入れれば電波捕らえてセンテンスを垂れ流してくれます。
接続も直接Groveケーブルで接続出来るので便利です。

折角なのでWebPageの見直しをしました。
Topページは選択ページであり、そこから分岐して設定ページとGPSセンテンスを表示するユーティリティ頁を表示可能としています。
問題点としてTOPページに戻る術が用意されていないことでした。URLを手動で変更すればいいのですが、スマホのブラウザだとこの作業は結構大変だという事も判りました。[Return]とかTOPページの戻るというような機能が必要だと感じたのです。

/*
 * 2022年12月26日 T.Wanibe
 * 2.5.6.0 [RETURN]ボタンの追加
 * 2.5.5.5 reboot時にNTPdからの時刻取得に失敗した場合の対処方法を検討
 *      GPSのStatusがA(有効)なのに時刻同期したいのはバグだと考え対処する。
 * 2.5.5.4 LinkStatusの扱いにバグがあったので修正した。
 *      復帰方法としてwatchdog_reboot(0,0,1)は理に適っている。ただ、その判断基準としてLinkStatusはダメなので別の方補を調査中
 * 2.5.5.2 EEPROMの書込でEEPROM.commit()を追加
 * 2.5.5.1 NTP受信したときのパケットをシリアルプリントする様にした
 * 2.5.5 MainLoopがちゃんと動いているかどうかを判断する為にLEDの点滅をさせる
 *      Timer割込が動いている事を確認するために7segLEDの更新を実施する。
 * 2.5.4 UtilPage等々追加する
 * 2.5.3 WebSerserを追加しユーティリティ機能を追加する フラッシュサイズについては余裕がある。
 *      HTMLコードは極力String型で一度に扱えるようにする。実行中のメモリの余裕も可成り有るので。
 *      Arduino-PicoではTextFinder.hのコンパイルが通らない。TextFinderを使わないパース方法を使用する必要がある
 * 2.5.2 GPS機能を追加する GPSのパースはライブラリを使わに実施する GxRMCを採用する
 * 2.5.1 ではNTPサーバー機能を追加する 内部RTCはLocalTimeとし 問い合わせに対してはUTCに変換する必要がある
 * 2.5.0.1起動時にNTP(192.168.0.199)にアクセスして内部RTCにセットして、その後TM1637LEDに表示しています。
 * 
 * 実行環境はPiPicoをGroveShieldに接続した状態で、SPIポートにW5500を接続して使います。CS=GPIO5です。
 * 固定IPとします。192.168.0.207 MACアドレスはダブらないように注意します。
 * アクセスするNTPサーバはLocalにある192.168.0.199です。
 * 最大2093056バイトのフラッシュメモリのうち、スケッチが107280バイト(5%)を使っています。
 * 最大262144バイトのRAMのうち、グローバル変数が14096バイト(5%)を使っていて、ローカル変数で248048バイト使うことができます。
 */
#define          TIMER_INTERRUPT_DEBUG          1
#define         _TIMERINTERRUPT_LOGLEVEL_       4
#include        <TimeLib.h>
#include        "TM1637.h"
#include        "RPi_Pico_TimerInterrupt.h"
#include        <SPI.h>
#include        <Ethernet.h>
#include        <EthernetUdp.h>
#include        <EEPROM.h>
extern "C" {
#include        <hardware/watchdog.h>
};
#define         CLK             18
#define         DIO             19
#define         NICReset        20
#define         NICInit         21
#define         SPI_SCK         2
#define         SPI_RX          4
#define         SPI_TX          3
#define         SPI_CS          5
#define         TIMER0_INTERVAL_MS      1000
#define         HttpPort        80
#define         DELIMITER       ","
#define         vers    "GPSNTP RPiPicoShield 2.5.6.0"
uint32_t        delay_ms        = 8000;                                 //8秒 最大8.3秒
const char      FVirsion[]      = "2.5.6.0";
byte            mac[]           = {0x00,0x08,0xDC,0x54,0x4D,0xD8};      //Wiznet
byte            ip[]            = {192, 168, 0, 207};
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};
String          HTTP_req; 
unsigned int    localPort       = 8888;                                 // local port to listen for UDP packets
//const char    timeServer[]    = "time.nist.gov";                      // time.nist.gov NTP server
char            timeServer[]    = "192.168.0.199";
const int       NTPport         = 123;
const int       NTP_PACKET_SIZE = 48;                                   // NTP time stamp is in the first 48 bytes of the message
byte            packetBuffer[NTP_PACKET_SIZE];                          //buffer to hold incoming and outgoing packets
byte            fTogle1         = LOW;
byte            fTogle2         = LOW;
float           timezone        = 9.0;
time_t          TimeZoneSec     = long(timezone * 3600);
float           unit            = 2.33E-7;
unsigned long   baseMilis       = millis();
unsigned long   miliTime;
struct          time_tm         *tm;                                    //STM32dinoとRP2040の構造体が異なる
time_t          currentTime,recieveTime,gpsTime;
unsigned long   currentHour,currentMin,currentSec;
int8_t          TimeDisp[]      = {0x00,0x00,0x00,0x00};
const unsigned long seventyYears = 2208988800UL;
char            buff[80];
char            buf1[32];
char            MacAddressStr[20];
char            IPAddressStr[20];
char            SubnetMaskStr[20];
char            GatewayStr[20];
char            NTPserverStr[20];
char            DateTimeStr[20];
char            Status          = 'V';
String          nmea;
String          bufIP                  = "192.168.0.200";
const uint8_t   daysInMonth [] PROGMEM = { 31,28,31,30,31,30,31,31,30,31,30,31 };//const or compiler complains
uint32_t        timestamp, tempval,microVal,fractions;
int             preH,nowH;
int             chYear;
String          setenceStr              = "$GPRMC";
String          StatusStr               = "V = 警告";
String          DateTime2Str            = "2020年12月24日 8時25分59秒.000";
String          DateStr;
String          TimeStr;
String          latitudeStr             = "北緯 35度41.1493分";
String          latitudeNSStr;
String          longitudeStr            = "東経 139度45.3994分";
String          longitudeEWStr;
String          VeloStr                 = "00.0";
String          DirStr                  = "0.0度";
String          ModeStr                 = "A = 自律方式";
String          MagDegStr;
String          MagDevStr;
String          NavStr;
double          latitude;
double          longitude;
float           gDayBuf[24][5];                                         //24時間分5要素データに変更
float           gTemp(NAN);
bool            gRTCOK;
typedef struct{
        uint32_t        UTC;
        long            LAT;                                            //10000倍した緯度
        long            LON;                                            //10000倍した経度
        int             DIR;                                            //100倍した値0〜3600
        int             SPD;                                            //速度(ノット単位)を100倍したもの
}RMC;
RMC             gRmc;
//GPS
char            chkHader[]      = "RMC";                                //このバージョンから3文字に変更
//内部カウンタ
unsigned long   gNTPqueryCount  = 0;
long            gLoopCount      = 3;                                    //1時間毎に更新予定 最初は1分後に更新したくて初期値を調整
long            gLoopTime       = 0;                                    //Loop()の実行時間を求める
long            gResetCount     = 0;
long            gPreTime,gNowTime; 
unsigned long   OperatingTime   = 0;                                    //稼働時間 Count2で1秒
int             LinkStatus;
int             gHardwareStatus;
//
const byte      ID = 0x99;
//オブジェクトコンストラクタ
EthernetServer  webServer(HttpPort);
EthernetClient  client;
TM1637          tm1637(CLK,DIO);
EthernetUDP     Udp;                                                    // A UDP instance to let us send and receive packets over UDP
RPI_PICO_Timer  ITimer0(0);
//------------EEPROM.read
void ReadID(){
        for (int i = 0; i < 6; i++){
                //mac[i]        = EEPROM.read(i+1);
                mac[i]          = EEPROM[i+1];
                if(Serial)      Serial.print("R_mac=");Serial.println(mac[i]);
        }
        for (int i = 0; i < 4; i++){
                //ip[i]         = EEPROM.read(i+7);
                ip[i]           = EEPROM[i+7];
                if(Serial)      Serial.print("R_ip=");Serial.println(ip[i]);
        }
        for (int i = 0; i < 4; i++){
                //subnet[i]     = EEPROM.read(i+11);
                subnet[i]       = EEPROM[i+11];
                if(Serial)      Serial.print("R_subnet=");Serial.println(subnet[i]);
        }
        for (int i = 0; i < 4; i++){
                //gateway[i]    = EEPROM.read(i+15);
                gateway[i]      = EEPROM[i+15];
                if(Serial)      Serial.print("R_gateway=");Serial.println(gateway[i]);
        }
        for (int i = 0; i < 4; i++){
                //NTPip[i]      = EEPROM.read(i+19);
                NTPip[i]        = EEPROM[i+19];
                if(Serial)      Serial.print("R_NTPip=");Serial.println(NTPip[i]);
        }
        //timezone = float(EEPROM.read(23)) / 10.0;
        timezone = float(EEPROM[23]) / 10.0;
        if(Serial)      Serial.print("R_timezone=");Serial.println(timezone);
}
//------------EEPROM.write
void WriteID(){
        for (int i = 0 ; i < 6; i++){
                //EEPROM.write(i + 1,mac[i]);
                EEPROM[i + 1]   = mac[i];
                if(Serial)      Serial.print("W_mac=");Serial.println(mac[i]);
        }
        for (int i = 0 ; i < 4; i++){
                //EEPROM.write(i + 7, ip[i]);
                EEPROM[i + 7]   = ip[i];
                if(Serial)      Serial.print("W_ip=");Serial.println(ip[i]);
        }
        for (int i = 0 ; i < 4; i++){
                //EEPROM.write(i + 11, subnet[i]);
                EEPROM[i + 11]  = subnet[i];
                if(Serial)      Serial.print("W_subnet=");Serial.println(subnet[i]);
        }
        for (int i = 0 ; i < 4; i++){
                //EEPROM.write(i + 15, gateway[i]);
                EEPROM[i + 15]  = gateway[i];
                if(Serial)      Serial.print("W_gateway=");Serial.println(gateway[i]);
        }
        for (int i = 0; i < 4; i++){
                //EEPROM.write(i + 19, NTPip[i]);
                EEPROM[i + 19]  = NTPip[i];
                if(Serial)      Serial.print("W_NTPip=");Serial.println(NTPip[i]);
        }
        //EEPROM.write(23,char(timezone * 10));
        EEPROM[23]      = char(timezone * 10);
        if(Serial)      Serial.print("W_timezone=");Serial.println(timezone);
        // IDを既知のビットに設定します。したがって、Arduinoをリセットすると、EEPROM値が使用されます。
        //EEPROM.write(256, ID);
        EEPROM[256]     =       ID;
        EEPROM.commit();                        //2.5.5.2で追加
        
        if(Serial)      Serial.print("W_ID=");Serial.println(ID,HEX);
}
//----------------------------------
void LANSetup(){
        EEPROM.begin(512);
        //int idcheck = EEPROM.read(256);
        int idcheck     =       EEPROM[256];
        if(Serial)      Serial.print("R_ID=");Serial.println(idcheck,HEX);
        Serial.print(F("LocalID = 0x"));Serial.println(idcheck,HEX);
        if (idcheck == ID){
                //idがIDと同じ値の場合、
                //これは、このスケッチがシールドを設定するために使用されたことを意味します。
                //EERPOMの値を読み取ってシールドを設定します。
                ReadID();
        }else{
                //idが一致しない場合、初期値を書き込む事にします。
                WriteID();
        }
        EEPROM.end();
        sprintf(MacAddressStr,"%02x.%02x.%02x.%02x.%02x.%02x",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
        sprintf(IPAddressStr,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
        sprintf(SubnetMaskStr,"%d.%d.%d.%d",subnet[0],subnet[1],subnet[2],subnet[3]);
        sprintf(GatewayStr,"%d.%d.%d.%d",gateway[0],gateway[1],gateway[2],gateway[3]);
        //Ethernet.begin(mac, ip);
//      Ethernet.begin(mac);                                            //DHCPの場合
//      Ethernet.begin(mac, ip, subnet);                                //SubnetMaskを意識した場合。
//      Ethernet.begin(mac, ip, subnet, gateway);                       //gatewayを意識した場合。
}
//--------------------------
void paramParse(String reqStr){
        int Code;
        int len         = reqStr.length();
        char* HTTP_c    = (char*)malloc(len+1);
        reqStr.toCharArray(HTTP_c, len);
        char bufff[10];
        //DT1 mac[0]            HEX
        int indexS      = reqStr.indexOf("DT1=");
        int indexE      = reqStr.indexOf("&",indexS);
        int k = 0;
        char c;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[0]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT2 mac[1]            HEX
        indexS = reqStr.indexOf("DT2=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[1]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT3 mac[2]            HEX
        indexS = reqStr.indexOf("DT3=");                                        //Serial.print("Pos=");Serial.println(indexS);
        indexE = reqStr.indexOf("&",indexS);                                    //Serial.print("Pos=");Serial.println(indexE);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);                                           //Serial.println(c);
                if (c == '='){
                        int m = indexE - indexS;                                //Serial.print("m=");Serial.println(m);
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[2]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                 }
        }
        //DT4 mac[3]            HEX
        indexS = reqStr.indexOf("DT4=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[3]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT5 mac[4]            HEX
        indexS = reqStr.indexOf("DT5=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[4]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[4]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT6 mac[5]            HEX
        indexS = reqStr.indexOf("DT6=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        mac[5]=int(strtol(bufff, NULL, 16));    //Serial.print(bufff);Serial.println(mac[5]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT7 ip[0]             DEC
        indexS = reqStr.indexOf("DT7=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[0]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT8 ip[1]             DEC
        indexS = reqStr.indexOf("DT8=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[1]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT9 ip[2]             DEC
        indexS = reqStr.indexOf("DT9=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[2]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT10 ip[3]            DEC
        indexS = reqStr.indexOf("DT10=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        ip[3]=int(strtol(bufff, NULL, 10));     //Serial.print(bufff);Serial.println(ip[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT11 subnet[0]        DEC
        indexS = reqStr.indexOf("DT11=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[0]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT12 subnet[1]        DEC
        indexS = reqStr.indexOf("DT12=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[1]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT13 subnet[2]        DEC
        indexS = reqStr.indexOf("DT13=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j); //Serial.println(bufff);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[2]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT14 subnet[3]        DEC
        indexS = reqStr.indexOf("DT14=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = HTTP_req.charAt(j);
                 if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        subnet[3]=int(strtol(bufff, NULL, 10)); //Serial.print(bufff);Serial.println(subnet[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT15 gateway[0]       DEC
        indexS = reqStr.indexOf("DT15=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[0]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT16 gateway[1]       DEC
        indexS = reqStr.indexOf("DT16=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[1]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT17 gateway[2]       DEC
        indexS = reqStr.indexOf("DT17=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[2]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT18 gateway[3]       DEC
        indexS = reqStr.indexOf("DT18=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        gateway[3]=int(strtol(bufff, NULL, 10));//Serial.print(bufff);Serial.println(gateway[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT19 NTPip[0]       DEC
        indexS = reqStr.indexOf("DT19=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        NTPip[0]=int(strtol(bufff, NULL, 10));  //Serial.print(bufff);Serial.println(NTPip[0]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT120 NTPip[1]       DEC
        indexS = reqStr.indexOf("DT20=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        NTPip[1]=int(strtol(bufff, NULL, 10));  //Serial.print(bufff);Serial.println(NTPip[1]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT21 NTPip[2]       DEC
        indexS = reqStr.indexOf("DT21=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        NTPip[2]=int(strtol(bufff, NULL, 10));  //Serial.print(bufff);Serial.println(NTPip[2]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }        
        }
        //DT22 NTPip[3]       DEC
        indexS = reqStr.indexOf("DT22=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        NTPip[3]=int(strtol(bufff, NULL, 10));  //Serial.print(bufff);Serial.println(NTPip[3]);
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
        //DT23 timezone       float
        indexS = reqStr.indexOf("DT23=");
        indexE = reqStr.indexOf("&",indexS);
        k = 0;
        for(int j = indexS;j<=indexE;j++){
                c = reqStr.charAt(j);
                if (c == '='){
                        int m = indexE - indexS;
                        for (int l = 1; l < m;l++){
                                c = reqStr.charAt(j+l);
                                if(c == '&'){
                                        bufff[k]='\0';                          //Serial.println(bufff);
                                        timezone =int((strtof(bufff, NULL)*10));
                                        break; 
                                }else{
                                        bufff[k++] = c;
                                }
                        }
                        break;
                }
        }
}
//--------------------------
void checkWebPage( EthernetClient client){
        if(Serial)      Serial.println(F("new webClient"));
        boolean restart = false;
        if (client) {
                // HTTPリクエスト空行(\r\n\r\n)で終わる。ので、空行を探す。
                boolean currentLineIsBlank = true;
                while (client.connected()) {
                        if( !client.available() ){
                                if(Serial)    Serial.print(F("."));
                                continue;
                        }
                        char c = client.read();
                        HTTP_req += c;
                        if(Serial)    Serial.print(c);
                        if( c == '\n'  && currentLineIsBlank ){                 // 空行発見。HTTPリクエスト終了。レスポンスを返す。
                                //Serial.print("RecieveLength=");Serial.println(HTTP_req.length());
                                if (HTTP_req.indexOf("/?")>0) {                 //setup?と/?を区別する必要がある
                                        if(Serial)    Serial.print(F("CASE1:"));Serial.print(gLoopCount);
                                        /*if(gLoopCount % 2){
                                                digitalWrite(LED_BUILTIN,HIGH); //Serial.println(F(" H"));
                                        }else{
                                                digitalWrite(LED_BUILTIN,LOW);  //Serial.println(F(" L"));
                                        }*/
                                        delay(100);
                                        HTTP_req = "";
                                        break;
                                }else if(HTTP_req.indexOf("setup")>0){
                                        //setup頁の場合 SBMが含まれていればEEPROMに書込、そうで無ければ表示のみ
                                        //setup?SBM=1&DT1=0&DT2=8&DT3=DC&DT4=54&DT5=4D&DT6=D0&DT1=0&DT2=8&DT3=220&DT4=84&DT5=77&DT6=208&DT7=192&DT8=168&DT9=0&DT10=200&DT11=255&DT12=255&DT13=255&DT14=0&DT15=192&DT16=168&DT17=0&DT18=1
                                        //TextFinderを使うとHTMLの切り出しは比較的容易これをSTRING型のままどう扱うか?
                                        if(Serial)    Serial.print(F("CASE2:"));Serial.println(gLoopCount);
                                        if (HTTP_req.indexOf("SBM")>0){
                                                //Serial.println(F("Found_SBM"));
                                                if(Serial)    Serial.print(F("CASE3:"));Serial.println(gLoopCount);
                                                paramParse(HTTP_req);
                                                // すべてのデータを取得したので、EEPROMに保存します。
                                                EEPROM.begin(512);
                                                WriteID();
                                                //データがEEPROMに書き込まれている場合は、arduinoをリセットする必要があります。
                                                //読込直す
                                                //int idcheck = EEPROM.read(256);
                                                int idcheck     =       EEPROM[256];
                                                if(Serial)    Serial.print(F("R_ID="));Serial.println(idcheck,HEX);
                                                if (idcheck == ID){
                                                        //idがIDと同じ値の場合、
                                                        //これは、このスケッチがシールドを設定するために使用されたことを意味します。
                                                        //EERPOMの値を読み取ってシールドを設定します。
                                                        ReadID();
                                                }
                                                EEPROM.end();
                                                //ハードウェアリセットボタンを使用する必要があります
                                                HTTP_req = "";
                                                client.stop();
                                                delay(1000);
                                                watchdog_reboot(0,0,1);
                                                break;
                                        }else if(HTTP_req.indexOf("setup1")>0){
                                                if(Serial)      Serial.println(F("setup1"));
                                                PrintSetUpPage(client);
                                                HTTP_req = "";
                                                break;
                                        }else if(HTTP_req.indexOf("setup2")>0){
                                                if(Serial)      Serial.println(F("setup2"));
                                                PrintUtilPage(client);
                                                HTTP_req = "";
                                                break;
                                        }else if(HTTP_req.indexOf("setup3")>0){
                                                if(Serial)      Serial.println(F("setup3"));
                                                pageLoadUtilsJS(client);
                                                HTTP_req = "";
                                                break;
                                        }else if(HTTP_req.indexOf("setup9")>0){
                                                if(Serial)      Serial.println(F("setup9"));
                                                pageIntroduction(client);
                                                HTTP_req = "";
                                                break;
                                        }else{
                                                if(Serial)      Serial.print(F("CASE404-1"));
                                                pageIntroduction(client);
                                                HTTP_req = "";
                                                break;
                                        }
                                }else if(HTTP_req.indexOf("\n")>0) {
                                        if(Serial)      Serial.println(F("CASE4"));
                                        pageIntroduction(client);
                                        HTTP_req = "";
                                        break;
                                }else if(HTTP_req.indexOf("/index")>0) {
                                        if(Serial)      Serial.println(F("CASE5"));
                                        pageIntroduction(client);
                                        HTTP_req = "";
                                        break;
                                }else{
                                        if(Serial)      Serial.print(F("CASE404-2"));
                                        PrintResponse404(client);
                                        HTTP_req = "";
                                        break;
                                }
                                HTTP_req = "";
                                break;                          // ループを抜ける
                        }
                        if(c ==  '\n'){                         // 新しい行の始まり。
                                currentLineIsBlank = true;
                        } else if(c !=  '\r' ){                 // この行は空行ではなかった。
                                currentLineIsBlank = false;
                        }
                }
                delay(1);
                client.stop();
        }     
}
//--------OK_200
String OK_200           =
        "HTTP/1.1 200 OK\n"
        "Content-Type: text/html\n";
//--------NG_404
String NG_404           =
        "HTTP/1.1 404 Not Found\n"
        "Content-Type: text/html\n"
        "Connnection: close\n";
//--------LoadUtilsJS
String LoadUtilsJS1     =
        "'use strict';\n"
"window.chartColors = {\n"
        "\tred: 'rgb(255, 99, 132)',\n"
        "\torange: 'rgb(255, 159, 64)',\n"
        "\tyellow: 'rgb(255, 205, 86)',\n"
        "\tgreen: 'rgb(75, 192, 192)',\n"
        "\tblue: 'rgb(54, 162, 235)',\n"
        "\tpurple: 'rgb(153, 102, 255)',\n"
        "\tgrey: 'rgb(201, 203, 207)'\n"
"};\n"
"(function(global) {\n"
        "\tvar MONTHS = [\n"
                "\t\t'January',\n"
                "\t\t'February',\n"
                "\t\t'March',\n"
                "\t\t'April',\n"
                "\t\t'May',\n"
                "\t\t'June',\n"
                "\t\t'July',\n"
                "\t\t'August',\n"
                "\t\t'September',\n"
                "\t\t'October',\n"
                "\t\t'November',\n"
                "\t\t'December'\n"
        "\t];\n"
        "\tvar COLORS = [\n"
                "\t\t'#4dc9f6',\n"
                "\t\t'#f67019',\n"
                "\t\t'#f53794',\n"
                "\t\t'#537bc4',\n"
                "\t\t'#acc236',\n"
                "\t\t'#166a8f',\n"
                "\t\t'#00a950',\n"
                "\t\t'#58595b',\n"
                "\t\t'#8549ba'\n"
        "\t];\n"
        "\tvar Samples = global.Samples || (global.Samples = {});\n"
        "\tvar Color = Chart.helpers.color;\n"
        "\tfunction applyDefaultNumbers(config) {\n"
                "\t\tvar cfg = config || {};\n"
                "\t\tcfg.min = cfg.min || 0;\n"
                "\t\tcfg.max = cfg.max || 1;\n"
                "\t\tcfg.from = cfg.from || [];\n"
                "\t\tcfg.count = cfg.count || 8;\n"
                "\t\tcfg.decimals = cfg.decimals || 8;\n"
                "\t\tcfg.continuity = cfg.continuity || 1;\n"
                "\t\treturn cfg;\n"
        "\t}\n";
String LoadUtilsJS2     =
        "\tSamples.utils = {\n"
                "\t\t// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/\n"
                "\t\tsrand: function(seed) {\n"
                "\t\t\tthis._seed = seed;\n"
                "\t\t},\n"
                "\t\trand: function(min, max) {\n"
                "\t\t\tvar seed = this._seed;\n"
                "\t\t\tmin = min === undefined ? 0 : min;\n"
                "\t\t\tmax = max === undefined ? 1 : max;\n"
                "\t\t\tthis._seed = (seed * 9301 + 49297) % 233280;\n"
                "\t\t\treturn min + (this._seed / 233280) * (max - min);\n"
                "\t\t},\n"
                "\t\tnumbers: function(config) {\n"
                        "\t\t\tvar cfg = applyDefaultNumbers(config);\n"
                        "\t\t\tvar dfactor = Math.pow(10, cfg.decimals) || 0;\n"
                        "\t\t\tvar data = [];\n"
                        "\t\t\tvar i, value;\n"
                        "\t\t\tfor (i = 0; i < cfg.count; ++i) {\n"
                                "\t\t\t\tvalue = (cfg.from[i] || 0) + this.rand(cfg.min, cfg.max);\n"
                                "\t\t\t\tif (this.rand() <= cfg.continuity) {\n"
                                "\t\t\t\t\tdata.push(Math.round(dfactor * value) / dfactor);\n"
                                "\t\t\t\t} else {\n"
                                "\t\t\t\t\tdata.push(null);\n"
                                "\t\t\t\t}\n"
                        "\t\t\t}\n"
                        "\t\t\treturn data;\n"
                "\t\t},\n"
                "\t\tlabels: function(config) {\n"
                        "\t\t\tvar cfg = config || {};\n"
                        "\t\t\tvar min = cfg.min || 0;\n"
                        "\t\t\tvar max = cfg.max || 100;\n"
                        "\t\t\tvar count = cfg.count || 8;\n"
                        "\t\t\tvar step = (max - min) / count;\n"
                        "\t\t\tvar decimals = cfg.decimals || 8;\n"
                        "\t\t\tvar dfactor = Math.pow(10, decimals) || 0;\n"
                        "\t\t\tvar prefix = cfg.prefix || '';\n"
                        "\t\t\tvar values = [];\n"
                        "\t\t\tvar i;\n"
                        "\t\t\tfor (i = min; i < max; i += step) {\n"
                        "\t\t\t\tvalues.push(prefix + Math.round(dfactor * i) / dfactor);\n"
                        "\t\t\t}\n"
                        "\t\t\treturn values;\n"
                "\t\t},\n"
                "\t\tmonths: function(config) {\n"
                        "\t\t\tvar cfg = config || {};\n"
                        "\t\t\tvar count = cfg.count || 12;\n"
                        "\t\t\tvar section = cfg.section;\n"
                        "\t\t\tvar values = [];\n"
                        "\t\t\tvar i, value;\n"
                        "\t\t\tfor (i = 0; i < count; ++i) {\n"
                                "\t\t\t\tvalue = MONTHS[Math.ceil(i) % 12];\n"
                                "\t\t\t\tvalues.push(value.substring(0, section));\n"
                        "\t\t\t}\n"
                        "\t\t\treturn values;\n"
                "\t\t},\n"
                "\t\tcolor: function(index) {\n"
                        "\t\t\treturn COLORS[index % COLORS.length];\n"
                "\t\t},\n"
                "\t\ttransparentize: function(color, opacity) {\n"
                        "\t\t\tvar alpha = opacity === undefined ? 0.5 : 1 - opacity;\n"
                        "\t\t\treturn Color(color).alpha(alpha).rgbString();\n"
                "\t\t}\n"
        "\t};\n";
String LoadUtilsJS3     =
        "\t// DEPRECATED\n"
        "\twindow.randomScalingFactor = function() {\n"
                "\t\treturn Math.round(Samples.utils.rand(-100, 100));\n"
        "\t};\n"
        "\t// INITIALIZATION\n"
        "\tSamples.utils.srand(Date.now());\n"
        "\t// Google Analytics\n"
        "\t/* eslint-disable */\n"
        "\tif (document.location.hostname.match(/^(www\\.)?chartjs\\.org$/)) {\n"
                "\t\t(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\n"
                "\t\t(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\n"
                "\t\tm=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\n"
                "\t\t})(window,document,'script','//www.google-analytics.com/analytics.js','ga');\n"
                "\t\tga('create', 'UA-28909194-3', 'auto');\n"
                "\t\tga('send', 'pageview');\n"
        "\t}\n"
        "\t/* eslint-enable */\n"
"}(this));\n";
//--------WebTopPage
String WebTopPage1      =
"<HTML>\n"
"<HEAD>\n"
        "\t<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html;CHARSET=UTF-8\">\n"
        "\t<TITLE>RP2040版 GPSNTP メニュー</TITLE>\n"
"</HEAD>\n"
"<BODY BGCOLOR='#ffffff'>\n"
"<H2><CENTER><FONT COLOR='#00ff00'>RP2040版 GPSNTP メニュー</FONT></CENTER></H2>\n"
"<P><CENTER><TABLE WIDTH='300' BORDER='0' CELLSPACING='0' CELLPADDING='0'>\n"
        "\t<TR>\n"
                "\t\t<TD WIDTH='100%'>\n"
                "\t\t<OL>\n"
                "\t\t\t<LI><FONT SIZE='+1'><A HREF=\"http://";
String WebTopPage2       =
                "/setup1\">設定メニュー</A>\n"
                "\t\t\t<LI><A HREF=\"http://";
String WebTopPage3       =
                "/setup2\">GPSセンテンス表示</A></FONT>\n"
                "\t\t</OL>\n"
                "\t\t</TD>\n"
        "\t</TR>\n"
"</TABLE></CENTER>\n"
"</BODY>\n"
"</HTML>\n";
//-------------SetPage
String SetPage1         =
"<!DOCTYPE HTML PUBLIC \"\">\n<html>\n<HEAD>\n\t<META http-equiv=\"Content-Type\" charset=Shift_JIS\">\n"
        "\t<META http-equiv=\"Content-Style-Type\">\n\t<TITLE>";
String SetPage2         =
        " Setup Page</TITLE>\n"
        "\t<SCRIPT>\n\t\tfunction HP(w1){parent.window.open(w1,'_top')}\n\t</SCRIPT>\n</HEAD>\n"
        "<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\">\n<BLOCKQUOTE><BLOCKQUOTE>\n"
        "<table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\">\n"
        "<tr><td>";
String SetPage3         =
        " Setup Page</td></tr></table><br>\n"
        "<script>\n\tfunction hex2num (s_hex) {\n\t\teval(\"var n_num=0X\" + s_hex);\n\t\treturn n_num;\n\t}\n</script>\n"
        "<tbody>\n<FORM><input type=\"hidden\" name=\"SBM\" value=\"1\">\n<table>\n<tr><td>MAC:</td><td>"
        "<input id=\"T1\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT1\" value=\"";
String SetPage4         =
        "\">.<input id=\"T3\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT2\" value=\"";
String SetPage5         =
        "\">.<input id=\"T5\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT3\" value=\"";
String SetPage6         =
        "\">.<input id=\"T7\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT4\" value=\"";
String SetPage7         =
        "\">.<input id=\"T9\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT5\" value=\"";
String SetPage8         =
        "\">.<input id=\"T11\" type=\"text\" size=\"3\" maxlength=\"2\" name=\"DT6\" value=\"";
String SetPage9         =
        "\"><input id=\"T2\" type=\"hidden\" name=\"DT1\"><input id=\"T4\" type=\"hidden\" name=\"DT2\n"
        "\"><input id=\"T6\" type=\"hidden\" name=\"DT3\"><input id=\"T8\" type=\"hidden\" name=\"DT4\n"
        "\"><input id=\"T10\" type=\"hidden\" name=\"DT5\"><input id=\"T12\" type=\"hidden\" name=\"DT6\n"
        "\"></td></tr>\n<tr><td>IP:</td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT7\" value=\"";
String SetPage10        =
       "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT8\" value=\"";
String SetPage11        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT9\" value=\"";
String SetPage12        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT10\" value=\"";
String SetPage13        =
        "\"></td></tr>\n<tr><td>MASK: </td><td><input type= \"text\" size=\"3\" maxlength=\"3\" name=\"DT11\" value=\"";
String SetPage14        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT12\" value=\"";
String SetPage15        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT13\" value=\"";
String SetPage16        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT14\" value=\"";
String SetPage17        =
        "\"></td></tr>\n<tr><td>GW: </td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT15\" value=\"";
String SetPage18        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT16\" value=\"";
String SetPage19        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT17\" value=\"";
String SetPage20        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT18\" value=\"";
String SetPage21        =
        "\"></td></tr><tr><td COLSPAN='2'>\n<HR ALIGN=CENTER></td></tr>\n"
        "<tr><td>NTPip: </td><td><input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT19\" value=\"";
String SetPage22        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT20\" value=\"";
String SetPage23        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT21\" value=\"";
String SetPage24        =
        "\">.<input type=\"text\" size=\"3\" maxlength=\"3\" name=\"DT22\" value=\"";
String SetPage25        =
        "\"></td></tr>\n"
        "<tr><td>TimeZone:</td><td><input type=\"text\" size=\"3\" maxlength=\"5\" name=\"DT23\" value=\"";
String SetPage26        =
        "\"></td></tr>\n<tr><td><br></td></tr><tr><td COLSPAN='2'><P ALIGN=RIGHT>"
        "<INPUT TYPE=\"button\" VALUE=\"RETURN\" onClick=\"HP('http://";
String SetPage27        =      
        "/index')\"/><input id=\"button1\"type=\"submit\" value=\"SUBMIT\" "
        "Onclick=\""
        "document.getElementById('T2').value = hex2num(document.getElementById('T1').value);\n"
        "\t\tdocument.getElementById('T4').value = hex2num(document.getElementById('T3').value);\n"
        "\t\tdocument.getElementById('T6').value = hex2num(document.getElementById('T5').value);\n"
        "\t\tdocument.getElementById('T8').value = hex2num(document.getElementById('T7').value);\n"
        "\t\tdocument.getElementById('T10').value = hex2num(document.getElementById('T9').value);\n"
        "\t\tdocument.getElementById('T12').value = hex2num(document.getElementById('T11').value);\""
        "></td></tr></tbody>\n</table>\n</BLOCKQUOTE></BLOCKQUOTE>\n</form>\n</BODY>\n</html>\n";
//------------------PrintSetUpPage
void PrintSetUpPage( EthernetClient client){
        client.println(OK_200);
        client.print(SetPage1);
        client.print(vers);
        client.print(SetPage2);
        client.print(vers);
        client.print(SetPage3);
        client.print(mac[0],HEX);
        client.print(SetPage4);
        client.print(mac[1],HEX);
        client.print(SetPage5);
        client.print(mac[2],HEX);
        client.print(SetPage6);
        client.print(mac[3],HEX);
        client.print(SetPage7);
        client.print(mac[4],HEX);
        client.print(SetPage8);
        client.print(mac[5],HEX);
        client.print(SetPage9);
        client.print(ip[0],DEC);
        client.print(SetPage10);
        client.print(ip[1],DEC);
        client.print(SetPage11);
        client.print(ip[2],DEC);
        client.print(SetPage12);
        client.print(ip[3],DEC);
        client.print(SetPage13);
        client.print(subnet[0],DEC);
        client.print(SetPage14);
        client.print(subnet[1],DEC);
        client.print(SetPage15);
        client.print(subnet[2],DEC);
        client.print(SetPage16);
        client.print(subnet[3],DEC);
        client.print(SetPage17);
        client.print(gateway[0],DEC);
        client.print(SetPage18);
        client.print(gateway[1],DEC);
        client.print(SetPage19);
        client.print(gateway[2],DEC);
        client.print(SetPage20);
        client.print(gateway[3],DEC);
        client.print(SetPage21);
        client.print(NTPip[0],DEC);
        client.print(SetPage22);
        client.print(NTPip[1],DEC);
        client.print(SetPage23);
        client.print(NTPip[2],DEC);
        client.print(SetPage24);
        client.print(NTPip[3],DEC);
        client.print(SetPage25);
        client.print(timezone,2);
        client.print(SetPage26);
        client.print(IPAddressStr);
        client.print(SetPage27);
}
//-------------UtilPage
String UtilPage1        =
        "<!DOCTYPE HTML PUBLIC \"\">\n"
        "<html>\n"
        "<HEAD>\n"
                "\t<META http-equiv=\"Content-Type\" charset=\"UTF-8\">\n"
                "\t<META http-equiv=\"Content-Style-Type\">\n"
                "\t<TITLE>";
String UtilPage2        =
                " Utility Page</TITLE>\n"
                "\t<script type='application/javascript' SRC='http://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.3.0/Chart.bundle.js'></script>\n"
                "\t<script type='application/javascript' SRC='http://192.168.0.199/setup3'></script>\n"
                "\t<style>\n"
                        "\t\tcanvas{\n"
                                "\t\t\t-moz-user-select: none;\n"
                                "\t\t\t-webkit-user-select: none;\n"
                                "\t\t\t-ms-user-select: none;\n"
                        "\t\t}\n"
                        "\t\thtml { font-family: Helvetica; display: inline-block; margin: 0px auto;}\n"
                        "\t\tbody{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n"
                        "\t\tp {font-size: 24px;color: #444444;margin-bottom: 10px;}\n"
                "\t</style>\n"
                "\t<SCRIPT>\n\t\tfunction HP(w1){parent.window.open(w1,'_top')}\n\t</SCRIPT>\n"
        "</HEAD>\n"
        "<BODY marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" style=\"margin: 0; padding: 0;\" BGCOLOR=\"#ffffff\">\n"
        "<FORM>\n"
        "<BLOCKQUOTE><BLOCKQUOTE>\n"
        "<P><table bgcolor=\"#17A1A5\" border=\"0\" width=\"100%\" cellpadding=\"1\" style=\"font-family:Verdana;color:#ffffff;font-size:12px;\" CELLSPACING=\"2\">\n"
        "<tr><td>";
String UtilPage3        =
        " Utility Page</td></tr></table><br>\n";
String UtilPage4        =
        "<TABLE WIDTH=\"100%\" BORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">"
        "<TR>\n\t<TD WIDTH=\"25%\">&nbsp;</TD><TD WIDTH=\"20%\">&nbsp;</TD><TD WIDTH=\"55%\"><P ALIGN=CENTER><INPUT TYPE=\"button\" VALUE=\"RETURN\" onClick=\"HP('http://";
String UtilPage41       =
        "/index')\"/></TD>\n"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">FirmwareVirsion:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage5        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">MacAddress:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage6        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">IPAddress:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage7        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">SubnetMask:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage8        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">BoardTemperature:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage9        =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\">NTP受信回数:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage10       =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\" NOWRAP>Data acquisition time(Local):</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage11       =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\" NOWRAP>Operating Time:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage111     =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\" NOWRAP>Loop Time:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage112     =
        "</TD>\n"
        "</TR>"
        "<TR>\n"
                "\t<TD WIDTH=\"25%\" NOWRAP>Reset実行回数:</TD>\n"
                "\t<TD WIDTH=\"20%\"></TD>\n"
                "\t<TD WIDTH=\"55%\">";
String UtilPage12       =
        "</TD>\n"
        "</TR></TABLE></P>\n"
        "<P><center><TABLE WIDTH=\"750\" BORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"0\" HEIGHT=\"101\">\n"
                "\t<CAPTION ALIGN=\"TOP\"><P ALIGN=LEFT>GPS センテンス</CAPTION>"
                "\t<TR>\n"
                        "\t\t<TD COLSPAN=\"2\" BGCOLOR=\"#000000\">\n"
                        "\t\t<BLOCKQUOTE>\n"
                                "\t\t\t<PRE><FONT COLOR=\"#ffffff\" SIZE=\"+1\">";
String UtilPage13       =
                "</FONT></PRE>\n"
                        "\t\t</BLOCKQUOTE>"
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">ステータス:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage14       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">日時(UTC):</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage15       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">位置情報:緯度</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage16       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">位置情報:経度</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage17       =
                "</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">移動の速度:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage18       =
                "[knot]</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">移動の真方位:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage19       =
                "[度]</TD>\n"
                "\t</TR>\n"
                "\t<TR>\n"
                        "\t\t<TD WIDTH=\"150\" HEIGHT=\"20\">モード:</TD>\n"
                        "\t\t<TD WIDTH=\"600\">";
String UtilPage20       =
                "</TD>\n"
                "\t</TR>\n"
        "</TABLE></center>\n"
        "<CENTER>\n"
                "\t<div style='width:75%;'><canvas id='canvas' width='750' height='400' style='display: block; width: 750px; height: 400px;'></canvas></div>\n"
        "</CENTER></BLOCKQUOTE></BLOCKQUOTE>\n"
        "</form>\n"
        "<script>\n"
                "\tvar randomScalingFactor = function() {\n"
                        "\t\t\treturn 18 + Math.random() * 10;\n"
                        "\t\t};\n";
String UtilPage21       =
                        "\t\tvar config = {\n"
                                "\t\t\ttype: 'line',\n\t\t\tdata: {\n"
                                        "\t\t\t\tlabels: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12' , '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'],\n"
                                        "\t\t\t\tdatasets: [{\n"
                                                "\t\t\t\t\tlabel: '緯度[度]',\n"
                                                "\t\t\t\t\tdata: data_00,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.red,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tcubicInterpolationMode: 'monotone',\n"
                                                "\t\t\t\t\tyAxisID: 'y1'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '経度[度]',\n"
                                                "\t\t\t\t\tdata: data_01,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.blue,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y2'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '速度[knot]',\n"
                                                "\t\t\t\t\tdata: data_02,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.orange,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y3'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '真方位[度]',\n"
                                                "\t\t\t\t\tdata: data_03,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.yellow,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y4'\n"
                                        "\t\t\t\t}, {\n"
                                                "\t\t\t\t\tlabel: '温度[℃]',\n"
                                                "\t\t\t\t\tdata: data_04,\n"
                                                "\t\t\t\t\tborderColor: window.chartColors.grey,\n"
                                                "\t\t\t\t\tbackgroundColor: 'rgba(0, 0, 0, 0)',\n"
                                                "\t\t\t\t\tfill: false,\n"
                                                "\t\t\t\t\tyAxisID: 'y5'\n"
                                        "\t\t\t\t}]\n"
                                "\t\t\t},\n"
                                "\t\t\toptions: {\n"
                                        "\t\t\t\tresponsive: true,\n"
                                        "\t\t\t\ttitle: {\n";
String UtilPage22       =
                                                "\t\t\t\t\tdisplay: true,\n"
                                                "\t\t\t\t\ttext: '今日のGPS位置情報'\n"
                                        "\t\t\t\t},\n"
                                        "\t\t\t\tlegend: {\n"
                                                "\t\t\t\t\tdisplay: true\n"
                                                "\t\t\t\t},\n"
                                                "\t\t\t\ttooltips: {\n"
                                                        "\t\t\t\t\tenabled: true,\n"
                                                        "\t\t\t\t\tmode: 'index'\n"
                                                "\t\t\t\t},\n"
                                                "\t\t\t\tscales: {\n"
                                                        "\t\t\t\t\txAxes: [{\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '時刻 [時]'\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t}],\n"
                                                        "\t\t\t\t\tyAxes: [{\n"
                                                                "\t\t\t\t\t\tid:'y1',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.red,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '緯度[度]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.red,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: -200,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  200\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y2',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.blue,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '経度[度]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.blue,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: -200,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  200\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y3',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.orange,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '速度[knot]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.orange,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: 0,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  40\n"
                                                                "\t\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y4',\n"
                                                                "\t\t\t\t\t\tposition: 'right',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.yellow,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '真方位[度]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.yellow,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: 0,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  400\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t},{\n"
                                                                "\t\t\t\t\t\tid:'y5',\n"
                                                                "\t\t\t\t\t\tposition: 'right',\n"
                                                                "\t\t\t\t\t\tdisplay: true,\n"
                                                                "\t\t\t\t\t\tscaleLabel: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.grey,\n"
                                                                        "\t\t\t\t\t\t\tdisplay: true,\n"
                                                                        "\t\t\t\t\t\t\tlabelString: '気温[℃]'\n"
                                                                "\t\t\t\t\t\t},\n"
                                                                "\t\t\t\t\t\tticks: {\n"
                                                                        "\t\t\t\t\t\t\tfontColor: window.chartColors.grey,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMin: 10,\n"
                                                                        "\t\t\t\t\t\t\tsuggestedMax:  50\n"
                                                                "\t\t\t\t\t\t}\n"
                                                        "\t\t\t\t\t}]\n"
                                                "\t\t\t\t}\n"
                                        "\t\t\t}\n"
                                "\t\t};\n" 
                                "\t\twindow.onload = function() {\n"
                                        "\t\t\tvar ctx = document.getElementById('canvas').getContext('2d');\n"
                                        "\t\t\twindow.myLine = new Chart(ctx, config);\n"
                                "\t\t};\n"
        "</script>\n"
        "</BODY></html>";
//-------------PrintUtilPage
void PrintUtilPage( EthernetClient client){
        client.println(OK_200);
        client.print(UtilPage1);
        client.print(vers);
        client.print(UtilPage2);
        client.print(vers);
        client.print(UtilPage3);
        client.print(UtilPage4);
        client.print(IPAddressStr);
        client.print(UtilPage41);
        client.print(FVirsion);
        client.print(UtilPage5);
        client.print(MacAddressStr);
        client.print(UtilPage6);
        client.print(IPAddressStr);
        client.print(UtilPage7);
        client.print(SubnetMaskStr);
        client.print(UtilPage8);
        sprintf(buf1,"%.2f[℃]",analogReadTemp());
        client.print(buf1);
        client.print(UtilPage9);
        sprintf(buf1,"%d[回]",gNTPqueryCount);
        client.print(buf1);
        client.print(UtilPage10);
        currentTime     = now() - seventyYears;
        sprintf(DateTimeStr,"%04u/%02u/%02u %02u:%02u:%02u",year(currentTime),month(currentTime),day(currentTime),hour(currentTime),minute(currentTime),second(currentTime));
        client.print(DateTimeStr);
        client.print(UtilPage11);
        sprintf(buf1,"%d[sec]",(OperatingTime / 2));
        client.print(buf1);
        client.print(UtilPage111);
        sprintf(buf1,"%d[ミリ秒]",gLoopTime);
        client.print(buf1);
        client.print(UtilPage112);
        sprintf(buf1,"%d[回]",gResetCount);
        client.print(buf1);
        client.print(UtilPage12);
        client.print(nmea);
        if(Serial)      Serial.println(nmea);
        analsysRMC();           //RMCの要素切り出し
        client.print(UtilPage13);
        client.print(StatusStr);
        client.print(UtilPage14);
        client.print(DateTime2Str);
        client.print(UtilPage15);
        client.print(latitudeNSStr);
        client.print(latitudeStr);
        client.print(F("\t("));client.print(latitude,8);client.print(F(")"));
        client.print(UtilPage16);
        client.print(longitudeEWStr);
        client.print(longitudeStr);
        client.print(F("\t("));client.print(longitude,8);client.print(F(")"));
        client.print(UtilPage17);
        client.print(VeloStr);
        client.print(UtilPage18);
        client.print(DirStr);
        client.print(UtilPage19);
        client.print(ModeStr);
        client.print(UtilPage20);
        client.print(F("\t\tvar data_00 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][0]) ? String('\0') : String(gDayBuf[i][0],6));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_01 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][1]) ? String('\0') : String(gDayBuf[i][1],6));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_02 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][2]) ? String('\0') : String(gDayBuf[i][2],2));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(F("\t\tvar data_03 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][3]) ? String('\0') : String(gDayBuf[i][3],2));
                client.print(F(","));
        }
        client.print(F("];\n"));        
        client.print(F("\t\tvar data_04 = ["));
        for(int i = 0; i<24 ;i++){
                client.print(isnan(gDayBuf[i][4]) ? String('\0') : String(gDayBuf[i][4],2));
                client.print(F(","));
        }
        client.print(F("];\n"));
        client.print(UtilPage21);
        client.print(UtilPage22);
}
//-------------WebPageTop
void pageIntroduction( EthernetClient client){
        client.println(OK_200);
        client.print(WebTopPage1);
        client.print(bufIP);
        client.print(WebTopPage2);
        client.print(bufIP);
        client.println(WebTopPage3);
        client.stop();
}
//-------------LoadUtilsJS
void pageLoadUtilsJS( EthernetClient client){
        client.println(OK_200);
        client.println(LoadUtilsJS1);                                     //バッファサイズを考慮して3分割しています。
        client.println(LoadUtilsJS2);
        client.println(LoadUtilsJS3);
        client.stop();
}
//------------PrintResponse404
void PrintResponse404( EthernetClient client ){
        client.println(NG_404);
        client.stop();
}
//-------------タイマ割込で呼ばれるルーチン クロック表示 500msec毎
bool    TimerHandler0(struct repeating_timer *t){
        OperatingTime++;
        currentTime     =       now();
        if(Serial)      Serial.println(currentTime);
        currentTime     %=  86400;
        currentHour     = currentTime / 3600;
        currentMin      = (currentTime % 3600)/60;
        TimeDisp[0]     = currentHour/ 10;
        TimeDisp[1]     = currentHour % 10;
        TimeDisp[2]     = currentMin / 10;
        TimeDisp[3]     = currentMin % 10;
        if(fTogle1)     tm1637.point(POINT_OFF);
        else            tm1637.point(POINT_ON);
        tm1637.display(TimeDisp);
        fTogle1         = !fTogle1;
        return true;
}
//---------------------
bool processNTP() {
        //利用可能なデータがある場合は、パケットを読み取ります
        //https://blog.goo.ne.jp/hiro239415/e/c426a545863921a13a9d6a70b7ae4484
        //NTP_Packet (48Byte)
        bool    req             =       false;
        int     packetSize      =       Udp.parsePacket();
        if(packetSize){
                digitalWrite(LED_BUILTIN,HIGH);                         //要求があったときにBuiltInLEDを点灯
                miliTime                = millis() - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                sprintf(buf1,"■%d\t%d\n",packetSize,fractions);
                if(Serial)     Serial.print(buf1);
                Udp.read(packetBuffer,NTP_PACKET_SIZE);
                if(Serial){
                        for (int i =0;i<48;i++){
                                Serial.print(packetBuffer[i],HEX);
                        }
                        Serial.println();
                }
                IPAddress       Remote  = Udp.remoteIP();
                int             PortNum = Udp.remotePort();
                //受信タイムスタンプ = サーバが受け取った時刻を予めセットしておく JSTなのでGMTに変換
                timestamp               = now()         - TimeZoneSec;
                miliTime                = millis()      - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                tempval                 = timestamp;
                packetBuffer[32]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[33]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[34]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[35]        = (tempval) & 0xFF;
                //
                microVal                = fractions;
                packetBuffer[36]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[37]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[38]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[39]        = microVal & 0xFF;
                 //ヘッダーセット
                packetBuffer[0]         = 0b00100100;                           // 閏秒警告なしLI, 4:SNTPサーバ(Version), 4:サーバ(Mode)
                packetBuffer[1]         = 1 ;                                   // 1:一次基準源(GPS等)(stratum
                packetBuffer[2]         = 5 ;                                   // ポーリング64秒デフォルト値 6(64秒)->5(32秒)
                packetBuffer[3]         = 0xF6;                                 // 精度 -3(0xFD)->-10(0xF6)に変更 msec
                packetBuffer[4]         = 0;                                    // ルート遅延
                packetBuffer[5]         = 0;
                packetBuffer[6]         = 8;
                packetBuffer[7]         = 0;
                packetBuffer[8]         = 0;                                    // ルート分散
                packetBuffer[9]         = 0;
                packetBuffer[10]        = 0xC;
                packetBuffer[11]        = 0;
                //
                packetBuffer[12]        = 71;                                   //"G";   ReferenceID
                packetBuffer[13]        = 80;                                   //"P";   ReferenceID
                packetBuffer[14]        = 83;                                   //"S";   ReferenceID
                packetBuffer[15]        = 0;                                    //"0";   ReferenceID
                // リファレンス時刻をセット(現在時間)
                timestamp               = now()         - TimeZoneSec;          //UTC
                if(Serial){
                        Serial.print(timestamp);Serial.print(F(":Time synchronization Request received\n"));
                }
                tempval                 = timestamp;
                microVal                = fractions;
                packetBuffer[16]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[17]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[18]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[19]        = (tempval) & 0xFF;
                packetBuffer[20]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[21]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[22]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[23]        = microVal & 0xFF;
                //オリジナル時間をコピー(サーバに要求が届いた時間)
                packetBuffer[24]        = packetBuffer[40];
                packetBuffer[25]        = packetBuffer[41];
                packetBuffer[26]        = packetBuffer[42];
                packetBuffer[27]        = packetBuffer[43];
                packetBuffer[28]        = packetBuffer[44];
                packetBuffer[29]        = packetBuffer[45];
                packetBuffer[30]        = packetBuffer[46];
                packetBuffer[31]        = packetBuffer[47];
                //送信時刻をセット
                timestamp               = now()         - TimeZoneSec;                  //UTC
                miliTime                = millis()      - baseMilis;
                fractions               = uint32_t(float(miliTime % 1000) / unit);
                tempval                 = timestamp;
                packetBuffer[40]        = (tempval >> 24) & 0XFF;
                tempval                 = timestamp;
                packetBuffer[41]        = (tempval >> 16) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[42]        = (tempval >> 8) & 0xFF;
                tempval                 = timestamp;
                packetBuffer[43]        = (tempval) & 0xFF;
                //transmit_timestamp_fractions
                microVal                = fractions; 
                packetBuffer[44]        = (microVal >> 24) & 0xFF;
                microVal                = fractions;
                packetBuffer[45]        = (microVal >> 16) & 0xFF;
                microVal                = fractions;
                packetBuffer[46]        = (microVal >> 8) & 0xFF;
                microVal                = fractions;
                packetBuffer[47]        = microVal & 0xFF;
                //NTP要求を送信したIPアドレスとポートに応答します
                Udp.beginPacket(Remote, PortNum);
                Udp.write(packetBuffer,NTP_PACKET_SIZE);
                Udp.endPacket();
                digitalWrite(LED_BUILTIN,LOW);                                  //処理完了で消灯
                sprintf(buf1,"●%d\t%d\t%d\t%d\n",packetBuffer[20],packetBuffer[21],packetBuffer[22],packetBuffer[23]);
                if(Serial)      Serial.print(buf1);
                req     = true;
                gNTPqueryCount++;
        }
        return req;
}
//-----------------指定されたアドレスのタイムサーバーにNTP要求を送信します
void sendNTPpacket(const char * address) {
        // バッファ内のすべてのバイトを0に設定します
        memset(packetBuffer, 0, NTP_PACKET_SIZE);
        // NTP要求を形成するために必要な値を初期化します(パケットの詳細については、上記のURLを参照してください)
        packetBuffer[0]         = 0b11100011;                                   // LI, Version, Mode
        packetBuffer[1]         = 0;                                            // Stratum, or type of clock
        packetBuffer[2]         = 6;                                            // ポーリング64秒デフォルト値
        packetBuffer[3]         = 0xEC;                                         // 精度
        // ルート遅延とルート分散の場合は8バイトのゼロ
        packetBuffer[12]        = 0x31;                                         // '1'
        packetBuffer[13]        = 0x4E;                                         // 'N'
        packetBuffer[14]        = 0x31;                                         // '1'
        packetBuffer[15]        = 0x34;                                         // '4'
        //すべてのNTPフィールドに値が指定されているため、タイムスタンプを要求するパケットを送信できます。
        Udp.beginPacket(address, NTPport);                                      // NTP要求はポート123に送信されます
        Udp.write(packetBuffer, NTP_PACKET_SIZE);
        Udp.endPacket();
}
//-----------------受信したNTPパケットを解析してRTCにセットします
bool parseNTPpacket(){
        // 返信が利用可能かどうかを確認するのを待ちます
        bool result = false;
        if (Udp.parsePacket()) {
                // パケットを受信しました。そこからデータを読み取ります
                Udp.read(packetBuffer, NTP_PACKET_SIZE);                        // パケットをバッファに読み込みます
                // タイムスタンプは、受信したパケットのバイト40から始まり、4バイトです。
                unsigned long secsSince1900;
                // 位置40から始まる4バイトを長整数に変換します
                secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
                secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
                secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
                secsSince1900 |= (unsigned long)packetBuffer[43];
                Serial.print("Seconds since Jan 1 1900 = ");
                Serial.println(secsSince1900);
                // エピックタイムに変換します。(local)
                unsigned long epoch = secsSince1900 - seventyYears + TimeZoneSec;
                Serial.print("Unix time = ");
                Serial.println(epoch);
                setTime(epoch);                                                 //RTC登録(LocalTime)
                result =  true;
        }else{
                result =  false;
        }
        return result;
}
//---------------NTP since 1900/01/01 retouch2020/12/25
static unsigned long int numberOfSecondsSince1900Epoch(uint16_t y, uint8_t m, uint8_t d, uint8_t h, uint8_t mm, uint8_t s,float timezone) {
        //2036年問題が存在する。unsigned long intの桁溢れが発生
        //桁溢れが発生したら受信側が対応する必要がある。サーバ側では64bit化するべきだが動かなくなる。
        //timezoneをfloat扱いにした
        int leapAdjustment = 0;
        if (y >= 1970) {
                y -= 1970;
                leapAdjustment  = 2;                            // LM:1970年はうるう年ではありませんでした!
        }
        uint16_t days = d;
        for (uint8_t i = 1; i < m; ++i)         days += pgm_read_byte(daysInMonth + i -1);
/*
        if (m > 2 && y % 4 == 0)                ++days;
*/
        if (m > 2 && (y + leapAdjustment) % 4 == 0)     ++days; // LM: Weak but okay for the present
        days += 365 * y + (y + 3) / 4 - 1;
        long offsetTime = long((float(h)+ timezone) * 3600.0);
        return days*24L*3600L + offsetTime + mm*60L + s + seventyYears;
}
//------------------
bool readSensor(void){
        if (Serial1.available()) {
                Serial1.readStringUntil('\n');                                  //読み捨てて先頭から読めるようにする
                nmea = Serial1.readStringUntil('\n');
                if(Serial)      Serial.println(nmea);
                //$GNRMC,022757.000,A,3430.62587,N,13316.66175,E,0.63,144.24,231220,,,A,V*02
                String  nmeames = nmea.substring(3,6);                          // $GP***
                int     count   = 0;
                while(!nmeames.equals(chkHader)){
                       nmea     = Serial1.readStringUntil('\n');
                       nmeames  = nmea.substring(3,6);                          // $GP***
                       if(Serial){
                                //Serial.print(nmea);Serial.print(F("\t"));Serial.println(nmeames);
                       }
                        if(count++ > 30)    break;
                }
                int     nextPos = 0;
                if ( nmeames.equals(chkHader)){                                 // get UTC
                        nextPos         = nmea.indexOf(DELIMITER);              //int indexOf(char ch, unsigned int fromIndex) const;
                        String shh      = nmea.substring(nextPos+1,nextPos+3);
                        String smm      = nmea.substring(nextPos+3,nextPos+5);
                        String sss      = nmea.substring(nextPos+5,nextPos+7);
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip UTC
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip Status
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 緯度
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 北緯か南緯か
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 経度
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 東経か西経か
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 地表における移動の速度[knot]
                        nextPos         = nmea.indexOf(DELIMITER,nextPos+1);    //skip 地表における移動の真方位[deg]
                        String sdd      = nmea.substring(nextPos+1,nextPos+3);
                        String smn      = nmea.substring(nextPos+3,nextPos+5);
                        String syy      = nmea.substring(nextPos+5,nextPos+7);
                        if(Serial)      Serial.println("20" + syy + smn + sdd + shh + smm + sss);
                        chYear          = syy.toInt() + 2000;
                        if ((chYear < 2001) || (chYear > 2079)){                //2001~2079をサポート
                                return false;
                        }else{
                                gpsTime =       numberOfSecondsSince1900Epoch(chYear,smn.toInt(),sdd.toInt(),shh.toInt(),smm.toInt(),sss.toInt(),timezone);
                                return true;
                        }
                }else{
                        return false;
                }
        }
        return false;
}
//------------------GPSにアクセスし、取得に成功したら内部時間を更新
bool ReadGPS(){
        bool valid      = false;
        if(readSensor()) {
                nowH    = now() / 3600;                         //内部時計はLocalTime
                if(nowH > preH){                                //1時間毎にRTCを更新する
                        preH    = nowH;
                        setTime(gpsTime);
                }
                valid      = true;
        }else{
                delay(100); 
                if(gLoopCount%60)       Serial.print(F("."));
                else                    Serial.println(F("."));
        }
        return valid;
}
//----------------- RMC文字列を解析してクラスタRMCにセットする
void    analsysRMC(void){
        //$GPRMC,021227.000,A,3459.9060,N,13652.6560,E,0.09,344.80,241220,,,A*6D
        //$GNRMC,072815.000,V,         , ,          , ,    ,      ,241220,,,N,V*27
        //RMCは要素数が固定されていないようなので注意が必要
        int     stPosi = 0;
        int     endPosi;
        char    State;
        //センテンス
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                setenceStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("setenceStr="));Serial.println(setenceStr);
        }
        stPosi  =       endPosi+1;
        //測位時刻(UTC時分秒)        UTC時刻:09時24分03秒307
        endPosi =       nmea.indexOf(',',stPosi);
        Serial.print(F("endPosi="));Serial.println(endPosi);
        if(!(endPosi<0)){
                TimeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("TimeStr="));Serial.println(TimeStr);
        }
        stPosi  =       endPosi+1;
        //測位状態 A:単独測位中またはDGPS測位中 V:未測位    単独測位中/DGPS測位中
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                StatusStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("StatusStr="));Serial.println(StatusStr);
        }
        stPosi  =       endPosi+1;
        //緯度。dddmm.mmmm (10進)     緯度 43.07328
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                latitudeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("latitudeStr="));Serial.println(latitudeStr);
        }
        stPosi  =       endPosi+1;
        //N:北緯、S:南緯       北緯
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                latitudeNSStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("latitudeNSStr="));Serial.println(latitudeNSStr);
        }
        stPosi  =       endPosi+1;
        //経度。dddmm.mmmm (10進)     経度 141.270980
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                longitudeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("longitudeStr="));Serial.println(longitudeStr);
        }
        stPosi  =       endPosi+1;
        //E:東経、W:西経       東経
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                longitudeEWStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("longitudeEWStr="));Serial.println(longitudeEWStr);
        }
        stPosi  =       endPosi+1;
        //速度(000.0〜270.0、単位:ノット)  速度 0 Knot
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                VeloStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("VeloStr="));Serial.println(VeloStr);
        }
        stPosi  =       endPosi+1;
        //真方位による進行方向(000.0〜359.9、単位:度)    240.3度
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                DirStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("DirStr="));Serial.println(DirStr);
        }
        stPosi  =       endPosi+1;
        //ddmmyy 日付(日、月、年)        日付 2017年7月15日
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                DateStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("DateStr="));Serial.println(DateStr);
        }
        stPosi  =       endPosi+1;
        //磁気偏差(000.0〜180.0、単位:度)  0(なし)
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                MagDegStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("MagDegStr="));Serial.println(MagDegStr);
        }
        stPosi  =       endPosi+1;
        //磁気偏差 E:磁気偏差が東より W:磁気偏差が西より      なし
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                MagDevStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("MagDevStr="));Serial.println(MagDevStr);
        }
        stPosi  =       endPosi+1;
        //測位mode N:未測位 A:単独測位 D:DGPS測位
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                ModeStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("ModeStr="));Serial.println(ModeStr);
        }else{
                ModeStr = nmea.substring(stPosi,stPosi+1);
                Serial.print(F("ModeStr="));Serial.println(ModeStr);
        }
        stPosi  =       endPosi+1;
        //ナビゲーション状態 S:Safe C:Caution U:Unsafe V:無効(RAIM 機能 OFF)
        endPosi =       nmea.indexOf(',',stPosi);
        if(!(endPosi<0)){
                NavStr = nmea.substring(stPosi,endPosi);
                Serial.print(F("NavStr="));Serial.println(NavStr);
        }else{
                NavStr = nmea.substring(stPosi,stPosi+1);
                Serial.print(F("NavStr="));Serial.println(NavStr);
        }
        Status = StatusStr.charAt(0);
        switch(Status){
                case 'A':
                        StatusStr = "A = 有効";
                        //digitalWrite(LED1, LOW);
                        break;
                case 'V':
                        StatusStr = "V = 警告";
                        //digitalWrite(LED1, HIGH);
                        break;
                default:
                        StatusStr = "";
                        //digitalWrite(LED1, HIGH);
                        break;        
        }
        DateTime2Str = "20" + DateStr.substring(4,6) + "年" + DateStr.substring(2,4) + "月" + DateStr.substring(0,2) + "日 " + TimeStr.substring(0,2) + "時" + TimeStr.substring(2,4) + "分" + TimeStr.substring(4,6) + "秒" + TimeStr.substring(7,10);
        State = latitudeNSStr.charAt(0);
        switch(State){
                case 'N':
                        latitudeNSStr = "北緯 ";
                        break;
                case 'S':
                        latitudeNSStr = "南緯 ";
                        break;
                default:
                        latitudeNSStr = "";
                        break;        
        }
        stPosi  = 0;
        endPosi = latitudeStr.indexOf('.',stPosi);
        if(endPosi>0){
                String latitudeStr1     = latitudeStr.substring(stPosi,endPosi-2);
                String latitudeStr2     = latitudeStr.substring(endPosi-2,endPosi);
                String latitudeStr3     = "." + latitudeStr.substring(endPosi+1);
                latitude        = latitudeStr1.toFloat() + (latitudeStr2.toFloat()/60.0) + (latitudeStr3.toFloat()/60.0);
                if(State == 'S')        latitude = -latitude;
                latitudeStr     = latitudeStr1 + "度" + latitudeStr2 + "分" + latitudeStr3;
        }
        State = longitudeEWStr.charAt(0);
        switch(State){
                case 'E':
                        longitudeEWStr = "東経 ";
                        break;
                case 'W':
                        longitudeEWStr = "西経 ";
                        break;
                default:
                        longitudeEWStr = "";
                        break;        
        }
        stPosi  = 0;
        endPosi = longitudeStr.indexOf('.',stPosi);
        if(endPosi>0){
                String longitudeStr1     = longitudeStr.substring(stPosi,endPosi-2);
                String longitudeStr2     = longitudeStr.substring(endPosi-2,endPosi);
                String longitudeStr3     = "." + longitudeStr.substring(endPosi+1);
                longitude        = longitudeStr1.toFloat() + (longitudeStr2.toFloat()/60.0) + (longitudeStr3.toFloat()/60.0);
                if(State == 'W')        longitude = -longitude;
                longitudeStr     = longitudeStr1 + "度" + longitudeStr2 + "分" + longitudeStr3;
        }        
        State = ModeStr.charAt(0);
        switch(State){
                case 'N':
                        ModeStr = "N = データなし";
                        break;
                case 'A':
                        ModeStr = "A = Autonomous(自律方式)";
                        break;
                case 'D':
                        ModeStr = "D = Differential(干渉測位方式)";
                        break;
                case 'E':
                        ModeStr = "E = Estimated(推定)";
                        break;
                case 'M':
                        ModeStr = "M = マニュアル入力";
                        break;
                case 'S':
                        ModeStr = "S = シミュレーター入力";
                        break;
                default:
                        ModeStr = State;
                        break;        
        }
        gRmc.UTC        =       timestamp;
        gRmc.LAT        =       long(latitude         * 10000.0);
        gRmc.LON        =       long(longitude        * 10000.0);
        gRmc.SPD        =       int(VeloStr.toFloat() * 100.0);
        gRmc.DIR        =       int(DirStr.toFloat()  * 100.0);
}
//-----------------
int     getHourTime(void){
        return (now() % 86400) / 3600;
}
//-----------------
void setup() {
        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(pin)を使用してCSピンを設定できます
        //Ethernet.init(10);                                                    // Most Arduino shields
        Ethernet.init(SPI_CS);                                                  //
        //Ethernet.init(0);                                                     // Teensy 2.0
        //Ethernet.init(20);                                                    // Teensy++ 2.0
        //Ethernet.init(15);                                                    // ESP8266 with Adafruit Featherwing Ethernet
        //Ethernet.init(33);                                                    // ESP32 with Adafruit Featherwing Ethernet
        //シリアル通信を開き、ポートが開くのを待ちます。
        Serial.begin(115200);
        //while(!Serial);
        //GPS用にUART0 を使用
        Serial1.setRX(1);
        Serial1.setTX(0);
        Serial1.begin(9600);
        /*
        while (!Serial) {
                ; // シリアルポートが接続するのを待ちます。 ネイティブUSBポートにのみ必要
                //シリアルモニタを開かないと先に進まないので注意が必要
        }
        */
        // start Ethernet and UDP
        LANSetup();
        Ethernet.begin(mac,ip);                                         //FIXIP サンプルスケッチはDHCPでした
        sprintf(buf1,"%d.%d.%d.%d",ip[0],ip[1],ip[2],ip[3]);
        bufIP = buf1;
        if(Serial){
                Serial.print(F("server is at "));Serial.println(Ethernet.localIP());
        }
        Udp.begin(NTPport);
        webServer.begin();
        //最初にNTPサーバから時刻を取得する
        sendNTPpacket(timeServer);                                      // NTPパケットをタイムサーバーに送信します
        delay(1000); 
        gRTCOK = parseNTPpacket();
        tm1637.init();
        tm1637.set(BRIGHT_TYPICAL);                                     //BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
        for(int i = 0;i<24;i++){
                for(int j = 0;j<5;j++){
                        gDayBuf[i][j] = NAN;
                }
        }
        //マイクロ秒単位の間隔
        if (ITimer0.attachInterruptInterval(TIMER0_INTERVAL_MS * 500, TimerHandler0)){
                if(Serial){
                        Serial.print(F("Starting ITimer0 OK, millis() = ")); Serial.println(millis());
                }
        }else{
                if(Serial){
                        Serial.println(F("Can't set ITimer0. Select another freq. or timer"));
                }
        }
        watchdog_reboot(0,0,delay_ms);
        gPreTime        =       millis();
        if(Serial)      Serial.println(F("EndSetup"));
}
//-----------------
int     preSet      = -1;
void loop() {
        //1秒のループ WDT8秒
        if (watchdog_caused_reboot()){
                if(Serial)    Serial.print("Rebooted by Watchdog!\n");
        }else{
                if(Serial)    Serial.print("Clean boot\n");
        }
        watchdog_update();
        bool    valid   = ReadGPS();                                            //GPSセンテンス読込
        int     h       = getHourTime();                                        //返値0-23
        if(!gRTCOK && (Status == 'A')){
                setTime(gpsTime);
                gRTCOK = true;
        }
        if(Serial){
                Serial.print("preH=");Serial.println(preSet);
                Serial.print("h=");Serial.println(h);
                Serial.print("Status=");Serial.println(Status);
        }
        if((Status == 'A') && (preSet != h)){
                //1時間おきに時刻を確認し、データをメモリに確保
                analsysRMC();
                preSet  = h;
                gDayBuf[h][0]   =       float(gRmc.LAT) / 10000.0;
                gDayBuf[h][1]   =       float(gRmc.LON) / 10000.0;
                gDayBuf[h][2]   =       float(gRmc.SPD) / 100.0;
                gDayBuf[h][3]   =       float(gRmc.DIR) / 100.0;
                gDayBuf[h][4]   =       analogReadTemp();
                //次回分のデータをNULL化
                h = (h+1) % 24;
                gDayBuf[h][0]   =       NAN;
                gDayBuf[h][1]   =       NAN;
                gDayBuf[h][2]   =       NAN;
                gDayBuf[h][3]   =       NAN;
                gDayBuf[h][4]   =       NAN;
                if(Serial)      Serial.print("DataSet");
        }
        LinkStatus      = Ethernet.linkStatus();
        if(Serial)      Serial.print("linkStatus:");
        switch (LinkStatus){
                case LinkON:
                        Serial.println("LinkON");
                        break;
                case LinkOFF:
                        Serial.println("LinkOFF");
                        if(Serial)      Serial.print("Reboot");
                        delay(1000);
                        watchdog_reboot(0,0,1);
                        break;
                case Unknown:
                default:
                        Serial.println("Unknown");
                        break;
        }
        gHardwareStatus  = Ethernet.hardwareStatus();
        if(Serial)      Serial.print("hardwareStatus:");        Serial.println(gHardwareStatus);
        if(gHardwareStatus == EthernetNoHardware)     watchdog_reboot(0,0,1);
        bool req        = processNTP();                                 //NTP要求確認
        client          = webServer.available();                        //HTTP要求確認
        if(client)      checkWebPage(client);
        client.stop();
        
        digitalWrite(LED_BUILTIN, fTogle2);
        fTogle2  = !fTogle2;
        gLoopCount++;
        if(Serial)      Serial.println(gLoopCount);
        gNowTime        = millis();
        gLoopTime       = gNowTime - gPreTime;
        gPreTime        = gNowTime;
}

※ちょっとバグがあります。
[return]を一回押しても更新されません。2回目を押してTOPページに更新されます。文字解析の仕組みに問題がありそうです。解決策が見つかり次第コード更新します


戯言(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社の登録商標です。
その他の企業名ならびに製品名は、それぞれの会社の商標もしくは登録商標です。
すべての商標および登録商標は、それぞれの所有者に帰属します。