[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

Example 8: Creating a New Database Record

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      long 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:

Lines 14–17:

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.

Lines 57–62:

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.

Lines 63–69:

This code generates unique file names and groups for each signal.

Lines 70–93:

Here, information specific to individual signals is gathered.

Line 94:

If the signal files can’t be created, this program can do nothing else useful, so it quits with an error message from osigfopen.

Lines 95–99:

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.

Line 101:

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.

Lines 103–107:

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.

Line 109:

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.

Line 111:

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.

Line 112:

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 ] [ >> ]

George B. Moody (george@mit.edu)