Dependencies:   ChaNFSSD mbed BMP085 SHT2x

main.cpp

Committer:
tosihisa
Date:
2012-02-27
Revision:
9:9ca3db7ed7cb
Parent:
8:fd243a6439f3

File content as of revision 9:9ca3db7ed7cb:

/*
 * このソフトウェアは、大阪市立大学と京都大学生存圏ミッション研究の共同研究の成果物です。
 * ソースコードそのもののライセンスは、各ソースコードのライセンスに沿って公開します。
 * 2012-1-4 Toshihisa T
 */

#define __MY_VERSION__  "0.89.2"

#define HAVE_TOGGLE_SW
#define HAVE_MICROSD
//#define MICROSD_FORMAT

#include "mbed.h"
#include "NMEA_parse.h"
#include "SDFileSystem.h"
#include "libT/mbed/tserialbuffer.h"
#include "BMP085.h"
#include "SHT2x.h"
#include "AD7994.h"
//#include "TextLCD.h"
#include "TextLCD_20X4.h"
#include "UBXPacket.h"

using namespace libT;

#define _USE_FS_NAME "sd"

Serial debug(USBTX,USBRX);

DigitalIn   gps_int0(p24);
DigitalOut  gps_reset(p25);
InterruptIn gps_pps(p26);
tSerialBuffer gps(p28,p27);
DigitalOut  gps_pps_led(LED2);
I2C i2c(p9, p10);        // sda, scl
BMP085 bmp085(p9, p10);
int bmp085_find = 0;
SHT2x sht25(p9,p10);
int sht25_find = 0;
AD7994 ad7994(p9,p10);
int ad7994_find = 0;
TextLCD_20X4 lcd(p15, p16, p17, p18, p19, p20); // rs, e, d4-d7
#ifdef  HAVE_TOGGLE_SW  /* { */
DigitalIn toggleSW(p22);
int toggleSW_scan = 0;
int toggleSW_pre  = -1;
#endif  /* } */
int toggleSW_now  = 0;
Ticker tick;
tSerialBuffer CO2(p13,p14);
Timer CO2_TMOUT;

SDFileSystem sd(p5, p6, p7, p8, _USE_FS_NAME);
int avaiableSD = -1;
unsigned short logNextCount = 0;
FILE *csvFP = NULL;
FILE *gpsFP = NULL;
int logSW = 0;
LocalFileSystem local("local");  

DigitalOut logled(LED3);
DigitalOut myled(LED1);

struct UBXPacket_s UBXPacket;

int pps_count = 0;
void gps_pps_rise()
{
    gps_pps_led = ((pps_count+=1) & 1) ? 1 : 0;
}

void logFile_Init() {
    DIR *d;
    struct dirent *p;
    unsigned short countCandidate;
    char *endptr;

    //この return を有効にすると、SDカードのチェックを行いません。
    //return;

    avaiableSD = 0;
    d = opendir("/" _USE_FS_NAME);
    if ( d != NULL ) {
        while ( (p = readdir(d)) != NULL ) {
            debug.printf("FILE - %s\x0d\x0a", p->d_name);
            if (strlen(p->d_name) == (sizeof("ENVxxxxx.CSV")-1)) {
                if (    ((p->d_name[0] == 'E') || (p->d_name[0] == 'e'))
                        && ((p->d_name[1] == 'N') || (p->d_name[1] == 'n'))
                        && ((p->d_name[2] == 'V') || (p->d_name[2] == 'v'))) {
                }
                countCandidate = (unsigned short)strtoul(&(p->d_name[3]),&endptr,10);
                if (strcasecmp(endptr,".CSV") == 0) {
                    if (countCandidate > logNextCount) {
                        logNextCount = countCandidate;
                    }
                }
            }
        }
        closedir(d);
        logNextCount++;
        avaiableSD = 1;
    }
}


