1 /*
2  #  Copyright (C) 2011,2012 Alois Schloegl, IST Austria <alois.schloegl@ist.ac.at>
3  #
4  #    This program is free software; you can redistribute it and/or modify
5  #    it under the terms of the GNU General Public License as published by
6  #    the Free Software Foundation; either version 3 of the License, or
7  #    (at your option) any later version.
8  #
9  #    This program is distributed in the hope that it will be useful,
10  #    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  #    GNU General Public License for more details.
13  #
14  #    You should have received a copy of the GNU General Public License
15  #    along with this program; If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19 
20    Supported Device(s):
21      Flow Meter GSM-D3KA-BN00 from Vögtlin Instruments
22 
23   DONE(+)/TODO(-):
24     - units of flow l/min oder m^3/h ??
25     + graceful handling of exit (close all handles even when stopped with <CTRL>-C
26     + one file per day, appending
27     + autostart
28     - file management, data compression, (/var/spool/... /etc/flowmon.conf
29     - init.d (flowmon start/stop)
30     - fix appending to *.log.gdf file after restart
31     - javascript interface
32 
33    Requirements:
34         g++
35         libz 1.2.5 or higher
36         libbiosig.a (v1.2 or higher) available from http://biosig.sf.net
37 
38 */
39 
40 
41 #include "../biosig.h"
42 
43 #include <errno.h>
44 #include <math.h>
45 #include <inttypes.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <time.h>
50 #include <sys/time.h>
51 
52 #include <termios.h>
53 #include <unistd.h>
54 #include <fcntl.h>
55 #include <sys/signal.h>
56 #include <sys/types.h>
57 
58 
59 #define LENBUF 300
60 #define BAUDRATE B9600
61 #define MODEMDEVICE "/dev/ttyUSB0"
62 #define _POSIX_SOURCE 1         //POSIX compliant source
63 #define FALSE 0
64 #define TRUE 1
65 
66 
67 int  wait_flag=TRUE;                     //TRUE while no signal received
68 //void signal_handler_IO (int status);    //definition of signal handler
69 char buf[LENBUF+1]  __attribute__ ((deprecated));
70 uint8_t idata[LENBUF];
71 uint8_t odata[LENBUF];
72 char manufacturer[1000];
73 
74 int fd;
75 FILE *fid=NULL;
76 FILE *fid2=NULL;
77 // biosig
78 HDRTYPE *hdr = NULL;
79 struct termios oldtio, newtio;       //place for old and new port settings for serial port
80 
stop()81 void stop() {
82         // reset terminal
83         if (fd>2) {
84                 tcsetattr(fd, TCSANOW, &oldtio);
85                 close(fd);
86         }
87 
88         // close gdf file
89         if (hdr) destructHDR(hdr);
90 
91         // close debug file
92         if (fid2) fclose(fid2);
93 }
94 
95 const void *outPtr = odata+3;
96 
97 /*
98         crc16_a001: computes crc of a modbus packet and writes it at the end;
99         (remark: its not CCITT's crc16 but uses 0xA001 polynomial)
100         input :
101                 data  : packet with its crc
102                 n     : length of data without the crc
103 
104         ouput : crc16 value
105 */
106 #if defined(__LITTLE_ENDIAN)
crc16_a001(uint8_t data[],size_t n)107 uint16_t crc16_a001(uint8_t data[], size_t n)
108 {
109         uint8_t flag;
110         size_t i,j;
111         union {
112                 uint16_t u16;
113                 uint8_t  u8[2];
114         } crc;
115 
116 	crc.u16 = 0xffff;
117 	for (i=0; i<n; i++) {
118 		crc.u8[0] = crc.u8[0]^data[i];
119 		for (j=0; j<8; j++) {
120 			flag = crc.u8[0] & 0x01;
121 			crc.u16 = crc.u16 >> 1;
122 			if (flag) crc.u16 = crc.u16^0xa001;
123 		}
124 	}
125 
126 	// write crc to end of data block
127         *(uint16_t*)(data+n) = crc.u16;
128 	return (uint16_t)crc.u16;
129 }
130 
read_register(uint8_t slave,uint8_t cmd,uint16_t reg)131 int read_register(uint8_t slave, uint8_t cmd, uint16_t reg) {
132 
133         idata[0] = slave;		// address
134         idata[1] = 3; 			//cmd;	// read -
135         *(uint16_t*)(idata+2) = bswap_16((uint16_t)reg);  // register
136         *(uint16_t*)(idata+4) = bswap_16(0x0004);  // length
137         crc16_a001(idata,6); // compute crc and add at and
138         tcflush(fd, TCIOFLUSH);
139         int c = write(fd,idata,8);
140 if (VERBOSE_LEVEL>8)  fprintf(stdout,"\n======= SENT %i bytes\n",c);
141         usleep(100000);
142         c = read(fd,odata,16);
143 if (VERBOSE_LEVEL>8)  fprintf(stdout,"\n======= RECEIVED %i bytes\n",c);
144         if (c<9 || odata[0] != slave) return (-1);
145 
146 if (VERBOSE_LEVEL==6)
147         fprintf(stdout,"\n======= REG:0x%04x RECEIVED %2i bytes U16[2]: 0x%08x %08x %08x %08x F:%10g %10g<%s> ",\
148                 reg,c,beu32p(odata),beu32p(odata+4),beu32p(odata+8),beu32p(odata+12), \
149                 (double)bef32p(odata+3), (double)bef32p(odata+7), (char*)(odata+3));
150 
151         uint16_t crc=bswap_16(crc16_a001(odata,c-2));
152 if (VERBOSE_LEVEL>8)
153      fprintf(stdout,"crc 0x%04x 0x%04x",bswap_16(crc),beu16p(odata+c-2));
154         usleep(10000);
155 
156         if (crc!=beu16p(odata+c-2)) return -1;
157 
158         return 0;
159 }
160 #else
161 #error CRC16 function not defined for big endian platform
162 #endif
163 
164 
main(int argc,char * argv[])165 int main(int argc, char *argv[]) {
166 
167 char *devicename = "/dev/ttyUSB0";
168 const char *outFile = NULL;
169 const char *debugFile = NULL;
170 
171                   // 00 = NONE, 01 = Odd, 02 = Even, 03 = Mark, 04 = Space
172 struct timeval tv;
173 struct timezone tz;
174 struct tm *tm;
175 struct tm T;
176 uint32_t oldDay=0, newDay;
177 gdf_time gdfTime;
178 char flag_GZIP = 0;
179 
180 char logfile[48] = "flowmonYYYYMMDD.log.gdf";
181 char debugfile[] = "flowmonDD.log.txt";
182 
183 
184         /***************************************************************************
185          *
186          *    input arguments
187          *
188          ***************************************************************************/
189 
190 	const char help[]=
191 		"FLOWMON reads data of the flow sensor through the serial terminal and stores it into a data file for archiving.\n"
192 		"   The current measurement values are also written into the file /var/www/flowsensor.html.\n"
193 		"   This software supports the device 'Flow Meter GSM-D3KA-BN00 (BHT Rotary Gas Meter) from Vögtlin Instruments'.\n\n"
194 		"Usage: flowmon -d devicename [-o outfile] [-D debugfile] [-V#]\n"
195 		"   devicename: default value is /dev/ttyS0\n"
196 		"   outfile:    logs the recorded data\n"
197                 "               If no outfile is provided, the data will be logged into daily files named flowmon<$date>.log.gdf \n"
198                 "   debugfile:  logs the data in ascii text\n"
199                 "               If no outfile is provided, the data will be logged into daily files named flowmon<$day-of-month>.log.txt \n"
200                 "   -V#		verbose level #=0 is no messages, #=9 is highest level(debugging) messages\n"
201                 "   -h, --help:        display this help text\n"
202                 "   -z		save outfile in gzipped format\n"
203                 " \n\n"
204 	;
205 	if (argc<2) {
206 		fprintf(stdout,"%s",help);
207 		return(0);
208 	}
209 
210 	/* Sanity checks of input arguments */
211 	int k = 0;
212 	while (k<argc) {
213 
214                 if (VERBOSE_LEVEL>3) fprintf(stdout,"%i/%i\t%s\n",k,argc,argv[k]);
215 
216                 if (0) {
217 		}
218 		else if (!strcmp(argv[k],"-d")) {
219 			devicename = argv[++k];
220 		}
221 		else if (!strcmp(argv[k],"-h") || !strcmp(argv[k],"--help") ) {
222                         fprintf(stdout,"%s",help);
223                         return 0;
224                 }
225 		else if (!strcmp(argv[k],"-o")) {
226 			k++;
227 			outFile = argv[k];
228                 }
229 		else if (!strcmp(argv[k],"-D")) {
230 			k++;
231 			debugFile = argv[k];
232 		}
233 		else if (!strncmp(argv[k],"-V",2)) {
234 	                char c = argv[k][2];
235 #ifndef VERBOSE_LEVEL
236 	                if ('0'<=c && c<='9')
237 	                        VERBOSE_LEVEL = c-'0';
238 #endif
239 		}
240 		else if (!strcmp(argv[k],"-z")) {
241 		        flag_GZIP = 1;
242 		}
243 		k++;
244 	}
245 
246         /***************************************************************************
247          *
248          *    initialization
249          *
250          ***************************************************************************/
251 
252         // clean up at exit
253         atexit(&stop);
254 
255         gettimeofday(&tv, &tz);
256         tm = gmtime(&tv.tv_sec);
257         gdfTime = tm_time2gdf_time(gmtime(&tv.tv_sec)) + (uint64_t)ldexp(tv.tv_usec*1e-6/(24*3600),32);
258         newDay = gdfTime>>32;
259         gdf_time2tm_time_r(gdfTime, &T);
260 
261 	if (VERBOSE_LEVEL>7) fprintf(stdout,"%s (line %d): err %d\n",__FILE__,__LINE__,errno);
262 
263         //open the device(com port) to be non-blocking (read will return immediately)
264         fd = open(devicename, O_RDWR | O_NOCTTY | O_NONBLOCK);
265         if (fd < 0) {
266                 perror(devicename);
267                 exit(EXIT_FAILURE);
268         }
269         tcgetattr(fd,&oldtio); // save current port settings
270 
271         if (VERBOSE_LEVEL>7) fprintf(stdout,"%s (line %d): fd=%d\n",__FILE__,__LINE__,fd);
272 
273         // set new port settings for canonical input processing
274         // newtio.c_cflag = BAUD | CRTSCTS | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
275         newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD | CSTOPB;
276         newtio.c_iflag = IGNPAR;
277         newtio.c_oflag = 0;
278         newtio.c_lflag = 0;       //ICANON;
279         newtio.c_cc[VMIN] = 1;
280         newtio.c_cc[VTIME]= 0;
281         tcflush(fd, TCIOFLUSH);
282         tcsetattr(fd,TCSANOW,&newtio);
283 
284         if (VERBOSE_LEVEL>7) fprintf(stdout,"%s (line %d): err %d\n",__FILE__,__LINE__,errno);
285         if (errno) {
286                 fprintf(stderr,"%s (line %d)  %d %s\n", __FILE__, __LINE__, errno, strerror(errno));
287                 stop();
288                 return(errno);
289         }
290 
291 #if 1
292 	if (debugFile)
293 	        fid2 = fopen(debugFile,"a");
294         else {
295 		sprintf(debugfile,"flowmon%02d.log.txt",tm->tm_mday);
296                 fid2 = fopen(debugfile,"a");
297         }
298 
299         {
300 		hdr = constructHDR(4 ,0);
301 		hdr->SampleRate = 1;
302 		hdr->SPR     =  1;
303 		hdr->NRec    = -1;
304 		hdr->EVENT.N =  0;
305 		hdr->FILE.COMPRESSION = 0;
306 
307 		{
308                         // channel 1: time stamp
309 			CHANNEL_TYPE *hc = hdr->CHANNEL + 0;
310 			hc->LeadIdCode = 0;
311 			strcpy(hc->Label,"time ");
312 			hc->GDFTYP  = 8;	// uint64
313 			hc->SPR     = hdr->SPR;
314 
315 			hc->PhysMax = ldexp(1,32);
316 			hc->PhysMin = 0;
317 			hc->DigMax  = ldexp(1,64);
318 			hc->DigMin  = 0;
319                         hc->PhysDimCode = PhysDimCode("d"); 	// days
320                         hdr->AS.bpb += GDFTYP_BITS[hc->GDFTYP]>>3;
321 		}
322 
323 		{
324                         // channel 2: volume
325 			CHANNEL_TYPE *hc = hdr->CHANNEL + 1;
326 			hc->LeadIdCode = 0;
327 			strcpy(hc->Label,"total volume ");
328 			hc->GDFTYP  = 6;        // uint32
329 			hc->GDFTYP  = 16;        // float32
330 			hc->SPR     = hdr->SPR;
331 			hc->PhysMax =  ldexp(1,32);
332 			hc->PhysMin = -hc->PhysMax;
333 			hc->DigMax  = hc->PhysMax;
334 			hc->DigMin  = hc->PhysMin;
335 			hdr->AS.bpb += GDFTYP_BITS[hc->GDFTYP]>>3;
336 
337                         read_register(247, 3, 0x6384) ; // f32: Skalierung Totalisator, and s8: Einheit des Totalisatorwertes mit 4 Byte offset.
338                         //read_register(247, 3, 0x6386) ; // s8: Einheit des Totalisatorwertes
339                         if (!strcmp((char*)(outPtr+4),"ln"))
340                                 hc->PhysDimCode = PhysDimCode("l");
341                         else
342                                 hc->PhysDimCode = 0; // "unknown"
343 		}
344 
345 		{
346                         // channel 3: flow
347 			CHANNEL_TYPE *hc = hdr->CHANNEL + 2;
348 			hc->LeadIdCode = 0;
349 			strcpy(hc->Label,"flow ");
350 			hc->GDFTYP  = 3;        // int16
351 			hc->GDFTYP  = 16;        // float32
352 			hc->SPR     = hdr->SPR;
353                         hdr->AS.bpb += GDFTYP_BITS[hc->GDFTYP]>>3;
354 
355                         read_register(247, 3, 0x6020) ; // f32: Endwert Messbereich
356                         hc->PhysMax = bef32p(outPtr);
357                         hc->PhysMin = -hc->PhysMax;
358                         hc->DigMax  = hc->PhysMax;
359                         hc->DigMin  = hc->PhysMin;
360                         read_register(247, 3, 0x6022) ; // s50: Bezeichnung Medium Lang
361                         strncpy(hc->Transducer,(char*)(outPtr+1),MAX_LENGTH_TRANSDUCER);
362                         read_register(247, 3, 0x6042) ; // s8: Bezeichnung Medium kurz
363                         strncpy(hc->Transducer,(char*)(outPtr),MAX_LENGTH_LABEL);
364 
365                         read_register(247, 3, 0x6046) ; // s8: Einheit Messwert
366                         if (!strcmp((char*)outPtr,"ln/h")) {
367                                 //hc->PhysDimCode = 3072; // "l min-1"
368                                 hc->PhysDimCode = 3104; // "l h-1"
369                         }
370                         else
371                                 hc->PhysDimCode = 0; // "unknown"
372 
373                         // read_register(247, 3, 0x6046) ; // s8: Einheit Messwert
374 
375                         read_register(247, 3, 0x6120) ; // u16: Verstärkung, Amplification; und u16 Heizleistung (2 byte offset), und u16: Dynamik (4 Byte offset)
376                         //read_register(247, 3, 0x6121) ; // u16: Heizleistung
377                         //read_register(247, 3, 0x6122) ; // u16: Dynamik
378 		}
379 
380 		{
381                         // channel 4: temparature
382 			CHANNEL_TYPE *hc = hdr->CHANNEL + 3;
383 			hc->LeadIdCode = 0;
384 			strcpy(hc->Label,"Temperature");
385 			hc->GDFTYP  = 16;        // float32
386 			hc->SPR     = hdr->SPR;
387 			hc->PhysMax = 500;
388 			hc->PhysMin = -500;
389 			hc->DigMax  = 500;
390 			hc->DigMin  = -500;
391                         hc->PhysDimCode = 6048; // degree Celsius
392                         hdr->AS.bpb += GDFTYP_BITS[hc->GDFTYP]>>3;
393 		}
394 
395                 if (hdr->NS > 4) {
396                         // channel 5: type of gas
397 			CHANNEL_TYPE *hc = hdr->CHANNEL + 4;
398 			hc->LeadIdCode = 0;
399 			strcpy(hc->Label,"typ of gas");
400 			hc->GDFTYP  = 2;        // uint8
401 			hc->SPR     = hdr->SPR;
402 			hc->PhysMax = 255;
403 			hc->PhysMin = 0;
404 			hc->DigMax  = 255;
405 			hc->DigMin  = 0;
406                         hc->PhysDimCode = 0;
407                         hdr->AS.bpb += GDFTYP_BITS[hc->GDFTYP]>>3;
408 		}
409 		for (k=0; k<hdr->NS; k++) {
410 		      CHANNEL_TYPE *hc = hdr->CHANNEL + k;
411 		      hc->LeadIdCode = 0;
412 		      hc->SPR = 1;
413 		}
414 
415 		hdr->AS.rawdata = (uint8_t*)realloc(hdr->AS.rawdata,hdr->AS.bpb);
416 
417 		hdr->ID.Manufacturer.Name  = "Voegtlin";
418 /*
419 		hdr->ID.Manufacturer.Model = "Flow Meter";
420 		hdr->ID.Manufacturer.Version = "GSM-D3KA-BN00";
421 		hdr->ID.Manufacturer.SerialNumber = "150427";
422 */
423                 read_register(247, 3, 0x0023) ;	// Typencode 1: Gerätebezeichnung Teil 1
424                 hdr->ID.Manufacturer.Model = (char*)manufacturer;
425                 strcpy(manufacturer,"FlowMeter ");
426                 strcat(manufacturer, outPtr);
427                 read_register(247, 3, 0x1004) ; // Typencode 2: Gerätebezeichnung Teil 2
428                 strcat(manufacturer, outPtr);
429 
430                 read_register(247, 3, 0x0020);	// u16: Hardware Version number,
431                 uint16_t HardWareVersion = beu16p(outPtr);
432                 // read_register(247, 3, 0x0021);  // u16: Software Version number: is available also from previous request with 2 byte offset
433                 uint16_t SoftWareVersion = beu16p(outPtr+2); // u16: Software Version number
434                 hdr->ID.Manufacturer.Version = manufacturer+strlen(manufacturer)+1;
435                 sprintf((char*)(hdr->ID.Manufacturer.Version),"Hardware: %d.%d.%d Software: %d.%d.%d", \
436                         HardWareVersion>>8, \
437                         (HardWareVersion & 0xF0)>>4, \
438                         HardWareVersion & 0x0F, \
439                         SoftWareVersion>>8, \
440                         (SoftWareVersion & 0xF0)>>4, \
441                         SoftWareVersion & 0x0F \
442                         );
443 
444                 read_register(247, 3, 0x001e) ; // u32: serial number
445                 hdr->ID.Manufacturer.SerialNumber = hdr->ID.Manufacturer.Version+strlen(hdr->ID.Manufacturer.Version)+1;
446                 sprintf((char*)(hdr->ID.Manufacturer.SerialNumber),"%d",beu32p(outPtr));
447 
448 		hdr->FLAG.UCAL = 1;
449 		hdr->TYPE      = GDF;
450 		hdr->VERSION   = 2.0;
451 		if (outFile) hdr->FileName  = strdup(outFile);
452         }
453 #endif
454 
455         read_register(247, 3, 0x0000) ;	// float32: Messwert Gasdurchfluss
456         read_register(247, 3, 0x0002) ; // float32: Temperatur
457         // read_register(247, 3, 0x0006) ; // float32: Sollwert Gasdurchfluss
458         // read_register(247, 3, 0x0008) ;	// float32: Messwert Analogeingang
459 
460         read_register(247, 3, 0x000c) ; // u16: Alarmmeldungen
461         read_register(247, 3, 0x000d) ; // u16: Hardwarefehler
462         //read_register(247, 3, 0x000e) ; // u16: Regelmode
463         //read_register(247, 3, 0x000f) ; // u16: Ramp
464 
465         read_register(247, 3, 0x0013) ; // device address: default 247 (0xf7)
466         //read_register(247, 3, 0x0020) ;
467         //read_register(247, 3, 0x0021) ;
468 
469         // read_register(247, 3, 0x5200) ; // u16: baud rate
470 
471 
472         read_register(247, 3, 0x0004) ;	// f32: Totalisator 1
473         read_register(247, 3, 0x6380) ; // f32: Totalisator 1, and f32 Totalisator 2 with 4 Byte offset.
474         //read_register(247, 3, 0x6382) ; // f32: Totalisator 2 - nicht rückstellbar
475         read_register(247, 3, 0x6384) ; // f32: Skalierung Totalisator, and s8: Einheit des Totalisatorwertes mit 4 Byte offset.
476         //read_register(247, 3, 0x6386) ; // s8: Einheit des Totalisatorwertes
477 
478         if (outFile) {
479                 // open once write all data into single log file
480                 hdr->FILE.COMPRESSION = flag_GZIP;
481 		hdr = sopen(outFile, "a", hdr);
482 		if (VERBOSE_LEVEL>7) hdr2ascii(hdr,stdout,4);
483 
484 		if (serror2(hdr)) {
485 			destructHDR(hdr);
486 			return(EXIT_FAILURE);
487 		}
488 
489 		if (hdr->FILE.OPEN < 2) {
490 			destructHDR(hdr);
491 			hdr = NULL;
492 			fprintf(stderr,"Could not open output file  %s\n", outFile);
493 			exit(-1);
494 		}
495 
496 		hdr->AS.rawdata = (uint8_t*)realloc(hdr->AS.rawdata,hdr->AS.bpb);
497 		if (hdr->NRec < 0) hdr->NRec = 0;
498 	}
499 
500         /***************************************************************************
501          *
502          *    processing: data is continuosly read from serial interface and written to log and debug file
503          *
504          ***************************************************************************/
505 
506         fid = fdopen(fd, "r+");
507 
508         while (1) {
509                 /***
510                         get data
511                 ***/
512 
513                 if (read_register(247, 3, 0x0004)) continue;	// f32: Totalisator 1
514                 float TotalVolume = bef32p(outPtr);
515 
516                 if (read_register(247, 3, 0x0000)) continue;	// float32: Messwert Gasdurchfluss, and f32: Temperatur with 4 byte offset
517                 //read_register(247, 3, 0x0002) ; // float32: Temperatur
518                 float Flow = bef32p(outPtr);
519                 float Temperature = bef32p(outPtr+4);
520 
521                 /*
522                 if (read_register(247, 3, 0x6380)) continue;	// f32: Totalisator 2
523                 float TotalVolume2 = bef32p(outPtr);
524                 float TotalVolume3 = bef32p(outPtr+4);
525                 */
526 
527                 gettimeofday(&tv, &tz);
528                 tm = gmtime(&tv.tv_sec);
529                 gdfTime = tm_time2gdf_time(gmtime(&tv.tv_sec)) + (uint64_t)ldexp(tv.tv_usec*1e-6/(24*3600),32);
530                 newDay = gdfTime>>32;
531                 gdf_time2tm_time_r(gdfTime, &T);
532                 if ( (newDay != oldDay) && !outFile) {
533                         // open/close daily log file
534 
535                         sclose(hdr);
536 			hdr->NRec = -1;
537                         sprintf(logfile,"flowmon%04d%02d%02d.log.gdf",T.tm_year+1900,T.tm_mon+1,T.tm_mday);
538                         hdr->FILE.COMPRESSION = flag_GZIP;
539                         hdr = sopen(logfile, "a", hdr);
540 
541                         if (serror2(hdr)) {
542 				destructHDR(hdr);
543 				return(EXIT_FAILURE);
544                         }
545 
546                         if (!hdr->FILE.OPEN) {
547 				destructHDR(hdr);
548 				hdr = NULL;
549         			fprintf(stderr,"Could not open output file  %s\n", logfile);
550 			}
551 
552 			hdr->AS.rawdata = (uint8_t*)realloc(hdr->AS.rawdata,hdr->AS.bpb);
553 			if (hdr->NRec<0) hdr->NRec = 0;
554                 }
555 
556                 if ( (newDay != oldDay) && !debugFile) {
557                         // open/close daily debug file
558 			if (fid2>0) fclose(fid2);
559 			sprintf(debugfile,"flowmon%02d.log.txt",T.tm_mday);
560 			fid2 = fopen(debugfile,"a");
561                 }
562 
563                 if (newDay != oldDay) {
564                         oldDay = newDay;
565                 };
566 
567 
568                 /***
569                         parse data
570                 ***/
571 
572                 memcpy(hdr->AS.rawdata+hdr->CHANNEL[0].bi,&gdfTime,8);
573                 *(float*)(hdr->AS.rawdata+hdr->CHANNEL[1].bi)=TotalVolume;
574                 *(float*)(hdr->AS.rawdata+hdr->CHANNEL[2].bi)=Flow;
575                 *(float*)(hdr->AS.rawdata+hdr->CHANNEL[3].bi)=Temperature;
576 
577                 if (hdr) {
578 
579                 if (VERBOSE_LEVEL>7) fprintf(stdout,"FLOWMON 230 %i, %i, %i\n", (int)hdr->NRec, hdr->AS.bpb, hdr->FILE.OPEN);
580                 if (VERBOSE_LEVEL>8) fprintf(stdout,"FLOWMON 240 %g, %g, %g\n", TotalVolume,Flow,Temperature);
581 
582                         hdr->NRec += ifwrite(hdr->AS.rawdata, hdr->AS.bpb, 1, hdr);
583                         ifflush(hdr);
584 
585 			/*******************************************************************
586 			 * Write HTML file
587 			 *******************************************************************/
588                         char buf[100];
589                         strfgdftime(buf,100,"%Y-%m-%d %H:%M:%S UTC",gdfTime);
590                         FILE *fid3 = fopen("/var/www/flowsensor.html","w");
591                         if (fid3 != NULL) {
592                                 fprintf(fid3,"<html><body><h1>Carbogen FlowSensor</h1><br><pre>Time:\t\t%s\n",buf);
593                                 fprintf(fid3,"Manufacturer:\t%s \nModel:\t\t%s\nSerialNo:\t%s\nVersion:\t%s\n",hdr->ID.Manufacturer.Name, hdr->ID.Manufacturer.Model,hdr->ID.Manufacturer.SerialNumber,hdr->ID.Manufacturer.Version);
594                                 fprintf(fid3,"Total Volume:\t%10.3f  l_n\n",TotalVolume);
595                                 //fprintf(fid3,"Total Volume 2:\t%10.3f  l_n (nicht ruecksetzbar)\n",TotalVolume2);
596                                 //fprintf(fid3,"Total Volume -:\t%10.3f  l_n (nicht ruecksetzbar)\n",TotalVolume3);
597                                 fprintf(fid3,"Flow:\t\t %10.4f l_n/h\n",Flow);
598                                 fprintf(fid3,"Temperature:\t%6.3f C\n</pre><META HTTP-EQUIV=\"refresh\" CONTENT=\"1\"></body></html>",Temperature);
599                                 fclose(fid3);
600                         }
601                 }
602 
603         }
604         stop();
605 
606 return(0);
607 }
608 
609 
610 
611