/*
*****************************************************************************
*
* Copyright (c) 2009 - 2022 Teunis van Beelen
* All rights reserved.
*
* Email: teuniz@protonmail.com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the copyright holder nor the names of its
*       contributors may be used to endorse or promote products derived from
*       this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************
*/

/****************************************************************************
 *
 * For more info about the EDF and EDF+ format, visit: http://edfplus.info/specs/
 *
 * For more info about the BDF and BDF+ format, visit: http://www.teuniz.net/edfbrowser/bdfplus%20format%20description.html
 *
 * note: In EDF, the resolution (or sensitivity) (e.g. uV/bit) and offset are stored using four parameters:
 * digital maximum and minimum, and physical maximum and minimum.
 * Here, digital means the raw data coming from a sensor or ADC. Physical means the units like uV.
 * The resolution in units per least significant bit is calculated as follows:
 *
 * units per bit = (physical max - physical min) / (digital max - digital min)
 *
 * The digital offset is calculated as follows:
 *
 * offset = (physical max / units per bit) - digital max
 *
 * For a better explanation about the relation between digital data and physical data,
 * read the document "Coding Schemes Used with Data Converters" (PDF):
 *
 * https://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=sbaa042
 *
 * note: An EDF file usually contains multiple so-called datarecords. One datarecord usually has a duration of one second (this is the default but it is not mandatory!).
 * In that case a file with a duration of five minutes contains 300 datarecords. The duration of a datarecord can be freely choosen but, if possible, use values from
 * 0.1 to 1 second for easier handling. Just make sure that the total size of one datarecord, expressed in bytes, does not exceed 10MByte (15MBytes for BDF(+)).
 *
 * The RECOMMENDATION of a maximum datarecordsize of 61440 bytes in the EDF and EDF+ specification was usefull in the time people were still using DOS as their main operating system.
 * Using DOS and fast (near) pointers (16-bit pointers), the maximum allocatable block of memory was 64KByte.
 * This is not a concern anymore so the maximum datarecord size now is limited to 10MByte for EDF(+) and 15MByte for BDF(+). This helps to accommodate for higher samplingrates
 * used by modern Analog to Digital Converters.
 *
 * EDF header character encoding: The EDF specification says that only (printable) ASCII characters are allowed.
 * When writing the header info, EDFlib will assume you are using Latin1 encoding and it will automatically convert
 * characters with accents, umlauts, tilde, etc. to their "normal" equivalent without the accent/umlaut/tilde/etc.
 * in order to create a valid EDF file.
 * The description of an EDF+ annotation on the other hand, is always encoded in UTF-8 (which is foreward compatible with ASCII).
 *
 * The samplefrequency of a signal is calculated as follows: sf = (smp_in_datarecord * EDFLIB_TIME_DIMENSION) / datarecord_duration
 *
 * Annotation signals
 * ==================
 *
 * EDF+ and BDF+ store the annotations in one or more signals (in order to be backwards compatibel with EDF and BDF).
 * The numbering of the signals in the file is zero based (starts at 0). Signals used for annotations are skipped by EDFlib.
 * This means that the annotationsignal(s) in the file are hided.
 * Use the function edf_get_annotation() to get the annotations.
 *
 * So, when a file contains 5 signals and the third signal is an annotations signal, the library will
 * report that there are only 4 signals in the file.
 * The library will "map" the signal numbers as follows: 0->0, 1->1, 2->3, 3->4.
 * This way you don't need to worry about which signals are annotationsignals, the library will take care of it.
 *
 * How the library stores time values
 * ==================================
 *
 * To avoid rounding errors, the library stores some timevalues in variables of type long long int.
 * In order not to lose the subsecond precision, all timevalues are scaled with a scaling factor: 10000000.
 * This will limit the timeresolution to 100 nanoSeconds. To calculate the amount of seconds, divide
 * the timevalue by 10000000 or use the macro EDFLIB_TIME_DIMENSION which is declared in edflib.h.
 * The following variables use this scaling when you open a file in read mode: "file_duration", "starttime_subsecond" and "onset".
 *
 * EDFlib and thread-safety
 * ========================
 * The following functions are always MT-unsafe:
 * edfopen_file_readonly()   (race condition)
 * edfclose_file()           (race condition)
 * edflib_get_handle()       (race condition)
 *
 * When writing to or reading from the same file, all EDFlib functions are MT-unsafe (race condition).
 *
 */