int CO2_Read(unsigned short *val)
{
    unsigned char sbuf[] = { 0xFE, 0x04, 0x00, 0x03, 0x00, 0x01, 0xD5, 0xC5 };
    unsigned char rbuf[7];
    int i;
    unsigned short crc;
    extern unsigned short modbus_CRC(unsigned char *DataPtr, unsigned short len);

    for(i=0;i < sizeof(sbuf);i++){
        //debug.printf("0x%02x ",sbuf[i]);
        CO2.putc(sbuf[i]);
    }
    CO2_TMOUT.start();
    for(i=0;i < sizeof(rbuf);i++){
        while(!CO2.readable()){
            if(CO2_TMOUT.read_ms() >= 1000){
                return -99; /* TIMEOUT */
            }
        }
        rbuf[i] = CO2.getc();
    }
    if(rbuf[0] != 0xFE){
        return -4;
    }
    if(rbuf[1] != 0x04){
        return -1;
    }
    if(rbuf[2] != 0x02){
        return -2;
    }
    crc = rbuf[6];
    crc = (crc << 8) | rbuf[5];
    if(crc != modbus_CRC(rbuf,5)){
        return -3;
    }
    *val = rbuf[3];
    *val = (*val << 8) | rbuf[4];
    return 0;
}

// BMP085 0xee
// AD7994 0x44
// SHT2x  0x80
int i2c_found() {
    int count = 0;
    lcd.locate(0,0);
    lcd.printf("%-19s","I2C Dev:");
    lcd.locate(8,0);
    for (int address=0; address<256; address+=2) {
        if (!i2c.write(address, NULL, 0)) { // 0 returned is ok
            switch(address){
                case 0xee: bmp085_find = 1; break;
                case 0x44: ad7994_find = 1; break;
                case 0x80: sht25_find = 1; break;
                default: break;
            }
            lcd.printf("%02X ",address);
            count++;
        }
    }
    return count;
}

unsigned char NMEA_CalcSum(unsigned char *str,int len)
{
    unsigned char sum = 0;
    int i;
    for(i = 0;i < len;i++){
        sum = sum ^ (*(str + i));
    }
    return sum;
}

void UBX_CalcSum(unsigned char *str,int len,unsigned char *sum)
{
    int i;
    *(sum + 0) = *(sum + 1) = 0;
    for(i = 0;i < len;i++){
        *(sum + 0) = *(sum + 0) + *(str+i);
        *(sum + 1) = *(sum + 1) + *(sum + 0);
    }
}

int UBX_WaitAck(struct UBXPacket_s *info)
{
    UBXPacket.cjobst = 0;

    while(1){
        while(gps.readable()) {
            if(UBXPacket_Parse(&UBXPacket,gps.getc()) == 100){
                if((UBXPacket.cls == 0x05) && (UBXPacket.id == 0x01)){
                    return 1; /* ACK */
                } else if((UBXPacket.cls == 0x05) && (UBXPacket.id == 0x00)){
                    return 0; /* NAK */
                } else {
                    UBXPacket.cjobst = 0;
                }
            }
        }
    }
}

unsigned long scanCount = 0;
unsigned long tickCount = 0;
unsigned long hzCount = 0;
unsigned long hzCount_tmp = 0;
void tickHandler()
{
    scanCount++;
    tickCount++;
    hzCount_tmp++;
    if(hzCount_tmp >= 50){
        hzCount_tmp = 0;
        hzCount++;
    }
#ifdef  HAVE_TOGGLE_SW  /* { */
    int nowRead;
    nowRead = toggleSW.read();
    if(nowRead != toggleSW_pre){
        toggleSW_pre = nowRead;
        toggleSW_scan = 0;
    } else {
        toggleSW_scan++;
        if(toggleSW_scan >= 3){
            toggleSW_now = toggleSW_pre;
            toggleSW_scan = 0;
        }
    }
#endif
}

unsigned char wbuf[512];
int widx = 0;

int logBtnPush = 0;
int logBtnAck  = 0;

