Go to the first, previous, next, last section, table of contents.


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 `header' file for the new record. Details of data acquisition are hardware-dependent and are not shown here.

 1  #include <stdio.h>
 2  #include <ecg/db.h>
 3
 4  main()
 5  {
 6      char answer[32], record[8], directory[32];
 7      int i, nsig = 0, v[DB_MAXSIG];
 8      long nsamp, t;
 9      double freq = 0.;
10      static char filename[DB_MAXSIG][32],
11          description[DB_MAXSIG][32], units[DB_MAXISIG][22];
12      static DB_Siginfo s[DB_MAXSIG];
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 [1-%d]: ",
20                 DB_MAXSIG);
21          fgets(answer, 32, stdin); sscanf(answer, "%d", &nsig);
22      } while (nsig < 1 || nsig > DB_MAXSIG);
23      do {
24          printf("Sampling frequency [Hz per signal, > 0]: ");
25          fgets(answer, 32, stdin); sscanf(answer, "%lf", &freq);
26      } while (setsampfreq(freq) < 0);
27      do {
28          printf("Length of record (H:M:S): ");
29          fgets(answer, 32, stdin);
30      } while ((nsamp = strtim(answer)) < 1L);
31      printf("Directory for signal files [up to 30 characters]: ");
32      fgets(directory, 32, stdin);
33      directory[strlen(directory)-1] = '\0';
34      printf("Save signals in difference format? [y/n]: ");
35      fgets(answer, 32, stdin);
36      s[0].fmt = (answer[0] == 'y') ? 8 : 16;
37      printf("Save all signals in one file? [y/n]: ");
38      fgets(answer, 32, stdin);
39      if (answer[0] == 'y') {
40          sprintf(filename[0], "%s/d.%s", directory, record);
41          for (i = 0; i < nsig; i++) {
42               s[i].fname = filename[0];
43               s[i].group = 0;
44          }
45      }
46      else {
47          for (i = 0; i < nsig; i++) {
48               sprintf(filename[i], "%s/d%d.%s", directory,i,record);
49               s[i].fname = filename[i];
50               s[i].group = i;
51          }
52      }
53      for (i = 0; i < nsig; i++) {
54          s[i].fmt = s[0].fmt; s[i].bsize = 0;
55          printf("Signal %d description [up to 30 characters]: ", i);
56          fgets(description[i], 32, stdin);
57          description[i][strlen(description[i])-1] = '\0';
58          s[i].desc = description[i];
59          printf("Signal %d units [up to 20 characters]: ", i);
60          fgets(units[i], 22, stdin);
61          units[i][strlen(units[i])-1] = '\0';
62          s[i].units = (*units[i]) ? units[i] : "mV";
63          do {
64              printf(" Signal %d gain [adu/%s]: ", i, s[i].units);
65              fgets(answer, 32, stdin);
66              sscanf(answer, "%lf", &s[i].gain);
67          } while (s[i].gain < 0.);
68          do {
69              printf(" Signal %d ADC resolution in bits [8-16]: ", i);
70              fgets(answer, 32, stdin);
71              sscanf(answer, "%d", &s[i].adcres);
72          } while (s[i].adcres < 8 || s[i].adcres > 16);
73          printf(" Signal %d ADC zero level [adu]: ", i);
74          fgets(answer, 32, stdin);
75          sscanf(answer, "%d", &s[i].adczero);
76      }
77      if (osigfopen(s, nsig) < nsig) exit(1);
78      printf("To begin sampling, press RETURN;  to specify a\n");
79      printf(" start time other than the current time, enter\n");
80      printf(" it in H:M:S format before pressing RETURN: ");
81      fgets(answer, 32, stdin); answer[strlen(answer)-1] = '\0';
82      setbasetime(answer);
83
84      initialize ADC here
85
86      for (t = 0; t < nsamp; t++) {
87          for (i = 0; i < nsig; i++)
88              v[i] = sample from ADC channel i
89          if (putvec(v) < 0) break;
90      }
91
92      stop ADC here
93
94      (void)newheader(record);
95      dbquit();
96      exit(0);
97  }

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 94.
Lines 39--45:
This code generates a file name and initializes the fname and group fields of the array of DB_Siginfo objects so that all signals will be saved in one file.
Lines 46--52:
This code generates unique file names and groups for each signal.
Lines 53--76:
Here, information specific to individual signals is gathered.
Line 77:
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 78--82:
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 84:
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 86--90:
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 92:
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 94:
All of the information needed to generate the `header' file has been stored in DB library internal data structures by osigfopen and putvec; we call newheader here (before dbquit) to create the new `header' file.
Line 95:
It is still necessary to use dbquit 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 dbquit.)


Go to the first, previous, next, last section, table of contents.



George B. Moody (george@hstbme.mit.edu)