How to decode TOB2 formatted file for Campbell Scientific DataLogger CR-5000
on PC linux with gcc, by Hiroki TANAKA 25SEP2003
1st STEP: read ASCII Header
とりあえず、6行あるので、全部読み飛ばす。
ASCIIデータなので、読めば何が書いてあるかは、それなりに判る(と思う)
2nd STEP: read Frame Header
フレームのヘッダは、8バイト(long intが2つ)でタイムスタンプになっている。
LSBらしい。まあ、良くわかんないけど、次のようなコードで無事に正しい数値になった。
unsigned long get_4byte_int() {
unsigned char c1, c2, c3, c4;
unsigned long r = 0;
c1 = fgetc(stdin);
c2 = fgetc(stdin);
c3 = fgetc(stdin);
c4 = fgetc(stdin);
r = (((c4 * 256L) + c3) * 256L + c2) * 256L + c1;
return r;
}
で、はじめの4バイトが1990年1月1日からの秒数
long y_sec[40];
set_second_for_year() {
y_sec[1990 - 1990] = 0L;
y_sec[1991 - 1990] = 31536000L;
y_sec[1992 - 1990] = 63072000L;
y_sec[1993 - 1990] = 94694400L;
y_sec[1994 - 1990] = 126230400L;
y_sec[1995 - 1990] = 157766400L;
y_sec[1996 - 1990] = 189302400L;
y_sec[1997 - 1990] = 220924800L;
y_sec[1998 - 1990] = 252460800L;
y_sec[1999 - 1990] = 283996800L;
y_sec[2000 - 1990] = 315532800L;
y_sec[2001 - 1990] = 347155200L;
y_sec[2002 - 1990] = 378691200L;
y_sec[2003 - 1990] = 410227200L;
y_sec[2004 - 1990] = 441763200L;
y_sec[2005 - 1990] = 473385600L;
y_sec[2006 - 1990] = 504921600L;
y_sec[2007 - 1990] = 536457600L;
y_sec[2008 - 1990] = 567993600L;
y_sec[2009 - 1990] = 599616000L;
y_sec[2010 - 1990] = 631152000L;
y_sec[2011 - 1990] = 662688000L;
y_sec[2012 - 1990] = 694224000L;
y_sec[2013 - 1990] = 725846400L;
y_sec[2014 - 1990] = 757382400L;
y_sec[2015 - 1990] = 788918400L;
y_sec[2016 - 1990] = 820454400L;
y_sec[2017 - 1990] = 852976800L;
y_sec[2018 - 1990] = 883612800L;
y_sec[2019 - 1990] = 915148800L;
y_sec[2020 - 1990] = 946684800L;
}
なんてので、とりあえず必要な辺りの秒数を押さえておく。
次の4バイトは、μsecなので、1000,000で割って足す。
3rd STEP: read Frame Data
データの形式は、ASCII Headerに書いてある。今回は、IEEE4LというのとFS2というのがあった。
(1) FS2のデコード
良くわかんないので、とりあえず2バイト読み込んで、
ビット毎に無理矢理分解(←ビット演算がわかってないので無理矢理)
で、前方から順々に決まったフォーマットで浮動小数点に直してあげる
double get_FP2() {
int i, j;
double r;
unsigned char S, b[16], c, a;
unsigned int E;
unsigned long M;
for(i = 0; i < 16; i += 8) {
c = fgetc(stdin);
for(j = 0, a = 0x80; j < 8; j++, a *= 0.5) {
b[i + j] = c / a;
c -= b[i + j] * a;
}
}
S = b[0];
E = (int)b[1] * 2 + (int)b[2];
M = (long)b[3];
for(i = 4; i < 16; i++) {
M *= (long)2L;
M += (long)b[i];
}
r = (double)M;
for(i = 0; i < E; i++) r *= 0.1;
if(S == 1) r *= -1.0;
return r;
}
(2) IEEE4Lのデコード
こちらも良くわかんないので、とりあえず4バイト読み込んで、
ビット毎に無理矢理分解(←悲しいかな、私がやるとああなるのです)
で、FP2の時と同じように前方から順々....と思ったら、うまくいかない。
後で読んだ方から...ということみたいです。
まあ、とにかくIEEE754のフォーマットで浮動小数点に直してあげる
double get_IEEE() {
int i, j;
double r, M;
unsigned char S, b[32], c, a, cc[4];
unsigned int E;
for(i = 24; i >= 0; i -= 8) {
if(i >= 32) i -= 32;
if(i < 0) i += 32;
c = fgetc(stdin);
cc[i / 8] = c;
for(j = 0, a = 0x80; j < 8; j++, a *= 0.5) {
b[i + j] = c / a;
c -= b[i + j] * a;
}
}
S = b[0];
E = (int)b[1];
for(i = 2; i <= 8; i++) {
E *= 2;
E += (int)b[i];
}
for(i = 31, M = 0.0; i >= 9; i--) {
M += (double)b[i];
M *= 0.5;
}
if(E == 0) {
r = M;
for(i = 0; i < 126; i++) r *= 0.5;
} else if(E > 127) {
r = 1.0 + M;
for(i = 0; i < E - 127; i++) r *= 2.0;
} else {
r = 1.0 + M;
for(i = 0; i < 127 - E; i++) r *= 0.5;
}
if(S == 1) r *= -1.0;
return r;
}
4th STEP: read Frame Footer
良くわかんないけど、4バイト読み飛ばす。何かしら意味はあるはずだが。。。
To be continue to next Frame ...