void logOpenClose()
{
    if(logBtnPush != logBtnAck){
        if(csvFP != NULL){
            fclose(csvFP);
            csvFP = NULL;
            if(gpsFP != NULL){
                if(widx > 0){
                    fwrite(&wbuf,sizeof(wbuf[0]),widx,gpsFP);
                    widx = 0;
                }
                fclose(gpsFP);
                gpsFP = NULL;
            }
            logled = 0; /* No logging */
            logNextCount++;
        } else {
            char name[64];
            sprintf(name,"/%s/ENV%05d.CSV",_USE_FS_NAME,logNextCount);
            csvFP = fopen(name,"w+b");
            sprintf(name,"/%s/ENV%05d.UBX",_USE_FS_NAME,logNextCount);
            gpsFP = fopen(name,"w+b");
            if((csvFP != NULL) && (gpsFP != NULL)){
                logled = 1; /* logging */
                widx = 0;   /* buffer clear */
            } else {
                if(csvFP) fclose(csvFP);
                if(gpsFP) fclose(gpsFP);
                logled = 0; /* Cannot start logging */
            }
        }
        logBtnAck = logBtnPush;
    }
}

void logBtnUpdate()
{
    if((logSW == 0) && (toggleSW_now != 0)){
        logBtnPush++; 
    }
    logSW = toggleSW_now;
}

void ClearScreen(void)
{
    lcd.locate(0,0); lcd.printf("%20s"," ");
    lcd.locate(0,1); lcd.printf("%20s"," ");
    lcd.locate(0,2); lcd.printf("%20s"," ");
    lcd.locate(0,3); lcd.printf("%20s"," ");
}

