WFDB Software Package 10.7.0
(22,443 bytes)
/* file: lcheck.c G. Moody 7 September 2001
Last revised: 18 May 2022
-------------------------------------------------------------------------------
wfdbcheck: test WFDB library
Copyright (C) 2001-2010 George B. Moody
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, see <http://www.gnu.org/licenses/>.
You may contact the author by e-mail (wfdb@physionet.org) or postal mail
(MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to this software,
please visit PhysioNet (http://www.physionet.org/).
_______________________________________________________________________________
*/
#include <stdio.h>
#include <wfdb/wfdb.h>
char *info, *pname, *prog_name();
int n, nsig, i, j, framelen, errors = 0, istat, vflag = 0;
char headerversion[40];
char *libversion;
char *p, *q, *defpath, *dbpath;
WFDB_Anninfo aiarray[2];
WFDB_Annotation annot;
WFDB_Calinfo cal;
WFDB_Siginfo *si;
WFDB_Sample *vector;
void help(), list_untested();
void check_annotations(char *record);
void check_signals(char *record, char *orec, int fmt, int split_info);
main(argc, argv)
int argc;
char *argv[];
{
pname = prog_name(argv[0]);
if (argc > 1) {
if (strcmp(argv[1], "-v") == 0) vflag = 1;
else if (strcmp(argv[1], "-V") == 0) vflag = 2;
else { help(); exit(1); }
}
if ((p = wfdberror()) == NULL) {
printf("Error: wfdberror() did not return a version string\n");
p = "unknown version of the WFDB library";
errors++;
}
libversion = calloc(sizeof(char), strlen(p)+1);
strcpy(libversion, p);
/* Print the library version number and date. */
fprintf(stderr, "Testing %s", libversion);
/* Check that the installed <wfdb/wfdb.h> matches the library. */
sprintf(headerversion, "WFDB library version %d.%d.%d",
WFDB_MAJOR, WFDB_MINOR, WFDB_RELEASE);
if (strncmp(libversion, headerversion, strlen(headerversion))) {
printf("Error: Library version does not match <wfdb/wfdb.h>\n"
" (<wfdb/wfdb.h> is from %s)\n", headerversion);
errors++;
}
else if (vflag)
printf("[OK]: Library version matches <wfdb/wfdb.h>\n");
/* If in verbose mode, print library defaults. */
if (vflag) {
static int format[WFDB_NFMTS] = WFDB_FMT_LIST;
printf("[OK]: WFDB %s NETFILES\n", WFDB_NETFILES ? "supports" :
"does not support");
printf("[OK]: WFDB_MAXANN = %d\n", WFDB_MAXANN);
printf("[OK]: WFDB_MAXSIG = %d\n", WFDB_MAXSIG);
printf("[OK]: WFDB_MAXSPF = %d\n", WFDB_MAXSPF);
printf("[OK]: WFDB_MAXRNL = %d\n", WFDB_MAXRNL);
printf("[OK]: WFDB_MAXUSL = %d\n", WFDB_MAXUSL);
printf("[OK]: WFDB_MAXDSL = %d\n", WFDB_MAXDSL);
printf("[OK]: Signal formats = {");
for (i = 0; i < WFDB_NFMTS; i++)
printf("%d%s", format[i], (i < WFDB_NFMTS-1) ? ", " : "}\n");
printf("[OK]: WFDB_DEFFREQ = %g\n", WFDB_DEFFREQ);
printf("[OK]: WFDB_DEFGAIN = %g\n", WFDB_DEFGAIN);
printf("[OK]: WFDB_DEFRES = %d\n", WFDB_DEFRES);
}
/* Test the WFDB library functions. */
aiarray[0].name = "atr"; aiarray[0].stat = WFDB_READ;
aiarray[1].name = "chk"; aiarray[1].stat = WFDB_WRITE;
/* *** getwfdb *** */
if ((p = getwfdb()) == NULL) {
printf("Error: No default WFDB path defined\n");
defpath = "";
errors++;
}
else {
defpath = calloc(sizeof(char), strlen(p)+1);
strcpy(defpath, p);
if (vflag)
printf("[OK]: Default WFDB path = %s\n", defpath);
}
/* *** setwfdb *** */
dbpath = calloc(sizeof(char), strlen(defpath)+10);
sprintf(dbpath, "data %s\n", defpath);
setwfdb(dbpath);
if ((p = getwfdb()) == NULL || strcmp(p, dbpath)) {
printf("Error: Could not set WFDB path\n");
errors++;
}
else if (vflag)
printf("[OK]: WFDB path modified successfully\n");
/* *** calopen *** */
i = calopen(NULL);
if (i != 0) {
printf("Error: Could not open calibration list, calopen returned %d\n", i);
errors++;
}
else if (vflag)
printf("[OK]: WFDB calibration list opened successfully\n");
/* *** getcal *** */
i = getcal("NBPfoo", "mmHg", &cal);
if (i != 0 || cal.low != 0.0 || cal.high != 100.0 || cal.scale != 100.0 ||
strcmp(cal.sigtype, "NBP") != 0 || strcmp(cal.units, "mmHg") != 0 ||
cal.caltype != (WFDB_DC_COUPLED | WFDB_CAL_SQUARE)) {
printf("Error: getcal returned %d, cal = { %g %g %g %s %s %d }\n", i,
cal.low, cal.high, cal.scale, cal.sigtype, cal.units, cal.caltype);
errors++;
}
else if (vflag)
printf("[OK]: getcal was successful\n");
/* *** putcal *** */
cal.sigtype = "foobar";
i = putcal(&cal);
if (i != 0) {
printf("Error: putcal returned %d\n", i);
errors++;
}
else if (vflag)
printf("[OK]: putcal returned 0\n");
i = getcal("foobar", "mmHg", &cal);
if (i != 0 || cal.low != 0.0 || cal.high != 100.0 || cal.scale != 100.0 ||
strcmp(cal.sigtype, "foobar") != 0 || strcmp(cal.units, "mmHg") != 0 ||
cal.caltype != (WFDB_DC_COUPLED | WFDB_CAL_SQUARE)) {
printf("Error: putcal failed, cal = { %g %g %g %s %s %d }\n",
cal.low, cal.high, cal.scale, cal.sigtype, cal.units, cal.caltype);
errors++;
}
else if (vflag)
printf("[OK]: putcal was successful\n");
/* *** newcal *** */
i = newcal("lcheck_cal");
if (i != 0) {
printf("Error: newcal returned %d\n", i);
errors++;
}
else if (vflag)
printf("[OK]: newcal was successful\n");
/* Test I/O using the local record first, converting signals to
another format and back. */
check_annotations("100s");
#ifdef WFDB_FLAC_SUPPORT
check_signals("100s", "100y", 516, 1);
#else
check_signals("100s", "100y", 16, 1);
#endif
check_signals("100y", "100z", 212, 0);
/* Test I/O again using the remote record. */
if (WFDB_NETFILES) {
if (vflag)
printf("[OK]: Repeating tests using NETFILES");
if (strstr(defpath, "://") == NULL) {
fprintf(stderr,
"\nWarning: default WFDB path does not include an http:// component\n");
setwfdb(". http://www.physionet.org/physiobank/database");
printf("WFDB path has been set to: %s\n", getwfdb());
}
else if (vflag) {
printf(" (reverting to default WFDB path)\n");
setwfdb(defpath);
}
check_annotations("udb/100s");
check_signals("udb/100s", "udb/100z", -1, 0);
}
/* If there were any errors detected by the WFDB library but not by this
program, this test will pick them up. */
if (errors == 0) {
if ((p = wfdberror()) == NULL) {
printf("Error: wfdberror() did not return a version string\n");
p = "unknown version of the WFDB library";
errors++;
}
if (strcmp(libversion, p)) {
printf("Error: WFDB library error(s) not detected by %s\n",
pname);
printf(" Last library error was: '%s'\n", p);
errors++;
}
else if (vflag)
printf("[OK]: no WFDB library errors\n");
}
/* In this section, test functions that can only be checked by looking
for library errors. */
/* *** flushcal *** */
flushcal();
i = getcal("foobar", "mmHg", &cal);
if (i == 0) {
printf("Error: flushcal did not empty the calibration list\n");
errors++;
}
else if (vflag)
printf("[OK]: flushcal was successful\n");
/* Summarize the results and exit. */
if (errors)
printf("%d error%s: test failed\n", errors, errors > 1 ? "s" :"");
else if (vflag)
printf("no errors: test succeeded\n");
if (vflag == 2)
list_untested();
exit(errors);
}
void check_annotations(char *record)
{
WFDB_Date d;
WFDB_Frequency f;
WFDB_Time t;
/* *** sampfreq *** */
if ((f = sampfreq(NULL)) != 0.0) {
printf("Error: sampfreq(NULL) returned %g (should have been 0)\n", f);
errors++;
}
else if (vflag)
printf("[OK]: sampfreq(NULL) returned %g\n", f);
/* *** setsampfreq *** */
if (istat = setsampfreq(100.0)) {
printf("Error: setsampfreq returned %d (should have been 0)\n", istat);
errors++;
}
if (sampfreq(NULL) != 100.0) {
printf("Error: failed to set sampling frequency using setsampfreq\n");
errors++;
}
else if (vflag)
printf("[OK]: setsampfreq changed sampling frequency successfully\n");
/* *** sampfreq, again *** */
if ((f = sampfreq(record)) != 360.0) {
printf("Error: sampfreq(%s) returned %g (should have been 360)\n",
record, f);
errors++;
}
else if (vflag)
printf("[OK]: sampfreq(%s) returned %g\n", record, f);
/* *** annopen *** */
istat = annopen(record, aiarray, 1);
if (istat) {
fprintf(stderr,
"Error: annopen of 1 file returned %d (should have been 0)\n", istat);
errors++;
}
else if (vflag)
printf("[OK]: annopen of 1 file succeeded\n");
istat = annopen(record, aiarray, 2);
if (istat) {
fprintf(stderr,
"Error: annopen of 2 files returned %d (should have been 0)\n", istat);
errors++;
}
else if (vflag)
printf("[OK]: annopen of 2 files succeeded\n");
/* *** strecg, ecgstr *** */
i = strecg("N");
if (i != 1) {
printf("Error: strecg returned %d (should have been 1)\n", i);
errors++;
}
else if (vflag)
printf("[OK]: strecg returned %d\n", i);
p = ecgstr(i);
if (strcmp(p, "N")) {
printf("Error: ecgstr returned '%s' (should have been 'N')\n", p);
errors++;
}
else if (vflag)
printf("[OK]: ecgstr returned '%s'\n", p);
/* *** strann, annstr, anndesc *** */
i = strann("N");
if (i != 1) {
printf("Error: strann returned %d (should have been 1)\n", i);
errors++;
}
else if (vflag)
printf("[OK]: strann returned %d\n", i);
p = annstr(i);
if (strcmp(p, "N")) {
printf("Error: annstr returned '%s' (should have been 'N')\n", p);
errors++;
}
else if (vflag)
printf("[OK]: annstr returned '%s'\n", p);
p = anndesc(i);
if (strcmp(p, "Normal beat")) {
printf("Error: anndesc returned '%s' (should have been 'Normal beat')\n",
p);
errors++;
}
else if (vflag)
printf("[OK]: anndesc returned '%s'\n", p);
/* *** setecgstr, setannstr, setanndesc *** */
i = setecgstr(1, "X");
p = ecgstr(1);
if (i != 0 || strcmp(p, "X")) {
printf("Error: setecgstr failed\n");
errors++;
}
else if (vflag)
printf("[OK]: setecgstr succeeded\n");
i = setannstr(-1, "Y");
p = annstr(1);
if (i != 0 || strcmp(p, "Y")) {
printf("Error: setannstr failed\n");
errors++;
}
else if (vflag)
printf("[OK]: setannstr succeeded\n");
i = setanndesc(-1, "ZZ zz");
p = anndesc(1);
if (i != 0 || strcmp(p, "ZZ zz")) {
printf("Error: setanndesc failed\n");
errors++;
}
else if (vflag)
printf("[OK]: setanndesc succeeded\n");
/* *** strtim, timstr *** */
t = strtim("0:5");
if (t != (WFDB_Time)(5.0 * f)) {
printf("Error: strtim returned %"WFDB_Pd_TIME
" (should have been %"WFDB_Pd_TIME")\n", t,
(WFDB_Time)(5.0 * f));
errors++;
}
else if (vflag)
printf("[OK]: strtim returned %"WFDB_Pd_TIME"\n", t);
p = timstr(t); q = " 0:05";
if (strcmp(p, q)) {
printf("Error: timstr returned '%s' (should have been '%s')\n", p, q);
errors++;
}
else if (vflag)
printf("[OK]: timstr returned '%s'\n", p);
/* *** strdat, datstr *** */
q = " 31/12/1999";
d = strdat(q);
if (d != 2451544L) {
printf("Error: strdat returned %ld (should have been 2451544)\n", d);
errors++;
}
else if (vflag)
printf("[OK]: strdat returned %ld\n", d);
p = datstr(d);
if (strcmp(p, q)) {
printf("Error: datstr returned '%s' (should have been '%s')\n", p, q);
errors++;
}
else if (vflag)
printf("[OK]: datstr returned '%s'\n", p);
/* *** iannsettime *** */
istat = iannsettime(t);
if (istat) {
printf("Error: iannsettime returned %d (should have been 0)\n",
istat);
errors++;
}
else if (vflag)
printf("[OK]: iannsettime skipping forward to %s\n",
timstr(t));
/* *** getann, stimstr *** */
for (i = 0; i < 5; i++) {
istat = getann(0, &annot);
if (istat != 0 && istat != -1) {
printf("Error: getann returned %d (should have been 0 or -1)\n",
istat);
errors++;
}
else if (vflag)
printf("[OK]: getann read: {%s %d %d %d} at %s (%"WFDB_Pd_TIME")\n",
annstr(annot.anntyp), annot.subtyp, annot.chan, annot.num,
mstimstr(annot.time), annot.time);
}
/* *** iannsettime, again *** */
istat = iannsettime(0L);
if (istat) {
printf("Error: iannsettime returned %d (should have been 0)\n",
istat);
errors++;
}
else if (vflag)
printf("[OK]: iannsettime skipping backward to %s\n",
timstr(0L));
/* *** getann, putann *** */
i = j = istat = 0;
while (istat == 0) {
istat = getann(0, &annot);
if (istat != 0 && istat != -1) {
printf("Error: getann returned %d (should have been 0 or -1)\n",
istat);
errors++;
}
else if (istat == 0) {
i++;
istat = putann(0, &annot);
if (istat != 0) {
printf("Error: putann returned %d (should have been 0)\n",
istat);
errors++;
}
else j++;
}
}
if (vflag)
printf("[OK]: %d annotations read, %d written\n", i, j);
}
void check_signals(char *record, char *orec, int ofmt, int split_info)
{
WFDB_Frequency f;
WFDB_Time t, tt;
double x;
/* *** isigopen *** */
/* Get the number of signals without opening any signal files. */
n = isigopen(record, NULL, 0);
if (n != 2) {
fprintf(stderr,
"Error: isigopen(%s, NULL, 0) returned %d (should have been 2)\n",
record, n);
errors++;
}
else if (vflag)
printf("[OK]: isigopen(%s, NULL, 0) succeeded\n", record);
/* Allocate WFDB_Siginfo structures before calling isigopen again. */
si = calloc(n, sizeof(WFDB_Siginfo));
nsig = isigopen(record, si, n);
/* Note that nsig equals n only if all signals were readable. */
/* Get the number of samples per frame. */
for (i = framelen = 0; i < nsig; i++)
framelen += si[i].spf;
/* Allocate WFDB_Samples before calling getframe. */
vector = calloc(framelen, sizeof(WFDB_Sample));
for (t = 0L; t < 5L; t++) {
if ((n = getframe(vector)) != nsig) {
printf("Error: getframe returned %d (should have been %d)\n",
n, nsig);
errors++;
break;
}
else if (vflag) {
printf("[OK]: (at %s) getframe returned {", mstimstr(t));
for (i = 0; i < framelen; i++)
printf("%5d%s", vector[i], i < framelen-1 ? ", " : "}\n");
}
}
/* *** aduphys, physadu *** */
x = aduphys((WFDB_Signal)0, (WFDB_Sample)1000);
if (x > -0.119999999 || x < -0.120000001) {
printf("Error: aduphys returned %g (should have been -0.12)\n", x);
errors++;
}
else if (vflag)
printf("[OK]: aduphys returned %g\n", x);
i = physadu((WFDB_Signal)0, x);
if (i != (WFDB_Sample)1000) {
printf("Error: physadu returned %d (should have been 1000)\n", i);
errors++;
}
else if (vflag)
printf("[OK]: physadu returned %d\n", i);
/* *** adumuv, muvadu *** */
i = adumuv((WFDB_Signal)0, (WFDB_Sample)1000);
if (i != 5000) {
printf("Error: adumuv returned %d (should have been 5000)\n", i);
errors++;
}
else if (vflag)
printf("[OK]: adumuv returned %d\n", i);
i = muvadu((WFDB_Signal)0, i);
if (i != (WFDB_Sample)1000) {
printf("Error: muvadu returned %d (should have been 1000)\n", i);
errors++;
}
else if (vflag)
printf("[OK]: muvadu returned %d\n", i);
/* *** sampfreq *** */
f = sampfreq(NULL);
if (f != 360.0) {
printf("Error: sampfreq returned %g (should have been 360)\n", f);
errors++;
}
else if (vflag)
printf("[OK]: sampfreq returned %g\n", f);
/* *** strtim *** */
t = strtim("0:20");
if (t != (WFDB_Time)(20.0 * f)) {
printf("Error: strtim returned %"WFDB_Pd_TIME
" (should have been %"WFDB_Pd_TIME")\n", t,
(WFDB_Time)(20.0 * f));
errors++;
}
else if (vflag)
printf("[OK]: strtim returned %"WFDB_Pd_TIME"\n", t);
p = timstr(t); q = " 0:20";
if (strcmp(p, q)) {
printf("Error: timstr returned '%s' (should have been '%s')\n", p, q);
errors++;
}
else if (vflag)
printf("[OK]: timstr returned '%s'\n", p);
/* *** isigsettime *** */
istat = isigsettime(t);
if (istat) {
printf("Error: isigsettime returned %d (should have been 0)\n",
istat);
errors++;
}
else if (vflag)
printf("[OK]: isigsettime skipping forward to %s\n",
timstr(t));
/* *** getvec *** */
for (tt = t; t < tt+5L; t++) {
if ((n = getvec(vector)) != nsig) {
printf("Error: getvec returned %d (should have been %d)\n",
n, nsig);
errors++;
break;
}
else if (vflag) {
printf("[OK]: (at %s) getvec returned {", mstimstr(t));
for (i = 0; i < nsig; i++)
printf("%5d%s", vector[i], i < nsig-1 ? ", " : "} [");
for (i = 0; i < nsig; i++)
printf("%5.3lf%s", aduphys(i, vector[i]), i < nsig-1?", ":"]\n");
}
}
/* *** isigsettime *** */
t = tt-1; /* try a backward skip, to one sample before the previous set */
istat = isigsettime(t);
if (istat) {
printf("Error: isigsettime returned %d (should have been 0)\n",
istat);
errors++;
}
else if (vflag)
printf("[OK]: isigsettime skipping backward to %s\n",
mstimstr(t));
/* *** getframe, again *** */
for ( ; t < tt+5L; t++) {
if ((n = getframe(vector)) != nsig) {
printf("Error: getframe returned %d (should have been %d)\n",
n, nsig);
errors++;
break;
}
else if (vflag) {
printf("[OK]: (at %s) getframe returned {", mstimstr(t));
for (i = 0; i < framelen; i++)
printf("%5d%s", vector[i], i < framelen-1 ? ", " : "}\n");
}
}
/* Now return to the beginning of the record and copy it. */
istat = isigsettime(t = 0L);
if (istat) {
printf("Error: isigsettime returned %d (should have been 0)\n",
istat);
errors++;
}
else if (vflag)
printf("[OK]: isigsettime skipping backward to %s\n",
mstimstr(t));
/* *** osigfopen *** */
for (i = 0; i < nsig; i++) {
si[i].fname = realloc(si[i].fname, strlen(orec) + 5);
sprintf(si[i].fname, "%s.dat", orec);
if (ofmt >= 0)
si[i].fmt = ofmt;
}
istat = osigfopen(si, nsig);
if (istat != nsig) {
printf("Error: osigfopen returned %d (should have been %d)\n",
istat, nsig);
errors++;
}
else if (vflag)
printf("[OK]: osigfopen returned %d\n", istat);
/* *** getframe (again), putvec *** */
while ((n = getframe(vector)) == nsig) {
t++;
if ((istat = putvec(vector)) != nsig) {
printf("Error: putvec returned %d (should have been %d)\n",
istat, nsig);
errors++;
break;
}
}
if (n != -1) { /* some error occurred while reading samples */
printf("Error: getframe returned %d (should have been %d) at %s\n",
n, nsig, mstimstr(t));
errors++;
}
else if (vflag) /* getframe reached EOF, checksums OK */
printf("[OK]: getframe read %"WFDB_Pd_TIME" samples\n", t);
if (istat != nsig) { /* some error occurred while writing samples */
printf("Error: putvec returned %d (should have been %d) at %s\n",
istat, nsig, mstimstr(t));
errors++;
}
else if (vflag) /* putvec wrote all samples without apparent error */
printf("[OK]: putvec wrote %"WFDB_Pd_TIME" samples\n", t);
/* *** newheader *** */
istat = newheader(orec);
if (istat) { /* some error occurred while writing the header */
printf("Error: newheader returned %d (should have been 0)\n", istat);
errors++;
}
else if (vflag) /* putvec wrote all samples without apparent error */
printf("[OK]: newheader created header for output record %s\n", orec);
/* *** getinfo, setinfo, putinfo *** */
n = 0;
if (info = getinfo(record)) {
if (split_info) {
istat = setinfo(orec);
if (istat) {
printf("Error: setinfo returned %d (should have been 0)\n", istat);
errors++;
}
else if (vflag)
printf("[OK]: setinfo created info for output record %s\n", orec);
}
do {
istat = putinfo(info);
if (istat) {
printf("Error: putinfo returned %d (should have been 0)\n", istat);
errors++;
}
else
n++;
} while (info = getinfo(NULL));
if (vflag)
printf("[OK]: %d info strings copied to record %s header\n", n, orec);
}
wfdbquit();
setecgstr(1, "N");
setannstr(-1, "N");
setanndesc(-1, "Normal beat");
}
char *prog_name(s)
char *s;
{
char *p = s + strlen(s);
#ifdef MSDOS
while (p >= s && *p != '\\' && *p != ':') {
if (*p == '.')
*p = '\0'; /* strip off extension */
if ('A' <= *p && *p <= 'Z')
*p += 'a' - 'A'; /* convert to lower case */
p--;
}
#else
while (p >= s && *p != '/')
p--;
#endif
return (p+1);
}
static char *help_strings[] = {
"usage: %s [OPTIONS ...]\n",
" -v verbose mode",
" -V verbose mode, also list untested functions",
NULL
};
void help()
{
int i;
(void)fprintf(stderr, help_strings[0], pname);
for (i = 1; help_strings[i] != NULL; i++)
(void)fprintf(stderr, "%s\n", help_strings[i]);
}
void list_untested()
{
printf(
"This program does not (yet) test the following WFDB library functions:\n");
printf("osigopen\n");
printf("wfdbinit\n");
printf("getspf\n");
printf("setgvmode\n");
printf("ungetann\n");
printf("isgsettime\n");
printf("iannclose\n");
printf("oannclose\n");
printf("setheader\n");
printf("setmsheader\n");
printf("wfdbgetskew\n");
printf("wfdbsetskew\n");
printf("wfdbgetstart\n");
printf("wfdbsetstart\n");
printf("getcfreq\n");
printf("setcfreq\n");
printf("getbasecount\n");
printf("setbasecount\n");
printf("setbasetime\n");
printf("wfdbquiet\n");
printf("wfdbverbose\n");
printf("setibsize\n");
printf("setobsize\n");
printf("wfdbfile\n");
printf("wfdbflush\n");
printf("setifreq\n");
printf("getifreq\n");
}