Barometer program : Data Logger function includes Barometer & temperature (BMP180), Humidity & temp. (RHT03), Sunshine (Cds), RTC(M41T62) data. : Logging data saves into EEPROM (AT24C1024) using ring buffer function.

Dependencies:   AT24C1024 RHT03 TextLCD BMP180 M41T62

Fork of mbed_blinky by Mbed

Please see https://mbed.org/users/kenjiArai/notebook/mbed-lpc1114fn28-barometer-with-data-logging/#

mon.cpp

Committer:
kenjiArai
Date:
2020-08-08
Revision:
18:b3a27f681171
Parent:
16:f164f8912201

File content as of revision 18:b3a27f681171:

/*
 * mbed Application program
 * Data logging & Monitor program for only LPC1114FN28
 *
 * Copyright (c) 2010,'14,'20 Kenji Arai / JH1PJL
 *  http://www7b.biglobe.ne.jp/~kenjia/
 *  https://os.mbed.com/users/kenjiArai/
 *      Created:  May  	   15th, 2010
 *		Spareted: June	   25th, 2014		mon() & mon_hw()
 *      Revised: August     8th, 2020
 */

//  Include --------------------------------------------------------------------
#include "mbed.h"
#include "m41t62_rtc.h"			// Own lib. / RTC control
#include "AT24C1024.h"			// Own lib. / EEPROM control
#include "dt_log.h"
#include "redirect_stdio.h"

//  Object ---------------------------------------------------------------------
extern I2C    xi2c;						// SDA, SCL
extern M41T62 xm41t62;					// STmicro RTC(M41T62)
AT24C1024     at24c1024(dp5,dp27);    	// Atmel 1Mbit EE-PROM

//  Definition -----------------------------------------------------------------
#define GETC(x)         		getc(x)
#define PUTC(x)					putc(x)
#define PRINTF(...)     		printf(__VA_ARGS__)
#define READABLE(x)     		readable(x)

// EEPROM
#define EEP_TOP					0x0

//  RAM ------------------------------------------------------------------------
char linebuf[64];
int buf_size = sizeof(linebuf);

// 	for EEPROM control
int16_t read_pointer;

typedef struct {
    uint16_t    head;
    uint16_t    tail;
} ring_t;

union _inf {
    uint8_t buf_pointer[PTR_SIZE];
    ring_t log_inf;
} inf;

typedef struct {
    uint32_t	time;
    uint16_t	vcc;
    uint16_t	baro;
    int16_t		b_temp;
    uint16_t	humi;
    int16_t		h_temp;
    uint16_t	lux;
} one_log;		// 16 bytes total

union _one {
    uint8_t bf[PKT_SIZE];
    one_log lg;
} one;

extern float baro;
extern float baro_temp;
extern float cal_vcc;
extern float lux;
extern float humidity;
extern float humidity_temp;
extern float lux;

//  ROM / Constant data --------------------------------------------------------
static const char *const mon_msg =
    "Monitor for mbed system, created on " __DATE__ "";

const char *const log_head =
//   $, 2014/6/29,12:43:16,3.293,1004.5,+29.3,45.8,+29.2,1234,*
    "$,YYYY/MM/DD,HH:MM:SS,Vcc  ,Press ,Temp ,Humi,Temp ,Lux  ,*";
const char *const msg_emty = "Data empty";
const char *const msg_end  = "\r\nreach to end";

//  Function prototypes --------------------------------------------------------
//extern void mon_hw(void);		// ROM& RAM limitation

//------------------------------------------------------------------------------
//  Control Program
//------------------------------------------------------------------------------
//  Put \r\n
void put_rn ( void )
{
    PUTC('\r');
    PUTC('\n');
}

//  Put \r
void put_r ( void )
{
    PUTC('\r');
}

// Put ", "
void put_lin ( void )
{
    PRINTF(", ");
}

// Put space n
void put_spc( uint8_t n)
{
    for(; n > 0; n--) {
        PUTC(' ');
    }
}

