1st working program
Dependencies: mbed-os_TYBLE16 BME280_SPI RX8025NB nRF51_Vdd MB85RSxx_SPI
see /users/kenjiArai/notebook/tyble16-module-as-mbed-os-5-board-mbedlization/
Diff: dt_logger.cpp
- Revision:
- 6:a3238e93f694
- Child:
- 7:cedbf234a089
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dt_logger.cpp Wed Dec 18 09:24:58 2019 +0000 @@ -0,0 +1,625 @@ +/* + * Mbed Application program / TYBLE-16 Data logger + * + * Copyright (c) 2019 Kenji Arai / JH1PJL + * http://www.page.sannet.ne.jp/kenjia/index.html + * https://os.mbed.com/users/kenjiArai/ + * Created: December 14th, 2019 + * Revised: December 17th, 2019 + */ + +// Include -------------------------------------------------------------------- +#include "mbed.h" +#include "dt_logger.h" + +// Object --------------------------------------------------------------------- +extern Serial pc; + +// Definition ----------------------------------------------------------------- +#define BAUD(x) pc.baud(x) +#define GETC(x) pc.getc(x) +#define PUTC(x) pc.putc(x) +#define PRINTF(...) pc.printf(__VA_ARGS__) +#define READABLE(x) pc.readable(x) + +// FRAM +#define FRAM_TOP 0x0 + +// RAM ------------------------------------------------------------------------ +char linebuf[64]; +int buf_size = sizeof(linebuf); + +// for FRAM 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; // 4byte + uint16_t vcc; // 2 + uint16_t baro; // 2 + int16_t temp; // 2 + uint16_t humi; // 2 + uint32_t dmy; // 4 +}one_log; // 16 bytes total + +union _one{ + uint8_t bf[PKT_SIZE]; + one_log lg; +}one; + +extern time_t log_sec; +extern float vcc_voltage; +extern float barometer; +extern float temperature; +extern float humidity; + +// ROM / Constant data -------------------------------------------------------- +const char *const mon_msg = + "Monitor for TYBLE16 Data logger, created on " __DATE__""; +// $,2019/12/21,12:43:16,3.29,1004.5,+29.3,45.8,* +const char *const log_head = "$,YYYY/MM/DD,HH:MM:SS,Vcc ,Press , Temp,Humi,*"; +const char *const msg_emty = "Data empty"; +const char *const msg_end = "\r\nreach to end"; + +// Function prototypes -------------------------------------------------------- +extern time_t w_check_rtc_time(RX8025 &ex_rtc); + +static void data_logger(MB85RSxx_SPI &fram, char *ptr); +static void msg_hlp (void); +static void time_enter_mode(RX8025 &ex_rtc, char *ptr); +static void chk_and_set_time(RX8025 &ex_rtc, char *ptr); +static int xatoi (char **str, unsigned long *res); +static void get_line(char *buff, int len); +static void put_rn(void); +static void put_r(void); +static void put_lin(void); +static void put_spc(uint8_t n); + +//------------------------------------------------------------------------------ +// Control Program +//------------------------------------------------------------------------------ +// ---------- Program starts here! --------------------------------------------- +int mon(RX8025 &ex_rtc, MB85RSxx_SPI &fram) +{ + char *ptr; + + if (READABLE()){ char c = GETC();} // dummy read + 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(); + time_enter_mode(ex_rtc, ptr); + break; + //-------------------------------------------------------------------------- + // check FRAM status + //-------------------------------------------------------------------------- + case 'd' : + put_r(); + data_logger(fram, ptr); + break; + //-------------------------------------------------------------------------- + // help + //-------------------------------------------------------------------------- + case '?' : + put_r(); + msg_hlp(); + break; + //-------------------------------------------------------------------------- + // Go back to main() + //-------------------------------------------------------------------------- + case 'q' : // Quit + PRINTF("\rReturn to main\r\n"); + PRINTF("cannot control anymore from here\r\n"); + return 0; + } + } +} +//------------------------------------------------------------------------------ +// Data Logging / Save into FRAM +//------------------------------------------------------------------------------ +/* + head = H, tail =T + state1: H=1(RING_TOP),T=1(RING_TOP) -> just after Clear command + state2: H=1,T=n -> n = 2 to RING_TAIL-1 (not filled yet) + state3: H=1,T=RING_TAIL -> need to check!!!! (just filled) + state4: H=2,T=1(RING_TOP) -> start ringed state + state5: H=n,T=n-1 -> n = 2 to RING_TAIL-1 (ringed) + state6: H=RING_TAIL,T=RING_TAIL-1 -> need to check!!!!! + state7: H=1(RING_TOP),T=RING_TAIL -> need to check!!!!! + state8: same as "state5" + -> Need to check state3,6,7 +*/ +// Make one data packet data structure +void dtlog_data_pack(void) +{ + one.lg.time = log_sec - DATE_COUNT_START; + one.lg.vcc = (uint16_t)(vcc_voltage * 100); + one.lg.baro = (uint16_t)(barometer * 10); + one.lg.temp = (int16_t) (temperature * 10); + one.lg.humi = (uint16_t)(humidity * 10); + one.lg.dmy = 0xffff; +} + +// 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(); + //--- Header + PUTC('$'); + //--- Time + seconds = one.lg.time + DATE_COUNT_START; + 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.%02d,", dt0/100, dt0%100); + //--- Pressure/Barometer + dt0 = one.lg.baro; + PRINTF("%04d.%01d,", dt0/10, dt0%10 ); + //--- Temperature + dt1 = one.lg.temp; + PRINTF("%+03d.%01d,", dt1/10, abs(dt1)%10 ); + //--- Humidity + dt0 = one.lg.humi; + PRINTF("%02d.%01d,", dt0/10, dt0%10 ); + //---- Tail + PUTC('*'); +} + +// Read buffer pointer +static void dtlog_pointer_read(MB85RSxx_SPI &fram) +{ + uint8_t i; + uint8_t *addr; + + // Read FRAM and save to buf_pointer[] + addr = (uint8_t *)FRAM_TOP; + fram.read((int)addr, inf.buf_pointer, PTR_SIZE); + PRINTF("Head=%d,Tail=%d\r\n", inf.log_inf.head, inf.log_inf.tail); +} + +// Write one packet +void dtlog_one_write(MB85RSxx_SPI &fram) +{ + uint8_t *addr; + + // Read FRAM buffer pointer to RAM + addr = (uint8_t *)FRAM_TOP; + fram.read((int)addr, inf.buf_pointer, PTR_SIZE); + PRINTF("Befre:Head=%d,Tail=%d -> ", inf.log_inf.head, inf.log_inf.tail); + // Write data_pack[] into FRAM + addr = (uint8_t *)(FRAM_TOP + (inf.log_inf.tail * PTR_SIZE)); + fram.write_enable(); + fram.write((int)addr, one.bf, PTR_SIZE); + fram.write_disable(); + // Increment buffer pointer in RAM + if (inf.log_inf.head == RING_TOP){ // check state1,2,3 + if (inf.log_inf.tail == RING_TAIL){ // check state3 + inf.log_inf.tail = RING_TOP; // set state4 + inf.log_inf.head = 2; // missing one oldest data + } else { + inf.log_inf.tail++; // set state2 + } + } else { // check state 4,5,6,7 + if (inf.log_inf.head == RING_TAIL){ // check state6 + inf.log_inf.head = RING_TOP; // set state7 + inf.log_inf.tail = RING_TAIL; + } else if (inf.log_inf.tail == inf.log_inf.head - 1){ // check state4,5 + ++inf.log_inf.tail; // continue state5 + ++inf.log_inf.head; + } + } + // Write buffer pointer into FRAM + addr = (uint8_t *)FRAM_TOP; + fram.write_enable(); + fram.write((int)addr, inf.buf_pointer, PTR_SIZE); + fram.write_disable(); + PRINTF("After:Head=%d,Tail=%d\r\n", inf.log_inf.head, inf.log_inf.tail); +} + +// Read some block from buffer +void dtlog_block_read(MB85RSxx_SPI &fram, int16_t *pt, uint16_t n) +{ + uint8_t *addr; + uint16_t num; + + dtlog_pointer_read(fram); + if (inf.log_inf.tail == inf.log_inf.head){ // Check pointer + PRINTF("%s", 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("%s", log_head); + for (num = 0; num < n; num++){ + // Read FRAM and save to data_pack[] + addr = (uint8_t *)(FRAM_TOP + (*pt * PTR_SIZE)); + fram.read((int)addr, one.bf, PTR_SIZE); + print_one_block_data(); + if (READABLE()){ GETC(); break;} + 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("%s", 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("%s", msg_end); + break; + } + } + } + } else if (inf.log_inf.tail == inf.log_inf.head - 1){// check state5 + *pt += 1; + if (*pt > RING_TAIL){ // same as :pt += 1 + *pt = RING_TOP; + } else if (*pt == inf.log_inf.tail){ // reach to end + PRINTF("%s", msg_end); + break; + } + } + } + } + put_rn(); +} + +// Clear all buffer +void dtlog_clear_all_buff(MB85RSxx_SPI &fram) +{ + uint8_t *addr; + + // Set initial data + inf.log_inf.head = inf.log_inf.tail = RING_TOP; + // Write buffer pointer + addr = (uint8_t *)FRAM_TOP; + fram.write_enable(); + fram.write((int)addr, inf.buf_pointer, PTR_SIZE); + fram.write_disable(); +} + +// FRAM buffer occupation +uint16_t dtlog_buf_occupation(MB85RSxx_SPI &fram) +{ + uint16_t dt = 0; + uint8_t *addr; + + // Read FRAM buffer pointer to RAM + addr = (uint8_t *)FRAM_TOP; + fram.read((int)addr, inf.buf_pointer, PTR_SIZE); + // check buffer pointer + if (inf.log_inf.head == inf.log_inf.tail){ + PRINTF("%s", msg_emty); + put_rn(); + return 0; + } + if (inf.log_inf.head == RING_TOP){ // check state1,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 state6 + if (inf.log_inf.tail == RING_TAIL - 1){ // check state6 + dt = inf.log_inf.tail - RING_TOP + 1; + } + } else if (inf.log_inf.tail == inf.log_inf.head - 1){ // check state4,5 + dt = RING_TAIL; + } else { // error + dt = 0; + } + } + return dt; +} + +// Read block number +void dtlog_num_of_block(MB85RSxx_SPI &fram) +{ + uint16_t dt; + + dt = dtlog_buf_occupation(fram); + if (dt == 0){ + PRINTF("%s", msg_emty); + } else { + PRINTF("Number of data = %d", dt); + put_rn(); + dt = (uint16_t)(((uint32_t)dt * 1000 )/ (BLK_NO - 2)); + PRINTF("FRAM Occupation = %d.%01d%%", dt / 10, dt % 10); + } + put_rn(); +} + +//------------------------------------------------------------------------------ +// Monitor +//------------------------------------------------------------------------------ +// Help Massage +void msg_hlp (void) +{ + PRINTF("%s", mon_msg); put_rn(); + PRINTF("d - Data logger"); put_rn(); + PRINTF("t - Check and set RTC"); put_rn(); + PRINTF("q - Return to main"); put_rn(); +} + +// Data Logger / Check status and Output data +static void data_logger(MB85RSxx_SPI &fram, char *ptr) +{ + char c; + unsigned long dt; + uint16_t n; + const char *const Msg = "Data Logger Mode, ?[Help]"; + + PRINTF("%s", Msg); + put_rn(); + // Get FRAM resource + dtlog_pointer_read(fram); + dt = inf.log_inf.head; + while (1){ + // Get FRAM resource + dtlog_pointer_read(fram); + 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(fram); + dtlog_block_read(fram, &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(fram); + } 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(fram, &read_pointer, n); + break; + case 0x0d : // CR + put_r(); + dtlog_block_read(fram, &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(fram, &read_pointer, n); + break; + case 'n' : + case 's' : // Status + put_r(); + dtlog_num_of_block(fram); + 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; + } + } +} + +void time_enter_mode(RX8025 &ex_rtc, char *pointer) +{ + char *ptr; + char linebuf[64]; + time_t seconds; + + pc.printf("Set time into RTC\r\n"); + pc.printf(" e.g. ->19 12 16 10 11 12 -> December 16th,'19, 10:11:12\r\n"); + seconds = w_check_rtc_time(ex_rtc); + strftime(linebuf, 50, "Current time: %Y/%m/%d,%H:%M:%S\r\n", + localtime(&seconds)); + pc.printf("%s", linebuf); + pc.printf(" If time is fine, just hit enter\r\n"); + pc.puts("->"); + if (pointer == 0) { + ptr = linebuf; + } else { + ptr = pointer; + } + get_line(ptr, sizeof(linebuf)); + pc.printf("\r"); + chk_and_set_time(ex_rtc, ptr); +} + +void chk_and_set_time(RX8025 &ex_rtc, char *ptr) +{ + unsigned long p1; + struct tm t; + time_t seconds; + + if (xatoi(&ptr, &p1)) { + t.tm_year = (uint8_t)p1 + 100; + pc.printf("Year:%d ", (int)p1); + xatoi( &ptr, &p1 ); + t.tm_mon = (uint8_t)p1 - 1; + pc.printf("Month:%d ", (int)p1); + xatoi( &ptr, &p1 ); + t.tm_mday = (uint8_t)p1; + pc.printf("Day:%d ", (int)p1); + xatoi( &ptr, &p1 ); + t.tm_hour = (uint8_t)p1; + pc.printf("Hour:%d ", (int)p1); + xatoi( &ptr, &p1 ); + t.tm_min = (uint8_t)p1; + pc.printf("Min:%d ", (int)p1); + xatoi( &ptr, &p1 ); + t.tm_sec = (uint8_t)p1; + pc.printf("Sec: %d \r\n", (int)p1); + } else { + return; + } + seconds = mktime(&t); + set_time(seconds); + struct tm *time_ajd = localtime(&seconds); + ex_rtc.set_time_rtc(time_ajd); + pc.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 + ); +} + +// Get key input data +void get_line (char *buff, int len) +{ + char c; + int idx = 0; + + for (;;) { + c = pc.getc(); + if (c == '\r') { + buff[idx++] = c; + break; + } + if ((c == '\b') && idx) { + idx--; + pc.putc(c); + pc.putc(' '); + pc.putc(c); + } + if (((uint8_t)c >= ' ') && (idx < len - 1)) { + buff[idx++] = c; + pc.putc(c); + } + } + buff[idx] = 0; + pc.putc('\n'); +} + +// 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; +} + +// 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(' '); }}