/* Useful high-level functions for programs dealing with EBS files. Copyright (C) 1994 M. Prosch, R. Schamburger, A. Grossmann Institut fuer Physiologie und Biokybernetik (IPB), Universitaet Erlangen, Deutschland Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and related publications and that both that copyright notice and this permission notice appear in supporting documentation. The authors make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. Send your comments, suggestions or bug reports to ftpebs@uni-erlangen.de Or mail to Institut fuer Physiologie und Biokybernetik Markus Prosch Universitaetsstrasse 17 D-91054 Erlangen Germany $Id: ebsclass.h,v 1.33 1995/03/06 11:53:03 aeheuer Exp $ */ #ifndef __ebsclass_h #define __ebsclass_h // ebsclass.h extern "C" { #include "ebs.h" #include "ebshead.h" #include #include #include } #ifndef DEBUG #define DEBUG #endif // #define MSDOS class EBSFile { private: char mode; //r=read m=modify w=write char *filename; FILE *fstream; int fd; EBS_FILE *ebsstruct; uint32 nchannels; // Anzahl der Kanaele USampleT nsamples; // Anzahl der Samples pro Kanal USampleT *nsamples_int; // Anzahl der Samples pro Kanal USampleT *nassumed; // Anzahl der anzunehmenden Samples ebs_fixedheader fixed; // Kopie des Fixedheaders unsigned long ebs_type; // z.B. CIB_16, TIB_16, ... int endian; // Littleendian oder Bigendian int data_could_grow; // kann die Datei wachsen (haengt vom Typ ab)? #ifndef MSDOS caddr_t datamap; // wohin die Data gemapped wird #endif USampleT filesize; // Groesse der EBS-Datei unsigned long mdata_offset; // Dataoffset von mmap unsigned long ddata_offset; // Dataoffset auf Platte unsigned long mdata_act; // augenblickliche Position im Datenblock short *getdata; // datamap + mdata_offset; // Zeiger auf eine ValueFunktion short (EBSFile::*ValueType)(uint32, USampleT); short *lastvaluechn; // der vorhergehende Wert fuers kompr. schreiben // Fuer jede Maschine und EBS-Type die richtige ValueFunktion #ifndef MSDOS short ValueT(uint32, USampleT); short ValueTR(uint32, USampleT); short ValueC(uint32, USampleT); short ValueCR(uint32, USampleT); #endif short ValueMSDOS(uint32, USampleT); short ValueNotSupp(uint32, USampleT); void InitChnInfo(uint32); int valid; // 1 = valid / 0 = invalid // this is a very important variable because of gnu c++ // does not yet support throw, this variable should // be aked by the user program if the last critical // operation was valid or the the whole class should not // touched any longer. This is especially important after // using the constructor! // Variablen die zum Schreiben eines Datenblocks benoetigt werden. uint32 writechannels; // Anzahl der Kanaele die geschrieben werden. USampleT writesamples; // Anzahl der Samples pro Kanal beim Schreiben. USampleT *writechnpos; // Zeiger innerhalb eines Kanals int count; // Soll mitgezaehlt werden? USampleT counter; // Falls ja, dann stehen hier die Samples. struct chninfo { USampleT lstartpos; // wenn der Datenblock von Platte USampleT lposnow; // gelesen wird. void *startpos; // wohin muss rewinded werden? void *posnow; // hier stand der letzte Sample USampleT samnow; // wievieltes Sample int16 samval; // Wert des letzten Samples int valid; // bereits initialisiert }; struct chninfo *channelinfo; struct eventlist_info { USampleT discpos; USampleT actpos; USampleT rewindpos; uint32 readpos; uint32 nevents; }; public: int compresseddata; // sind die Daten kompriemiert (TRUE,FALSE)? class NoMem { }; // Ausnahme: kein Speicher class FileError { }; // Ausnahme: Dateifehler class WrongNSamples { }; // Ausnahme: Anzahl der Samples ist falsch class FileTooBig { }; // Ausnahme: 64Bit Dateien sind zu gross enum TimeInfo {no_date_or_time, only_year, only_date, only_time, date_and_time}; enum DescriptionTime {realtime, offset}; struct EBSTm{ int year; /* 1900 - 2100 */ int month; /* 1 - 12 */ int day; /* 1 - 31 */ int hour; /* 0 - 23 */ int minute; /* 0 - 59 */ int second; /* 0 - 59 */ double fraction; /* 0 <= x < 1 */ }; class EBSTime { public: TimeInfo info; private: int utc; /* 0=> YMDHMSF only, else => UTC and YMDHMSF */ time_t time; EBSTm etm; friend class EBSFile; public: EBSTime operator+ (EBSTm); EBSTime operator+ (double); EBSTime operator+ (USampleT); }; enum Sex {sex_unknown = 0, sex_male = 1, sex_female = 2, }; struct ChannelDescription { char *short_description; char *long_description; }; struct ChannelLocation { uint32 channel, picture; int x1, y1, x2, y2; }; struct ChannelLocations { uint32 nlocations; ChannelLocation *location; }; struct PreferredIntegerRange { int16 min; int16 max; }; struct Unit { double quotient; char *unit; int specified; // spezifiziert? }; struct ChannelGroup { char *name; char *description; uint32 nchannels; uint32 *channel; }; struct ChannelGroups { uint32 ngroups; ChannelGroup *group; }; struct ProcessingHistory { uint32 nlines; char **line; }; struct LocationDiagram { void *ptr; uint32 size; }; struct Filter { int type; // low / high / notch double cutoff_freq; double falloff; int falloff_specified; // ist falloff bekannt? }; struct Filters { int nfilters; Filter *filter; }; struct EventList { char *name; char *description; uint32 nevents; }; struct Event { uint32 channel; USampleT position; USampleT length; char *description; }; // abstrakte Basisklasse; Enthaelt Methoden fuer das Lesen und Schreiben von // Event-Listen class DEventList { protected: EventList *evl; // Enthaelt die Listen-Info int valid; // !=0, falls Fehler auftauchte void init(void); // Initialisierungs-Methode, zum Aufruf aus den Konstruktoren void CopyEvent(Event *dest, const Event *src); // Kopiert den Inhalt von src nach dest public: // Konstruktoren DEventList(void); // name und description sind die der Event-Liste DEventList(char const *name, char const *description); // gibt den Naechsten Event zurueck und erhoeht den Listen-Zeiger // der zurueckgegebene Wert bleibt nur bis zum Naechsten Aufruf erhalten virtual const Event *GetEvent(void); // gibt den Naechsten Event zurueck, ohne den Listen-Zeiger zu erhoehen // der zurueckgegebene Wert bleibt nur bis zum Naechsten Aufruf erhalten virtual const Event *LookEvent(void) = 0; // erhoeht den Listen-Zeiger Rueckgabe 0: ok ansonsten Listenende virtual int SkipEvent(void) = 0; // setzt die Leseposition innerhalb der Liste auf den Anfang zurueck virtual void Rewind(void) = 0; // schreibt die Liste in das angegebene Objekt int Put(EBSFile *ebsf); // schreibt die Liste in eine neue Datei, // bzw. modifiziert eine bestehende durch Hinzufuegen int Put(char *filename); // liefert den Namen der Liste char const *GetName(void) { return evl->name; }; // liefert die Beschreibung der Liste char const *GetDescription(void) { return evl->description; }; // liefert die Anzahl der Events in der Liste int GetNEvents(void) { return evl->nevents; }; // gibt an, ob die letzte Operation erfolgreich beendet wurde int Valid(void) { return valid; }; // liefert wert != 0, falls Liste leer ist int IsEmpty(void) { return (evl->nevents == 0); }; virtual ~DEventList(void); }; // Klasse zum Lesen einer Liste aus einem EBSFile-Objekt class EBSEventList : public DEventList { private: EBSFile *ebsf; // enthaelt das EBSFile-Objekt int32 listnr; // Listen-Nummer uint32 offset; // Offset, der auf die Position aufaddiert wird uint32 readpos; // aktuelle Leseposition int32 length; // gemeinsame Laenge der Events; -1: alle aus Original uebernehmen int32 begin; // Nr. des Events, ab dem gelesen werden soll int32 end; // Nr. des Events, bis zu dem gelesen werden soll; -1: bis Ende USampleT actpos; // Dateiposition des aktuellen Events USampleT nextpos; // Dateiposition des naechsten Events USampleT rewindpos; // Dateiposition des ersten Events USampleT GetFirstPos(void); //ermittelt die Dateiposition des ersten Events public: // Konstruktor EBSEventList(EBSFile *mebsf, uint32 mlistnr, uint32 moffset = 0, int32 mlength = -1, uint32 mbegin = 0, int32 mend = -1); virtual const Event *LookEvent(void); virtual int SkipEvent(void); virtual void Rewind(void); }; // Klasse zum Schreiben einer Liste class OutEventList : public DEventList { private: // Struktur zum Aufbau der verketteten Liste typedef struct EvListEl { Event *ev; EvListEl *next; } EvListEl; EvListEl *first; // markiert den Anfang der verketteten Liste EvListEl *current; // das aktuelle Element EvListEl *last; // das letzte Element public: // Konstruktor; name und description sind die der Event-Liste OutEventList(char const *name, char const *description); // Hinzufuegen eines einzelnen Events // Rueckgabewert != 0: Chronologie wurde nicht eingehalten; Operation abgebrochen int Append(Event const *ev); // Hinzufuegen einer ganzen Event-Liste // Rueckgabewert != 0: Chronologie wurde nicht eingehalten; Operation abgebrochen int Append(DEventList *evlist); virtual const Event *LookEvent(void); virtual int SkipEvent(void); virtual void Rewind(void); // Loeschen der Events void Clear(void); virtual ~OutEventList(void); }; char *emptystring; // falls Attribut nicht vorhanden ist private: int usedefaults; char *patientname; // Name des Patienten EBSTime *dateofbirth; // Geburtstag des Patienten Sex sexofpatient; // Geschlecht des Patienten char *patientid; // Patienten ID char *institution; // Name des Instituts des Aufnahme EBSTime *rectimebuf; // Recordingtime: Datum und Zeit char *shortdesc; // Kurzbeschreibung char *description; // Ausfuehrliche Beschreibung ChannelGroups *chngroups; // Channel Groups ChannelLocations *chlocations; // Channellocations ProcessingHistory *prochistory; // Processing history double *samplerate; // Samplerate PreferredIntegerRange *prefrange; // Pointer auf prefered integer range ChannelDescription *chdescriptions; // Channeldescriptios Unit *units; // Units Filters *filters; // Filter double *yscale; // Umrechnung auf phys. Einheit eventlist_info *eventlist_int; // wo befindet sich die Gruppe auf Disk? EventList *eventlist; // Daten zu den Eventlists uint32 neventlists; // Wieviele Eventlists gibt es Event event; // hier wird ein Event abgelegt; DescriptionTime description_type; TimeInfo description_info; int description_fractions; // wandelt ein Zeitattribute nach EBSTime void buf2ebs_time_t(void const *, unsigned long, EBSTime *); //Wandelt EBSTime in ein Zeitargument um void *ebs_time_t2buf(void *buf, unsigned long length, EBSTime const *ebs_time); // bestimmt die Anzahl der Samples, auch wenn nicht in Datei gegeben USampleT determinesamples(void); int mapdatablock(void); // mapped den Datenblock void InitWriteChn(void); // Positionen fuer die einzelnen Kanaele init. void GetEventInfo(void); void BeforePutAttr (void); protected: void SetInvalid(void); public: EBSFile(char const *, char m = 'r', int defaults= 0); ~EBSFile(void); // Ist bei der letzten EBSclass Operation etwas passiert, was ein // Weiterarbeiten nicht mehr moeglich macht, so kann man mit // Valid() abfragen, ob die Klasse noch gueltig ist. // valid = 1 / invalid = 0; int Valid (void); // Filename char const *GetFilenameWithPath (void); char const *GetOnlyFilename (void); // Name des Patienten char const *GetPatientName(void); int SetPatientName(char const *); // Geburtstag des Patienten EBSTime GetPatientBirthday(void); int SetPatientBirthday(EBSTime); // Geschlecht des Patienten: 1 male / 2 female / 0 unknown Sex GetPatientSex(void); int SetPatientSex(Sex); // ID des Patienten char const *GetPatientID(void); int SetPatientID(char const *); // In welchen Institut wurde die Aufnahme erstellt? char const *GetInstitution(void); int SetInstitution(char const *); // Aufnahmezeit EBSTime GetRecordingTime(void); int SetRecordingTime(EBSTime); // Kurzbeschreibung char const *GetShortDescription(void); int SetShortDescription(char const *); // Beschreibung zu der Aufnahme char const *GetDescription(void); int SetDescription(char const *); // Kanalgruppen ChannelGroups const *GetChannelGroups(void); int SetChannelGroups(ChannelGroups const *); // Liefert die Position zurueck und setzt die Groesse LocationDiagram const *GetLocationDiagram(void); int SetLocationDiagram(LocationDiagram const *); // Positionen der Elektroden ChannelLocations const *GetChannelLocations(void); int SetChannelLocations(ChannelLocations const *); // Was wurde mit dieser Aufnahme schon alles angestellt? ProcessingHistory const *GetProcessingHistory(void); int SetProcessingHistory(ProcessingHistory const *); // Abtastraten der Kanaele double const *GetSampleRate(void); int SetSampleRate(double const *); double GetMaxSampleRate(void); double GetMinSampleRate(void); // Prefered Integer Range aller Kanaele PreferredIntegerRange const *GetPreferredIntegerRange(void); int SetPreferredIntegerRange (PreferredIntegerRange const *); // Kanalbeschreibung aller Kanaele ChannelDescription const *GetChannelDescription(void); int SetChannelDescription (ChannelDescription const *); // Units aller Kanaele Unit const *GetUnits (void); int SetUnits (Unit const *); // Filter aller Kanaele Filters const *GetFilters (void); int SetFilters(Filters const *); // Anzahl der Kanaele uint32 GetNChannels(void); // Anzahl der Samples aller Kanaele USampleT const *GetNSamples(void); USampleT GetMaxSamples(void); // End of the recording EBSTime GetRecordingEnd(void); char const *GetRecordingLength(void); // Anzunehmende Anzahl der Samples USampleT const *EBSFile::GetAssumedNSamples(void); int SetAssumedNSamples(USampleT const *assumed); // Assumed end of the recording EBSTime GetAssumedRecordingEnd(void); char const *GetAssumedRecordingLength(void); // EBS Zeit in eine Zeichenkette wandeln // Liefert Pointer auf Zeichenkette zurueck und // uebernimmt ebs-Zeit, Puffer, Puffergroesse char const *EBSTimeToString(EBSTime const *, char* ptr=NULL, unsigned long l=0); char const *EBSTimeToString2(EBSTime const *ebs_time, TimeInfo info, int fractions, char *buf=NULL, unsigned long buflen=0); char const *EBSTimeToString(EBSTime ebs_time, char* ptr=NULL, unsigned long l=0); char const *EBSTimeToString2(EBSTime ebs_time, TimeInfo info, int fractions, char *buf=NULL, unsigned long buflen=0); EBSTime EBSTimeAtSampleNo(uint32 channel, USampleT sampleno); char const *TimeAtSampleNo(uint32 channel, USampleT sampleno, TimeInfo info, int fractions, char *buf=NULL, unsigned long buflen=0); char const *OffsetAtSampleNo (uint32 channel, USampleT sampleno, int fractions, char *buf=NULL, unsigned long buflen=0); void SetDescriptionAtSampleNo (DescriptionTime type, int fractions, TimeInfo info); char const *DescriptionAtSampleNo (uint32 channel, USampleT sampleno); // EBS Zeit in EBSTm Struktur wandeln; EBSTm EBSTimeToTm(EBSTime ebs_time); // EBSTm Struktur in EBSTime wandeln EBSTime EBSTmToTime(EBSTm etm, TimeInfo info); // Liefert den Wert an der Position (Kanal, Sample) short Value(uint32 channel, USampleT sample) { // somit ist dies inline #ifdef DEBUG if((channel > nchannels) || (sample > nsamples)) { fprintf(stderr, "Value(): invalid arguments, out of range.\n"); fprintf(stderr, " maxchannel %d ; maxsample %ld\n", nchannels, (long) nsamples); fprintf(stderr, " c %d ; s %ld\n", channel, (long) sample); exit(1); } #endif channelinfo[channel].samnow = sample+1; return (this->*ValueType)(channel, sample); } // Liefert den Wert an der Position (Kanal, Sample) in der pysikalischen // Einheit double PhysicalValue(uint32 channel, USampleT sample); private: /* // Naechster Wert eines Kanals short NextValue(unsigned long); // Spule Kanal zurueck void RewindValue(unsigned long); */ public: // Hole die Anzahl der Eventlisten uint32 GetNEventLists(void); // Liefert die Informationen zu einer Eventliste EventList const *GetEventList(uint32); // Gehe an den Anfang einer Eventliste bzw. zum x-ten Event. // (group, event) int RewindEventList(uint32, uint32 = 0); // Naechsten Event einer Liste auslesen. Event const *GetNextEvent(uint32); // EBS-Typ, Anzahl der Kanaele, Anzahl der Samples (opt. beachte Format) // Sollte ein Fehler auftreten, oder aber nicht zulaessige Paramter // uebergeben worden sein (z.B. keine Samples angegeben und CIB Format), // so wird eine -1 zurueckgeliefert. War alles in Ordnung so wird // eine 0 zurueckgeliefert. int InitDataPart(uint32, uint32, USampleT= ~0); // Teilt der EBS-Klasse mit, dass keine weiteren Daten geschrieben werden. // Dabei ist zu beachten, dass als letztes auch der letzte Wert geschrieben // worden wurde. Bei CIB und TIB ist dies der letzte Wert des letzten // Kanals. Ist mit SetDatum(chn, samp) gearbeitet worden, so ist im // Besonderen darauf zu achten, dass als letztes der letzte Wert des // letzten Kanals geschrieben worden ist. int EndOfWritingData(void); // setze Anzahl der Kanaele fuer eine neue EBS Datei int SetNChannels(uint32); // Schreibt den naechsten Wert x auf Kanal i. // i, x int SetNextDatumOnChn(uint32, int16); // Traegt in Kanal i das k Sample mit Wert x ein. // i, k, x int SetDatum(uint32, USampleT, int16); // Hier werden nacheinander alle Samples, je nach Format CIB oder TIB die // Reihenfolge beachten, ueber alle Kanaele geschrieben. int SetNextDatum(short); // Erzeugt erste Eventlist int SetEventlist(char* name, char* description, uint32 nevents, Event* events); // haengt weitere Eventlisten an int AppEventlist(char* name, char* description, uint32 nevents, Event* events); // *** don't use functions under that line! *** }; #endif