[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This program creates a new record from scratch. It asks the user for information about the signals to be sampled, then records them, and finally creates a ‘hea’ file for the new record. Details of data acquisition are hardware-dependent and are not shown here.
1 #include <stdio.h> 2 #include <wfdb/wfdb.h> 3 4 main() 5 { 6 char answer[32], record[8], directory[32]; 7 int i, nsig = 0; 8 WFDB_Time nsamp, t; 9 double freq = 0.; 10 char **filename, **description, **units; 11 WFDB_Sample *v; 12 WFDB_Siginfo *s; 13 14 do { 15 printf("Choose a record name [up to 6 characters]: "); 16 fgets(record, 8, stdin); record[strlen(record)-1] = '\0'; 17 } while (newheader(record) < 0); 18 do { 19 printf("Number of signals to be recorded [>0]: "); 20 fgets(answer, 32, stdin); sscanf(answer, "%d", &nsig); 21 } while (nsig < 1); 22 s = (WFDB_Siginfo *)malloc(nsig * sizeof(WFDB_Siginfo)); 23 v = (WFDB_Sample *)malloc(nsig * sizeof(WFDB_Sample)); 24 filename = (char **)malloc(nsig * sizeof(char *)); 25 description = (char **)malloc(nsig * sizeof(char *)); 26 units = (char **)malloc(nsig * sizeof(char *)); 27 if (s == NULL || v == NULL || filename == NULL || 28 description == NULL || units == NULL) { 29 fprintf(stderr, "insufficient memory\n"); 30 exit(1); 31 } 32 for (i = 0; i < nsig; i++) { 33 if ((filename[i] = (char *)malloc(32)) == NULL || 34 (description[i] = (char *)malloc(32)) == NULL || 35 (units[i] = (char *)malloc(32)) == NULL) { 36 fprintf(stderr, "insufficient memory\n"); 37 exit(1); 38 } 39 } 40 do { 41 printf("Sampling frequency [Hz per signal, > 0]: "); 42 fgets(answer, 32, stdin); sscanf(answer, "%lf", &freq); 43 } while (setsampfreq(freq) < 0); 44 do { 45 printf("Length of record (H:M:S): "); 46 fgets(answer, 32, stdin); 47 } while ((nsamp = strtim(answer)) < 1L); 48 printf("Directory for signal files [up to 30 characters]: "); 49 fgets(directory, 32, stdin); 50 directory[strlen(directory)-1] = '\0'; 51 printf("Save signals in difference format? [y/n]: "); 52 fgets(answer, 32, stdin); 53 s[0].fmt = (answer[0] == 'y') ? 8 : 16; 54 printf("Save all signals in one file? [y/n]: "); 55 fgets(answer, 32, stdin); 56 if (answer[0] == 'y') { 57 sprintf(filename[0], "%s/d.%s", directory, record); 58 for (i = 0; i < nsig; i++) { 59 s[i].fname = filename[0]; 60 s[i].group = 0; 61 } 62 } 63 else { 64 for (i = 0; i < nsig; i++) { 65 sprintf(filename[i], "%s/d%d.%s", directory,i,record); 66 s[i].fname = filename[i]; 67 s[i].group = i; 68 } 69 } 70 for (i = 0; i < nsig; i++) { 71 s[i].fmt = s[0].fmt; s[i].bsize = 0; 72 printf("Signal %d description [up to 30 characters]: ", i); 73 fgets(description[i], 32, stdin); 74 description[i][strlen(description[i])-1] = '\0'; 75 s[i].desc = description[i]; 76 printf("Signal %d units [up to 20 characters]: ", i); 77 fgets(units[i], 22, stdin); 78 units[i][strlen(units[i])-1] = '\0'; 79 s[i].units = (*units[i]) ? units[i] : "mV"; 80 do { 81 printf(" Signal %d gain [adu/%s]: ", i, s[i].units); 82 fgets(answer, 32, stdin); 83 sscanf(answer, "%lf", &s[i].gain); 84 } while (s[i].gain < 0.); 85 do { 86 printf(" Signal %d ADC resolution in bits [8-16]: ", i); 87 fgets(answer, 32, stdin); 88 sscanf(answer, "%d", &s[i].adcres); 89 } while (s[i].adcres < 8 || s[i].adcres > 16); 90 printf(" Signal %d ADC zero level [adu]: ", i); 91 fgets(answer, 32, stdin); 92 sscanf(answer, "%d", &s[i].adczero); 93 } 94 if (osigfopen(s, nsig) < nsig) exit(1); 95 printf("To begin sampling, press RETURN; to specify a\n"); 96 printf(" start time other than the current time, enter\n"); 97 printf(" it in H:M:S format before pressing RETURN: "); 98 fgets(answer, 32, stdin); answer[strlen(answer)-1] = '\0'; 99 setbasetime(answer); 100 101 adinit(); 102 103 for (t = 0; t < nsamp; t++) { 104 for (i = 0; i < nsig; i++) 105 v[i] = adget(i); 106 if (putvec(v) < 0) break; 107 } 108 109 adquit(); 110 111 (void)newheader(record); 112 wfdbquit(); 113 exit(0); 114 } |
(See http://physionet.org/physiotools/wfdb/examples/example8.c for a copy of this program.)
Notes:
This code uses newheader
to determine if a legal record name was
entered (since we don’t want to digitize the signals and then find out
that we can’t create the header file). The header file
created in line 17 will be overwritten in line 111.
This code generates a file name and initializes the fname
and
group
fields of the array of WFDB_Siginfo
objects so that all
signals will be saved in one file.
This code generates unique file names and groups for each signal.
Here, information specific to individual signals is gathered.
If the signal files can’t be created, this program can do nothing else
useful, so it quits with an error message from osigfopen
.
Just before sampling begins, we set the base time. Note that an empty
string argument for setbasetime
gives us the current time read from
the system clock.
What goes here will be hardware dependent. Typically it is necessary to set up a timer for the ADC, allocate DMA buffers, specify interrupt vectors, and initiate the first conversion(s). This program might also be used to create a database record from prerecorded data in a non-supported format; in this case, we might simply open the file containing the prerecorded data here.
Here is where the samples are acquired (using hardware-dependent code
not shown here) and recorded (using putvec
). At high sampling
frequencies, it is critical to make this code as fast as possible. It
could be made faster by judicious use of register
and pointer
variables if necessary. In an extreme case the entire loop, possibly
including putvec
itself, can be written in assembly language;
since it is only a small fraction of the entire program, doing so is
within reason.
This final piece of hardware-dependent code typically clears the ADC control register, stops the timer, and frees any system resources such as DMA channels or interrupts.
All of the information needed to generate the header file has been
stored in WFDB library internal data structures by osigfopen
and
putvec
; we call newheader
here (before wfdbquit
) to
create the new ‘hea’ file.
It is still necessary to use wfdbquit
to close the signal file(s),
even after calling newheader
. (In fact, it would be possible,
though not likely to be useful, to record more samples and to generate
another header file before calling wfdbquit
.)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
PhysioNet (wfdb@physionet.org)