int main() {
    int ret = 0;
    float p, t1;
    float h, t2;
    int temp;
    unsigned short CO2_val = 0;
    char c;
    unsigned long UBXCount = 0;
    int GPS_isRaw = 0;
    int CO2_find = 0;
    int year=0;
    int mon=0;
    int day=0;
    int hour=0;
    int min=0;
    int sec=0;
    int pre_sec = -1;
    struct tm t;
 
    p = -99.0;
    t1 = -99.0;
    t2 = -99.0;
    h = -99.0;

    tick.attach_us(&tickHandler,(10*1000));
 
    debug.format(8,Serial::None,1);
    debug.baud(115200);
    debug.printf("ENV Logger \"%s\" Start (BUILD:[" __DATE__ "/" __TIME__ "])\n",__MY_VERSION__);

    lcd.locate(0,0);
    lcd.printf("ENV Logger \"%s\"",__MY_VERSION__);

    lcd.locate(0,1);
    lcd.printf("WAKE UP I/O...");
    wait(5.0);
 
    ClearScreen();

    //===================================================
    i2c_found();
 
    //===================================================
    CO2.format(8,Serial::None,1);
    CO2.baud(9600);
    CO2.recvStart();

    lcd.locate(0,1);
    lcd.printf("Check CO2:");
    CO2_find = 0;
    ret = CO2_Read(&CO2_val);
    switch(ret){
        case 0:
            lcd.printf("OK");
            CO2_find = 1;
            break;
        case -99:
            lcd.printf("NOT FOUND");
            break;
        default:
            lcd.printf("NG");
            break;
    }
    CO2_val = 0;

    //===================================================
    lcd.locate(0,2);
    lcd.printf("Initalize GPS:");

    UBXPacket.cjobst = 0;

    gps_pps.rise(gps_pps_rise);
    gps.format(8,Serial::None,1);
    gps.baud(9600);

    gps_reset = 1;
    wait(0.5);
    gps_reset = 0;

    wait(0.5);
    if(1){
        //unsigned char modeStr[] = "PUBX,41,1,0007,0003,115200,0";
        //unsigned char modeStr[] = "PUBX,41,1,0007,0001,115200,0";
        unsigned char modeStr[] = "PUBX,41,1,0007,0001,38400,0";
        unsigned char sum = NMEA_CalcSum(modeStr,strlen((char *)modeStr));
        debug.printf("SEND:[%s](0x%02X)\n",modeStr,sum);
        gps.printf("$%s*%02X%c%c",modeStr,sum,0x0d,0x0a);

        debug.printf("CHG BAUD:115200\n");
        gps.format(8,Serial::None,1);
        gps.baud(38400);
    }

    gps.recvStart();
    wait(0.5);

    GPS_isRaw = 1;
    if(1){
        unsigned char chkStr[][11] = {
            { 0xB5,0x62,0x06,0x01,0x03,0x00,0x02,0x10,0x01,0xFF,0xFF }, //RXM-RAW (0x02 0x10)
            { 0xB5,0x62,0x06,0x01,0x03,0x00,0x02,0x30,0x01,0xFF,0xFF }, //RXM-ALM (0x02 0x30)
            //{ 0xB5,0x62,0x06,0x01,0x03,0x00,0x02,0x31,0x01,0xFF,0xFF }, //RXM-EPH (0x02 0x31)
            //{ 0xB5,0x62,0x06,0x01,0x03,0x00,0x02,0x41,0x02,0xFF,0xFF },
            { 0xB5,0x62,0x06,0x01,0x03,0x00,0x02,0x11,0x01,0xFF,0xFF }, //RXM-SFRB (0x02 0x11)
            { 0xB5,0x62,0x06,0x01,0x03,0x00,0x02,0x20,0x01,0xFF,0xFF }, //RXM-SVSI (0x02 0x20)
            { 0xB5,0x62,0x06,0x01,0x03,0x00,0x01,0x21,0x01,0xFF,0xFF }, //NAV-TIMEUTC (0x01 0x21)
            { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF }, //END
        };
        int i,j;
        int isAck;

        for(j=0;chkStr[j][0] != 0x00;j++){
            UBX_CalcSum(&chkStr[j][2],7,&chkStr[j][9]);
            for(i = 0; i < sizeof(chkStr[0]);i++){
                gps.putc(chkStr[j][i]);
            }
            isAck = UBX_WaitAck(&UBXPacket);
            debug.printf("%d : SET UBX Rate : %s\n",j,(isAck == 1) ? "ACK" : "NAK");
            if(isAck != 1){
                GPS_isRaw = 0;
            }
       }
    }
    UBXPacket.cjobst = 0;
    lcd.locate(0,2);
    lcd.printf("Initalize GPS:%s",(GPS_isRaw) ? "OK" : "NG");

//  ad7994.Start();

    //===================================================
#ifdef MICROSD_FORMAT
    lcd.locate(0,3);
    lcd.printf("Format MicroSD:");
    sd.format();
    lcd.locate(0,3);
    lcd.printf("Format MicroSD:Done");
    wait(3.0);
#endif

#ifdef HAVE_MICROSD
    lcd.locate(0,3);
    lcd.printf("Check MicroSD:     ");
    logFile_Init();
#endif
    lcd.locate(0,3);
    switch(avaiableSD){
        case 0:
            lcd.printf("Check MicroSD:NG");
            break;
        case 1:
            lcd.printf("Check MicroSD:OK");
            break;
        default:
            lcd.printf("Check MicroSD:SKIP");
            break;
    }

    //===================================================

    wait(3.0);

    ClearScreen();

    pre_sec = -1;
    while(1) {
        //lcd.cls();
        //lcd.locate(0,0);
        //lcd.printf("SCAN:%-10ld",scanCount);

        logBtnUpdate();

        while(gps.readable()) {
            c = gps.getc();
            if(gpsFP != NULL){
                wbuf[widx] = c;
                widx++;
                if(widx >= sizeof(wbuf)){
                    fwrite(wbuf,sizeof(wbuf[0]),widx,gpsFP);
                    widx = 0;
                }
            }
            if(UBXPacket_Parse(&UBXPacket,c) == 100){
                UBXCount++;
                if((UBXPacket.cls == 0x01) && (UBXPacket.id == 0x21)){
                    /* NAV-TIMEUTC */
                    year = (((unsigned short)UBXPacket.body[13]) << 8) | UBXPacket.body[12];
                    mon  = UBXPacket.body[14];
                    day  = UBXPacket.body[15];
                    hour = UBXPacket.body[16];
                    min  = UBXPacket.body[17];
                    sec  = UBXPacket.body[18];
                    
                    t.tm_sec = sec;    // 0-59
                    t.tm_min = min;    // 0-59
                    t.tm_hour = hour;   // 0-23
                    t.tm_mday = day;   // 1-31
                    t.tm_mon = mon-1;     // 0-11
                    t.tm_year = year-1900;  // year since 1900
                    set_time(mktime(&t));
                }
                debug.printf("%ld : GET UBX Packet (Class=0x%02X,ID=0x%02X,LEN=%d)\n",
                            scanCount,
                            UBXPacket.cls,
                            UBXPacket.id,
                            UBXPacket.len );
                UBXPacket.cjobst = 0;
            }
        }
        if(UBXPacket.cjobst == 0){
            logOpenClose();
        }
 
        lcd.locate(0,0);
        lcd.printf("%c%04d-%02d-%02d %02d:%02d:%02d",(gpsFP) ? '*' : ' ',year,mon,day,hour,min,sec);

        if(pre_sec != sec){
            pre_sec = sec;

            if(bmp085_find){
                float tmp1,tmp2;
                bmp085.update();
                tmp1 = bmp085.get_pressure();
                tmp2 = bmp085.get_temperature();
                if(tmp2 < 100.0){
                    p = tmp1;
                    t1 = tmp2;
                }
            }
            lcd.locate(0,1); lcd.printf("%-8.2fhPa %-6.2fC", p, t1);

            if(sht25_find){
                if(sht25.SHT2x_MeasurePoll(TEMP,&temp) == 0){
                    t2 = sht25.SHT2x_CalcTemperatureC(temp);
                }
                if(sht25.SHT2x_MeasurePoll(HUMIDITY,&temp) == 0){
                    h = sht25.SHT2x_CalcRH(temp);
                }
                sht25.SHT2x_SoftReset();
            }
            lcd.locate(0,2); lcd.printf("%-6.2fC %-6.2fRH", t2, h);

            if(CO2_find){
                if((ret = CO2_Read(&CO2_val)) != 0){
                    CO2_val = 0;
                    CO2_find = 0;
                }
            }
            lcd.locate(0,3); lcd.printf("CO2:%5d.%1dppm\n",CO2_val/10,CO2_val%10);

            if(csvFP){
                fprintf(csvFP,"%04d-%02d-%02d %02d:%02d:%02d,",year,mon,day,hour,min,sec);
                fprintf(csvFP,"%-8.2f,hPa,%-6.2f,C,%-6.2f,C,%-6.2f,RH,%5d.%1d,ppm\x0d\x0a", p, t1, t2, h,CO2_val/10,CO2_val%10);
            }
        }
#if 0
        ad7994.update();
        lcd.locate(0,3);
        lcd.printf("A/D:%04X/%04X",
                     ad7994.readChn(0),
                     ad7994.readChn(1));
#endif
        myled = (hzCount & 1);
        //wait(0.1);
    }
}