/* compile with options "-D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE" */

#ifndef EDFLIB_INCLUDED
#define EDFLIB_INCLUDED

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define EDFLIB_TIME_DIMENSION     (10000000LL)
#define EDFLIB_MAXSIGNALS                (640)
#define EDFLIB_MAX_ANNOTATION_LEN        (512)

#define EDFSEEK_SET  (0)
#define EDFSEEK_CUR  (1)
#define EDFSEEK_END  (2)

/* the following defines are used in the member "filetype" of the edf_hdr_struct
   and as return value for the function edfopen_file_readonly() */
#define EDFLIB_FILETYPE_EDF                  (0)
#define EDFLIB_FILETYPE_EDFPLUS              (1)
#define EDFLIB_FILETYPE_BDF                  (2)
#define EDFLIB_FILETYPE_BDFPLUS              (3)
#define EDFLIB_MALLOC_ERROR                 (-1)
#define EDFLIB_NO_SUCH_FILE_OR_DIRECTORY    (-2)

/* when this error occurs, try to open the file with EDFbrowser,
   it will give you full details about the cause of the error. */
#define EDFLIB_FILE_CONTAINS_FORMAT_ERRORS  (-3)

#define EDFLIB_MAXFILES_REACHED             (-4)
#define EDFLIB_FILE_READ_ERROR              (-5)
#define EDFLIB_FILE_ALREADY_OPENED          (-6)
#define EDFLIB_FILETYPE_ERROR               (-7)
#define EDFLIB_FILE_WRITE_ERROR             (-8)
#define EDFLIB_NUMBER_OF_SIGNALS_INVALID    (-9)
#define EDFLIB_FILE_IS_DISCONTINUOUS       (-10)
#define EDFLIB_INVALID_READ_ANNOTS_VALUE   (-11)
#define EDFLIB_ARCH_ERROR                  (-12)

/* values for annotations */
#define EDFLIB_DO_NOT_READ_ANNOTATIONS  (0)
#define EDFLIB_READ_ANNOTATIONS         (1)
#define EDFLIB_READ_ALL_ANNOTATIONS     (2)

/* the following defines are possible errors returned by the first sample write action */
#define EDFLIB_NO_SIGNALS                  (-20)
#define EDFLIB_TOO_MANY_SIGNALS            (-21)
#define EDFLIB_NO_SAMPLES_IN_RECORD        (-22)
#define EDFLIB_DIGMIN_IS_DIGMAX            (-23)
#define EDFLIB_DIGMAX_LOWER_THAN_DIGMIN    (-24)
#define EDFLIB_PHYSMIN_IS_PHYSMAX          (-25)
#define EDFLIB_DATARECORD_SIZE_TOO_BIG     (-26)

