From 1502df658e0de66863f3c51d862ce91239f4c0a5 Mon Sep 17 00:00:00 2001 From: Naoya Takamura Date: Fri, 9 Dec 2011 17:20:22 +0900 Subject: [PATCH] 1sec and high smpling file record add. --- Makefile | 4 +- ad_file.c | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ad_file.h | 53 ++++++++++++ ad_ring.c | 200 ++++++++++++++++++++++++++++++++++++++++++++ ad_ring.h | 70 ++++++++++++++++ conf.c | 154 ++++++++++++++++++++++++++++++++++ conf.h | 13 +++ makefile.host | 35 ++++++++ my_thread.h | 5 ++ ring.c | 142 ++++++++++++++++++++++++++++++++ ring.h | 33 ++++++++ scilog | Bin 11368 -> 28140 bytes scilog.c | 24 ++++-- spi.h | 29 ++----- sts.c | 40 +++++++++ sts.h | 17 ++++ test | Bin 0 -> 13644 bytes test.c | 23 ++++++ thread_rcv.c | 131 +++++++++++++++++++++++++++-- thread_rec.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ thread_rec.h | 11 +++ 21 files changed, 1457 insertions(+), 38 deletions(-) create mode 100644 ad_file.c create mode 100644 ad_file.h create mode 100644 ad_ring.c create mode 100644 ad_ring.h create mode 100644 conf.c create mode 100644 conf.h create mode 100755 makefile.host create mode 100644 ring.c create mode 100644 ring.h create mode 100644 sts.c create mode 100644 sts.h create mode 100755 test create mode 100644 test.c create mode 100644 thread_rec.c create mode 100644 thread_rec.h diff --git a/Makefile b/Makefile index cbb33cb..aa1ff2f 100644 --- a/Makefile +++ b/Makefile @@ -30,9 +30,9 @@ INCDIR = ${STAGEDIR}/include TARGET = scilog -OBJS = scilog.o spi.o thread_rcv.o +OBJS = scilog.o spi.o thread_rcv.o ring.o ad_ring.o thread_rec.o sts.o ad_file.o conf.o -HDRS = mes_print.h debug_print.h spi.h my_thread.h +HDRS = mes_print.h debug_print.h spi.h my_thread.h ring.h ad_ring.h thread_rec.h sts.h ad_file.h conf.h ${TARGET} : $(OBJS) $(HDRS) ${CC} ${CFLAGS} ${OBJS} -L ${LIBDIR} -o ${TARGET} diff --git a/ad_file.c b/ad_file.c new file mode 100644 index 0000000..fd3ca15 --- /dev/null +++ b/ad_file.c @@ -0,0 +1,260 @@ +/* + 1secファイル + 高速サンプルファイル + +#define DEBUG_FILE_MIN + 定義するとファイルが1日単位ではなく指定された分単位になる + ただし、ファイルのサイズは1日と同じサイズのまま +#deifne DEBUG_FILE_MIN_PERIOD + ファイルの単位 + 単位 分 + +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ad_ring.h" +#include "ad_file.h" +#include "debug_print.h" +#include "conf.h" + +// mkdir_p()で使用する +#define MKDIR_MODE "755" + +/**** util +*/ +/* + 指定さえれたディレクトリを作成 + 親がないときは親まで作る + char *mode + 755とか + return + 0=OK + -1=ERROR +*/ +static int mkdir_p(const char *path, char *mode) +{ + struct stat st; + char cmd[128]; + + // コピー先ディレクトリ存在しなければ作成する + if (stat(path, &st) == -1) { + PDEBUG("mkdir_p(): make dir %s\n", path); + + sprintf(cmd, "mkdir -p -m %s %s > /dev/null 2> /dev/null &", mode, path); + switch(system(cmd)) { + case 127: + // shell exec error + PDEBUG("mkdir_p(): shell exec error\n"); + syslog(LOG_ERR, "mkdir_p(): system() shell exec error"); + return -1; + case -1: + // error + PDEBUG("mkdir_p(): error\n"); + syslog(LOG_ERR, "mkdir_p(): system() error"); + return -1; + default: + // 作成されるまで待つ + sleep(3); + return 0; + } + } + return 0; +} + + +/**** 1秒ファイル関係 ************************************************************ +*/ +/* + 1秒データファイル オープン + + Return: + 1 = Error + 0 = OK + */ +int sec_file_open(FILE **fp, AdData *D) +{ + char szDir[64]; + struct stat st; + char fname[64]; + char path[128]; + + // サブディレクトリ作成 + sprintf(szDir, "%s/%s/%04d/%02d", DIR_DATA, sid_getp(), D->t.tm_year+1900, D->t.tm_mon+1); + // ディレクトリ存在しなければ作成する + if (stat(szDir, &st) == -1) mkdir_p(szDir, MKDIR_MODE); + + // ファイル名作成 +#ifdef DEBUG_FILE_MIN + sprintf(fname, "%04d%02d%02d_%02d%02d.sec", + D->t.tm_year+1900, D->t.tm_mon+1, D->t.tm_mday, D->t.tm_hour, D->t.tm_min / DEBUG_FILE_MIN_PERIOD * DEBUG_FILE_MIN_PERIOD); +#else + sprintf(fname, "%04d%02d%02d.sec", D->t.tm_year+1900, D->t.tm_mon+1, D->t.tm_mday); +#endif + // フルパス作成 + strcpy(path, szDir); + strcat(path, "/"); + strcat(path, fname); + PDEBUGF("path=%s\n", path); + + *fp = fopen(path, "a"); + if (*fp == NULL) { + syslog(LOG_ERR, "%s(): fopen() ERROR. %s", __FUNCTION__, strerror(errno)); + return 1; + } + return 0; +} +/* + Return: + 1 = Error + 0 = OK + */ +int sec_file_out(FILE *fp, char *out, int len) +{ + int ret; + + if (fp == NULL) return 1; + if ((ret = fwrite(out, 1, len, fp)) < len) { + syslog(LOG_ERR, "%s(): fwrite() return %d < %d. %s", __FUNCTION__, ret, len, strerror(errno)); + return 1; + } + return 0; +} +/* + 1秒データファイル クローズ + + Return: + 1 = Error + 0 = OK + */ +int sec_file_close(FILE *fp) +{ + if (fp == NULL) return 1; + fclose(fp); + return 0; +} + +/* + 1secファイル記録用データ作る +*/ +int sec_make_rec_data(AdData *ad, char *buf) +{ + char buf2[32]; + int ch; + + sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d,%3lu,%02X", + ad->gps.year, ad->gps.month, ad->gps.day, ad->gps.hour, ad->gps.min, ad->gps.sec, + ad->gps.tacc, ad->gps.valid); + for(ch = 0; ch < AD_CHNUM; ch++) { + sprintf(buf2, ",%+7ld", ad->data1sec[ch]); + strcat(buf, buf2); + } + strcat(buf, "\n"); + return 0; +} +/**** 高速サンプルファイル関係 ************************************************************ +*/ +/* + Return: + 1 = Error + 0 = OK + */ +int high_file_open(FILE **fp, AdData *D) +{ + char szDir[64]; + struct stat st; + char fname[64]; + char path[128]; + + // サブディレクトリ作成 + sprintf(szDir, "%s/%s/%04d/%02d", DIR_DATA, sid_getp(), D->t.tm_year+1900, D->t.tm_mon+1); + // ディレクトリ存在しなければ作成する + if (stat(szDir, &st) == -1) mkdir_p(szDir, MKDIR_MODE); + + // ファイル名作成 +#ifdef DEBUG_FILE_MIN + sprintf(fname, "%04d%02d%02d_%02d%02d.sec", + D->t.tm_year+1900, D->t.tm_mon+1, D->t.tm_mday, D->t.tm_hour, D->t.tm_min / DEBUG_FILE_MIN_PERIOD * DEBUG_FILE_MIN_PERIOD); +#else + sprintf(fname, "%04d%02d%02d%02d.high", D->t.tm_year+1900, D->t.tm_mon+1, D->t.tm_mday, D->t.tm_hour); +#endif + // フルパス作成 + strcpy(path, szDir); + strcat(path, "/"); + strcat(path, fname); + PDEBUGF("path=%s\n", path); + + *fp = fopen(path, "a"); + if (*fp == NULL) { + syslog(LOG_ERR, "%s(): fopen() ERROR. %s", __FUNCTION__, strerror(errno)); + return 1; + } + return 0; +} +/* + Return: + 1 = Error + 0 = OK + */ +int high_file_out(FILE *fp, char *out, int len) +{ + int ret; + + if (fp == NULL) return 1; + if ((ret = fwrite(out, 1, len, fp)) < len) { + syslog(LOG_ERR, "%s(): fwrite() return %d < %d. %s", __FUNCTION__, ret, len, strerror(errno)); + return 1; + } + return 0; +} +/* + Return: + 1 = Error + 0 = OK + */ +int high_file_close(FILE *fp) +{ + if (fp == NULL) return 1; + fclose(fp); + return 0; +} + +/* + 記録用データ作る +*/ +int high_make_rec_data(AdData *ad, char *ptr) +{ + unsigned char *src; + int ch, i, j; + + *ptr++ = ad->gps.year & 0xFF; + *ptr++ = (ad->gps.year >> 8) & 0xFF; + *ptr++ = ad->gps.month; + *ptr++ = ad->gps.day; + *ptr++ = ad->gps.hour; + *ptr++ = ad->gps.min; + *ptr++ = ad->gps.sec; + *ptr++ = ad->gps.nano; + *ptr++ = ad->gps.valid; + // + src = ad->data; + for(ch = 0; ch < AD_CHNUM; ch++) { + for(i = 0; i < AD_SAMPLE; i++) { + for(j = 0; j < AD_BYTES; j++) { + *ptr++ = *src++; + } + src++; + } + } + return 0; +} + + + + diff --git a/ad_file.h b/ad_file.h new file mode 100644 index 0000000..f479e2d --- /dev/null +++ b/ad_file.h @@ -0,0 +1,53 @@ +#if !defined(__AD_FILE_H__) +#define __AD_FILE_H__ + +#include "ad_ring.h" + +// データ記録用dir 末尾に/付けない +#ifdef DUMMY + #define DIR_DATA "/home/ntaka/dev/arm2011n/data" +#else + #define DIR_DATA "/home/data" +#endif + +#if 0 +// NAV-TIMEUTCパケットのファイル記録用データタイプ +typedef struct { + unsigned long tow; // ms GPS Millisecond Time of Week + unsigned long tacc; // ns Time Accuracy Estimate + long nano; // ns Nanoseconds of second, range -1e9 .. 1e9 (UTC) + unsigned int year __attribute__((aligned(1))); // 12 UTC + unsigned char month __attribute__((aligned(1))); // 16 + unsigned char day __attribute__((aligned(1))); + unsigned char hour __attribute__((aligned(1))); + unsigned char min __attribute__((aligned(1))); + unsigned char sec __attribute__((aligned(1))); + unsigned char valid __attribute__((aligned(1))); // Validity Flags + // bit0 validTOW 1 = Valid Time of Week + // bit1 validWKN 1 = Valid Week Number + // bit2 validUTC 1 = Valid UTC (Leap Seconds already known) +} UbloxNavTimeUtcRecType __attribute__((aligned(1))); + +// 高速サンプルデータ記録用データタイプ +typedef struct { + UbloxNavTimeUtcRecType gps; // GPSタイムスタンプ + unsigned char data[AD_CHNUM][AD_SAMPLE][AD_BYTES]; // AD +} HighSampleRecType; + +#define HIGH_WRITE_LEN szieof(HighSampleRecType) +#endif + +#define HIGH_WRITE_LEN (9 + AD_CHNUM*AD_SAMPLE*AD_BYTES) // 仮で50Hz 記録周波数で変わるので要変更!!!!!!!!!!!!!! + + +int sec_file_open(FILE **fp, AdData *D); +int sec_file_out(FILE *fp, char *out, int len); +int sec_file_close(FILE *fp); +int sec_make_rec_data(AdData *ad, char *buf); + +int high_file_open(FILE **fp, AdData *D); +int high_file_out(FILE *fp, char *out, int len); +int high_file_close(FILE *fp); +int high_make_rec_data(AdData *ad, char *buf); + +#endif diff --git a/ad_ring.c b/ad_ring.c new file mode 100644 index 0000000..ccec6ef --- /dev/null +++ b/ad_ring.c @@ -0,0 +1,200 @@ +#include +#include + + +#include "ring.h" +#include "ad_ring.h" +#include "mes_print.h" + +// Ring Buffer読み込みポインタ個数 +#define AD_RING_READ_NUM 2 +// Ring Buffer読み込みポインター 1sec記録用 +#define AD_RING_READ_PTR1 0 +// Ring Buffer読み込みポインター 1min記録用 +#define AD_RING_READ_PTR2 1 + +static AdData ad_ring_buf[AD_RING_NUM]; + +// ミューテックス +static pthread_mutex_t mutex_ad_ring = PTHREAD_MUTEX_INITIALIZER; + +// Ring buffer +static RING_T *ring; + +int ad_ring_init(void) +{ +pthread_mutex_lock(&mutex_ad_ring); + ring = ring_create(AD_RING_READ_NUM); + if (ring == NULL) { + PERRF("ERROR ring_create() == NULL\n"); +pthread_mutex_unlock(&mutex_ad_ring); + return -1; + } + ring_init(ring, AD_RING_NUM); +pthread_mutex_unlock(&mutex_ad_ring); + return 0; +} +void ad_ring_clear_sec(void) +{ + ring_clear(ring, AD_RING_READ_PTR1); +} +void ad_ring_clear_high(void) +{ + ring_clear(ring, AD_RING_READ_PTR2); +} +void ad_ring_clear_latest(void) +{ + ring_latest_set(ring, -1); +} + +// 読み出し位置 1secデータ記録で使用 +int ad_ring_read_get_sec(void) +{ + return ring_read_get(ring, AD_RING_READ_PTR1); +} +void ad_ring_read_set_sec(int i) +{ + ring_read_set(ring, AD_RING_READ_PTR1, i); +} +void ad_ring_read_plus_sec(void) +{ + ring_read_plus(ring, AD_RING_READ_PTR1); +} +// 読み出し位置 高速データ記録で使用 +int ad_ring_read_get_high(void) +{ + return ring_read_get(ring, AD_RING_READ_PTR2); +} +void ad_ring_read_set_high(int i) +{ + ring_read_set(ring, AD_RING_READ_PTR2, i); +} +void ad_ring_read_plus_high(void) +{ + ring_read_plus(ring, AD_RING_READ_PTR2); +} + +// 書き込み位置 AD受信で使用 +int ad_ring_write_get(void) +{ + return ring_write_get(ring); +} +void ad_ring_write_plus(void) +{ + ring_write_plus(ring); +} +// 読み込んでいないデータ数 +int ad_ring_num_get_sec(void) +{ + return ring_num_get(ring, AD_RING_READ_PTR1); +} +// 読み込んでいないデータ数 +int ad_ring_num_get_high(void) +{ + return ring_num_get(ring, AD_RING_READ_PTR2); +} +// 最新データ位置 表示 +int ad_ring_latest_get(void) +{ + return ring_latest_get(ring); +} +void ad_ring_latest_set(int i) +{ + ring_latest_set(ring, i); +} +// データ取得 +AdData* ad_ring_get(int ptr) +{ + AdData* p; +pthread_mutex_lock(&mutex_ad_ring); + p = &ad_ring_buf[ptr]; +pthread_mutex_unlock(&mutex_ad_ring); + return p; +} +/* + バッファにデータコピー +*/ +void ad_ring_set(AdData *data) +{ + int i; + +pthread_mutex_lock(&mutex_ad_ring); + i = ring_write_get(ring); + ad_ring_buf[i] = *data; + // 最新データ位置セット + ring_latest_set(ring, i); +pthread_mutex_unlock(&mutex_ad_ring); +} + +/* + パケットバッファフル? + 1=Full + 0=not Full +*/ +int ad_ring_is_full(void) +{ + return ring_is_full(ring, AD_RING_READ_PTR1); +} + + +/**** CUnit test +*/ +#ifdef CUNIT +static void test_ad_ring(void) +{ + ad_ring_init(); + + // CLEAR + ad_ring_clear_sec(); + CU_ASSERT(ad_ring_read_get_sec() == 0); + ad_ring_clear_high(); + CU_ASSERT(ad_ring_read_get_high() == 0); + ad_ring_clear_latest(); + CU_ASSERT(ad_ring_latest_get() == -1); + + // PLUS + ad_ring_read_plus_sec(); + CU_ASSERT(ad_ring_read_get_sec() == 1); + ad_ring_read_plus_high(); + CU_ASSERT(ad_ring_read_get_high() == 1); + ad_ring_write_plus(); + CU_ASSERT(ad_ring_write_get() == 1); + + // 境界値でPLUS + ad_ring_read_set_sec(AD_RING_NUM - 1); + ad_ring_read_plus_sec(); + CU_ASSERT(ad_ring_read_get_sec() == 0); + + ad_ring_read_set_high(AD_RING_NUM - 1); + ad_ring_read_plus_high(); + CU_ASSERT(ad_ring_read_get_high() == 0); + + ring->write = AD_RING_NUM - 1; + ad_ring_write_plus(); + CU_ASSERT(ad_ring_write_get() == 0); + + // + ring->write = 1; + ring->read[AD_RING_READ_PTR1] = 0; + CU_ASSERT(ad_ring_num_get_sec() == 1); + + ring->write = 0; + ring->read[AD_RING_READ_PTR1] = AD_RING_NUM - 1; + CU_ASSERT(ad_ring_num_get_sec() == 1); + + ring->write = 1; + ring->read[AD_RING_READ_PTR2] = 0; + CU_ASSERT(ad_ring_num_get_high() == 1); + + ring->write = 0; + ring->read[AD_RING_READ_PTR2] = AD_RING_NUM - 1; + CU_ASSERT(ad_ring_num_get_high() == 1); + +} + +void ad_ring_test(CU_pSuite test_suite) +{ + CU_add_test(test_suite, "test_ad_ring", test_ad_ring); + +} +#endif diff --git a/ad_ring.h b/ad_ring.h new file mode 100644 index 0000000..f63ddd0 --- /dev/null +++ b/ad_ring.h @@ -0,0 +1,70 @@ +#if !defined(__AVG_RING_H__) +#define __AVG_RING_H__ + +#include + +// リングバッファサイズ 個数 +#define AD_RING_NUM (60 * 5) + +#define AD_CHNUM 6 // AD CH数 +#define AD_SAMPLE 50 // AD ICの出力レート [Hz] +#define AD_BYTES 3 // AD 1sample dataのバイト数 + +// NAV-TIMEUTCパケットのデータ格納 +typedef struct { + unsigned long tow; // ms GPS Millisecond Time of Week + unsigned long tacc; // ns Time Accuracy Estimate + long nano; // ns Nanoseconds of second, range -1e9 .. 1e9 (UTC) + unsigned int year; // UTC + unsigned char month; // + unsigned char day; + unsigned char hour; + unsigned char min; + unsigned char sec; + unsigned char valid; // Validity Flags + // bit0 validTOW 1 = Valid Time of Week + // bit1 validWKN 1 = Valid Week Number + // bit2 validUTC 1 = Valid UTC (Leap Seconds already known) +} UbloxNavTimeUtc; + +// リングバッファのデータタイプ +typedef struct { + UbloxNavTimeUtc gps; // GPSタイムスタンプ SPIで受信 + struct tm t; // タイムスタンプ struct tmの月は(0〜11)なので注意 年は1900からのオフセット + long data1sec[AD_CHNUM]; // 1sec平均値 SPIで受信 + long data[AD_CHNUM][AD_SAMPLE]; // AD_SAMPLE[Hz]の生データ SPIで受信 + long avg[AD_CHNUM][AD_SAMPLE]; // 平均後データ +} AdData; + + + +int ad_ring_init(void); + +void ad_ring_clear_sec(void); +void ad_ring_clear_high(void); +void ad_ring_clear_latest(void); + +int ad_ring_read_get_sec(void); +void ad_ring_read_set_sec(int i); +void ad_ring_read_plus_sec(void); +int ad_ring_num_get_sec(void); + +int ad_ring_read_get_high(void); +void ad_ring_read_set_high(int i); +void ad_ring_read_plus_high(void); +int ad_ring_num_get_high(void); + +int ad_ring_write_get(void); +void ad_ring_write_plus(void); +int ad_ring_latest_get(void); +void ad_ring_latest_set(int i); +AdData* ad_ring_get(int ptr); +void ad_ring_set(AdData *data); +int ad_ring_full(void); + +#ifdef CUNIT + #include + void ad_ring_test(CU_pSuite test_suite); +#endif + +#endif diff --git a/conf.c b/conf.c new file mode 100644 index 0000000..da6e9af --- /dev/null +++ b/conf.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include + +#include "conf.h" +#include "debug_print.h" + +// +/**** Station ID *************************************************** +*/ +#define SID_MAX 16 +static char gsid[SID_MAX + 1]; + +// ミューテックス +static pthread_mutex_t mutex_sid = PTHREAD_MUTEX_INITIALIZER; + +void sid_set(char *s) +{ +pthread_mutex_lock(&mutex_sid); + strncpy(gsid, s, SID_MAX); + gsid[SID_MAX] = 0; +pthread_mutex_unlock(&mutex_sid); +} +void sid_get(char *s) +{ +pthread_mutex_lock(&mutex_sid); + strncpy(s, gsid, SID_MAX); + s[SID_MAX] = 0; +pthread_mutex_unlock(&mutex_sid); +} +char *sid_getp(void) +{ + return gsid; +} + +// +/**** 設定ファイル ******************************************* +*/ +/* + 文字列の前から空白を取り除く +*/ +static void trims_space(char *name) +{ + char c; + char *name0; + int len; + + name0 = name; + len = strlen(name); + + // 最初の非空白文字までポインタ移動 + while (*name) { + c = *name; + if (c != ' ') break; + name++; + len--; + } + if (len < 0) return; + // 移動 + if (name0 != name) memmove(name0, name, len); + // 末尾に0入れる + name0[len] = 0; +} +/* + 文字列の後ろから空白を取り除く +*/ +static void trime_space(char *name) +{ + char c; + int len, i; + + // 文字列末尾 + len = strlen(name); + name += (len - 1); + // 最初の非空白文字までポインタ移動 + for(i = len - 1; i >= 0; i--) { + c = *name; + if (c != ' ') break; + name--; + } + // 末尾に0入れる + *(name + 1) = 0; +} +/* + 文字列の前後から空白を取り除く +*/ +static void trim_space(char *name) +{ + if (name == NULL) return; + trims_space(name); + trime_space(name); +} +/* + 文字列の末尾からCR LFを除く +*/ +static void trim_crlf(char *name) +{ + int i; + int len; + char *src, *dst; + + if (name == NULL) return; + len = strlen(name); + src = name; + dst = name; + for(i = 0; i < len; i++) { + if (*src != 0x0d && *src != 0x0a) { + *dst = *src; + dst++; + } + src++; + } + *dst = 0; +} + +/* + 読み込み + +return + -1=ERR + 0=OK +*/ +int conf_read(void) +{ + FILE *fp; + char buf[256]; + char buf2[256]; + + fp = fopen(CONF_FILE, "rt"); + if (fp == NULL) { + syslog(LOG_ERR, "conf_read(): conf file not found. %s", CONF_FILE); + return -1; + } + + syslog(LOG_INFO, "conf_read():"); + while(fgets(buf, sizeof(buf), fp)) { + // CR LF除く + trim_crlf(buf); + trim_space(buf); + PDEBUG(buf); + PDEBUG("\n"); + // Station ID + if (sscanf(buf, "sid = %s", buf2) == 1) { + sid_set(buf2); + syslog(LOG_INFO, "sid=%s", sid_getp()); + } + } + fclose(fp); + return 0; +} + + diff --git a/conf.h b/conf.h new file mode 100644 index 0000000..ed313ef --- /dev/null +++ b/conf.h @@ -0,0 +1,13 @@ +#if !defined(__CONF_H__) +#define __CONF_H__ + +// 設定ファイル +#define CONF_FILE "/etc/meas.conf" + +void sid_set(char *s); +void sid_get(char *s); +char *sid_getp(void); +int conf_read(void); + + +#endif diff --git a/makefile.host b/makefile.host new file mode 100755 index 0000000..0f9a208 --- /dev/null +++ b/makefile.host @@ -0,0 +1,35 @@ +CC = gcc + +# -DDUMMY ダミーデータで動作する +all: CFLAGS = -DDUMMY +cunit: CFLAGS = -DCUNIT + +LDFLAGS = +LIBS = -lm -lpthread +TEST_LIBS = $(LIBS) -lcunit + +SRCS0 = thread_rcv.c spi.c ring.c ad_ring.c rec.c sts.c ad_file.c +SRCS = scilog.c $(SRCS0) +TEST_SRCS = test.c $(SRCS0) + +HDRS = mes_print.h debug_print.h my_thread.h spi.h ring.h ad_ring.h rec.h sts.h ad_file.h + +OBJS = $(SRCS:.c=.o) +TEST_OBJS = $(TEST_SRCS:.c=.o) + +PROGRAM = scilog +TEST_PROG = test + +all: $(PROGRAM) + +cunit: $(TEST_PROG) + +$(PROGRAM): $(OBJS) $(HDRS) + $(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $(PROGRAM) + +$(TEST_PROG): $(TEST_OBJS) $(HDRS) + $(CC) $(TEST_OBJS) $(LDFLAGS) $(TEST_LIBS) -o $(TEST_PROG) + +clean:; rm -f *.o *~ $(PROGRAM) $(TEST_PROG) + +### End of Makefile diff --git a/my_thread.h b/my_thread.h index de034b9..10976f1 100644 --- a/my_thread.h +++ b/my_thread.h @@ -3,4 +3,9 @@ void* thread_rcv(void* pParam); +#ifdef CUNIT + #include + void thread_rcv_test(CU_pSuite test_suite); +#endif + #endif diff --git a/ring.c b/ring.c new file mode 100644 index 0000000..c13422e --- /dev/null +++ b/ring.c @@ -0,0 +1,142 @@ +/* + Ring Buffer用基本機能 + write位置 + read位置 +*/ +#include +#include +#include + +#include "ring.h" + +#define READ_NUM_MAX 256 +// ミューテックス +static pthread_mutex_t mutex_ring = PTHREAD_MUTEX_INITIALIZER; + +/* + int read_num + 読み込みポインタの個数 +*/ +RING_T* ring_create(int read_num) +{ + RING_T *t; + if (read_num <= 0) return NULL; + if (read_num > READ_NUM_MAX) return NULL; + + t = malloc(sizeof(RING_T)); + if (t != NULL) { + // readポインタ確保 + t->read = malloc(sizeof(int) * read_num); + if (t->read == NULL) { + free(t); + return NULL; + } + t->read_num = read_num; + } + return t; +} +void ring_destroy(RING_T *t) +{ + free(t->read); + free(t); +} +/* + int num: バッファの個数 +*/ +void ring_init(RING_T *t, int num) +{ + int i; + +pthread_mutex_lock(&mutex_ring); + t->write = 0; + for(i = 0; i < t->read_num; i++) { + t->read[i] = 0; + } + t->latest = -1; + t->num = num; +pthread_mutex_unlock(&mutex_ring); +} +void ring_clear(RING_T *t, int no) +{ + ring_read_set(t, no, ring_write_get(t)); +} +/* + 読み出し位置 + int no + readポインタ番号 +*/ +int ring_read_get(RING_T *t, int no) +{ + int i; +pthread_mutex_lock(&mutex_ring); + i = t->read[no]; +pthread_mutex_unlock(&mutex_ring); + return i; +} +void ring_read_set(RING_T *t, int no, int i) +{ +pthread_mutex_lock(&mutex_ring); + t->read[no] = i; +pthread_mutex_unlock(&mutex_ring); +} +void ring_read_plus(RING_T *t, int no) +{ +pthread_mutex_lock(&mutex_ring); + t->read[no]++; + if (t->read[no] >= t->num) t->read[no] = 0; +pthread_mutex_unlock(&mutex_ring); +} + +// 書き込み位置 +int ring_write_get(RING_T *t) +{ + int i; +pthread_mutex_lock(&mutex_ring); + i = t->write; +pthread_mutex_unlock(&mutex_ring); + return i; +} +void ring_write_plus(RING_T *t) +{ +pthread_mutex_lock(&mutex_ring); + t->write++; + if (t->write >= t->num) t->write = 0; +pthread_mutex_unlock(&mutex_ring); +} +// 読み込んでいないデータ数 +int ring_num_get(RING_T *t, int no) +{ + int i; + +pthread_mutex_lock(&mutex_ring); + i = t->write - t->read[no]; + if (i < 0) i += t->num; +pthread_mutex_unlock(&mutex_ring); + return i; +} +// 最新データ位置 +int ring_latest_get(RING_T *t) +{ + int i; +pthread_mutex_lock(&mutex_ring); + i = t->latest; +pthread_mutex_unlock(&mutex_ring); + return i; +} +void ring_latest_set(RING_T *t, int i) +{ +pthread_mutex_lock(&mutex_ring); + t->latest = i; +pthread_mutex_unlock(&mutex_ring); +} + +/* + パケットバッファフル? + 1=Full + 0=not Full +*/ +int ring_is_full(RING_T *t, int no) +{ + if (ring_num_get(t, no) >= t->num - 1) return 1; + return 0; +} diff --git a/ring.h b/ring.h new file mode 100644 index 0000000..21337eb --- /dev/null +++ b/ring.h @@ -0,0 +1,33 @@ + + +#if !defined(__RING_H__) +#define __RING_H__ + +typedef struct { + // 読み出し位置 複数設定できる + int *read; + // 書き込み位置 + int write; + // 最新データ位置 + int latest; + // バッファ個数 + int num; + // readポインタ個数 + int read_num; +} RING_T; + +RING_T* ring_create(int read_num); +void ring_destroy(RING_T *t); +void ring_init(RING_T *t, int num); +void ring_clear(RING_T *t, int no); +int ring_read_get(RING_T *t, int no); +void ring_read_set(RING_T *t, int no, int i); +void ring_read_plus(RING_T *t, int no); +int ring_write_get(RING_T *t); +void ring_write_plus(RING_T *t); +int ring_num_get(RING_T *t, int no); +int ring_latest_get(RING_T *t); +void ring_latest_set(RING_T *t, int i); +int ring_is_full(RING_T *t, int no); + +#endif diff --git a/scilog b/scilog index 4d6aa724eb53f3b2e0eeb386ce5896523a129cdd..f26b48978ae2f8220b17765da0f693cc29b30198 100755 GIT binary patch literal 28140 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 literal 11368 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 RY|u=SZ~T>iBoqtyvSc^x9-G~Ce<)ZH za9zu~rsXWOUW+ZX*VenkEA{RuTCoXuL_M!U`FN+jR#S_g+nBTlO-%r6~2nDIB6k zd{SH?EAxI~e__w0pXcdPy%K+a$yv+8vAoz>I7cbucbOorTcNI3Ji%({6nu<^?<}==!ao zTlL!^OGeaS`>zcK)?OR*P74M?@eQtM*oC%HHku~sH!o>NPPLOV%MnSRfJobr9tnPL z#_e6l=U=z$JN=uUer{9slb8HAX%i9IKi1nOoHp@BLvsc()Oex*{8e z(HRH@Nbz{RMl>FX`80_6qA^(|9Eyg6J|hwj87zxR2DC5|Th!GZ^mX|{F;6TI4zV1< zVgXMua2NPhp^3I7Aw>M8|rg!@u6>^aO$;>I?chVj{XR z8Vs)!U7jHNBT&m1iHJbBBNh~$cShLS&hAJc6zhZpYA_AjmYvlz{MV}jUB^Z#7MO`~nEIJORpqDYl zVqC!#3(*9oW3e_dh4)o5y-)}z(~E?tVv5D2hH04)Q<khn!+ zTF~D@+$b?E>E|*xSSv9t>R&_bl$e(FvqOUw64S!|Zek%ZE$!bxJn|k2s%dfm7UBVk zX?g!P;-eCC1pM2HdnM*b_#Y1WxTdQAS zt@7{whTU=Na=$%gcVzw@OrzTif;pyJ=H3TUB7WnZZAgFOz=&-fvg5b!-IBzRZT8F2 zt9tfRexld*U9w~+BuSR+vtN#6j*OuITjCk}%GHN^Vpofvr~Zokke?WyxTg%f$==xb z11v-4!hU-d%d$tGJG`AdCq@#(&de2PVE_Co2f2`PVHV(AgN|e_fdNzVt18ooDSK7s z7-oddSHYVzze43q4Spa}${emqyB#U_3Ev*>{3-WnU2ocbqI|#D<{nA7PuMg#X$5bq z())ThUU0-umaJmo6So^p&OT4?uQl!aa=2!*%z(loNAEI>d8_VaU%d zU$%AlK`dt+wB*11KAY9!cA~C#$hJK*21{WoS@mudKchdonT5mQiW zo`0GPdFqd;W5@p|b^5|zq;@D)Q-lp3S;4L%#VRXP>8U-E4ZdklO{mKJC*>xm;x}=S zzhd*%X$iqlM(2+1vODP9et0#Un|n{@B%AbpO_k-TLw%w0r*(?eXr8@4`9zwng?G-PkNFw*c1%OVi0l<$8z zeXtjqwBk$dV}9o|tg~~kWJn&BNpC9osKPI5{C5ifOyk`O|A$OQpy36Xdp5oES!53E zLdR39s%lbqS5>7Sp&}q>`XJSytTO!w6`*Wl`XEK4Y(n}G3Po8(DppmNYOZpm+F);V zZUIc!pRA#!5r%5gGN0(Rr*|aT`~%0S&Sd@sm=lu0mN>{dWA1qoWAFXe{B z@3RowvnkVKA3N;~cHMMEfyDkloh9*zmUzPlNo+nnW^L)6mC7p z-{tk=Mfr~2^8LMVQ?7UP_=;cBUE#vNQmNxjmD(Q!ol=&Z%4W}{=-#}db!REMH~Zm= zPMeAzG8Mh?N396@*drwDQ8usWJ(x-LC?R`v9$G5QS^2Q3WphqTRe!Pp;-`V2G?Yqw zL@ZCpjIFS={+y-bbEPZ(fVRnL$U&jy_M^4w~c_x3$&@U*d-+lFGd^PSyf+lfj4UD73!mYHr>IK8-F^>`V~nnm(c(PT?o zdY~Jlg(=N7Kl4NQndYZHMdF)$X2&^6cn%ktjTRC*r=M$hFp*iEr`7bkM^S{wjZsrD z&lEB@fCIKN)t=2n3uZp9ne?+yVv|E`9xJ!XA@?T%Cnc`P=;BM$h&;4=rri)^m( z_NoUlG#LR6Aon*aTc~~yU5+C8pw;(!iS4L5|4>gUj&x(i4ers+ugXdebe7feoRMlN zLuaJS%DkS5AhHz$Fbzxz4=STY&C=^oTHGMBz0_VNwWAyEQ7yXf9qSNG)Wz4UPU=cM z6JUypREZ|1QA-;}myIo~Vmq3yNF1`!&a&sGZV4O9W*@ry(gK1qiI#OuUVe=(`+;mJ z%w@MUzvSG_|6-1}rv*=v7)n|wt$wBUi-7eQnO5HacCJ%7rPED8s;0mk>-%+y?OB-c z*p$B1v!;h_ypYlx%WQeO1|Tf&Jvn)=%VO~2@jW*Na|?KLW5D)ME?t4oQ_>a2p-@}C zaO|7tIqi;gYgyt=+w7xvk3GPLzM(O4qUb6Rvjqo9na@KE^5n>TADioUA4cgO{$NJj z_T)WSoAzvhJ9EKW{7C*WqXhLNA$91$ePF`lhkW#_gdom;3Z#2Je^Sbqx^72azA6k| zEj5r2Ps5V07rJ$uW|0r&+Jh(NxLHW4r@^gzk|T1)koeR5i_6(H2a9WRez#T0$JGy% zu89?RqAXBNl`GFx7%48)>mqA>tC+~bSBeW&00P?dOQ>dM;r)h@>gv^lzmZ@iZ$ko$ODNKR4p%qnPCZQ`%lgQ>JgUOOXLeTY8?- zDlot4qhB_q-ENV_`K(;PJhabDhSc-2+7weP50`29u@7R#o>0?tjJmZFa{$lPht=Hv7HEtBGeSjmZ+;~su@g5$<6 z{RwlO+Y>|f?9p^7isGXQdB`N6bFAl)d+|h*nTk%_hOwbRv)lez12Kd$Q9 z*+K8r>RG{fS5zh;B(>95h^f`rTo?2TJou^Oek0OxhpR&bopa|pYd6%^)=i&LKXaDC zHNkLb-IUr53l=n3N~hHcd?nyX_sZJU_^)c3^+b*~Z@$sAa7p{(X?3etBEM|j;+AGN zKmj|?_>HwQj9A#9t{KxUt%6l*rZ|PWwRLH$6X)*hj1GLCi1|>6wk~OJZiX2=UV|j` zz|7%O0CMYmF~wG!D-WV7l;tS08?tgy6?RXR%R~QsjrS$wm4xD5R(`3`l$Mh!zffQR z|3CbnwgA=yd1j+iHkK=?j{KIw{1?oW-(vU@#&2?bt>U-1-@lg)Ke!d&Q-GgJ;QI>F z7l1i`zm3X#GvlEhRxTO1E{x*fneU7H5cw8_!()NZ8{$mT?qGfxDZjU}9>1IOkPq8f zco)ji)-dbhAtAg97}<{;_|05bdK-Ny`4aRYej0H);!TLHh-(oei1#8sg!moA#}N-9 z{v7dj#J3Ska93bF;-?X(Bi@9l<!&CzK9qBY<`k~z#;%xWEz(#-rGA~m2RvV-Tew2un9nuurbW|Yo^>W#7mB;q#sm0x zAMgqnk>3;b3zv6e2=Y`Kizvz+zDShcAtjp$4A3IJAo*3MI~Wr#Ip1CQf{MKS0P2c_ z<#$4t&u?@_JY7EF>WGCSQ7BN!Uw1$dgm}6F9Z(QPMf|v=G*uHH7*Q$Q#qXionCFr5 zvmSkxJ|gd50MLhYAdO)%B0gY9K6y_91ShZ#^0gSC4pH;@;n%#2QKgxXYQFi% zCg;P0;A=z~=LG}#7?&V&POyEPCoh0+1d;OwiR7W*FGu8DAs^?}QvjS#I_NCF;p;iU z`LGHK`6W>6Wqro=h@3;ra~|yiLksfM%QD@MyO8IT4$C+Xhr!48XnEwLb0-ir-x=_o z0mD9%k86bH7ey~3kBq3e^-ES1^7w`%%J(c53KoC;hAj}?(1k8S#_Q^ zARot0-ru=O*$Yqx&G%y<&BqUU_DSdFd)mUs4|ZkX(=sSf=MN)K8&j{m7X-cmvkZyk zECYEM1`w&A?c*D} z*NO4qfV*YN;B6Dg_Q=b4+<;ma2-$>lL&$HU18M# zz0Z}(l}OEBMVD-Ho+`{u8(N}#_feq4S)pkFD> zrv&9c3Qv?+|CEYPE-tcki1cy5JmI6|+5gHS`qjWZqUps1CY^Wgc;KV?8-aO#r|stk=E)sBkL~*$ zFyD>Wn(gxfYk#nbkIOq^dOW!b@Gg)Qe+yXqmks{)17PhxPCR8k4*dK>c83%C#-sl~ z1$OMTJEofWMc~S>+a2^o(q9Mu;#chs`UNrf>NioJ<4$}USOJX8MxOLb zf$JfEiisx!^IiyNI_Wcr&A|F@VD4)yBE1(@rSApALk2{cO zd*3Xg+py%d!hX8{Wx(IG=)Y1eiBcrxH2{Zqz<*773xVsw&y|ewmjMq0bNwdv0PnZR z3j%ilPd4dy0I#z2KM8z4=(>Mj0oH-~zYVPYr2_u4w}^fa_<&_RUM!-&1{u*VwY*?xYDdJFc|<695hg#K%PYyw^dc@#0Op*>*fkU8AMxOKsi|7v*;ePv%S0nnk}M_Q(K&D zBHMQ@umk?1=gXWT`U>D3uy>W&{s8dUwB2zF?9BeefbX=7M-te22lWA99jNacz%N<+ zdoS>6%+DF1QQi~4`!GHl_X976J?c&Rao__OpB57j08g{D|0J-r|EGX;p#F=orO&mr z_e$XH(Ek`{)L#QUM$gBRi^Yw=ygSxv(&qzP@5J5${CSH!16T*@6CIIQG#2md#QBk7 zG_@^lHJTSKYvUbRV}1d;rO86_hK+T>@LEsMkS}b8C%!@8WeoRIV?M8IR^7~*f&?Sr z-9U65ZinJ6&+x{(x^M|r>2WWaFV!q)owwL+XhbzSpVuPa4y6_zD50$dM|TCsXI@`N z*o&K}#)9@GO>K*oE-?((jG6WI;_Q>QXmY>NdegjSW9fng%iL{7+q|2a-Lx-Xiw#dC;@K$g$QBgHo65qN zf7_CIix)KszVn**X{pih!U~b_M%id1f3BySY%P-f`bbb!kniKX-`v=!FXq+?*uao? zo@E77X4Dr$L*-T9j%ZxnURIZctyRsI=|e;F2oM!N^wM>H80BSW+>h=y{CCQ>#5NdG zyF4(^qSbk1cQ78!b(KuKP<^f|(y}Y+%=G=PODh)K(~fAZK_4!P=liYhjPr`Kwac=a zr8Tr34pxm$uM`7Ek(a-f(8vbTBtc!KHVW@#v$DEW&P&u*HHKjsd0E#=)mD+CD~)ol z`|8#j>Pok@1g1Odmb&a*UZ_?Rh#H;oU{Lu`?qnFl?2U#EzbE7ka@xsNL(kxx=SY`R zcgL;TwP?;wIf}RzFZ1eKz`0m0o+)i+ +#include +#include + +#include "my_thread.h" +#include "spi.h" +#include "ad_ring.h" + +int main (int argc, char *argv[]) +{ + CU_pSuite test_suite; + CU_initialize_registry(); + test_suite = CU_add_suite("scilog", NULL, NULL); + + thread_rcv_test(test_suite); + ad_ring_test(test_suite); + + CU_console_run_tests(); + + CU_cleanup_registry(); + +} diff --git a/thread_rcv.c b/thread_rcv.c index daeff85..75e2403 100644 --- a/thread_rcv.c +++ b/thread_rcv.c @@ -5,18 +5,38 @@ #include #include #include +#include #include "spi.h" +#include "ad_ring.h" - -static int decode(char *buf, ADbufType *ad) +/* + Little Endian + 3byte -> signed long(4byte) +*/ +static long b3_to_long32(unsigned char *ptr) +{ + char buf[4]; + + buf[0] = *ptr++; + buf[1] = *ptr++; + buf[2] = *ptr; + if (*ptr & 0x80) { + buf[3] = 0xFF; + } else { + buf[3] = 0; + } + return *((long*)buf); +} +static int decode(char *buf, AdData *ad) { UbloxNavTimeUtc *gps; u_int8_t *ptr; int ch; + int i; ptr = (u_int8_t*)buf; - gps = &(ad->t); + gps = &(ad->gps); if (*ptr++ != SPI_HEAD_CHAR) return -1; // GPS @@ -36,18 +56,42 @@ static int decode(char *buf, ADbufType *ad) ptr += 4; } // 50Hz data + for(ch = 0; ch < AD_CHNUM; ch++) { + for(i = 0; i < AD_SAMPLE; i++) { + ad->data[ch][i] = b3_to_long32(ptr); + ptr += 3; + } + } + // Checksum + // gps->struct tm + ad->t.tm_year = gps->year - 1900; + ad->t.tm_mon = gps->month - 1; // struct tmの月は(0〜11)なので注意 + ad->t.tm_mday = gps->day; + ad->t.tm_hour = gps->hour; + ad->t.tm_min = gps->min; + ad->t.tm_sec = gps->sec; + return 0; } +/* + int freq + 平均化後の周波数 Hz +*/ +static void do_avg(int freq, AdData *ad) +{ +// 仮コード + memcpy(ad->avg, ad->data, AD_CHNUM*AD_SAMPLE*AD_BYTES); +} void* thread_rcv(void* pParam) { while(1) { fd_set fds; char buf[SPI_DATA_LEN+256]; int i; - int ch; +// int ch; int fd_spi; -ADbufType ad; + AdData ad, *ad_ptr; fd_spi = spi_get_fd(); // select の準備 @@ -67,7 +111,11 @@ ADbufType ad; // ring_zero(); // データ取得 spi_rx_get(buf); + // デコード decode(buf, &ad); + // 平均 仮コード 要変更 + do_avg(AD_SAMPLE, &ad); +#if 0 printf("%04d/%02d/%02d %02d:%02d:%02d.%09ld,%6lums,%6luns,%02X", ad.t.year, ad.t.month, ad.t.day, ad.t.hour, ad.t.min, ad.t.sec, ad.t.nano, ad.t.tow, ad.t.tacc, ad.t.valid); @@ -75,6 +123,22 @@ for(ch = 0; ch < AD_CHNUM; ch++) { printf(",%+7ld", ad.data1sec[ch]); } printf("\r\n"); +for(ch = 0; ch < AD_CHNUM; ch++) { + printf(",%+7ld", ad.data[ch][0]); +} +printf("\r\n"); +for(ch = 0; ch < AD_CHNUM; ch++) { + printf(",%+7ld", ad.data[ch][49]); +} +printf("\r\n"); +#endif + // ADリングバッファに書き込み + ad_ptr = ad_ring_get(ad_ring_write_get()); + *ad_ptr = ad; + // 最新データ位置 + ad_ring_latest_set(ad_ring_write_get()); + // 書き込み位置+1 + ad_ring_write_plus(); } // while((i = sub_dnum_get()) > 0) { } // if(FD_ISSET(fd_sub, &fds)) { @@ -82,3 +146,60 @@ printf("\r\n"); return NULL; } +// +/**** CUnit test +*/ +#ifdef CUNIT +#include + +static void test_b3_to_long32(void) +{ + long l; + char buf[SPI_DATA_LEN+256]; + AdData ad; + int i; + + buf[0] = 0x56; + buf[1] = 0x34; + buf[2] = 0x12; + l = b3_to_long32(buf); + CU_ASSERT(l == 0x00123456); + + buf[0] = 0x56; + buf[1] = 0x34; + buf[2] = 0x82; + l = b3_to_long32(buf); + CU_ASSERT(l == (long)0xFF823456); + + buf[0] = 0xFF; + buf[1] = 0xFF; + buf[2] = 0xFF; + l = b3_to_long32(buf); + CU_ASSERT(l == -1); + + buf[0] = '$'; + i = SPI_OFS_DATA; + buf[i++] = 0x56; + buf[i++] = 0x34; + buf[i++] = 0x12; + decode(buf, &ad); + CU_ASSERT(ad.data[0][0] == 0x123456); + + buf[0] = '$'; + i = SPI_OFS_DATA + AD_CHNUM * AD_SAMPLE * 3; + i -= 3; + buf[i++] = 0x56; + buf[i++] = 0x34; + buf[i++] = 0x12; + decode(buf, &ad); + CU_ASSERT(ad.data[AD_CHNUM-1][AD_SAMPLE-1] == 0x123456); +} + +void thread_rcv_test(CU_pSuite test_suite) +{ + + CU_add_test(test_suite, "test_b3_to_long32", test_b3_to_long32); + +} + +#endif diff --git a/thread_rec.c b/thread_rec.c new file mode 100644 index 0000000..fd431b3 --- /dev/null +++ b/thread_rec.c @@ -0,0 +1,251 @@ + +#include +#include +#include +#include + +#include "ad_ring.h" +#include "sts.h" +#include "debug_print.h" +#include "ad_file.h" + +// 1secファイル書き込み間隔 sec +#define SEC_FLUSH_NUM 1 +//#define SEC_FLUSH_NUM 60 + +// 高速サンプルファイル書き込み間隔 sec +#define HIGH_FLUSH_NUM 1 + +// 日付変化検出用 +static struct tm high_tm; +static struct tm sec_tm; + +// +/**** 時刻校正待ち + パケット中の時刻が有効になるのを待つ + + Return: + 次の状態 +*/ +int ProcTimeFix(void) +{ + AdData *d; + static int latest = -1; + /* + 時刻校正終わったら、記録開始 + */ + if (latest == ad_ring_latest_get()) return STS_TIME_FIX; + latest = ad_ring_latest_get(); + if (latest >= 0) { + // 最新データの時刻取得 + d = ad_ring_get(latest); + // GPS Validチェック + if (d->gps.valid & 0x07) { + PDEBUG("ProcTimeFix: rec init.\n"); + return STS_REC_INIT; + } + } + return STS_TIME_FIX; +} + +// +/**** 記録初期化 + + Return: + 次の状態 +*/ +int ProcRecInit(void) +{ + AdData *d; + + if (ad_ring_latest_get() >= 0) { + // 記録開始 + ad_ring_clear_sec(); + ad_ring_clear_high(); + + // 最新データの時刻取得 + d = ad_ring_get(ad_ring_latest_get()); + // 日付変化検出用変数初期化 + high_tm = d->t; + sec_tm = d->t; + + PDEBUG("ProcRecInit: rec start.\n"); + return STS_REC; + } + return STS_REC_INIT; +} + +/**** 記録中 + 定期的にカードに書き込み + + Return: + 次の状態 +*/ +int ProcRec(void) +{ + AdData *d; + FILE *fp = NULL; + char buf[HIGH_WRITE_LEN+128]; + +// +/**** 1secデータ記録 +*/ + /* + パケットバッファにデータたまった? + */ + if (ad_ring_num_get_sec() >= SEC_FLUSH_NUM) { + // データ取り出し + d = ad_ring_get(ad_ring_read_get_sec()); + // ファイルオープン + sec_file_open(&fp, d); + + // 書き込みループ + while(ad_ring_num_get_sec() > 0) { + // データ取り出し + d = ad_ring_get(ad_ring_read_get_sec()); +PDEBUG("%04d/%02d/%02d %02d:%02d:%02d.%09ld,%6lums,%6luns,%02X", + d->gps.year, d->gps.month, d->gps.day, d->gps.hour, d->gps.min, d->gps.sec, d->gps.nano, + d->gps.tow, d->gps.tacc, d->gps.valid); +int ch; +for(ch = 0; ch < AD_CHNUM; ch++) { + PDEBUG(",%+7ld", d->data1sec[ch]); +} +PDEBUG("\r\n"); + + // 日にち変わった ファイル切換する +#ifdef DEBUG_FILE_MIN + // デバッグ用 ?分ごとファイル切り替え + if ((d->t.tm_min % DEBUG_FILE_MIN_PERIOD) == 0 && (d->t.tm_sec == 0) && (d->t.tm_min != sec_tm.tm_min)) { +#else + if (d->t.tm_year != sec_tm.tm_year || d->t.tm_mon != sec_tm.tm_mon || d->t.tm_mday != sec_tm.tm_mday) { +#endif + // 日付変わったのでファイル切り替える + // 前のファイル閉じる + if (fp != NULL) sec_file_close(fp); + // ファイルオープン + if (sec_file_open(&fp, d)) { + PDEBUG("REC: FG file change ERROR\n"); + syslog(LOG_INFO, "REC: FG file change ERROR\n"); + } else { + PDEBUG("REC: FG file change OK\n"); + syslog(LOG_INFO, "REC: FG file change OK\n"); + } + } + // ファイルに書き込むデータ作成 + sec_make_rec_data(d, buf); + // ファイルに1データ書き込み Open/Closeなし + if (sec_file_out(fp, buf, strlen(buf))) { + /* 書き込みエラー */ + // 読み出し位置クリア + ad_ring_clear_sec(); + // ファイル閉じる + sec_file_close(fp); + // + PDEBUG("ProcRec: 1sec file write err\n"); + syslog(LOG_INFO, "REC: 1sec file write error\n"); + return STS_FILE_ERR; + } + // 読み込み位置進める + ad_ring_read_plus_sec(); + // タイムスタンプ記録 + sec_tm = d->t; + } + // ファイル閉じる + sec_file_close(fp); + // + PDEBUG("ProcRec: 1sec file write.\n"); + } +// +/**** 高速サンプルデータ記録 +*/ + /* + パケットバッファにデータたまった? + */ + if (ad_ring_num_get_high() >= HIGH_FLUSH_NUM) { + // データ取り出し + d = ad_ring_get(ad_ring_read_get_high()); + // ファイルオープン + high_file_open(&fp, d); + + // 書き込みループ + while(ad_ring_num_get_high() > 0) { + // データ取り出し + d = ad_ring_get(ad_ring_read_get_high()); + // 時が変わった ファイル切換する +#ifdef DEBUG_FILE_MIN + // デバッグ用 ?分ごとファイル切り替え + if ((d->t.tm_min % DEBUG_FILE_MIN_PERIOD) == 0 && (d->t.tm_high == 0) && (d->t.tm_min != hightm.tm_min)) { +#else + if (d->t.tm_year != high_tm.tm_year || d->t.tm_mon != high_tm.tm_mon || d->t.tm_mday != high_tm.tm_mday + || d->t.tm_hour != high_tm.tm_hour) { +#endif + // 時が変わったのでファイル切り替える + // 前のファイル閉じる + if (fp != NULL) high_file_close(fp); + // ファイルオープン + if (high_file_open(&fp, d)) { + PDEBUG("REC: FG file change ERROR\n"); + syslog(LOG_INFO, "REC: HIGH file change ERROR\n"); + } else { + PDEBUG("REC: FG file change OK\n"); + syslog(LOG_INFO, "REC: HIGH file change OK\n"); + } + } + // ファイルに書き込むデータ作成 + high_make_rec_data(d, buf); + // ファイルに1データ書き込み Open/Closeなし + if (high_file_out(fp, buf, HIGH_WRITE_LEN)) { + /* 書き込みエラー */ + // 読み出し位置クリア + ad_ring_clear_high(); + // ファイル閉じる + high_file_close(fp); + // + PDEBUG("ProcRec: HIGH file write err\n"); + syslog(LOG_INFO, "REC: HIGH file write error\n"); + return STS_FILE_ERR; + } + // 読み込み位置進める + ad_ring_read_plus_high(); + // タイムスタンプ記録 + high_tm = d->t; + } + // ファイル閉じる + high_file_close(fp); + // + PDEBUG("ProcRec: HIGH file write.\n"); + } + + return STS_REC; +} + +void* thread_rec(void* pParam) +{ + while(1) { + usleep(10*1000); + switch (sts_get()) { + /* 時刻校正中 */ + case STS_TIME_FIX: + sts_set(ProcTimeFix()); + break; + /* 記録初期化 */ + case STS_REC_INIT: + sts_set(ProcRecInit()); + break; + /* 記録中 */ + case STS_REC: + sts_set(ProcRec()); + break; + /* 記録OFF中 */ + case STS_REC_OFF: +// sts_set(ProcRecOff()); + break; + /* ファイルエラー発生中 */ + case STS_FILE_ERR: +// sts_set(ProcErr()); + break; + default: + break; + } + } // メインループ終わり +} diff --git a/thread_rec.h b/thread_rec.h new file mode 100644 index 0000000..dec9fe6 --- /dev/null +++ b/thread_rec.h @@ -0,0 +1,11 @@ +#if !defined(__REC_H__) +#define __REC_H__ + + + +int ProcTimeFix(void); +int ProcRecInit(void); +int ProcRec(void); +void* thread_rec(void* pParam); + +#endif -- 2.11.0