hattori&ide

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Loggermain.cpp Source File

Loggermain.cpp

00001 /*更新情報
00002  * 2016/01/20
00003  * LCD表示 現在時刻から経過時間へ変更
00004  * LCD表示 単位記号の位置変更
00005  *
00006  * 2016/01/29
00007  * postアドレス変更 TEST→myLogger
00008  *
00009  * 2016/01/30
00010  * サーバー送信データ変更,末尾にデータ取得時間追加
00011  *
00012  * 2016/02/08
00013  * 配列の要素数をconst定数化
00014  * LapUSBSaveDataのcsvデータがおかしかったので修正
00015  * ラップをラップタイムが3分30秒以内の場合は加算しないように修正
00016  * CalculateSet関数を分割
00017  *
00018  * 2016/02/22
00019  * 初期化ルーチンを関数に分割
00020  * GPS対応
00021  * データバックアップ,引き継ぎ機能追加,ファイル名を日付に変更
00022  *
00023  * 2016/02/24
00024  * エラー処理追加, メンテナンス
00025  *
00026  * 2016/04~
00027  * タイマー処理測定→http送信による遅延を無害化
00028  * 加速度センサデータ保存、モーター回転数から速度算出
00029  *
00030  * 2016/04/24
00031  * ラップスイッチ ピン変化割り込み化
00032  * 配列過剰書き込み 対策済み
00033 
00034  * 2016/05/11
00035  * ファイル名変更 日付/各データ(ファイル構造化)
00036  * GPSセンテンス保存 走行ラインGoogle Earth等で閲覧可
00037  *
00038  * 2016/06/01
00039  * スタート前時,積算しないように設定(関数の引数で変更可)
00040  *
00041  * 2016/06/10
00042  * INA226設定レジスタ変更
00043  * wait変更
00044  *
00045  * 2016/06/15
00046  * MITSUBA CANデータ対応 回転数データ取得
00047  *
00048  * 2016/07/03
00049  * INA226 異常データ対策
00050  * 絶縁監視(漏れ電流)エラー出力機能追加
00051  *
00052  * 2016/07/11
00053  * DriverEmergency機能追加
00054  *
00055  * 2016/07/17
00056  * Web送信データ変更 平均→積算
00057  * LAP送信データ追加 コントロールライン通過時刻
00058  *
00059  * 2016/07/25
00060  * Webデータ送信 桁数一部変更
00061  * CalculateSet関数修正
00062  *
00063  * 2016/08/02
00064  * ReadyStartLCD()にGPSがfixしたらGPS OKと表示するようにした
00065  *
00066  * 2017/08/02
00067  * INA226 測定平均回数 16 → 128
00068  * 2017/08/05 12:00:00自動スタート
00069  *
00070  * 2021/07/10
00071  * バッテリー容量を3.6 * 3.35 * 30 * 14から3.6 * 3.45 * 26 * 16 に変更
00072  *
00073  */
00074 
00075 #include "mbed.h"
00076 #include "INA226.hpp"
00077 #include "TextOLED.h"
00078 #include "MSCFileSystem.h"
00079 #include "EthernetNetIf.h"
00080 #include "TCPSocket.h"
00081 #include "TinyHTTP.h"
00082 #include "NTPClient.h"
00083 #include "RTC.h"
00084 #include "MBed_Adafruit_GPS.h"
00085 #include "MITSUBA_CAN.h"
00086 //#include "MMA8652.h"
00087 
00088 // INA226用I2Cアドレス I2Cアドレスはmbedの場合1ビット左シフトしたアドレスになる
00089 const int batteryMonitorAddress = 0x80;         // 0b10000000 (GG)
00090 const int panelMonitorAddress = 0x82;           // 0b10000010 (G1)
00091 const int motorMonitorAddress = 0x9E;           // 0b10011110 (CC)
00092 const unsigned short configuration = 0x4897;    // 平均化処理やタイミング
00093 
00094 /*------------------------------設定変更厳禁------------------------------*/
00095 const double voltageCalibration =  10 / 1.1;          // 分圧比(10倍に補正)
00096 const unsigned short calibration = 0x1400;      // シャント電圧補正係数
00097 const unsigned short calibrationPanel = 0x2800; // シャント電圧補正係数(パネル)
00098 const double currentCalibration[] = {1.5, 0.5, 1.5};
00099 // [0]: バッテリ [1]: パネル [2]: モータ
00100 /*------------------------------設定変更厳禁------------------------------*/
00101 
00102 const double batteryCapacity = 3.6 * 3.45 * 26 * 16;       // 公称電圧*電流容量*直列数*並列数←2021鈴鹿仕様に変更
00103 
00104 const int offsetTime = 60 * 60 * 9;     // 9時間(標準時との時差) = 日本時間
00105 const int storageTime = 8;              // 8秒ごとにサーバーへ送信 10秒はサイズ的に厳しい
00106 const int storageOffset = 5;            // 5秒間分余分に配列を用意しておく
00107 const int lapTime_limit = 60 * 4;       // LAPタイム 4分00秒以内はキャンセル
00108 const double kmph = 1.852;              // 1ノット = 1.852 km/h
00109 const double pulseConvert = 0.1303;     // 車速パルス -> 速度変換係数
00110 const double rpmConvert = 0.104399;       // rpm -> km/h 変換係数
00111 
00112 /*各配列要素数*/
00113 const int RealtimeData_i = 3;
00114 const int RealtimeData_j = 5;
00115 const int LapoutData_i = 3;
00116 const int LapoutData_j = 3;
00117 const int timeStr_i = 6;
00118 const int preLapdata_i = 3;
00119 const int preLapdata_j = 2;
00120 
00121 // バッファーサイズ
00122 const int RequestStr_maxsize = 1210;   // 1600とかでは送信できない メモリ破壊?
00123 const int LapRequestStr_maxsize = 110;
00124 const int SerialSendStr_maxsize = 200;
00125 const int timeStr_maxsize = 32;
00126 const int fileName_maxsize = 32;
00127 
00128 Serial debug(USBTX, USBRX);
00129 Serial Xbee(p13, p14);
00130 Serial gpsSerial(p28, p27);
00131 Adafruit_GPS myGPS(&gpsSerial);
00132 
00133 CAN mitsuba_can(p30, p29);
00134 MITSUBA canlog(mitsuba_can, 250000);
00135 //MMA8652 acc(p9, p10);  // sda, scl
00136 
00137 DigitalOut sublogger_sec(p24);
00138 DigitalOut sublogger_min(p25);
00139 // 引数は(rs,e,d4,d5,d6,d7) 接続しないピンはGNDに落としておくと安定する
00140 TextOLED lcd(p15, p16, p17, p18, p19, p20, TextOLED::LCD20x4);
00141 
00142 I2C i2c(p9, p10);  // sda, scl
00143 INA226 BatteryMonitor(i2c, batteryMonitorAddress, 10000);
00144 INA226 PanelMonitor(i2c, panelMonitorAddress, 10000);
00145 INA226 MotorMonitor(i2c, motorMonitorAddress, 10000);
00146 
00147 MSCFileSystem msc("usb");  // USBメモリには/usb/...でアクセス
00148 
00149 EthernetNetIf eth;
00150 NTPClient ntp;
00151 
00152 DigitalOut isoError(p6);         // 絶縁監視エラー出力
00153 
00154 InterruptIn lapSw(p7);          // lapスイッチ  ON: 0, OFF:1
00155 InterruptIn motorPulse(p12);    // モーターパルス
00156 
00157 struct LogData {
00158   char timeStr[timeStr_i][timeStr_maxsize];
00159   /* [0]:タイムスタンプ    20160801121356
00160      [1]:現在時刻          12:13:56
00161      [2]:経過時間          00:13:56
00162      [3]:カウント用        00:01:30
00163      [4]:LCD用ラップタイム 05:15
00164      [5]:通過時刻          12:05:00*/
00165   unsigned int lap;                                    // ラップ数
00166   unsigned int lapTime;                                // ラップタイム
00167   int totalTime;                              // 経過時間
00168   double RealtimeData[RealtimeData_i][RealtimeData_j]; // 1秒毎の測定データ
00169   double LapoutData[LapoutData_i][LapoutData_j];       // ラップ平均等
00170   double batteryVoltage;              // バッテリー電圧
00171   double remainBatteryParcent;        // バッテリー残量[%]
00172   double remainBatteryWh;             // バッテリー残量[Wh]
00173   double motorSpeed;                  // モーター速度[km/h] CAN
00174   double motorSpeed_pulse;            // モーター速度[km/h] パルス
00175   double motorAngle;
00176   double gpsSpeed;                    // GPS速度[km/h]
00177   // float accData[3];                // 3軸加速度 0:x, 1:y, 2:z[何Gか]
00178   double latitude;                    // 緯度
00179   double longitude;                   // 経度
00180 };
00181 
00182 // グローバル変数
00183 bool secTimer = false;
00184 bool lapSave = false;
00185 bool lapSave_forsub=false;
00186 bool emergency = false;
00187 time_t startUnixTime = 0;
00188 struct LogData logdata = {0};
00189 struct LogData Postdata[storageTime + storageOffset] = {0}; // storageTimeかつかつはまずい?
00190 unsigned int postcount = 0;                                 // logdataを貯める時間をカウント
00191 unsigned int lapTimeValue = 0;                              // スイッチ判定用のラップタイム
00192 unsigned int pulseCount = 0;                                // 車速パルスカウント
00193 time_t prelapUnixTime = 0;                                  // 前のラップタイムのUNIXタイム
00194 double preLapdata[preLapdata_i][preLapdata_j] = {0};        // 前のラップデータ
00195 
00196 // プロトタイプ宣言
00197 void SetTimer(void);
00198 void MainFuncTimer(void);
00199 void SwFuncInterrupt(void);
00200 void MotorPulseCount(void);
00201 void print(const char *str, int row, int col);
00202 int SetupINA226(void);
00203 int SetupEthernet(void);
00204 int SetupUSB(struct LogData *data, char name[][fileName_maxsize]);
00205 int ReadBackup(struct LogData *data, double predata[][preLapdata_j], time_t *preTime);
00206 int FetchGPSdata(const char name[][fileName_maxsize]);
00207 void CalculateSet(struct LogData *data, bool run);
00208 unsigned int CalculateTimeSet(struct LogData *data, time_t preTime);
00209 void LapCalculateSet(struct LogData *data, double predata[][preLapdata_j], time_t *preTime);
00210 int httpPost(const struct LogData postdata[], int *httpRes);
00211 void LaphttpPost(const struct LogData *data, int *httpRes);
00212 void EmergencyhttpPost(const struct LogData *data);
00213 void LCD(const struct LogData *data);
00214 void ReadyStartLCD(const struct LogData *data);
00215 int USBSaveData(const struct LogData postdata[], const char name[][fileName_maxsize]);
00216 int LapUSBSaveData(const struct LogData *data, const char name[][fileName_maxsize]);
00217 int SaveBackup(const struct LogData *data, const double predata[][preLapdata_j], time_t preTime);
00218 void XbeeSerial(const struct LogData *data);
00219 void InsulateMonitor(const struct LogData *data);
00220 
00221 int main(){
00222   int httpResponce = 0;                       // httpリクエスト送信時のレスポンス
00223   int LaphttpResponce = 0;
00224   char fileName[3][fileName_maxsize] = {0};   // USBファイル名  [0]:LOG, [1]:LAP, [2]:GPS
00225 
00226   debug.baud(9600);
00227   Xbee.baud(57600);  // 安心と信頼()の57600bps
00228   myGPS.begin(9600);
00229   myGPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
00230   myGPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
00231   myGPS.sendCommand(PGCMD_ANTENNA);
00232 
00233   lcd.cls();
00234 
00235 sublogger_sec=0;
00236 sublogger_min=0;
00237 
00238   // エラー時は自動的にリセット
00239 
00240   if(SetupINA226()) {
00241     NVIC_SystemReset();
00242     return -1;
00243   }
00244 
00245   if(SetupEthernet()) {
00246     NVIC_SystemReset();
00247     return -1;
00248   }
00249 
00250   // Host server(IpAddr(), 123, "ntp.jst.mfeed.ad.jp");  // NTP時刻取得 調子悪い?
00251   Host server(IpAddr(), 123, "ntp.nict.jp");
00252   ntp.setTime(server);       // RTCにセット
00253 
00254   if(SetupUSB(&logdata, fileName)) {
00255     NVIC_SystemReset();
00256     return -1;
00257   }
00258 
00259   wait(1.0);
00260   lcd.cls();
00261 
00262   RTC::attach(&SetTimer, RTC::Second);       // SetTimer()を1秒毎に実行する
00263 
00264   // スタート前ループ
00265   // 初回起動時 backup.csvが存在していないときのみ実行
00266   if(ReadBackup(&logdata, preLapdata, &prelapUnixTime)) {
00267     while(1) {
00268       if(!lapSw || time(NULL) == 1564801200) {  // 2019/8/3/12:00:00 自動スタート←2年前になってたかも
00269         startUnixTime = time(NULL) + offsetTime+600;    // スタート時刻取得
00270         break;
00271       }
00272       if(secTimer) {
00273         CalculateTimeSet(&logdata, prelapUnixTime);
00274         CalculateSet(&logdata, false);
00275         ReadyStartLCD(&logdata);
00276         InsulateMonitor(&logdata);
00277         secTimer = false;
00278       }
00279     }
00280   }
00281   /*
00282      else {
00283      // NTP時刻が異常な時(スタートから5時間以上) 自動的にリセット
00284      if(labs(startUnixTime - (time(NULL) + offsetTime)) > 5 * 3600) {
00285       print("NTP Time isoError\n", 0, 0);
00286       RTC::detach(RTC::Second);
00287       NVIC_SystemReset();
00288       return -1;
00289      }
00290      }
00291    */
00292   lapSw.fall(&SwFuncInterrupt);          // ピン立ち下がり割り込みに設定
00293   motorPulse.fall(&MotorPulseCount);
00294 
00295   RTC::detach(RTC::Second);
00296   lcd.cls();
00297   wait(0.5);       // lapSwが0になるのを待つ
00298 
00299   RTC::attach(&MainFuncTimer, RTC::Second);  // MainFuncTimerを1秒ごとに実行
00300 
00301 // メインループ
00302   while(1) {
00303     FetchGPSdata(fileName);  // GPSセンテンス取得・解析
00304     if(emergency) {
00305       EmergencyhttpPost(&logdata);
00306       emergency = false;
00307     }
00308     if(lapSave) {
00309       LaphttpPost(&logdata, &LaphttpResponce);                 // LAPデータ送信
00310       LapUSBSaveData(&logdata, fileName);
00311       lapSave = false;
00312     }
00313     if(secTimer) {                                                // fopen関連は割り込みで実行できない
00314       SaveBackup(&logdata, preLapdata, prelapUnixTime);           // バックアップ
00315       secTimer = false;
00316     }
00317     if(postcount >= storageTime) {                 // storageTime個のデータが集まったら
00318       postcount = 0;
00319       USBSaveData(Postdata, fileName);             // USBにデータ保存
00320       httpPost(Postdata, &httpResponce);
00321       // debug.printf("\n%d\n", httpResponce);
00322     }
00323   }
00324 }
00325 
00326 /*--------------------------割り込み実行の関数 ここから-------------------------------*/
00327 // RTCタイマーで1秒ごとに実行(スタート前)
00328 void SetTimer(){
00329   secTimer = true;
00330 }
00331 
00332 // RTCタイマーで1秒ごとに実行(走行時)
00333 void MainFuncTimer(){
00334   secTimer = true;
00335   canlog.GetCanData(FRAME0);  // FRAME0のデータを取得
00336   lapTimeValue = CalculateTimeSet(&logdata, prelapUnixTime);  // 時間に関するデータを計算
00337   CalculateSet(&logdata, true);                               // データ取得・計算し,格納
00338   LCD(&logdata);                                              // LCDにデータ表示
00339   Postdata[postcount++] = logdata;                            // 蓄積
00340   if(postcount >= storageTime + storageOffset) {              // 配列上限超えると強制リセット
00341     postcount = 0;
00342   }
00343   InsulateMonitor(&logdata);
00344 }
00345 
00346 // スイッチ割り込み
00347 // lapTime_limit未満は緊急スイッチとして動作→非表示に(2019.8.1)
00348 void SwFuncInterrupt(){
00349   if(lapTimeValue >= lapTime_limit) {
00350     LapCalculateSet(&logdata, preLapdata, &prelapUnixTime);  // LAPデータ計算
00351     XbeeSerial(&logdata);                                    // LAPデータをxbeeで送信
00352     lapSave = true;                                          // Web 送信,USB保存のフラグ
00353     lapSave_forsub=true;
00354   }
00355   else{
00356     //lcd.cls();
00357     //print("Driver Emergency", 2, 1);
00358     wait(1.0);
00359     lcd.cls();
00360     emergency = true;      // 緊急スイッチ,web送信フラグ
00361   }
00362 }
00363 
00364 void MotorPulseCount(){
00365   pulseCount++;    // ストリーム等でデバックすると遅延で正確にパルス数を測定できない
00366 }
00367 
00368 /*--------------------------割り込み実行の関数 ここまで-------------------------------*/
00369 
00370 /*-------------------------------ユーザー定義関数-------------------------------------*/
00371 
00372 /** 全てのストリーム系に文字列を出力
00373  * @param const char *str 送信文字列
00374  * @param int row 列
00375  * @param int col 行
00376  */
00377 void print(const char *str, int row, int col){
00378   debug.printf("%s", str);
00379   Xbee.printf("%s", str);
00380   lcd.locate(row, col);
00381   lcd.printf("%s", str);
00382 }
00383 
00384 /** INA226 レジスタ書き込み等
00385  * @return 0:成功     -1:失敗
00386  */
00387 int SetupINA226(){
00388   unsigned short val_1 = 0;
00389   unsigned short val_2 = 0;
00390   unsigned short val_3 = 0;
00391 
00392   // INA226の存在を確認
00393   if(!BatteryMonitor.isExist()) {
00394     print("INA226B not found!\n", 0, 0);
00395   }
00396   if(!PanelMonitor.isExist()) {
00397     print("INA226P not found!\n", 0, 1);
00398   }
00399   if(!MotorMonitor.isExist()) {
00400     print("INA226M not found!\n", 0, 2);
00401     return -1;
00402   }
00403 
00404   // INA226のレジスタの値を正しく読めるか確認
00405   if(BatteryMonitor.rawRead(0x00, &val_1) != 0) {
00406     print("INA226B read Error!\n", 0, 0);
00407     return -1;
00408   }
00409   if(PanelMonitor.rawRead(0x00, &val_2) != 0) {
00410     print("INA226P read Error!\n", 0, 1);
00411     return -1;
00412   }
00413   if(MotorMonitor.rawRead(0x00, &val_3) != 0) {
00414     print("INA226M read Error!\n", 0, 2);
00415     return -1;
00416   }
00417 
00418   // 各INA226にレジスタ値を書き込む
00419   BatteryMonitor.setConfiguration(configuration);
00420   PanelMonitor.setConfiguration(configuration);
00421   MotorMonitor.setConfiguration(configuration);
00422   BatteryMonitor.setCurrentCalibration(calibration);
00423   PanelMonitor.setCurrentCalibration(calibrationPanel);
00424   MotorMonitor.setCurrentCalibration(calibration);
00425 
00426   print("INA226 OK!\n", 0, 0);
00427   return 0;
00428 }
00429 
00430 /** ネット関連 初期化
00431  * @return 0: 成功 -1: 失敗
00432  */
00433 int SetupEthernet(){
00434   EthernetErr ethErr = eth.setup();
00435   if(ethErr) {
00436     debug.printf("Error %d in setup.\n", ethErr);
00437     Xbee.printf("Error %d in setup.\n", ethErr);
00438     lcd.locate(0, 1);
00439     lcd.printf("Setup Error %d", ethErr);
00440     return -1;
00441   }
00442 
00443   print("Ethernet OK!\n", 0, 1);
00444   return 0;
00445 }
00446 
00447 /** USBメモリ書き込み初期化 ファイル名設定
00448  * @param struct LogData LogData 構造体
00449  * @param char name ファイル名が書き込まれる配列
00450  *
00451  * @return 0: 成功 -1: 失敗
00452  */
00453 int SetupUSB(struct LogData *data, char name[][fileName_maxsize]){
00454   time_t createdTime = time(NULL) + offsetTime;
00455   // 日付がファイル名
00456   strftime(name[0], fileName_maxsize, "/usb/%y%m%d_log.csv", localtime(&createdTime));
00457   strftime(name[1], fileName_maxsize, "/usb/%y%m%d_LAPdata.csv", localtime(&createdTime));
00458   strftime(name[2], fileName_maxsize, "/usb/%y%m%d_GPSNMEA.log", localtime(&createdTime));
00459 
00460   FILE *fp = fopen(name[0], "a");
00461   if(fp == NULL) {
00462     print("USB can\'t be opened!\n", 0, 2);
00463     return -1;
00464   }
00465   else{
00466     strftime(data->timeStr[0], timeStr_maxsize, "%Y%m%d%H%M%S", localtime(&createdTime));
00467     fprintf(fp, "%s\n", data->timeStr[0]);    // 試しに現在時刻を書き込み
00468   }
00469   fclose(fp);
00470 
00471   print("USB OK!\n", 0, 2);
00472   return 0;
00473 }
00474 
00475 /** バックアップデータを読み込み,LogData構造体に格納
00476  * @param struct LogData バックアップからLogData 構造体に書き込む
00477  * @param double predata バックアップから前のラップタイムデータを書き込む
00478  * @param time_t *preTime バックアップから前のラップタイムを書き込む
00479  *
00480  * @return 0:成功     1:バックアップデータが存在していない
00481  */
00482 int ReadBackup(struct LogData *data, double predata[][preLapdata_j], time_t *preTime){
00483   int i;
00484   FILE *fp_back = fopen("/usb/backup.csv", "r");
00485   if(fp_back == NULL) {
00486     debug.printf("Backup File No Exist\n");
00487     return 1;  // 初回起動時 backup.csvはSaveBackup関数が実行された時に作成される
00488   }
00489   else{
00490     fscanf(fp_back, "%d,%d,%d,%d", &(data->lap), &(data->lapTime), &startUnixTime, preTime);
00491     for(i = 0; i < RealtimeData_i; i++) {
00492       fscanf(fp_back, "%lf,%lf,", &(data->RealtimeData[i][2]), &(data->RealtimeData[i][3]));  // 電流和,電力和
00493     }
00494     for(i = 0; i < preLapdata_i; i++) {
00495       fscanf(fp_back, "%lf,%lf,", &predata[i][0], &predata[i][1]);
00496     }
00497   }
00498   fclose(fp_back);
00499   return 0;
00500 }
00501 
00502 /** シリアルGPSデータを解析,保存
00503  * @param const char name ファイル名が保存されている配列
00504  *
00505  * @return 0:成功    -1:失敗
00506  */
00507 int FetchGPSdata(const char name[][fileName_maxsize]){
00508   // char c;
00509   while(1) {
00510     myGPS.read();                            // ただ読むだけでなくて,GPSセンテンスを文字列化している
00511     // if (c) debug.printf("%c", c);
00512     if (myGPS.newNMEAreceived()) {           // センテンスが一文取得できたかどうか
00513       if (!myGPS.parse(myGPS.lastNMEA())) {  // 解析が完了したかどうか していない場合はもう一度ループ(breakスキップ)
00514         continue;
00515       }
00516       break;                                 // 解析終了した場合はループを抜ける
00517     }
00518   }
00519   // 直前のGPSセンテンスをUSBに保存
00520   FILE *fp = fopen(name[2], "a");
00521   if(fp == NULL) {
00522     debug.printf("USB Error\n");
00523     return -1;
00524   }
00525   else{
00526     fprintf(fp, "%s", myGPS.lastNMEA());
00527   }
00528   fclose(fp);
00529   return 0;
00530 }
00531 
00532 /** 1秒毎に電圧・電流測定,計算後のデータを構造体に格納
00533  * @param struct LogData
00534  * @param  bool run : true 積算する false 積算しない
00535  */
00536 void CalculateSet(struct LogData *data, bool run){
00537   int i;
00538   bool retry = false;
00539   int count = 0;
00540 
00541   double voltage_tmp = 0;      // 仮に電圧,電流データを保存しておく
00542   double current_tmp[RealtimeData_i] = {0};
00543 
00544   // 異常な値の場合は,再度データを取り直す
00545   do {
00546     retry = false;
00547     BatteryMonitor.getVoltage(&voltage_tmp);     // 電圧
00548     BatteryMonitor.getCurrent(&current_tmp[0]); // バッテリー電流
00549     PanelMonitor.getCurrent(&current_tmp[1]);   // パネル電流
00550     MotorMonitor.getCurrent(&current_tmp[2]);   // モーター電流
00551 
00552     if(voltage_tmp > 200) retry = true;         // 電圧が200V以上は異常
00553     for(i = 0; i < RealtimeData_i; i++) {
00554       if(current_tmp[i] > 200) retry = true;    // 電流が200A以上は異常
00555     }
00556     count++;
00557   } while(retry && count < 5);  // 5回とっても異常な場合はさすがにループを抜ける
00558 
00559   // 0割の有無を確認した後,配列に格納する
00560   if(data->totalTime != 0) {
00561     data->batteryVoltage = voltage_tmp * voltageCalibration;             // 分圧電圧を補正
00562     for(i = 0; i < RealtimeData_i; i++) {
00563       data->RealtimeData[i][0] = current_tmp[i] * currentCalibration[i];  // 電流補正
00564       data->RealtimeData[i][1] = data->batteryVoltage * data->RealtimeData[i][0];   // 電力
00565       if(run) data->RealtimeData[i][2] += data->RealtimeData[i][0];                 // 電流の和
00566       if(run) data->RealtimeData[i][3] += data->RealtimeData[i][1];                 // 電力の和
00567       data->RealtimeData[i][4] = data->RealtimeData[i][3] / 3600;                   // 積算電力
00568     }
00569     data->remainBatteryWh = batteryCapacity - data->RealtimeData[0][4];     // バッテリー残量[Wh]
00570     data->remainBatteryParcent = (data->remainBatteryWh / batteryCapacity) * 100;    // バッテリー残量[%]
00571     data->motorSpeed = canlog.rpmMotor * rpmConvert;  // CAN通信で回転数取得 km/h変換
00572     data->motorAngle = canlog.angle;  // 進角
00573     debug.printf("angle:%.2f\n", canlog.angle);
00574     data->motorSpeed_pulse = pulseCount * pulseConvert;     // 1秒間でカウントしたパルスを速度に変換
00575     pulseCount = 0;
00576     data->gpsSpeed = myGPS.speed * kmph;  // GPS速度
00577     data->latitude = myGPS.latitude;     // GPS緯度
00578     data->longitude = myGPS.longitude;   // GPS経度
00579     //acc.ReadXYZ(data->accData);          // 3軸加速度
00580   }
00581 }
00582 
00583 /** 時刻関連のデータを計算,格納
00584  * @param struct LogData
00585  * @param time_t preTime  前のラップタイム
00586  *
00587  * @return unsigned int ラップタイム
00588  */
00589 unsigned int CalculateTimeSet(struct LogData *data, time_t preTime){
00590   time_t nowTime;              // 現在時刻
00591   time_t laptime_temp;         // ラップタイム算出用
00592   time_t totalTime_temp;       // 経過時間用
00593 
00594   nowTime = time(NULL) + offsetTime;                // RTCからUNIXタイムを取得し,日本時間に修正 現在時刻
00595   totalTime_temp = nowTime - startUnixTime;         // 経過時間 (現在時刻とスタート時刻の差)
00596   data->totalTime = (int) totalTime_temp;  // 経過時間(秒)
00597   if(!data->lap) {
00598     if(nowTime < startUnixTime){
00599       laptime_temp = 0;
00600     }
00601     else{
00602       laptime_temp = nowTime - startUnixTime;
00603     }         // 現在時刻とスタート時刻の差 = 初回のラップタイム
00604   }
00605   else{
00606     laptime_temp = nowTime - preTime;               // 現在時刻と前のラップタイムの時刻の差 = ラップタイム
00607   }
00608   if(laptime_temp<0){
00609     laptime_temp = 0;
00610   }
00611   // strftimeでUNIXタイムを適切にフォーマット
00612   strftime(data->timeStr[0], timeStr_maxsize, "%Y%m%d%H%M%S", localtime(&nowTime));   // PHP,USB用
00613   strftime(data->timeStr[1], timeStr_maxsize, "%T", localtime(&nowTime));             // LCDの現在時刻用
00614   strftime(data->timeStr[2], timeStr_maxsize, "%T", localtime(&totalTime_temp));      // LCDの経過時間用
00615   strftime(data->timeStr[3], timeStr_maxsize, "%M\'%S", localtime(&laptime_temp));    // LCDのラップ経過時刻用
00616 
00617 
00618 if(lapSave_forsub==true){
00619     sublogger_min=1;
00620     lapSave_forsub=false;
00621     }
00622 else{    sublogger_min=0;}
00623 sublogger_sec=1;
00624 sublogger_sec=0;
00625 
00626 
00627 
00628   return (unsigned int) laptime_temp;
00629 }
00630 
00631 /** ラップ平均・積算値を計算し構造体に格納
00632  * @param struct LogData
00633  * @param double predata  前のラップタイムのデータ
00634  * @param time_t *preTime 前のラップタイムを書き込む
00635  */
00636 void LapCalculateSet(struct LogData *data, double predata[][preLapdata_j], time_t *preTime){
00637   int i, j;
00638   time_t laptime_temp;
00639 
00640   // 0周目から1周目になるときの動作
00641   if(!data->lap) {
00642     data->lapTime = (int)(time(NULL) + offsetTime - startUnixTime);
00643     if(time(NULL) + offsetTime - startUnixTime<0){
00644       laptime_temp = 0;
00645     }
00646     else{
00647       laptime_temp = time(NULL) + offsetTime - startUnixTime;
00648     }            // 現在時刻とスタート時刻の差 = 初回のラップタイム
00649     strftime(data->timeStr[4], timeStr_maxsize, "%M\'%S", localtime(&laptime_temp));     // LCD用にフォーマット
00650   }
00651   // それ以外の動作
00652   else{
00653     data->lapTime = (unsigned int)(time(NULL) + offsetTime - *preTime);
00654     laptime_temp = time(NULL) + offsetTime - *preTime;
00655     strftime(data->timeStr[4], timeStr_maxsize, "%M\'%S", localtime(&laptime_temp));
00656   }
00657   data->lap = data->lap + 1;             // ラップ加算
00658   *preTime = time(NULL) + offsetTime;    // 現在時刻を前のラップタイムのUNIXタイムとする
00659   strftime(data->timeStr[5], timeStr_maxsize, "%T", localtime(preTime));  // コントロールライン通過時刻
00660 
00661 // 0割の有無を確認した後,配列に格納 前のデータとの差で一周分を算出
00662   if(data->lapTime) {
00663     for(i = 0; i < LapoutData_i; i++) {
00664       data->LapoutData[i][0] = (data->RealtimeData[i][2] - predata[i][0]) / data->lapTime;   // ラップ平均電流
00665       data->LapoutData[i][1] = (data->RealtimeData[i][3] - predata[i][1]) / data->lapTime;   // ラップ平均電力
00666       data->LapoutData[i][2] = (data->RealtimeData[i][3] - predata[i][1]) / 3600;            // ラップ電力量
00667     }
00668     for(i = 0; i < preLapdata_i; i++) {
00669       for(j = 0; j < preLapdata_j; j++) {
00670         predata[i][j] = data->RealtimeData[i][j + 2];                 // 前のデータを記憶しておく
00671       }
00672     }
00673   }
00674 }
00675 
00676 /*この関数では構造体を引数に,httpリクエスト文を作成しサーバーにポストします
00677  * リクエスト文(POSTデータ) key[]=value1&key[]=value2&...
00678  * keyがp[]でvalueがカンマで結合した1秒間データ(8秒分なので8個作ることになる)
00679  * keyをkey[]形式にするとphp側で添字配列として受け取ることができる
00680    ---骨格---
00681    構造体のデータをchar型に変換してsnprintfでフォーマットしていく(追記方式)
00682    そうして,httpRequest関数に渡す
00683  */
00684 /** データをネット送信
00685  * @param const struct LogData
00686  * @param *httpRes   HTTPレスポンスコード
00687  */
00688 int httpPost(const struct LogData postdata[], int *httpRes){
00689   IpAddr ip(133, 68, 205, 140);
00690   Host host;
00691   host.setName("solar-car.club.nitech.ac.jp");
00692   host.setIp(ip);
00693 
00694   int i, j, k;
00695   char RequestStr[RequestStr_maxsize] = {0};
00696 
00697   // リクエスト文を作成していく
00698   for(k = 0; k < storageTime; k++) {
00699     snprintf(RequestStr, RequestStr_maxsize, "%sp[]=%s,%d,%d,%d,%.2f",              // pがkey
00700              RequestStr,
00701              postdata[k].timeStr[1],
00702              postdata[k].lap,
00703              postdata[k].lapTime,
00704              postdata[k].totalTime,
00705              postdata[k].batteryVoltage);
00706     for(j = 0; j < 2; j++) {
00707       for(i = 0; i < RealtimeData_i; i++) {
00708         snprintf(RequestStr, RequestStr_maxsize, "%s,%.1f", RequestStr, postdata[k].RealtimeData[i][j]);     // 電流,電力
00709       }
00710     }
00711     for(i = 0; i < RealtimeData_i; i++) {
00712       snprintf(RequestStr, RequestStr_maxsize, "%s,%.1f", RequestStr, postdata[k].RealtimeData[i][4]);       // 積算電力
00713     }
00714     snprintf(RequestStr, RequestStr_maxsize, "%s,%.2f,%.2f,%.1f,%.4f,%.4f,%s",
00715              RequestStr,
00716              postdata[k].remainBatteryParcent,
00717              postdata[k].remainBatteryWh,
00718              postdata[k].motorSpeed,
00719              postdata[k].latitude,
00720              postdata[k].longitude,
00721              postdata[k].timeStr[0]);
00722     if(k < (storageTime - 1)) {
00723       snprintf(RequestStr, RequestStr_maxsize, "%s&", RequestStr);        // 最後のデータの末尾には&は不要
00724     }
00725   }
00726   *httpRes = httpRequest(METHOD_POST, 8000, &host,"/myLogger/Get/GetRealtimeData.php", "Content-Type: application/x-www-form-urlencoded\r\n", RequestStr);
00727   // debug.printf("%s", RequestStr);
00728 
00729   return 0;
00730 }
00731 
00732 void LaphttpPost(const struct LogData *data, int *httpRes){
00733   IpAddr ip(133, 68, 205, 140);
00734   Host host;
00735   host.setName("solar-car.club.nitech.ac.jp");
00736   host.setIp(ip);
00737 
00738   char LapRequestStr[LapRequestStr_maxsize] = {0};
00739   int i, j;
00740 
00741   snprintf(LapRequestStr, LapRequestStr_maxsize, "q=%s,%d,%d", data->timeStr[5], data->lap, data->lapTime);
00742   for(j = 0; j < LapoutData_j; j++) {
00743     for(i = 0; i < LapoutData_i; i++) {
00744       snprintf(LapRequestStr, LapRequestStr_maxsize, "%s,%.2f", LapRequestStr, data->LapoutData[i][j]);                   // 列に関して出力
00745     }
00746   }
00747   snprintf(LapRequestStr, LapRequestStr_maxsize, "%s,%s", LapRequestStr, data->timeStr[0]);
00748   *httpRes = httpRequest(METHOD_POST, HTTP_TIMEOUT, &host, "/myLogger/Get/GetLapoutData.php", "Content-Type: application/x-www-form-urlencoded\r\n", LapRequestStr);
00749   // debug.printf("%s", LapRequestStr);
00750 }
00751 
00752 void EmergencyhttpPost(const struct LogData *data){
00753   IpAddr ip(133, 68, 205, 140);
00754   Host host;
00755   host.setName("solar-car.club.nitech.ac.jp");
00756   host.setIp(ip);
00757 
00758   char sendStr[32] = {0};
00759 
00760   snprintf(sendStr, 32, "p=%s,%s", data->timeStr[1], data->timeStr[0]);
00761   httpRequest(METHOD_POST, HTTP_TIMEOUT, &host, "/myLogger/Get/GetEmergency.php", "Content-Type: application/x-www-form-urlencoded\r\n", sendStr);
00762 }
00763 
00764 /*LCDへのデータ表示を行う locate関数は0行0列からはじまり,引数は(列,行)*/
00765 void LCD(const struct LogData *data){
00766   lcd.locate(0, 0);
00767   lcd.printf("SP");
00768   lcd.locate(3, 0);
00769   lcd.printf("%3.0f", data->motorSpeed);
00770   lcd.locate(7, 0);
00771   lcd.printf("km/h");
00772   lcd.locate(12, 0);
00773   lcd.printf("%s", data->timeStr[1]);
00774 
00775   lcd.locate(0, 1);
00776   lcd.printf("B");
00777   lcd.locate(3, 1);
00778   lcd.printf("%5.1f", data->remainBatteryParcent);
00779   lcd.locate(9, 1);
00780   lcd.printf("%%");
00781   lcd.locate(15, 1);
00782   lcd.printf("%s", data->timeStr[3]);
00783 
00784   lcd.locate(0, 2);
00785   lcd.printf("V");
00786   lcd.locate(3, 2);
00787   lcd.printf("%5.1f", data->batteryVoltage);
00788   lcd.locate(9, 2);
00789   lcd.printf("V");
00790   lcd.locate(12, 2);
00791   lcd.printf("LAP");
00792   lcd.locate(15, 2);
00793   lcd.printf("%s", data->timeStr[4]);
00794 
00795   lcd.locate(0, 3);
00796   lcd.printf("M");
00797   lcd.locate(1, 3);
00798   lcd.printf("%7.1f", data->RealtimeData[2][1]);
00799   lcd.locate(9, 3);
00800   lcd.printf("W");
00801   lcd.locate(12, 3);
00802   lcd.printf("%3.0f", data->LapoutData[2][2]);
00803   lcd.locate(15, 3);
00804   lcd.printf("Wh");
00805   lcd.locate(18, 3);
00806   lcd.printf("%d", data->lap);
00807 }
00808 
00809 void ReadyStartLCD(const struct LogData *data){
00810   lcd.locate(2, 0);
00811   lcd.printf(">>Push to Start<<");
00812 
00813   lcd.locate(0, 1);
00814   lcd.printf("B");
00815   lcd.locate(2, 1);
00816   lcd.printf("%5.1f", data->remainBatteryParcent);
00817   lcd.locate(8, 1);
00818   lcd.printf("%%");
00819   lcd.locate(11, 1);
00820   lcd.printf("Now Time");
00821 
00822   lcd.locate(0, 2);
00823   lcd.printf("V");
00824   lcd.locate(2, 2);
00825   lcd.printf("%5.1f", data->batteryVoltage);
00826   lcd.locate(8, 2);
00827   lcd.printf("V");
00828   lcd.locate(11, 2);
00829   lcd.printf("%s", data->timeStr[1]);
00830 
00831   lcd.locate(0, 3);
00832   lcd.printf("P");
00833   lcd.locate(1, 3);
00834   lcd.printf("%6.1f", data->RealtimeData[0][1]);
00835   lcd.locate(8, 3);
00836   lcd.printf("W");
00837   if(myGPS.fix) {
00838     lcd.locate(11, 3);
00839     lcd.printf("GPS OK");
00840   }
00841 }
00842 
00843 /*構造体のデータをUSBメモリへデータを保存(csvファイル)*/
00844 int USBSaveData(const struct LogData postdata[], const char name[][fileName_maxsize]){
00845   int i, j, k;
00846   FILE *fp = fopen(name[0], "a");
00847 
00848   if(fp == NULL) {
00849     debug.printf("USB can\'t open\n");
00850     return -1;
00851   }
00852   else{
00853     for(k = 0; k < storageTime; k++) {
00854       fprintf(fp, "%s,%d,%d,%d,%.2f,", postdata[k].timeStr[1], postdata[k].lap, postdata[k].lapTime, postdata[k].totalTime, postdata[k].batteryVoltage);
00855       for(j = 0; j < RealtimeData_j; j++) {
00856         for(i = 0; i < RealtimeData_i; i++) {
00857           fprintf(fp, "%.3f,", postdata[k].RealtimeData[i][j]);                         // 列に関して出力(全データ)
00858         }
00859       }
00860       fprintf(fp, "%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\n", postdata[k].remainBatteryParcent, postdata[k].remainBatteryWh, postdata[k].motorSpeed, postdata[k].motorSpeed_pulse, postdata[k].gpsSpeed, postdata[k].motorAngle);
00861 /*
00862       for(i = 0; i < 3; i++) {
00863         if(i == 2) {
00864           fprintf(fp, "%.5f\n", postdata[k].accData[i]);
00865         }
00866         else{
00867           fprintf(fp, "%.5f,", postdata[k].accData[i]);
00868         }
00869       }
00870  */
00871     }
00872   }
00873   fclose(fp);
00874   return 0;
00875 }
00876 
00877 int LapUSBSaveData(const struct LogData *data, const char name[][fileName_maxsize]){
00878   int i, j;
00879 
00880   FILE *fp = fopen(name[1], "a");
00881   if(fp == NULL) {
00882     debug.printf("USB can\'t open\n");
00883     return -1;
00884   }
00885   else{
00886     fprintf(fp, "\n%s,%d,%d,%d", data->timeStr[5], data->lap, data->lapTime, data->totalTime);
00887     for(j = 0; j < LapoutData_j; j++) {
00888       for(i = 0; i < LapoutData_i; i++) {
00889         fprintf(fp, ",%7.2f", data->LapoutData[i][j]);                         // 列に関して(ラップ平均等の全データ)
00890       }
00891     }
00892   }
00893   fclose(fp);
00894 
00895   return 0;
00896 }
00897 
00898 /** 蓄積されているデータをcsvファイルにバックアップ
00899  * @param const strct LogData
00900  * @param const double predata
00901  * @param time_t preTime
00902  */
00903 int SaveBackup(const struct LogData *data, const double predata[][preLapdata_j], time_t preTime){
00904   int i, j;
00905 
00906   FILE *fp_back = fopen("/usb/backup.csv", "w");
00907   if(fp_back == NULL) {
00908     debug.printf("USB can\'t open!\n");
00909     return -1;
00910   }
00911   else{
00912     fprintf(fp_back, "%d,%d,%d,%d\r\n", data->lap, data->totalTime, (unsigned int)startUnixTime, (unsigned int)preTime);
00913     for(i = 0; i < RealtimeData_i; i++) {
00914       for(j = 0; j < 2; j++) {
00915         fprintf(fp_back, "%f,", data->RealtimeData[i][j+2]);  // 電流和,電力和
00916       }
00917       fprintf(fp_back, "\r\n");
00918     }
00919     for(i = 0; i < preLapdata_i; i++) {
00920       for(j = 0; j < preLapdata_j; j++) {
00921         fprintf(fp_back, "%f,", predata[i][j]);
00922       }
00923       fprintf(fp_back, "\r\n");
00924     }
00925   }
00926   fclose(fp_back);
00927 
00928   return 0;
00929 }
00930 
00931 /*基本はhttp通信を使いますが,何かあったときにシリアル通信できるようにしておきます
00932  *送信データは基本的にラップ数,ラップタイム,LapoutData
00933  */
00934 void XbeeSerial(const struct LogData *data){
00935   int i, j;
00936   char SerialSendStr[SerialSendStr_maxsize] = {0};
00937 
00938   snprintf(SerialSendStr, SerialSendStr_maxsize, "\nLAP: %d, %s, BV:%6.2f[V],%6.2f[%%],%7.2f[Wh],\n",
00939            data->lap,
00940            data->timeStr[4],
00941            data->batteryVoltage,
00942            data->remainBatteryParcent,
00943            data->remainBatteryWh);
00944   snprintf(SerialSendStr, SerialSendStr_maxsize, "%s            Battery, Panel, Motor\nAllAve[W]: ", SerialSendStr);
00945   for(i = 0; i < RealtimeData_i; i++) {
00946     snprintf(SerialSendStr, SerialSendStr_maxsize, "%s%7.2f,", SerialSendStr, data->RealtimeData[i][4]);  // 平均電力
00947   }
00948   snprintf(SerialSendStr, SerialSendStr_maxsize, "%s\nlapAve[W]: ", SerialSendStr);   // 改行
00949   for(j = 1; j < LapoutData_j; j++) {
00950     for(i = 0; i < LapoutData_i; i++) {
00951       snprintf(SerialSendStr, SerialSendStr_maxsize, "%s%7.2f,", SerialSendStr, data->LapoutData[i][j]);   // ラップ平均,積算
00952     }
00953     if(j == 1) snprintf(SerialSendStr, SerialSendStr_maxsize, "%s\nlapWh[Wh]: ", SerialSendStr);  // 改行
00954   }
00955   Xbee.printf("%s\n", SerialSendStr);   // Xbeeでシリアル送信
00956 }
00957 
00958 // 絶縁監視機能(漏れ電流測定)
00959 // 電流の値が0.5A以下の場合は例外
00960 // バッテリ+パネル電流ーモータ電流が1A以上になった場合、エラー出力
00961 void InsulateMonitor(const struct LogData *data){
00962   bool stopDecison = false;
00963 
00964   for(int i = 0; i < RealtimeData_i; i++) {
00965     if(data->RealtimeData[i][0] < 0.5) {
00966       stopDecison = true;
00967       break;
00968     }
00969   }
00970   if(!stopDecison) {
00971     if((data->RealtimeData[0][0] + data->RealtimeData[1][0] - data->RealtimeData[2][0]) < 1) {
00972       isoError = 0;    // 正常
00973     }
00974     else{
00975       // isoError = 1;    // エラー
00976     }
00977   }
00978 }
00979