最終更新日:2022/12/26
Pico版GPSNTPサーバの基本的な動作確認が出来ましたので、GPSモジュールをM5Stack用GPSユニット(5694)に置き換え極力スマートな形態で実現したいと思います。
M5Stack用GPSユニット自体は出荷時状態のまま電源を与えれば、センテンスを取得することが可能になります。まずは購入時のまま電源投入で使う事を想定してコーディングしてみました。
実際に定期的に取得出来るセンテンスは以下の通りです。
14:07:47.818 -> $GNGGA,050750.000,,,,,0,00,25.5,,,,,,*7D 14:07:47.852 -> $GNGLL,,,,,050750.000,V,N*63 14:07:47.886 -> $GPGSA,A,1,,,,,,,,,,,,,25.5,25.5,25.5*02 14:07:47.920 -> $BDGSA,A,1,,,,,,,,,,,,,25.5,25.5,25.5*13 14:07:47.988 -> $GPGSV,1,1,01,29,,,24*75 14:07:47.988 -> $BDGSV,1,1,00*68 14:07:48.022 -> $GNRMC,050750.000,V,,,,,,,190722,,,N*5B 14:07:48.055 -> $GNVTG,,,,,,,,,N*2E 14:07:48.089 -> $GNZDA,050750.000,19,07,2022,00,00*42 14:07:48.123 -> $GPTXT,01,01,01,ANTENNA OPEN*25$GxRMCをピックアップして解析しています。
このGPSユニットはちょっと消費電流が大きいみたいです。
/* * 2022年5月30日 T.Wanibe * 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バイトのフラッシュメモリのうち、スケッチが106728バイト(5%)を使っています。 * 最大262144バイトのRAMのうち、グローバル変数が14072バイト(5%)を使っていて、ローカル変数で248072バイト使うことができます。 */ #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.5" uint32_t delay_ms = 8000; //8秒 最大8.3秒 const char FVirsion[] = "2.5.5.5"; 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(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" "\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(){ // 返信が利用可能かどうかを確認するのを待ちます 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; } |
GPSユニットの設定変更したい場合ですが、PCと接続して変更した方が楽ですね。世の中にはAT6558用のツールも存在するようです。
ドキュメント:https://docs.m5stack.com/#/en/unit/gps リンク切れか?
ライブラリ:https://github.com/m5stack/M5Stack/tree/master/examples/Unit/GPS_AT6558 ESP32環境でないとそのままは使えないです。
免責事項
本ソフトウエアは、あなたに対して何も保証しません。本ソフトウエアの関係者(他の利用者も含む)は、あなたに対して一切責任を負いません。
あなたが、本ソフトウエアを利用(コンパイル後の再利用など全てを含む)する場合は、自己責任で行う必要があります。本ソフトウエアの著作権は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社の登録商標です。
その他の企業名ならびに製品名は、それぞれの会社の商標もしくは登録商標です。
すべての商標および登録商標は、それぞれの所有者に帰属します。