1 /*
2 
3     Copyright (C) 2021 Alois Schloegl <alois.schloegl@gmail.com>
4 
5     This file is part of the "BioSig for C/C++" repository
6     (biosig4c++) at http://biosig.sf.net/
7 
8     BioSig is free software; you can redistribute it and/or
9     modify it under the terms of the GNU General Public License
10     as published by the Free Software Foundation; either version 3
11     of the License, or (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 
21  */
22 
23 
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stddef.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "../biosig.h"
32 
33 /******************************************************************************
34 	read CADWELL file formats (EAS, EZ3, ARC)
35  ******************************************************************************/
sopen_cadwell_read(HDRTYPE * hdr)36 void sopen_cadwell_read(HDRTYPE* hdr) {
37 
38 	if (VERBOSE_LEVEL > 8) fprintf(stdout,"%s (line %d) %s(hdr)\n", __FILE__, __LINE__, __func__);
39 
40 	if (hdr->TYPE==EAS) {
41 		/* 12 bit ADC ?
42 		   200 Hz
43 		   77*800 samples
44 		   EEGData section has a periodicity of 202*2 (404 bytes)
45 			800samples*16channels*2byte=25600  = 0x6400)
46 		*/
47 		hdr->NS  = 16;  // so far all example files had 16 channels
48 		hdr->SPR  = 1;
49 		hdr->NRec = 0;
50 		unsigned lengthHeader0 = leu32p(hdr->AS.Header + 0x30);
51 		unsigned lengthHeader1 = leu32p(hdr->AS.Header + 0x34);	// this is varying amoung data sets - meaning unknown
52 		assert(lengthHeader0==0x0400);
53 
54 		for (int k=0; k*0x20 < lengthHeader1; k++) {
55 			char *sectName =       hdr->AS.Header + 0x6c + k*0x20;
56 			size_t sectPos= leu32p(hdr->AS.Header + 0x7c + k*0x20);
57 			size_t sectN1 = leu32p(hdr->AS.Header + 0x80 + k*0x20);
58 			size_t sectN2 = leu32p(hdr->AS.Header + 0x84 + k*0x20);
59 			size_t sectN3 = leu32p(hdr->AS.Header + 0x88 + k*0x20);
60 
61 			if (!sectPos
62 			 || memcmp("SctHdr\0\0", hdr->AS.Header+sectPos, 8)
63 			 || memcmp(hdr->AS.Header+sectPos+8, sectName, 16))
64 			{
65 				if (VERBOSE_LEVEL > 8) fprintf(stdout,"%s (line %d): break loop (0x%x %s)\n",__FILE__,__LINE__, sectPos, sectName);
66 				break;
67 			}
68 
69 			uint64_t curSec, nextSec;
70 			int flag=1;
71 			do {
72 				curSec  = leu64p(hdr->AS.Header + sectPos + 24);
73 				nextSec = leu64p(hdr->AS.Header + sectPos + 32);
74 
75 		if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %d): 0x%08x %s  0x%08lx 0x%08lx \n",__FILE__,__LINE__, sectPos, sectName, curSec, nextSec);
76 				if (flag && !strcmp(sectName,"EEGData")) {
77 		if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %d): 0x%08x %s  0x%08lx 0x%08lx \n",__FILE__,__LINE__, sectPos, sectName, curSec, nextSec);
78 					FILE *fid2=fopen("tmp.bin","w");
79 					fwrite(hdr->AS.Header + curSec+120, 1, nextSec-curSec-120,fid2);
80 					fclose(fid2);
81 					FILE *fid=fopen("tmp.asc","w");
82 					for (size_t k0=curSec+8*15; k0 < nextSec; k0+=2) {
83 						fprintf(fid,"%d\n",bei16p(hdr->AS.Header + curSec + k0+1));
84 					}
85 					fclose(fid);
86 					flag = 0;
87 				}
88 				sectPos = nextSec;
89 			} while (nextSec != (size_t)-1L);
90 		}
91 		biosigERROR(hdr, B4C_FORMAT_UNSUPPORTED, "Format EAS(Cadwell): unsupported ");
92 	}
93 
94 	else if (hdr->TYPE==EZ3) {
95 		hdr->VERSION = strtod((char*)hdr->AS.Header+21, NULL);
96 		// 16 bit ADC ?
97 		// 250 Hz ?
98 
99 		if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %d)0x%8x\n",__FILE__,__LINE__,hdr->HeadLen);
100 
101 		uint32_t posH1  = leu32p(hdr->AS.Header + 0x10);
102 		if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %d)0x%8x\n",__FILE__,__LINE__,posH1);
103 
104 		uint32_t posH1b = leu32p(hdr->AS.Header + 0x20);
105 		if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %d)0x%8x\n",__FILE__,__LINE__,posH1b);
106 
107 		uint32_t posH2  = leu32p(hdr->AS.Header + 0x38);
108 		if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %d)0x%8x\n",__FILE__,__LINE__,posH2);
109 
110 		uint32_t posH2b = leu32p(hdr->AS.Header + posH1 + 0x38);
111 
112 		if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %d) 0x%08x 0x%08x 0x%08x 0x%08x \n",__FILE__,__LINE__,posH1,posH1b,posH2,posH2b);
113 
114 		assert(posH1==posH1b);
115 		assert(posH2==posH2b);
116 
117 		if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %d)\n",__FILE__,__LINE__);
118 
119 		// start date/time
120 		{
121 			char *tmp = hdr->AS.Header + 0x5c;
122 			struct tm t;
123 			t.tm_year = strtol(tmp,&tmp,10)-1900;
124 			t.tm_mon = strtol(tmp+1,&tmp,10)-1;
125 			t.tm_mday = strtol(tmp+1,&tmp,10);
126 			t.tm_hour = strtol(tmp+1,&tmp,10);
127 			t.tm_min = strtol(tmp+1,&tmp,10);
128 			t.tm_sec = strtol(tmp+1,&tmp,10);
129 			hdr->T0 = tm_time2gdf_time(&t);
130 		}
131 
132 		uint32_t pos0=posH1+0x40;
133 		for (size_t k = posH1+0x40; k < posH2; k += 0x30) {
134 			char *tmp    = hdr->AS.Header + k + 1;
135 			uint32_t pos = leu32p(hdr->AS.Header + k + 0x28);
136 			if (tmp[0]=='\0') break;
137 
138 			if (VERBOSE_LEVEL > 7) fprintf(stdout,"%s (line %d): Label=<%s> %10d(0x%08x) [sz=%d]\n",__FILE__,__LINE__, tmp, pos, pos, pos-pos0);
139 			pos0=pos;
140 		}
141 
142 		biosigERROR(hdr, B4C_FORMAT_UNSUPPORTED, "Format EZ3(Cadwell): unsupported ");
143 	}
144 	else if (hdr->TYPE==ARC) {
145 		biosigERROR(hdr, B4C_FORMAT_UNSUPPORTED, "Format ARC(Cadwell): unsupported ");
146 	}
147 }
148 
149