/*
 * 2012-2-26 V0.89.2
 * ●ログデータの保存開始・終了のタイミングを変更。
 *   ublox のパケットデータ単位で保存開始・終了するようにした。
 *   今まではバイト単位で保存開始・終了していたため、タイミングに
 *   よっては先頭と最後が正しく記録できていなかった。
 * ●ublox の受信ボーレートを 115200bps から 38400bps に変更。
 *   なるべく負荷を下げるため。
 * ●ファイル保存用のバッファも 1024 から 512 に変更。
 *   これもなるべく負荷を下げるため。
 *   正しく記録出来なかったのはファイル保存用のバッファサイズによる模様。
 * このバージョンで、10分間記録する分には特にエラーは発生していない。
 * このバージョンで長時間ログ採取テストを行う。
 */
/*
 * 2012-2-26 V0.88
 * ublox から受診した日付時刻を RTC に保存するようにした。
 * ファイルの日付をRTCに保存している日付を設定するようにした。
 * これで、マイクロSDをパソコンで見るとき、ファイルの日付が
 * 正しく記録される。
 */
/* V0.87 is nothing... */
/*
 * 2012-2-23 V0.86
 * Eugenio さんからの連絡で、RXM-EPH は
 * 受信する必要が無いので受信しないようにした。
 */
