From 531b35a8c74ae505caa8f86a766b18ee0d86755a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Michal=20Mal=C3=BD?= Date: Sun, 29 Jun 2014 13:46:05 +0200 Subject: [PATCH] Initial commit --- libhpcs.c | 602 ++++++++++++++++++++++++++++++++++++++++++++++++++++ libhpcs.h | 57 +++++ libhpcs_p.h | 131 ++++++++++++ 3 files changed, 790 insertions(+) create mode 100644 libhpcs.c create mode 100644 libhpcs.h create mode 100644 libhpcs_p.h diff --git a/libhpcs.c b/libhpcs.c new file mode 100644 index 0000000..68eaf63 --- /dev/null +++ b/libhpcs.c @@ -0,0 +1,602 @@ +#include "libhpcs.h" +#include "libhpcs_p.h" +#include +#include +#include + +char* hpcs_error_to_string(const enum HPCS_RetCode err) +{ + char* msg; + + switch (err) { + case HPCS_OK: + msg = malloc(strlen(HPCS_OK_STR) + 1); + strcpy(msg, HPCS_OK_STR); + return msg; + case HPCS_E_NULLPTR: + msg = malloc(strlen(HPCS_E_NULLPTR_STR) + 1); + strcpy(msg, HPCS_E_NULLPTR_STR); + return msg; + case HPCS_E_CANT_OPEN: + msg = malloc(strlen(HPCS_E_CANT_OPEN_STR) + 1); + strcpy(msg, HPCS_E_CANT_OPEN_STR); + return msg; + case HPCS_E_PARSE_ERROR: + msg = malloc(strlen(HPCS_E_PARSE_ERROR_STR) + 1); + strcpy(msg, HPCS_E_PARSE_ERROR_STR); + return msg; + case HPCS_E_UNKNOWN_TYPE: + msg = malloc(strlen(HPCS_E_UNKNOWN_TYPE_STR) + 1); + strcpy(msg, HPCS_E_UNKNOWN_TYPE_STR); + return msg; + default: + msg = malloc(strlen(HPCS_E__UNKNOWN_EC_STR) + 1); + strcpy(msg, HPCS_E__UNKNOWN_EC_STR); + return msg; + } +} + +enum HPCS_RetCode hpcs_read_file(const char* filename, struct HPCS_MeasuredData* mdata) +{ + FILE* datafile; + enum HPCS_ParseCode pret; + enum HPCS_RetCode ret; + + if (mdata == NULL) + return HPCS_E_NULLPTR; + + datafile = fopen(filename, "rb"); + if (datafile == NULL) + return HPCS_E_CANT_OPEN; + + pret = read_string_at_offset(datafile, DATA_OFFSET_FILE_DESC, &mdata->file_description); + if (pret != PARSE_OK) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + pret = read_string_at_offset(datafile, DATA_OFFSET_SAMPLE_INFO, &mdata->sample_info); + if (pret != PARSE_OK) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + pret = read_string_at_offset(datafile, DATA_OFFSET_OPERATOR_NAME, &mdata->operator_name); + if (pret != PARSE_OK) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + pret = read_date(datafile, &mdata->date); + if (pret != PARSE_OK) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + pret = read_string_at_offset(datafile, DATA_OFFSET_CS_VER, &mdata->cs_ver); + if (pret != PARSE_OK) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + pret = read_string_at_offset(datafile, DATA_OFFSET_Y_UNITS, &mdata->y_units); + if (pret != PARSE_OK) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + pret = read_string_at_offset(datafile, DATA_OFFSET_CS_REV, &mdata->cs_rev); + if (pret != PARSE_OK) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + pret = read_sampling_rate(datafile, &mdata->sampling_rate); + if (pret != PARSE_OK) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + pret = autodetect_file_type(datafile, &mdata->file_type); + if (pret != PARSE_OK) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + + if (mdata->file_type == TYPE_CE_DAD) { + pret = read_dad_wavelength(datafile, WAVELENGTH_MEASURED, &mdata->dad_wavelength_msr); + if (pret != PARSE_OK && pret != PARSE_W_NO_DATA) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + pret = read_dad_wavelength(datafile, WAVELENGTH_REFERENCE, &mdata->dad_wavelength_ref); + if (pret != PARSE_OK && pret != PARSE_W_NO_DATA) { + ret = HPCS_E_PARSE_ERROR; + goto out; + } + } + + switch (mdata->file_type) { + case TYPE_CE_CURRENT: + pret = read_fixed_signal(datafile, &mdata->data, &mdata->data_count, CE_CURRENT_STEP, mdata->sampling_rate); + break; + case TYPE_CE_CCD: + pret = read_floating_signal(datafile, &mdata->data, &mdata->data_count, CE_CCD_STEP, mdata->sampling_rate); + break; + case TYPE_CE_DAD: + pret = read_fixed_signal(datafile, &mdata->data, &mdata->data_count, CE_DAD_STEP, mdata->sampling_rate); + break; + case TYPE_CE_POWER: + case TYPE_CE_VOLTAGE: + pret = read_fixed_signal(datafile, &mdata->data, &mdata->data_count, CE_PWR_VOLT_STEP, mdata->sampling_rate); + break; + case TYPE_UNKNOWN: + ret = HPCS_E_UNKNOWN_TYPE; + goto out; + } + + if (pret != PARSE_OK) { + ret = HPCS_E_PARSE_ERROR; + } + else + ret = HPCS_OK; +out: + fclose(datafile); + return ret; +} + +static enum HPCS_ParseCode autodetect_file_type(FILE* datafile, enum HPCS_File_Type* file_type) +{ + char* type_str; + char* type_id; + char* delim; + size_t len; + enum HPCS_ParseCode pret; + + pret = read_string_at_offset(datafile, DATA_OFFSET_DEVSIG_INFO, &type_str); + if (pret != PARSE_OK) + return pret; + + delim = strchr(type_str, DATA_FILE_COMMA); + if (delim == NULL) { + free(type_str); + return PARSE_E_NOT_FOUND; + } + + len = delim - type_str; + type_id = malloc(len + 1); + memcpy(type_id, type_str, len); + type_id[len] = 0; + + if (strcmp(FILE_TYPE_CE_CCD, type_id) == 0) + *file_type = TYPE_CE_CCD; + else if (strcmp(FILE_TYPE_CE_CURRENT, type_id) == 0) + *file_type = TYPE_CE_CURRENT; + else if (strstr(type_id, FILE_TYPE_CE_DAD) != NULL) + *file_type = TYPE_CE_DAD; + else if (strcmp(FILE_TYPE_CE_POWER, type_id) == 0) + *file_type = TYPE_CE_POWER; + else if (strcmp(FILE_TYPE_CE_VOLTAGE, type_id) == 0) + *file_type = TYPE_CE_VOLTAGE; + else + *file_type = TYPE_UNKNOWN; + + return PARSE_OK; +} + +static enum HPCS_DataCheckCode check_for_marker(const char* const segment, size_t* const next_marker_idx) +{ + if (segment[0] == BIN_MARKER_END && segment[1] == BIN_MARKER_END) + return DCHECK_EOF; + else if (segment[0] == BIN_MARKER_A && segment[1] != BIN_MARKER_END) { + *next_marker_idx += (uint8_t)segment[1] + 1; + return DCHECK_GOT_MARKER; + } else + return DCHECK_E_NO_MARKER; +} + +static enum HPCS_ParseCode read_dad_wavelength(FILE* datafile, const enum HPCS_Wavelength_Type wl_type, uint16_t* const wavelength) +{ + char* start_idx, *end_idx, *temp, *type_str; + size_t len; + enum HPCS_ParseCode pret; + + *wavelength = 0; + pret = read_string_at_offset(datafile, DATA_OFFSET_DEVSIG_INFO, &type_str); + if (pret != PARSE_OK) + return pret; + + switch (wl_type) { + case WAVELENGTH_MEASURED: + start_idx = strstr(type_str, WAVELENGTH_MEASURED_TEXT); + break; + case WAVELENGTH_REFERENCE: + start_idx = strstr(type_str, WAVELENGTH_REFERENCE_TEXT); + break; + default: + return PARSE_E_INV_PARAM; + } + + if (start_idx == NULL) + return PARSE_W_NO_DATA; + + end_idx = strchr(start_idx, WAVELENGTH_DELIMITER_TEXT); + if (end_idx == NULL) + return PARSE_E_NOT_FOUND; + + len = end_idx - (start_idx + 4); + temp = malloc(len + 1); + if (temp == NULL) + return PARSE_E_NO_MEM; + memcpy(temp, start_idx + 4, len); + temp[len] = 0; + + *wavelength = strtoul(temp, NULL, 10); + free(temp); + return PARSE_OK; +} + +static enum HPCS_ParseCode read_date(FILE* datafile, struct HPCS_Date* date) +{ + char* date_str; + char* date_time_delim; + char* dm_delim, *my_delim; + char* hm_delim, *ms_delim; + char temp[32]; + size_t len; + enum HPCS_ParseCode pret; + + pret = read_string_at_offset(datafile, DATA_OFFSET_DATE, &date_str); + if (pret != PARSE_OK) + return pret; + + /* Find date / time delimiter */ + date_time_delim = strchr(date_str, DATA_FILE_COMMA); + if (date_time_delim == NULL) { + free(date_str); + return PARSE_E_NOT_FOUND; + } + + /* Get day */ + dm_delim = strchr(date_str, DATA_FILE_DASH); + if (dm_delim == NULL) { + free(date_str); + return PARSE_E_NOT_FOUND; + } + len = dm_delim - date_str; + memcpy(temp, date_str, len); + temp[len] = 0; + date->day = strtoul(temp, NULL, 10); + + /* Get month */ + my_delim = strchr(dm_delim + 1, DATA_FILE_DASH); + if (dm_delim == NULL) { + free(date_str); + return PARSE_E_NOT_FOUND; + } + len = my_delim - (dm_delim + 1); + memcpy(temp, dm_delim + 1, len); + temp[len] = 0; + date->month = month_to_number(temp); + + /* Get year */ + len = date_time_delim - (my_delim + 1); + memcpy(temp, my_delim + 1, len); + temp[len] = 0; + date->year = strtoul(temp, NULL, 10); + if (date->year < 90) /* Y2K workaround */ + date->year += 2000; + + /* Get hour */ + hm_delim = strchr(date_time_delim + 1, DATA_FILE_COLON); + if (hm_delim == NULL) { + free(date_str); + return PARSE_E_NOT_FOUND; + } + len = hm_delim - (date_time_delim + 1); + memcpy(temp, date_time_delim + 1, len); + temp[len] = 0; + date->hour = strtoul(temp, NULL, 10); + + /* Get minute */ + ms_delim = strchr(hm_delim + 1, DATA_FILE_COLON); + if (ms_delim == NULL) { + free(date_str); + return PARSE_E_NOT_FOUND; + } + len = ms_delim - (hm_delim + 1); + memcpy(temp, hm_delim + 1, len); + temp[len] = 0; + date->minute = strtoul(temp, NULL, 10); + + /* Get second */ + date->second = strtoul(ms_delim + 1, NULL, 10); + + return PARSE_OK; +} + +static uint8_t month_to_number(const char* const month) +{ + if (strcmp(MON_JAN_STR, month) == 0) + return 1; + else if (strcmp(MON_FEB_STR, month) == 0) + return 2; + else if (strcmp(MON_MAR_STR, month) == 0) + return 3; + else if (strcmp(MON_APR_STR, month) == 0) + return 4; + else if (strcmp(MON_MAY_STR, month) == 0) + return 5; + else if (strcmp(MON_JUN_STR, month) == 0) + return 6; + else if (strcmp(MON_JUL_STR, month) == 0) + return 7; + else if (strcmp(MON_AUG_STR, month) == 0) + return 8; + else if (strcmp(MON_SEP_STR, month) == 0) + return 9; + else if (strcmp(MON_OCT_STR, month) == 0) + return 10; + else if (strcmp(MON_NOV_STR, month) == 0) + return 11; + else if (strcmp(MON_DEC_STR, month) == 0) + return 12; + else + return 0; +} + +static enum HPCS_ParseCode read_fixed_signal(FILE* datafile, struct HPCS_TVPair** pairs, size_t* pairs_count, + const HPCS_step step, const double sampling_rate) +{ + const double time_step = 1 / (60 * sampling_rate); + size_t alloc_size = 60 * sampling_rate; + bool read_file = true; + double value = 0; + double time = 0; + size_t segments_read = 0; + size_t data_segments_read = 0; + size_t next_marker_idx = 0; + char raw[2]; + size_t r; + enum HPCS_DataCheckCode dret; + + fseek(datafile, DATA_OFFSET_DATA_START, SEEK_SET); + if (feof(datafile)) + return PARSE_E_OUT_OF_RANGE; + + /* Data block must begin with a marker, read it */ + r = fread(raw, SEGMENT_SIZE, 1, datafile); + if (r != 1) + return PARSE_E_CANT_READ; + segments_read++; + + dret = check_for_marker(raw, &next_marker_idx); + switch (dret) { + case DCHECK_EOF: + case DCHECK_E_NO_MARKER: + return PARSE_E_NOT_FOUND; /* First segment is not a marker */ + default: + break; + } + + *pairs = malloc(sizeof(struct HPCS_TVPair) * alloc_size); + if (pairs == NULL) + return PARSE_E_NO_MEM; + + while (read_file) { + if (ferror(datafile)) { + free(*pairs); + *pairs = NULL; + return PARSE_E_CANT_READ; + } + if (feof(datafile)) + break; + + r = fread(raw, SEGMENT_SIZE, 1, datafile); + if (r != 1) { + free(*pairs); + *pairs = NULL; + return PARSE_E_CANT_READ; + } + segments_read++; + + if (alloc_size == data_segments_read) { + struct HPCS_TVPair* nptr; + alloc_size += 60 * sampling_rate; + nptr = realloc(*pairs, sizeof(struct HPCS_TVPair) * alloc_size); + + if (nptr == NULL) { + free(*pairs); + *pairs = NULL; + return PARSE_E_NO_MEM; + } + + *pairs = nptr; + } + + if (segments_read - 1 == next_marker_idx) { + dret = check_for_marker(raw, &next_marker_idx); + switch (dret) { + case DCHECK_GOT_MARKER: + break; + case DCHECK_EOF: + read_file = false; + break; + default: + free(*pairs); + *pairs = NULL; + return PARSE_E_NOT_FOUND; + } + } else { + be_to_cpu(raw); + value += (*(int16_t*)(raw)) * step; + + (*pairs)[data_segments_read].time = time; + (*pairs)[data_segments_read].value = value; + data_segments_read++; + time += time_step; + } + } + + *pairs_count = data_segments_read; + return PARSE_OK; +} + +static enum HPCS_ParseCode read_floating_signal(FILE* datafile, struct HPCS_TVPair** pairs, size_t* pairs_count, + const HPCS_step step, const double sampling_rate) +{ + const double time_step = 1 / (60 * sampling_rate); + size_t alloc_size = 60 * sampling_rate; + bool read_file = true; + double value = 0; + double time = 0; + size_t segments_read = 0; + size_t data_segments_read = 0; + size_t next_marker_idx = 0; + char raw[2]; + size_t r; + enum HPCS_DataCheckCode dret; + + fseek(datafile, DATA_OFFSET_DATA_START, SEEK_SET); + if (feof(datafile)) + return PARSE_E_OUT_OF_RANGE; + + r = fread(raw, SEGMENT_SIZE, 1, datafile); + if (r != 1) + return PARSE_E_CANT_READ; + segments_read++; + + dret = check_for_marker(raw, &next_marker_idx); + switch (dret) { + case DCHECK_EOF: + case DCHECK_E_NO_MARKER: + return PARSE_E_NOT_FOUND; + default: + break; + } + + *pairs = malloc(sizeof(struct HPCS_TVPair) * alloc_size); + if (*pairs == NULL) + return PARSE_E_NO_MEM; + + while (read_file) { + if (ferror(datafile)) { + free(*pairs); + *pairs = NULL; + return PARSE_E_CANT_READ; + } + if (feof(datafile)) + break; + + r = fread(raw, SEGMENT_SIZE, 1, datafile); + if (r != 1) { + free(*pairs); + *pairs = NULL; + return PARSE_E_CANT_READ; + } + segments_read++; + + /* Expand storage if there is more data than we can store */ + if (alloc_size == data_segments_read) { + struct HPCS_TVPair* nptr; + alloc_size += 60 * sampling_rate; + nptr = realloc(*pairs, sizeof(struct HPCS_TVPair) * alloc_size); + + if (nptr == NULL) { + free(*pairs); + *pairs = NULL; + return PARSE_E_NO_MEM; + } + + *pairs = nptr; + } + + /* Check for markers */ + if (segments_read - 1 == next_marker_idx) { + dret = check_for_marker(raw, &next_marker_idx); + switch (dret) { + case DCHECK_GOT_MARKER: + break; + case DCHECK_EOF: + read_file = false; + break; + default: + free(*pairs); + *pairs = NULL; + return PARSE_E_NOT_FOUND; + } + } else { + /* Check for a sudden jump of value */ + if (raw[0] == BIN_MARKER_JUMP && raw[1] == BIN_MARKER_END) { + char lraw[4]; + int32_t _v; + + fread(lraw, LARGE_SEGMENT_SIZE, 1, datafile); + if (feof(datafile) || ferror(datafile)) { + free(*pairs); + *pairs = NULL; + return PARSE_E_CANT_READ; + } + + be_to_cpu(lraw); + _v = *(int32_t*)lraw; + value = _v * step; + } else { + int16_t _v; + + be_to_cpu(raw); + _v = *(int16_t*)raw; + value += _v * step; + } + + (*pairs)[data_segments_read].time = time; + (*pairs)[data_segments_read].value = value; + data_segments_read++; + time += time_step; + } + } + + *pairs_count = data_segments_read; + return PARSE_OK; +} + +static enum HPCS_ParseCode read_sampling_rate(FILE* datafile, double* sampling_rate) +{ + char raw[2]; + uint16_t number; + size_t r; + + fseek(datafile, DATA_OFFSET_SAMPLING_RATE, SEEK_SET); + if (feof(datafile)) + return PARSE_E_OUT_OF_RANGE; + + r = fread(raw, SEGMENT_SIZE, 1, datafile); + if (r != 1) + return PARSE_E_CANT_READ; + + be_to_cpu(raw); + number = *(uint16_t*)(raw); + *sampling_rate = number / 10.0; + + return PARSE_OK; +} + +static enum HPCS_ParseCode read_string_at_offset(FILE* datafile, const HPCS_offset offset, char** const result) +{ + char* string; + uint8_t str_length, idx; + size_t r; + + fseek(datafile, offset, SEEK_SET); + if (feof(datafile)) + return PARSE_E_OUT_OF_RANGE; + + r = fread(&str_length, SMALL_SEGMENT_SIZE, 1, datafile); + if (r != 1) + return PARSE_E_CANT_READ; + + string = malloc(str_length + 1); + if (string == NULL) + return PARSE_E_NO_MEM; + + for (idx = 0; idx < str_length; idx++) { + fread(string+idx, SMALL_SEGMENT_SIZE, 1, datafile); + fseek(datafile, SMALL_SEGMENT_SIZE, SEEK_CUR); + } + string[str_length] = 0; + + *result = string; + return PARSE_OK; +} diff --git a/libhpcs.h b/libhpcs.h new file mode 100644 index 0000000..c9b3507 --- /dev/null +++ b/libhpcs.h @@ -0,0 +1,57 @@ +#include +#include + +enum HPCS_File_Type { + TYPE_CE_CURRENT, + TYPE_CE_CCD, + TYPE_CE_DAD, + TYPE_CE_POWER, + TYPE_CE_VOLTAGE, + TYPE_UNKNOWN +}; + +enum HPCS_RetCode { + HPCS_OK, + HPCS_E_NULLPTR, + HPCS_E_CANT_OPEN, + HPCS_E_PARSE_ERROR, + HPCS_E_UNKNOWN_TYPE +}; + +struct HPCS_Date { + uint32_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; +}; + +struct HPCS_TVPair { + double time; + double value; +}; + +struct HPCS_MeasuredData { + char* file_description; + char* sample_info; + char* operator_name; + struct HPCS_Date date; + char* method_name; + char* cs_ver; + char* cs_rev; + char* y_units; + double sampling_rate; + uint16_t dad_wavelength_msr; + uint16_t dad_wavelength_ref; + enum HPCS_File_Type file_type; + struct HPCS_TVPair* data; + size_t data_count; +}; + +#ifdef __WIN32__ +__declspec(dllexport) enum HPCS_RetCode __cdecl hpcs_read_file(const char* const filename, struct HPCS_MeasuredData* mdata); +#else +enum HPCS_RetCode hpcs_read_file(const char* const filename, struct HPCS_MeasuredData* mdata); +char* hpcs_error_to_string(const enum HPCS_RetCode); +#endif diff --git a/libhpcs_p.h b/libhpcs_p.h new file mode 100644 index 0000000..09f4674 --- /dev/null +++ b/libhpcs_p.h @@ -0,0 +1,131 @@ +#include + +enum HPCS_DataCheckCode { + DCHECK_GOT_MARKER, + DCHECK_EOF, + DCHECK_E_NO_MARKER +}; + +enum HPCS_ParseCode { + PARSE_OK, + PARSE_E_OUT_OF_RANGE, + PARSE_E_NO_MEM, + PARSE_E_CANT_READ, + PARSE_E_NOT_FOUND, + PARSE_E_INV_PARAM, + PARSE_W_NO_DATA +}; + +enum HPCS_Wavelength_Type { + WAVELENGTH_MEASURED, + WAVELENGTH_REFERENCE +}; + +typedef size_t HPCS_offset; +typedef double HPCS_step; +typedef size_t HPCS_segsize; + + +/* Identifiers of file types found at offset 0x1075 */ +const char* FILE_TYPE_CE_CCD = "HPCE1L"; +const char* FILE_TYPE_CE_CURRENT = "HPCE1C"; +const char* FILE_TYPE_CE_DAD = "DAD1"; +const char* FILE_TYPE_CE_VOLTAGE = "HPCE1V"; +const char* FILE_TYPE_CE_POWER = "HPCE1P"; + +/* Char and text values */ +const char* WAVELENGTH_MEASURED_TEXT = "Sig="; +const char* WAVELENGTH_REFERENCE_TEXT = "Ref="; +const char WAVELENGTH_DELIMITER_TEXT = ','; +const char DATA_FILE_COMMA = (const char)(0x2C); +const char DATA_FILE_DASH = (const char)(0x2D); +const char DATA_FILE_COLON = (const char)(0x3A); +const char* MON_JAN_STR = "Jan"; +const char* MON_FEB_STR = "Feb"; +const char* MON_MAR_STR = "Mar"; +const char* MON_APR_STR = "Apr"; +const char* MON_MAY_STR = "May"; +const char* MON_JUN_STR = "Jun"; +const char* MON_JUL_STR = "Jul"; +const char* MON_AUG_STR = "Aug"; +const char* MON_SEP_STR = "Sep"; +const char* MON_OCT_STR = "Oct"; +const char* MON_NOV_STR = "Nov"; +const char* MON_DEC_STR = "Dec"; + +/* Precision of measured values. */ +const HPCS_step CE_CURRENT_STEP = 0.01; +const HPCS_step CE_CCD_STEP = 0.0000596046450027643; +const HPCS_step CE_DAD_STEP = 0.000476837158203; +const HPCS_step CE_PWR_VOLT_STEP = 0.001; + +/* Offsets containing data of interest in .ch files */ +const HPCS_offset DATA_OFFSET_FILE_DESC = 0x15B; +const HPCS_offset DATA_OFFSET_SAMPLE_INFO = 0x35A; +const HPCS_offset DATA_OFFSET_OPERATOR_NAME = 0x758; +const HPCS_offset DATA_OFFSET_DATE = 0x957; +const HPCS_offset DATA_OFFSET_METHOD_NAME = 0xA0E; +const HPCS_offset DATA_OFFSET_CS_VER = 0xE11; +const HPCS_offset DATA_OFFSET_CS_REV = 0xEDA; +const HPCS_offset DATA_OFFSET_SAMPLING_RATE = 0x101C; +const HPCS_offset DATA_OFFSET_Y_UNITS = 0x104C; +const HPCS_offset DATA_OFFSET_DEVSIG_INFO = 0x1075; +const HPCS_offset DATA_OFFSET_DATA_START = 0x1800; + +/* Values of markers found in .ch files */ +const char BIN_MARKER_A = 0x10; +const char BIN_MARKER_END = 0x00; +const char BIN_MARKER_JUMP = (const char)(0x80); + +const HPCS_segsize SMALL_SEGMENT_SIZE = 1; +const HPCS_segsize SEGMENT_SIZE = 2; +const HPCS_segsize LARGE_SEGMENT_SIZE = 4; + +const char* HPCS_OK_STR = "OK."; +const char* HPCS_E_NULLPTR_STR = "Null pointer to measured data struct."; +const char* HPCS_E_CANT_OPEN_STR = "Cannot open the specified file."; +const char* HPCS_E_PARSE_ERROR_STR = "Cannot parse the specified file, it might be corrupted or of unknown type."; +const char* HPCS_E_UNKNOWN_TYPE_STR = "The specified file contains an unknown type of measurement."; +const char* HPCS_E__UNKNOWN_EC_STR = "Unknown error code."; + +static enum HPCS_ParseCode autodetect_file_type(FILE* datafile, enum HPCS_File_Type* file_type); +static enum HPCS_DataCheckCode check_for_marker(const char* const segment, size_t* const next_marker_idx); +static enum HPCS_ParseCode read_dad_wavelength(FILE* datafile, const enum HPCS_Wavelength_Type wl_type, uint16_t* const wavelength); +static uint8_t month_to_number(const char* const month); +static enum HPCS_ParseCode read_date(FILE* datafile, struct HPCS_Date* const date); +static enum HPCS_ParseCode read_fixed_signal(FILE* datafile, struct HPCS_TVPair** pairs, size_t* pairs_count, + const HPCS_step step, const double sampling_rate); +static enum HPCS_ParseCode read_floating_signal(FILE* datafile, struct HPCS_TVPair** pairs, size_t* pairs_count, + const HPCS_step step, const double sampling_rate); +static enum HPCS_ParseCode read_sampling_rate(FILE* datafile, double* sampling_rate); +static enum HPCS_ParseCode read_string_at_offset(FILE* datafile, const HPCS_offset, char** const result); + + +#ifdef _HPCS_LITTLE_ENDIAN +#define be_to_cpu(bytes) reverse_endianness((char*)bytes, sizeof(bytes)); + +void reverse_endianness(char* bytes, size_t sz) { + size_t i; + for (i = 0; i < sz/2; i++) { + char t = bytes[i]; + bytes[i] = bytes[sz - i - 1]; + bytes[sz - i - 1] = t; + } + +} + +#elif defined _HPCS_BIG_ENDIAN +#define be_to_cpu(bytes) +#else +#error "Endiannes has not been determined." +#endif + +#ifdef NDEBUG +void print_debug(const char* msg) +{ + fprintf(stderr, "%s\n"m msg); +} +#else +void print_debug(const char* msg) { return; } +#endif //NDEBUG + -- 2.43.5