//  Change string -> integer
int xatoi (char **str, unsigned long *res)
{
    unsigned long val;
    unsigned char c, radix, s = 0;

    while ((c = **str) == ' ') (*str)++;
    if (c == '-') {
        s = 1;
        c = *(++(*str));
    }
    if (c == '0') {
        c = *(++(*str));
        if (c <= ' ') {
            *res = 0;
            return 1;
        }
        if (c == 'x') {
            radix = 16;
            c = *(++(*str));
        } else {
            if (c == 'b') {
                radix = 2;
                c = *(++(*str));
            } else {
                if ((c >= '0')&&(c <= '9')) {
                    radix = 8;
                }	else {
                    return 0;
                }
            }
        }
    } else {
        if ((c < '1')||(c > '9')) {
            return 0;
        }
        radix = 10;
    }
    val = 0;
    while (c > ' ') {
        if (c >= 'a') c -= 0x20;
        c -= '0';
        if (c >= 17) {
            c -= 7;
            if (c <= 9) return 0;
        }
        if (c >= radix) return 0;
        val = val * radix + c;
        c = *(++(*str));
    }
    if (s) val = -val;
    *res = val;
    return 1;
}

//------------------------------------------------------------------------------
// Data Logging / Save into EEPROM
//------------------------------------------------------------------------------
/*
    head = H, tail =T
	state 1:	H=1(RING_TOP),T=1(RING_TOP)	-> just after Clear command
	state 2:	H=1,T=n		-> n = 2 to RING_TAIL-1 (not filled yet)
	state 3:	H=1,T=RING_TAIL	-> need to check!!!! (just filled)
	state 4:	H=2,T=1(RING_TOP) -> start ringed state
	state 5:	H=n,T=n-1	-> n = 2 to RING_TAIL-1 (ringed)
	state 6:	H=RING_TAIL,T=RING_TAIL-1 -> need to check!!!!!
	state 7:	H=1(RING_TOP),T=RING_TAIL -> need to check!!!!!
	state 8:	same as "state 5"
		-> Need to check state 3,6,7
*/
//  Make one data packet data structure
void dtlog_data_pack(void)
{
    struct tm t;

    xm41t62.read_rtc_std(&t);
    one.lg.time = mktime(&t);
    one.lg.vcc = (uint16_t)(cal_vcc * 1000);
    one.lg.baro = (uint16_t)(baro * 10);
    one.lg.b_temp = (int16_t)(baro_temp * 10);
    one.lg.humi = (uint16_t)(humidity * 10);
    one.lg.h_temp = (int16_t)(humidity_temp * 10);
    one.lg.lux = (uint16_t)lux;
}