/*
 * 2012-2-11 V0.85
 * SDFileSystem を ChaNFS ベースに変更した。
 * 一番の理由はSDカードのフォーマットがしたいため。
 * main.cpp に #define MICROSD_FORMAT を追加。
 * これを有効にしてバイナリを作成すると、起動時に
 * SDカードのフォーマットをする(フォーマットには2,3分程かかる)
 */
/*
 * 2012-2-10 V0.84
 * *GPSデータの保存拡張子を .GPS から .UBX に変更。
 *  UBXバイナリである事を示す。rtklib で処理できることを確認。
 * *mbedライブラリ、FATFileSystemライブラリを最新に更新。
 */
/*
 * 2012-2-5 V0.83
 * センサー、I/Oの検出順番を変更(H/W 組立時の試験を兼ねる)
 * 下記の順番でセンサーやI/Oの検出をする。
 * I2C → CO2センサー → U-Blox(raw-mode) → マイクロSD
 * マイクロSD が未装着でも U-Blox の raw-mode までは
 * 進めるので、H/W 組立後の基本チェックが可能。
 */
/*
 * 2012-2-5 V0.82
 * バイクによる実走試験での結果を反映。
 * 1) ログボタンのON/OFFでLEDも光らせるが、ケースに収めると
 *    LED だと分からなくなるので、液晶画面でもログのON/OFFが
 *    分かるようにした。ログをONすると、画面左上に'*'を出す。
 * 2) SHT25 が、時々オフセットがかかったかの様な値を返すので、
 *    下記の修正を行った。但しこの修正が確実かはまだ分からない。
 *    a) 関数の戻り値が正常な場合に値を採用する。これは必要。
 *    b) 温湿度の取得後、SHT25 に対してソフトリセット命令を
 *       毎回送る。これでうまく行くようならこれでいく。
 *       →2012-2-10 今のところ問題は見つからない。これで進める。
 */
/*
 * 2012-2-5 V0.81
 * 気圧センサーが時々不正な値を出力する。気温が100度を超える値になる。
 * ソフトバグか、センサー自身の問題かは切り分けていないが、気温が100度を
 * 超えることはあり得ないので、100度を超える気温は値として採用しない様に
 * した。
 */
/*
 * 2012-2-5 V0.8
 * 1) GPS レシーバ受信バッファが少ないので拡大(512->8K)
 * 2) 起動時に、各センサーの接続チェックを行い、起動時に見つかった
 *    センサーとだけ通信するようにした。これにより CO2 センサーが
 *    無くても動きます。
 * 3) NAV-TIMEUTC を受信し、表示するようにした。
 * 4) センサーデータのスキャンタイミングを、NAV-TIMEUTC の
 *    秒が変わった直後とした。つまり1秒おきにセンサーデータを
 *    スキャンする。
 * 5) センサーデータの保存データ(ENVnnnnn.CSV) の先頭に
 *    NAV-TIMEUTC の日付時刻を入れるようにした。
 *    これで何時何分のセンサーデータか分かるようにした。
 */
/*
 * 2012-1-29 V0.7
 * ログ機能の追加。スイッチを押すとログのON/OFFが出来る。
 * ログ収集中は、mbed LED3 が点灯する。
 */
/*
 * 2012-1-29 V0.6
 * 1) スキャンカウントの変更。今までは1秒周期だったが、
 *    100ミリ秒周期でセンサーデータを得るようにした。
 * 2) モーメンタリSW対応。
 */
/*
 * 2012-1-23 V0.5
 * U-Blox,気圧センサー,温度センサー,CO2センサーの値を表示するようにした。
 * U-Blox は受信できたパケット数を表示する。
 * マイクロSDへの保存機能はまだ(H/W的に動くのは確認済み)
 */