#ifdef __cplusplus
extern "C" {
#endif

struct edf_param_struct{         /* this structure contains all the relevant EDF-signal parameters of one signal */
  char   label[17];              /* label (name) of the signal, null-terminated string */
  long long smp_in_file;         /* number of samples of this signal in the file */
  double phys_max;               /* physical maximum, usually the maximum input of the ADC */
  double phys_min;               /* physical minimum, usually the minimum input of the ADC */
  int    dig_max;                /* digital maximum, usually the maximum output of the ADC, cannot not be higher than 32767 for EDF or 8388607 for BDF */
  int    dig_min;                /* digital minimum, usually the minimum output of the ADC, cannot not be lower than -32768 for EDF or -8388608 for BDF */
  int    smp_in_datarecord;      /* number of samples of this signal in a datarecord, if the datarecord has a duration of one second (default), then it equals the samplerate */
  char   physdimension[9];       /* physical dimension (uV, bpm, mA, etc.), null-terminated string */
  char   prefilter[81];          /* null-terminated string */
  char   transducer[81];         /* null-terminated string */
      };

struct edf_annotation_struct{                           /* this structure is used for annotations */
        long long onset;                                /* onset time of the event, expressed in units of 100 nanoSeconds and relative to the start of the file */
        long long duration_l;                           /* duration time, expressed in units of 100 nanoSeconds, a value of -10000000 means unused (duration not present) */
        char duration[16];                              /* duration time, this is a null-terminated ASCII text-string */
        char annotation[EDFLIB_MAX_ANNOTATION_LEN + 1]; /* description of the event in UTF-8, this is a null terminated string */
       };

struct edf_hdr_struct{            /* this structure contains all the relevant EDF header info and will be filled when calling the function edf_open_file_readonly() */
  int       handle;               /* a handle (identifier) used to distinguish the different files */
  int       filetype;             /* 0: EDF, 1: EDF+, 2: BDF, 3: BDF+, a negative number means an error */
  int       edfsignals;           /* number of EDF signals in the file, annotation channels are NOT included */
  long long file_duration;        /* duration of the file expressed in units of 100 nanoSeconds */
  int       startdate_day;
  int       startdate_month;
  int       startdate_year;
  long long starttime_subsecond;  /* starttime offset expressed in units of 100 nanoSeconds. Is always less than 10000000 (one second). Only used by EDF+ and BDF+ */
  int       starttime_second;
  int       starttime_minute;
  int       starttime_hour;
  char      patient[81];                                  /* null-terminated string, contains patientfield of header, is always empty when filetype is EDFPLUS or BDFPLUS */
  char      recording[81];                                /* null-terminated string, contains recordingfield of header, is always empty when filetype is EDFPLUS or BDFPLUS */
  char      patientcode[81];                              /* null-terminated string, is always empty when filetype is EDF or BDF */
  char      gender[16];                                   /* null-terminated string, is always empty when filetype is EDF or BDF */
  char      birthdate[16];                                /* null-terminated string, is always empty when filetype is EDF or BDF */
  int       birthdate_day;                                /* 1 - 31 */
  int       birthdate_month;                              /* 1 - 12 */
  int       birthdate_year;
  char      patient_name[81];                             /* null-terminated string, is always empty when filetype is EDF or BDF */
  char      patient_additional[81];                       /* null-terminated string, is always empty when filetype is EDF or BDF */
  char      admincode[81];                                /* null-terminated string, is always empty when filetype is EDF or BDF */
  char      technician[81];                               /* null-terminated string, is always empty when filetype is EDF or BDF */
  char      equipment[81];                                /* null-terminated string, is always empty when filetype is EDF or BDF */
  char      recording_additional[81];                     /* null-terminated string, is always empty when filetype is EDF or BDF */
  long long datarecord_duration;                          /* duration of a datarecord expressed in units of 100 nanoSeconds */
  long long datarecords_in_file;                          /* number of datarecords in the file */
  long long annotations_in_file;                          /* number of annotations in the file */
  struct edf_param_struct signalparam[EDFLIB_MAXSIGNALS]; /* array of structs which contain the relevant signal parameters */
       };

/*****************  the following functions are used to read files **************************/

int edfopen_file_readonly(const char *path, struct edf_hdr_struct *edfhdr, int read_annotations);
/* opens an existing file for reading
 * path is a null-terminated string containing the path to the file
 * hdr is a pointer to an edf_hdr_struct, all fields in this struct will be overwritten
 * the edf_hdr_struct will be filled with all the relevant header- and signalinfo/parameters

 * read_annotations must have one of the following values:
 *   EDFLIB_DO_NOT_READ_ANNOTATIONS      annotations will not be read (this saves time when opening a very large EDF+ or BDF+ file
 *   EDFLIB_READ_ANNOTATIONS             annotations will be read immediately, stops when an annotation has
 *                                       been found which contains the description "Recording ends"
 *   EDFLIB_READ_ALL_ANNOTATIONS         all annotations will be read immediately

 * returns 0 on success, in case of an error it returns -1 and an errorcode will be set in the member "filetype" of struct edf_hdr_struct
 * This function is required if you want to read a file
 */

int edfread_physical_samples(int handle, int edfsignal, int n, double *buf);
/* reads n samples from edfsignal, starting from the current sample position indicator, into buf (edfsignal starts at 0)
 * the values are converted to their physical values e.g. microVolts, beats per minute, etc.
 * bufsize should be equal to or bigger than sizeof(double[n])
 * the sample position indicator will be increased with the amount of samples read
 * returns the amount of samples read (this can be less than n or zero!)
 * or -1 in case of an error
 */

int edfread_digital_samples(int handle, int edfsignal, int n, int *buf);
/* reads n samples from edfsignal, starting from the current sample position indicator, into buf (edfsignal starts at 0)
 * the values are the "raw" digital values
 * bufsize should be equal to or bigger than sizeof(int[n])
 * the sample position indicator will be increased with the amount of samples read
 * returns the amount of samples read (this can be less than n or zero!)
 * or -1 in case of an error
 */

long long edfseek(int handle, int edfsignal, long long offset, int whence);
/* The edfseek() function sets the sample position indicator for the edfsignal pointed to by edfsignal.
 * The new position, measured in samples, is obtained by adding offset samples to the position specified by whence.
 * If whence is set to EDFSEEK_SET, EDFSEEK_CUR, or EDFSEEK_END, the offset is relative to the start of the file,
 * the current position indicator, or end-of-file, respectively.
 * Returns the current offset. Otherwise, -1 is returned.
 * note that every signal has it's own independent sample position indicator and edfseek() affects only one of them
 */

long long edftell(int handle, int edfsignal);
/* The edftell() function obtains the current value of the sample position indicator for the edfsignal pointed to by edfsignal.
 * Returns the current offset. Otherwise, -1 is returned
 * note that every signal has it's own independent sample position indicator and edftell() affects only one of them
 */

void edfrewind(int handle, int edfsignal);
/* The edfrewind() function sets the sample position indicator for the edfsignal pointed to by edfsignal to the beginning of the file.
 * It is equivalent to: (void) edfseek(int handle, int edfsignal, 0LL, EDFSEEK_SET)
 * note that every signal has it's own independent sample position indicator and edfrewind() affects only one of them
 */

int edf_get_annotation(int handle, int n, struct edf_annotation_struct *annot);
/* Fills the edf_annotation_struct with the annotation n, returns 0 on success, otherwise -1
 * The string that describes the annotation/event is encoded in UTF-8
 * To obtain the number of annotations in a file, check edf_hdr_struct -> annotations_in_file.
 * returns 0 on success or -1 in case of an error
 */

/*****************  the following functions are used in read and write mode **************************/

int edfclose_file(int handle);
/* closes (and in case of writing, finalizes) the file
 * returns -1 in case of an error, 0 on success
 * this function MUST be called when you are finished reading or writing
 * This function is required after reading or writing. Failing to do so will cause
 * unnessecary memory usage and in case of writing it will cause a corrupted and incomplete file
 */

int edflib_version(void);
/* Returns the version number of this library, multiplied by hundred. if version is "1.00" than it will return 100
 */

int edflib_is_file_used(const char *path);
/* returns 1 if the file is used, either for reading or writing, otherwise returns 0
 */

int edflib_get_number_of_open_files(void);
/* returns the number of open files, either for reading or writing
 */

int edflib_get_handle(int file_number);
/* returns the handle of an opened file, either for reading or writing
 * file_number is zero based (starts with 0)
 * returns -1 if the file is not opened
 */

/*****************  the following functions are used to write files **************************/

int edfopen_file_writeonly(const char *path, int filetype, int number_of_signals);
/* opens an new file for writing. warning, an already existing file with the same name will be silently overwritten without advance warning!
 * path is a null-terminated string containing the path and name of the file
 * filetype must be EDFLIB_FILETYPE_EDFPLUS or EDFLIB_FILETYPE_BDFPLUS
 * returns a handle on success, you need this handle for the other functions
 * in case of an error it returns a negative number corresponding to one of the following values:
 * EDFLIB_MALLOC_ERROR
 * EDFLIB_NO_SUCH_FILE_OR_DIRECTORY
 * EDFLIB_MAXFILES_REACHED
 * EDFLIB_FILE_ALREADY_OPENED
 * EDFLIB_NUMBER_OF_SIGNALS_INVALID
 * EDFLIB_ARCH_ERROR
 * This function is required if you want to write a file (or use edfopen_file_writeonly_with_params())
 */

int edfopen_file_writeonly_with_params(const char *path, int filetype, int number_of_signals, int samplefrequency, double phys_max_min, const char *phys_dim);
/* this is a convenience function that can create a new EDF file and initializes the most important parameters.
 * it assumes that all signals are sharing the same parameters (you can still change them though).
 * warning, an already existing file with the same name will be silently overwritten without advance warning!
 * path is a null-terminated string containing the path and name of the file
 * filetype must be EDFLIB_FILETYPE_EDFPLUS or EDFLIB_FILETYPE_BDFPLUS
 * Sets the samplefrequency of all signals. (In reality, it sets the number of samples per datarecord which equals the samplefrequency only when
 * the datarecords have a duration of 1 second)
 * Sets the physical maximum of all signals to phys_max_min.
 * Sets the physical minimum of all signals to -phys_max_min.
 * Sets the physical dimension (unit) of all signals ("uV", "BPM", "mA", "Degr.", etc.).
 * phys_dim is a pointer to a NULL-terminated ASCII-string containing the physical dimension of the signals
 * returns a handle on success, you need this handle for the other functions
 * in case of an error it returns a negative number corresponding to one of the following values:
 * EDFLIB_MALLOC_ERROR
 * EDFLIB_NO_SUCH_FILE_OR_DIRECTORY
 * EDFLIB_MAXFILES_REACHED
 * EDFLIB_FILE_ALREADY_OPENED
 * EDFLIB_NUMBER_OF_SIGNALS_INVALID
 * EDFLIB_ARCH_ERROR
 * This function is required if you want to write a file (or use edfopen_file_writeonly())
 */

int edf_set_samplefrequency(int handle, int edfsignal, int samplefrequency);
/* Sets the samplefrequency of signal edfsignal. In reality, it sets the number of samples in a datarecord
 * which equals the samplefrequency only when the datarecords have a duration of 1 second.
 * The effective samplefrequency is: samplefrequency / datarecord duration
 * Returns 0 on success, otherwise -1
 * This function is required for every signal and can be called only after opening a
 * file in writemode and before the first sample write action
 */

int edf_set_physical_maximum(int handle, int edfsignal, double phys_max);
/* Sets the maximum physical value of signal edfsignal. (the value of the input of the ADC when the output equals the value of "digital maximum")
 * It is the highest value that the equipment is able to record. It does not necessarily mean the signal recorded reaches this level
 * Must be un-equal to physical minimum
 * Returns 0 on success, otherwise -1
 * This function is required for every signal and can be called only after opening a
 * file in writemode and before the first sample write action
 */

int edf_set_physical_minimum(int handle, int edfsignal, double phys_min);
/* Sets the minimum physical value of signal edfsignal. (the value of the input of the ADC when the output equals the value of "digital minimum")
 * It is the lowest value that the equipment is able to record. It does not necessarily mean the signal recorded reaches this level
 * Usually this will be (-(phys_max))
 * Must be un-equal to physical maximum
 * Returns 0 on success, otherwise -1
 * This function is required for every signal and can be called only after opening a
 * file in writemode and before the first sample write action
 */

int edf_set_digital_maximum(int handle, int edfsignal, int dig_max);
/* Sets the maximum digital value of signal edfsignal. The maximum value is 32767 for EDF+ and 8388607 for BDF+
 * It is the highest value that the equipment is able to record. It does not necessarily mean the signal recorded reaches this level
 * Usually it's the extreme output of the ADC
 * Must be higher than digital minimum
 * Returns 0 on success, otherwise -1
 * This function is required for every signal and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edf_set_digital_minimum(int handle, int edfsignal, int dig_min);
/* Sets the minimum digital value of signal edfsignal. The minimum value is -32768 for EDF+ and -8388608 for BDF+
 * It is the lowest value that the equipment is able to record. It does not necessarily mean the signal recorded reaches this level
 * Usually it's the extreme output of the ADC
 * Usually this will be (-(dig_max + 1))
 * Must be lower than digital maximum
 * Returns 0 on success, otherwise -1
 * This function is required for every signal and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edf_set_label(int handle, int edfsignal, const char *label);
/* Sets the label (name) of signal edfsignal. ("FP1", "SaO2", etc.)
 * label is a pointer to a NULL-terminated ASCII-string containing the label (name) of the signal edfsignal
 * Returns 0 on success, otherwise -1
 * This function is recommended for every signal when you want to write a file
 * and can be called only after opening a file in writemode and before the first sample write action
 */

int edf_set_prefilter(int handle, int edfsignal, const char *prefilter);
/* Sets the prefilter of signal edfsignal ("HP:0.1Hz", "LP:75Hz N:50Hz", etc.).
 * prefilter is a pointer to a NULL-terminated ASCII-string containing the prefilter text of the signal edfsignal
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode and before
 * the first sample write action
 */

int edf_set_transducer(int handle, int edfsignal, const char *transducer);
/* Sets the transducer of signal edfsignal ("AgAgCl cup electrodes", etc.).
 * transducer is a pointer to a NULL-terminated ASCII-string containing the transducer text of the signal edfsignal
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode and before
 * the first sample write action
 */

int edf_set_physical_dimension(int handle, int edfsignal, const char *phys_dim);
/* Sets the physical dimension (unit) of signal edfsignal. ("uV", "BPM", "mA", "Degr.", etc.)
 * phys_dim is a pointer to a NULL-terminated ASCII-string containing the physical dimension of the signal edfsignal
 * Returns 0 on success, otherwise -1
 * This function is recommended for every signal when you want to write a file
 * and can be called only after opening a file in writemode and before the first sample write action
 */

int edf_set_startdatetime(int handle, int startdate_year, int startdate_month, int startdate_day,
                                      int starttime_hour, int starttime_minute, int starttime_second);
/* Sets the startdate and starttime.
 * year: 1985 - 2084, month: 1 - 12, day: 1 - 31
 * hour: 0 - 23, minute: 0 - 59, second: 0 - 59
 * If not called, the library will use the system date and time at runtime
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 * Note: for anonymization purposes, the consensus is to use 1985-01-01 00:00:00 for the startdate and starttime.
 */

int edf_set_patientname(int handle, const char *patientname);
/* Sets the patientname. patientname is a pointer to a null-terminated ASCII-string.
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edf_set_patientcode(int handle, const char *patientcode);
/* Sets the patientcode. patientcode is a pointer to a null-terminated ASCII-string.
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edf_set_gender(int handle, int gender);
/* Sets the gender. 1 is male, 0 is female.
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edf_set_birthdate(int handle, int birthdate_year, int birthdate_month, int birthdate_day);
/* Sets the birthdate.
 * year: 1800 - 3000, month: 1 - 12, day: 1 - 31
 * This function is optional
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edf_set_patient_additional(int handle, const char *patient_additional);
/* Sets the additional patientinfo. patient_additional is a pointer to a null-terminated ASCII-string.
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edf_set_admincode(int handle, const char *admincode);
/* Sets the admincode. admincode is a pointer to a null-terminated ASCII-string.
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edf_set_technician(int handle, const char *technician);
/* Sets the technicians name. technician is a pointer to a null-terminated ASCII-string.
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edf_set_equipment(int handle, const char *equipment);
/* Sets the name of the equipment used during the aquisition. equipment is a pointer to a null-terminated ASCII-string.
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edf_set_recording_additional(int handle, const char *recording_additional);
/* Sets the additional recordinginfo. recording_additional is a pointer to a null-terminated ASCII-string.
 * Returns 0 on success, otherwise -1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 */

int edfwrite_physical_samples(int handle, double *buf);
/* Writes n physical samples (uV, mA, Ohm) from *buf belonging to one signal
 * where n is the samplefrequency of that signal.
 * The physical samples will be converted to digital samples using the
 * values of physical maximum, physical minimum, digital maximum and digital minimum
 * The number of samples written is equal to the samplefrequency of the signal
 * Size of buf should be equal to or bigger than sizeof(double[samplefrequency])
 * Call this function for every signal in the file. The order is important!
 * When there are 4 signals in the file,  the order of calling this function
 * must be: signal 0, signal 1, signal 2, signal 3, signal 0, signal 1, signal 2, etc.
 * Returns 0 on success, otherwise -1
 */

int edf_blockwrite_physical_samples(int handle, double *buf);
/* Writes physical samples (uV, mA, Ohm) from *buf
 * buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc.
 * where n is the samplefrequency of that signal.
 * buf must be filled with samples from all signals, starting with signal 0, 1, 2, etc.
 * one block equals one second
 * The physical samples will be converted to digital samples using the
 * values of physical maximum, physical minimum, digital maximum and digital minimum
 * The number of samples written is equal to the sum of the samplefrequencies of all signals
 * Size of buf should be equal to or bigger than sizeof(double) multiplied by the sum of the samplefrequencies of all signals
 * Returns 0 on success, otherwise -1
 */

int edfwrite_digital_short_samples(int handle, short *buf);
/* Writes n "raw" digital samples from *buf belonging to one signal
 * where n is the samplefrequency of that signal.
 * The samples will be written to the file without any conversion.
 * Because the size of a short is 16-bit, do not use this function with BDF (24-bit)
 * The number of samples written is equal to the samplefrequency of the signal
 * Size of buf should be equal to or bigger than sizeof(short[samplefrequency])
 * Call this function for every signal in the file. The order is important!
 * When there are 4 signals in the file,  the order of calling this function
 * must be: signal 0, signal 1, signal 2, signal 3, signal 0, signal 1, signal 2, etc.
 * Returns 0 on success, otherwise -1
 */

int edfwrite_digital_samples(int handle, int *buf);
/* Writes n "raw" digital samples from *buf belonging to one signal
 * where n is the samplefrequency of that signal.
 * The 16 (or 24 in case of BDF) least significant bits of the sample will be written to the
 * file without any conversion.
 * The number of samples written is equal to the samplefrequency of the signal
 * Size of buf should be equal to or bigger than sizeof(int[samplefrequency])
 * Call this function for every signal in the file. The order is important!
 * When there are 4 signals in the file,  the order of calling this function
 * must be: signal 0, signal 1, signal 2, signal 3, signal 0, signal 1, signal 2, etc.
 * Returns 0 on success, otherwise -1
 */

int edf_blockwrite_digital_3byte_samples(int handle, void *buf);
/* Writes "raw" digital samples from *buf.
 * buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc.
 * where n is the samplefrequency of that signal.
 * One block equals one second. One sample equals 3 bytes, order is little endian (least significant byte first)
 * Encoding is second's complement, most significant bit of most significant byte is the sign-bit
 * The samples will be written to the file without any conversion.
 * Because the size of a 3-byte sample is 24-bit, this function can only be used when writing a BDF file
 * The number of samples written is equal to the sum of the samplefrequencies of all signals.
 * Size of buf should be equal to or bigger than: the sum of the samplefrequencies of all signals x 3 bytes
 * Returns 0 on success, otherwise -1
 */

int edf_blockwrite_digital_short_samples(int handle, short *buf);
/* Writes "raw" digital samples from *buf.
 * buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc.
 * where n is the samplefrequency of that signal.
 * One block equals one second.
 * The samples will be written to the file without any conversion.
 * Because the size of a short is 16-bit, do not use this function with BDF (24-bit)
 * The number of samples written is equal to the sum of the samplefrequencies of all signals.
 * Size of buf should be equal to or bigger than sizeof(short) multiplied by the sum of the samplefrequencies of all signals
 * Returns 0 on success, otherwise -1
 */

int edf_blockwrite_digital_samples(int handle, int *buf);
/* Writes "raw" digital samples from *buf.
 * buf must be filled with samples from all signals, starting with n samples of signal 0, n samples of signal 1, n samples of signal 2, etc.
 * where n is the samplefrequency of that signal.
 * One block equals one second.
 * The 16 (or 24 in case of BDF) least significant bits of the sample will be written to the
 * file without any conversion.
 * The number of samples written is equal to the sum of the samplefrequencies of all signals.
 * Size of buf should be equal to or bigger than sizeof(int) multiplied by the sum of the samplefrequencies of all signals
 * Returns 0 on success, otherwise -1
 */

int edfwrite_annotation_utf8(int handle, long long onset, long long duration, const char *description);
/* writes an annotation/event to the file
 * onset is relative to the start of the file
 * onset and duration are in units of 100 microSeconds!     resolution is 0.0001 second!
 * for example: 34.071 seconds must be written as 340710
 * if duration is unknown or not applicable: set a negative number (-1)
 * description is a null-terminated UTF8-string containing the text that describes the event
 * This function is optional and can be called only after opening a file in writemode
 * and before closing the file
 */

int edfwrite_annotation_latin1(int handle, long long onset, long long duration, const char *description);
/* writes an annotation/event to the file
 * onset is relative to the start of the file
 * onset and duration are in units of 100 microSeconds!     resolution is 0.0001 second!
 * for example: 34.071 seconds must be written as 340710
 * if duration is unknown or not applicable: set a negative number (-1)
 * description is a null-terminated Latin1-string containing the text that describes the event
 * This function is optional and can be called only after opening a file in writemode
 * and before closing the file
 */

int edf_set_datarecord_duration(int handle, int duration);
/* Sets the datarecord duration. The default value is 1 second.
 * ATTENTION: the argument "duration" is expressed in units of 10 microSeconds!
 * So, if you want to set the datarecord duration to 0.1 second, you must give
 * the argument "duration" a value of "10000".
 * This function is optional, normally you don't need to change the default value.
 * The datarecord duration must be in the range 0.001 to 60 seconds.
 * Returns 0 on success, otherwise -1
 * This function is NOT REQUIRED but can be called after opening a
 * file in writemode and before the first sample write action.
 * This function can be used when you want to use a samplerate
 * which is not an integer. For example, if you want to use a samplerate of 0.5 Hz,
 * set the samplefrequency to 5 Hz and the datarecord duration to 10 seconds,
 * or set the samplefrequency to 1 Hz and the datarecord duration to 2 seconds.
 * Do not use this function if not necessary.
 */

int edf_set_micro_datarecord_duration(int handle, int duration);
/* Sets the datarecord duration to a very small value.
 * ATTENTION: the argument "duration" is expressed in units of 1 microSecond!
 * This function is optional, normally you don't need to change the default value.
 * The datarecord duration must be in the range 1 to 9999 micro-seconds.
 * Returns 0 on success, otherwise -1
 * This function is NOT REQUIRED but can be called after opening a
 * file in writemode and before the first sample write action.
 * This function can be used when you want to use a very high samplerate.
 * For example, if you want to use a samplerate of 5 GHz,
 * set the samplefrequency to 5000 Hz and the datarecord duration to 1 micro-second.
 * Do not use this function if not necessary.
 * This function was added to accommodate for high speed ADC's e.g. Digital Sampling Oscilloscopes
 */

int edf_set_number_of_annotation_signals(int handle, int annot_signals);
/* Sets the number of annotation signals. The default value is 1
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 * Normally you don't need to change the default value. Only when the number of annotations
 * you want to write is higher than the number of datarecords in the recording, you can use
 * this function to increase the storage space for annotations
 * Minimum is 1, maximum is 64
 * Returns 0 on success, otherwise -1
 */

int edf_set_subsecond_starttime(int handle, int subsecond);
/* Sets the subsecond starttime expressed in units of 100 nanoSeconds
 * Valid range is 0 to 9999999 inclusive. Default is 0
 * This function is optional and can be called only after opening a file in writemode
 * and before the first sample write action
 * Returns 0 on success, otherwise -1
 * It is strongly recommended to use a maximum resolution of no more than 100 micro-Seconds.
 * e.g. use 1234000  to set a starttime offset of 0.1234 seconds (instead of 1234567)
 * in other words, leave the last 3 digits at zero
 */

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif






