int configure_channels(struct xdf* xdf, unsigned int neeg, unsigned int nsens) { unsigned int i; struct xdfch* ch = NULL; /* Set the default settings of the next channels. There is no need to setup the stored data type (XDF_CF_STOTYPE) neither the digital min or max since BDF supports only int24 data type and those settings are thus set by default */ xdf_set_conf(xdf, XDF_CF_ARRTYPE, XDFFLOAT, XDF_CF_ARRINDEX, 0, XDF_CF_ARROFFSET, 0,/* starting offset (will be automatically incremented after a channel is added) */ XDF_CF_TRANSDUCTER, "Active Electrode", XDF_CF_PREFILTERING, "HP: DC; LP: 100 Hz", XDF_CF_PMIN, -2.0, XDF_CF_PMAX, 2.0, XDF_CF_UNIT, "uV", XDF_CF_RESERVED, "EEG", XDF_NOF); /* Add EEG channels */ for (i = 0; i < neeg; i++) if (xdf_add_channel(xdf, eeglabels[i]) == NULL) return -1;; /* Setup and add sensor channels */ xdf_set_conf(xdf, XDF_CF_ARRTYPE, XDFDOUBLE, XDF_CF_ARRINDEX, 1, XDF_CF_ARROFFSET, 0, XDF_NOF); for (i = 0; i < nsens; i++) if (xdf_add_channel(xdf, senslabels[i]) == NULL) return -1; /* Add and setup trigger channel (show another way to setup a channel) */ ch = xdf_add_channel(xdf, "Status"); if (ch == NULL) return -1; xdf_set_chconf(ch, XDF_CF_ARRTYPE, XDFINT32, XDF_CF_ARRINDEX, 2, XDF_CF_ARROFFSET, 0, XDF_CF_TRANSDUCTER, "Triggers and Status", XDF_CF_PREFILTERING, "No filtering", XDF_CF_PMIN, -8388608.0, XDF_CF_PMAX, 8388607.0, XDF_CF_UNIT, "Boolean", XDF_CF_RESERVED, "TRI", XDF_NOF); return 0; }
int main(int argc, char *argv[]) { (void) argc; (void) argv; struct xdf *xdf = NULL; int step, retval = EXIT_FAILURE; unsigned int ns, i; size_t strides[NARRAYS] = { NEEG*sizeof(eeg[0]), NSENS*sizeof(sens[0]), sizeof(trigger[0]) }; /************************************************* * File preparation * *************************************************/ step = 0; xdf = xdf_open(filename, XDF_WRITE, XDF_BDF); if (xdf == NULL) goto exit; xdf_set_conf(xdf, XDF_F_SAMPLING_FREQ, FS, XDF_NOF); step++; if (configure_channels(xdf, NEEG, NSENS)) goto exit; step++; if (xdf_define_arrays(xdf, NARRAYS, strides) || xdf_prepare_transfer(xdf) ) goto exit; /************************************************ * Writing loop * *************************************************/ step++; for (i=0; i<TOTAL_NS; i+=NS) { ns = ((TOTAL_NS - i) >= NS) ? NS : (TOTAL_NS - i); generate_signal(NEEG, eeg, NSENS, sens, trigger, FS, ns); if (xdf_write(xdf, ns, eeg, sens, trigger) < 0) goto exit; } retval = EXIT_SUCCESS; exit: if (retval != EXIT_SUCCESS) { fprintf(stderr, "Error while %s : (%i) %s\n", stepmsg[step], errno, strerror(errno)); } xdf_close(xdf); return retval; }
static int set_default_trigger(struct xdf* xdf, int arrindex, enum xdftype arrtype, double pmin, double pmax) { return xdf_set_conf(xdf, XDF_CF_ARRTYPE, arrtype, XDF_CF_ARRINDEX, arrindex, XDF_CF_ARROFFSET, 0, XDF_CF_TRANSDUCTER, "Triggers and Status", XDF_CF_PREFILTERING, "No filtering", XDF_CF_STOTYPE, XDFINT32, XDF_CF_PMIN, pmin, XDF_CF_PMAX, pmax, XDF_CF_UNIT, "Boolean", XDF_CF_RESERVED, "TRI", XDF_NOF); }
static int set_default_analog(struct xdf* xdf, int arrindex, enum xdftype arrtype) { return xdf_set_conf(xdf, XDF_CF_ARRTYPE, arrtype, XDF_CF_ARRINDEX, arrindex, XDF_CF_ARROFFSET, 0, XDF_CF_TRANSDUCTER, "Active Electrode", XDF_CF_PREFILTERING, "HP: DC; LP: 417 Hz", XDF_CF_DMIN, -262144.0, XDF_CF_DMAX, 262143.0, XDF_CF_PMIN, -262144.0, XDF_CF_PMAX, 262143.0, XDF_CF_UNIT, "uV", XDF_CF_RESERVED, "EEG", XDF_NOF); }
int acq_prepare_rec(struct acq* acq, const char* filename) { struct xdf* xdf; int j, fs; if (!acq || !filename) return 0; // Create the BDF file xdf = xdf_open(filename, XDF_WRITE, XDF_BDF); if (!xdf) goto abort; // Configuration file general header fs = egd_get_cap(acq->dev, EGD_CAP_FS, NULL); xdf_set_conf(xdf, XDF_F_REC_DURATION, 1.0, XDF_F_REC_NSAMPLE, fs, XDF_NOF); // Set up the file recording channels for (j=0; j<3; j++) if (setup_xdf_channel_group(acq, j, xdf)) goto abort; // Make the file ready for recording xdf_define_arrays(xdf, 3, acq->strides); if (xdf_prepare_transfer(xdf)) goto abort; acq->xdf = xdf; return 0; abort: fprintf(stderr, "Preparing recording file: %s\n", strerror(errno)); xdf_close(xdf); return -1; }
static int setup_xdf_channel_group(struct acq* acq, int igrp, struct xdf* xdf) { char label[32], transducter[128], unit[16], filtering[128]; double mm[2]; unsigned int j; struct grpconf* grp = acq->grp + igrp; egd_channel_info(acq->dev, grp->sensortype, grp->index, EGD_UNIT, unit, EGD_TRANSDUCTER, transducter, EGD_PREFILTERING, filtering, EGD_MM_D, mm, EGD_EOL); xdf_set_conf(xdf, XDF_CF_ARRINDEX, grp->iarray, XDF_CF_ARROFFSET, grp->arr_offset, XDF_CF_ARRDIGITAL, 0, XDF_CF_ARRTYPE, egd_to_xdf[grp->datatype], XDF_CF_PMIN, mm[0], XDF_CF_PMAX, mm[1], XDF_CF_TRANSDUCTER, transducter, XDF_CF_PREFILTERING, filtering, XDF_CF_UNIT, unit, XDF_NOF); for (j = 0; j < grp->nch; j++) { egd_channel_info(acq->dev, grp->sensortype, j, EGD_LABEL, label, EGD_EOL); // Add the channel to the BDF if (xdf_add_channel(xdf, label) == NULL) return -1; } return 0; }
int generate_xdffile(const char* filename) { eeg_t* eegdata; sens_t* exgdata; tri1_t* tri1data; tri2_t* tri2data; int retcode = -1; struct xdf* xdf = NULL; int i,j, evttype1, evttype2; char tmpstr[16]; size_t strides[4] = { NEEG*sizeof(*eegdata), NEXG*sizeof(*exgdata), NTRI*sizeof(*tri1data), NTRI*sizeof(*tri2data), }; // Allocate the temporary buffers for samples eegdata = malloc(NEEG*NSAMPLE*sizeof(*eegdata)); exgdata = malloc(NEXG*NSAMPLE*sizeof(*exgdata)); tri1data = malloc(NTRI*NSAMPLE*sizeof(*tri1data)); tri2data = malloc(NTRI*NSAMPLE*sizeof(*tri2data)); if (!eegdata || !exgdata || !tri1data || !tri2data) goto exit; xdf = xdf_open(filename, XDF_WRITE, XDF_GDF1); if (!xdf) goto exit; xdf_set_conf(xdf, XDF_F_SAMPLING_FREQ, (int)SAMPLINGRATE, XDF_F_SESS_DESC, sess_str, XDF_F_SUBJ_DESC, subj_str, XDF_NOF); // Specify the structure (channels and sampling rate) if (set_default_analog(xdf, 0, EEG_TYPE)) goto exit; for (j=0; j<NEEG; j++) { sprintf(tmpstr, "EEG%i", j); if (!xdf_add_channel(xdf, tmpstr)) goto exit; } if (set_default_analog(xdf, 1, SENS_TYPE)) goto exit; for (j=0; j<NEXG; j++) { sprintf(tmpstr, "EXG%i", j); if (!xdf_add_channel(xdf, tmpstr)) goto exit; } if (set_default_trigger(xdf, 2, TRI1_TYPE, TRI1_MIN, TRI1_MAX)) goto exit; for (j=0; j<NTRI; j++) { sprintf(tmpstr, "TRI1%i", j); if (!xdf_add_channel(xdf, tmpstr)) goto exit; } if (set_default_trigger(xdf, 3, TRI2_TYPE, TRI2_MIN, TRI2_MAX)) goto exit; for (j=0; j<NTRI; j++) { sprintf(tmpstr, "TRI2%i", j); if (!xdf_add_channel(xdf, tmpstr)) goto exit; } // Add events code evttype1 = xdf_add_evttype(xdf, 0x101, NULL); evttype2 = xdf_add_evttype(xdf, 0x204, NULL); if (evttype1 < 0 || evttype2 < 0) goto exit; // Make the the file ready for accepting samples xdf_define_arrays(xdf, 4, strides); if (xdf_prepare_transfer(xdf) < 0) goto exit; // Feed with samples for (i=0; i<NITERATION; i++) { // Set data signals and unscaled them set_signal_values(eegdata, exgdata, tri1data, tri2data); if (xdf_write(xdf, NSAMPLE, eegdata, exgdata, tri1data, tri2data) < 0) goto exit; if (xdf_add_event(xdf, evttype1, NSAMPLE*i/(double)SAMPLINGRATE, -1) || xdf_add_event(xdf, evttype2, (NSAMPLE*(i+1)-1)/(double)SAMPLINGRATE, -1)) goto exit; } retcode = 0; exit: // if phase is non zero, a problem occured if (retcode) fprintf(stderr, "\terror: %s\n", strerror(errno)); // Clean the structures and ressources xdf_close(xdf); free(eegdata); free(exgdata); free(tri1data); free(tri2data); return retcode; }