//  Print one packet as normalized data
void print_one_block_data(void)
{
    struct tm *t;
    time_t seconds;
    uint16_t dt0;
    int16_t dt1;

    put_rn();
    PUTC( '$' );
    //--- Time
    seconds = one.lg.time;
    t = localtime(&seconds);
    PRINTF(",%04d/%02d/%02d,%02d:%02d:%02d,",
           t->tm_year + 1900, t->tm_mon + 1,
           t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
    //--- Vcc
    dt0 = one.lg.vcc;
    PRINTF("%01d.%03d,", dt0/1000, dt0%1000);
    //--- Pressure
    dt0 = one.lg.baro;
    PRINTF("%04d.%01d,", dt0/10, dt0%10 );
    //--- Temp.
    dt1 = one.lg.b_temp;
    PRINTF("%+03d.%01d,", dt1/10, abs(dt1)%10 );
    //--- Humidity
    dt0 = one.lg.humi;
    PRINTF("%02d.%01d,", dt0/10, dt0%10 );
    //--- Temp.
    dt1 = one.lg.h_temp;
    PRINTF("%+03d.%01d,", dt1/10, abs(dt1)%10 );
    //--- Lux
    dt0 = one.lg.lux;
    PRINTF("%05d,*", dt0);
}

// Read buffer pointer
static void dtlog_pointer_read(void)
{
    uint8_t i;
    uint8_t *addr;

    /* Read EEPROM and save to buf_pointer[] */
    for ( i = 0; i < PTR_SIZE; i++ ) {
        addr = (uint8_t *)(EEP_TOP + i);
        inf.buf_pointer[i]  = at24c1024.read((int)addr);
        ThisThread::sleep_for(2ms);
    }
// PRINTF("head %d, Tail %d\r\n", inf.log_inf.head, inf.log_inf.tail);
}

//  Write one packet
void dtlog_one_write(void)
{
    uint8_t i;
    uint8_t *addr;

    // Read EEPROM buffer pointer to RAM
    for ( i = 0; i < PTR_SIZE; i++ ) {
        addr = (uint8_t *)(EEP_TOP + i);
        inf.buf_pointer[i]  = at24c1024.read((int)addr);
        ThisThread::sleep_for(2ms);
    }
//PRINTF("head %d, Tail %d\r\n", inf.log_inf.head, inf.log_inf.tail);
    // Write data_pack[] into  EEPROM
    for (i = 0; i < PKT_SIZE; i++) {
        addr = (uint8_t *)(EEP_TOP + (inf.log_inf.tail * PTR_SIZE) + i);
        at24c1024.write((int)addr, one.bf[i]);
        ThisThread::sleep_for(8ms);
    }
    // Increment buffer pointer in RAM
    if (inf.log_inf.head == RING_TOP) {	// check state 1,2,3
        if (inf.log_inf.tail == RING_TAIL) {	// check state 3
            inf.log_inf.tail = RING_TOP;		// set state 4
            inf.log_inf.head = 2;				// missing one oldest data
        } else {
            inf.log_inf.tail++;					// set state 2
        }
    } else {	// check state 4,5,6,7
        if (inf.log_inf.head == RING_TAIL) { // check state 6
            inf.log_inf.head = RING_TOP; 	// set state 7
            inf.log_inf.tail = RING_TAIL;
            // check state 4,5
        } else if (inf.log_inf.tail == inf.log_inf.head - 1) {
            ++inf.log_inf.tail;		// continue state 5
            ++inf.log_inf.head;
        }
    }
    // Write buffer pointer into EEPROM
    for (i = 0; i < PTR_SIZE; i++) {
        addr = (uint8_t *)(EEP_TOP + i);
        at24c1024.write((int)addr, inf.buf_pointer[i]);
        ThisThread::sleep_for(8ms);
    }
}

// Read some block from buffer
void dtlog_block_read(int16_t *pt, uint16_t n)
{
    uint8_t i;
    uint8_t *addr;
    uint16_t num;

    dtlog_pointer_read();
    if (inf.log_inf.tail == inf.log_inf.head) { // Check pointer
        PRINTF(msg_emty);
        put_rn();
        return;
    }
    PRINTF("Head:%d, Tail:%d, Start pointer:%d, Number of data:%d\r\n",
           inf.log_inf.head, inf.log_inf.tail, *pt, n);
    PRINTF( log_head );
    for (num = 0; num < n; num++) {
        /* Read EEPROM and save to data_pack[] */
        for (i = 0; i < PKT_SIZE; i++) {
            addr = (uint8_t *)(EEP_TOP + (*pt * PTR_SIZE) + i);
            one.bf[i]  =at24c1024.read((int)addr);
            ThisThread::sleep_for(2ms);
        }
        print_one_block_data();
        if (READABLE()) {
            GETC();
            break;
        }
        ThisThread::sleep_for(1ms);
        if (inf.log_inf.head == RING_TOP) {	// check state 1,2,3
            *pt += 1;
            if (*pt >= inf.log_inf.tail) { // check state 2,3
                PRINTF(msg_end);
                break;
            }
        } else {	// state 4,5,6,7
            if (inf.log_inf.head == RING_TAIL) { // check state 6
                if (inf.log_inf.tail == RING_TAIL -1) { // check state 6
                    if (*pt == RING_TAIL) { // same as  :pt += 1
                        *pt = RING_TOP;
                    } else { // next read
                        *pt += 1;
                        if (*pt >= inf.log_inf.tail) {
                            PRINTF(msg_end);
                            break;
                        }
                    }
                }
                // check state 5
            } else if (inf.log_inf.tail == inf.log_inf.head - 1) {
                *pt += 1;
                if (*pt > RING_TAIL) { // same as  :pt += 1
                    *pt = RING_TOP;
                } else if (*pt == inf.log_inf.tail) { // reach to end
                    PRINTF(msg_end);
                    break;
                }
            }
        }
    }
    put_rn();
}

//  Clear all buffer
void dtlog_clear_all_buff(void)
{
    uint8_t i;
    uint8_t *addr;

    /* Set initial data */
    inf.log_inf.head = inf.log_inf.tail = RING_TOP;
    /* Write buffer pointer */
    for (i = 0; i < PTR_SIZE; i++) {
        addr = (uint8_t *)(EEP_TOP + i);
        at24c1024.write((int)addr, inf.buf_pointer[i]);
        ThisThread::sleep_for(8ms);
    }
}

// EEPROM buffer occupation
uint16_t dtlog_buf_occupation(void)
{
    uint16_t i = 0;
    uint16_t dt = 0;
    uint8_t *addr;

    // Read EEPROM buffer pointer to RAM
    for ( i = 0; i < PTR_SIZE; i++ ) {
        addr = (uint8_t *)(EEP_TOP + i);
        inf.buf_pointer[i]  = at24c1024.read((int)addr);
        ThisThread::sleep_for(2ms);
    }
    // check buffer pointer
    if (inf.log_inf.head == inf.log_inf.tail) {
        PRINTF(msg_emty);
        put_rn();
        return 0;
    }
    if (inf.log_inf.head == RING_TOP) {	// check state 1,2,3
        dt = inf.log_inf.tail - inf.log_inf.head;
    } else {	// state 4,5,6,7
        if (inf.log_inf.head == RING_TAIL) {	// check state 6
            if (inf.log_inf.tail == RING_TAIL - 1) {	// check state 6
                dt = inf.log_inf.tail - RING_TOP + 1;
            }
            // check state 4,5
        } else if (inf.log_inf.tail == inf.log_inf.head - 1) {
            dt = RING_TAIL;
        } else {	// error
            dt = 0;
        }
    }
    return dt;
}

//  Read block number
void dtlog_num_of_block(void)
{
    uint16_t dt;

    dt = dtlog_buf_occupation();
    if (dt == 0) {
        PRINTF(msg_emty);
    } else {
        PRINTF("Number of data = %d", dt);
        put_rn();
        dt = (uint16_t)(((uint32_t)dt * 1000 )/ (BLK_NO - 2));
        PRINTF("EEPROM Occupation = %d.%01d%%", dt / 10, dt % 10);
    }
    put_rn();
}

//------------------------------------------------------------------------------
//	Monitor
//------------------------------------------------------------------------------
//  Help Massage
void msg_hlp (void)
{
    PRINTF(mon_msg);
    put_rn();
    PRINTF("d - Data logger");
    put_rn();
    PRINTF("t - Check and set RTC");
    put_rn();
    PRINTF("x - Goto HW monitor");
    put_rn();
    PRINTF("q - Return to main");
    put_rn();
}

//  Get key input data
void get_line (char *buff, int len)
{
    char c;
    int idx = 0;

    for (;;) {
        c = GETC();
        //    Added by Kenji Arai / JH1PJL   May 9th, 2010
        if (c == '\r') {
            buff[idx++] = c;
            break;
        }
        if ((c == '\b') && idx) {
            idx--;
            PUTC(c);
            PUTC(' ');
            PUTC(c);
        }
        if (((uint8_t)c >= ' ') && (idx < len - 1)) {
            buff[idx++] = c;
            PUTC(c);
        }
    }
    buff[idx] = 0;
    PUTC('\n');
}


// RTC related subroutines
void chk_and_set_time(char *ptr)
{
    unsigned long p1;
    struct tm t;

    if (xatoi(&ptr, &p1)) {
        t.tm_year		= (uint8_t)p1 + 100;
        PRINTF("Year:%d ",(int)p1);
        xatoi( &ptr, &p1 );
        t.tm_mon		= (uint8_t)p1 - 1;
        PRINTF("Month:%d ",(int)p1);
        xatoi( &ptr, &p1 );
        t.tm_mday		= (uint8_t)p1;
        PRINTF("Day:%d ",(int)p1);
        xatoi( &ptr, &p1 );
        t.tm_hour		= (uint8_t)p1;
        PRINTF("Hour:%d ",(int)p1);
        xatoi( &ptr, &p1 );
        t.tm_min    	= (uint8_t)p1;
        PRINTF("Min:%d ",(int)p1);
        xatoi( &ptr, &p1 );
        t.tm_sec 		= (uint8_t)p1;
        PRINTF("Sec: %d \r\n",(int)p1);
        xm41t62.write_rtc_std(&t);
    }
    xm41t62.read_rtc_std(&t);
    // Show Time with several example
    // ex.1
    PRINTF("Date: %04d/%02d/%02d, %02d:%02d:%02d\r\n",
           t.tm_year + 1900, t.tm_mon + 1,
           t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
#if 0
    time_t seconds;
    char buf[40];

    seconds = mktime(&t);
    // ex.2
    strftime(buf, 40, "%x %X", localtime(&seconds));
    PRINTF("Date: %s\r\n", buf);
    // ex.3
    strftime(buf, 40, "%I:%M:%S %p (%Y/%m/%d)", localtime(&seconds));
    PRINTF("Date: %s\r\n", buf);
    // ex.4
    strftime(buf, 40, "%B %d,'%y, %H:%M:%S", localtime(&seconds));
    PRINTF("Date: %s\r\n", buf);
#endif
}

//	Data Logger / Check status and Output data
static void data_logger(char *ptr)
{
    char c;
    unsigned long dt;
    uint16_t n;
    const char * Msg  = "Data Logger Mode, ?[Help]";

    PRINTF("%s", Msg);
    put_rn();
    /* Get EEPROM resource */
    dtlog_pointer_read();
    dt = inf.log_inf.head;
    while (1) {
        /* Get EEPROM resource */
        dtlog_pointer_read();
        PRINTF("DL>");
        ptr = linebuf;
        get_line(ptr, buf_size);
        switch (*ptr++) {
            case 'a' :
                put_r();
                read_pointer = inf.log_inf.head;
                n = dtlog_buf_occupation();
                dtlog_block_read(&read_pointer, n);
                break;
            case 'c' :	// Clear data
                put_r();
                PRINTF("Delete all data?");
                put_rn();
                PRINTF("Enter y/n (n-cancel)");
                put_rn();
                c = GETC();
                PUTC(c);
                put_rn();
                if (c == 'y') {
                    PRINTF("Cleared all logging data");
                    dtlog_clear_all_buff();
                } else {
                    PRINTF("Canceled");
                }
                put_rn();
                break;
            case 'd' :	// d <pointer> [<count>] - Dump buffer
                put_r();
                if (xatoi(&ptr, &dt)) {
                    read_pointer = (uint16_t)dt;
                } else {
                    read_pointer = inf.log_inf.head;
                }
                if (xatoi(&ptr, &dt)) {
                    n = (uint8_t)dt;
                } else {
                    n = BLK_SIZE;
                }
                if (read_pointer == 0) {
                    read_pointer = 1;
                }
                dtlog_block_read(&read_pointer, n);
                break;
            case 0x0d :	// CR
                put_r();
                dtlog_block_read(&read_pointer, BLK_SIZE);
                break;
            case 'b' :	// Back
                put_r();
                read_pointer -= (BLK_SIZE * 2);
                if (read_pointer <= 0) {
                    read_pointer = 1;
                }
                dtlog_block_read(&read_pointer, n);
                break;
            case 'n' :
            case 's' :	// Status
                put_r();
                dtlog_num_of_block();
                break;
            case 'q' :	// exit
                linebuf[0] = 0;
                return;
            case '?' :
                put_r();
                PRINTF("d - <pointer> [<count>] Dump one block data");
                put_rn();
                PRINTF("a - Dump all log data");
                put_rn();
                PRINTF("c - Clear log data");
                put_rn();
                PRINTF("s - Logger status");
                put_rn();
                PRINTF("q - Exit DL mode");
                put_rn();
                break;
            default:
                PUTC('?');
                put_rn();
                break;
        }
    }
}

// ---------- Program starts here! ---------------------------------------------
int mon(void)
{
    char *ptr;

    put_rn();
    put_rn();
    PRINTF("%s [Help:'?' key]", mon_msg);
    put_rn();
    for (;;) {
        put_r();
        PUTC('>');
        ptr = linebuf;
        get_line(ptr, sizeof(linebuf));
        switch (*ptr++) {
            //------------------------------------------------------------------
            //  check and set RTC
            //------------------------------------------------------------------
            case 't' :
                put_r();
                chk_and_set_time(ptr);
                break;
            //------------------------------------------------------------------
            //  check EEPROM status
            //------------------------------------------------------------------
            case 'd' :
                put_r();
                data_logger(ptr);
                break;
            //------------------------------------------------------------------
            //  help
            //------------------------------------------------------------------
            case '?' :
                put_r();
                msg_hlp();
                break;
            //------------------------------------------------------------------
            //  Go to special command
            //------------------------------------------------------------------
            case 'x' :    //
                PRINTF("->ROM & RAM size limitation. ");
                PRINTF("-> Cannot impliment the function\r\n");
                //mon_hw();
                PRINTF("->Came back monitor\r\n");
                break;
            //------------------------------------------------------------------
            //  Go back to main()
            //------------------------------------------------------------------
            case 'q' :        // Quit
                PRINTF("\rReturn to main\r\n");
                PRINTF("cannot control anymore from here\r\n");
                return 0;
        }
    }
}