diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 288d28a..f1e306d 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -37,10 +37,6 @@ #define UNDEFINED 0xFFFFFFFF -#define ALL 0 -#define FIXED 1 -#define MANUAL 2 - #define HEADER 1 #define PROFILE 2 @@ -108,10 +104,12 @@ typedef struct hw_ostc_layout_t { } hw_ostc_layout_t; typedef struct hw_ostc_gasmix_t { + unsigned int id; unsigned int oxygen; unsigned int helium; unsigned int type; unsigned int enabled; + unsigned int active; unsigned int diluent; } hw_ostc_gasmix_t; @@ -126,6 +124,7 @@ typedef struct hw_ostc_parser_t { const hw_ostc_layout_t *layout; unsigned int ngasmixes; unsigned int nfixed; + unsigned int ndisabled; unsigned int initial; unsigned int initial_setpoint; unsigned int initial_cns; @@ -136,6 +135,8 @@ static dc_status_t hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_dateti static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); +static dc_status_t hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t callback, void *userdata); + static const dc_parser_vtable_t hw_ostc_parser_vtable = { sizeof(hw_ostc_parser_t), DC_FAMILY_HW_OSTC, @@ -194,15 +195,10 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { }; static unsigned int -hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil, unsigned int type) +hw_ostc_find_gasmix_manual (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil) { - unsigned int offset = 0; + unsigned int offset = parser->nfixed - parser->ndisabled; unsigned int count = parser->ngasmixes; - if (type == FIXED) { - count = parser->nfixed; - } else if (type == MANUAL) { - offset = parser->nfixed; - } unsigned int i = offset; while (i < count) { @@ -214,6 +210,22 @@ hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, return i; } +static unsigned int +hw_ostc_find_gasmix_fixed (hw_ostc_parser_t *parser, unsigned int id) +{ + unsigned int offset = 0; + unsigned int count = parser->nfixed - parser->ndisabled; + + unsigned int i = offset; + while (i < count) { + if (id == parser->gasmix[i].id) + break; + i++; + } + + return i; +} + static unsigned int hw_ostc_is_ccr (unsigned int divemode, unsigned int version) { @@ -295,19 +307,23 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) initial = data[31]; } for (unsigned int i = 0; i < ngasmixes; ++i) { + gasmix[i].id = i + 1; gasmix[i].oxygen = data[25 + 2 * i]; gasmix[i].helium = 0; gasmix[i].type = 0; gasmix[i].enabled = 1; + gasmix[i].active = 0; gasmix[i].diluent = 0; } } else if (version == 0x23 || version == 0x24) { ngasmixes = 5; for (unsigned int i = 0; i < ngasmixes; ++i) { + gasmix[i].id = i + 1; gasmix[i].oxygen = data[28 + 4 * i + 0]; gasmix[i].helium = data[28 + 4 * i + 1]; gasmix[i].type = data[28 + 4 * i + 3]; gasmix[i].enabled = gasmix[i].type != 0; + gasmix[i].active = 0; gasmix[i].diluent = ccr; // Find the first gas marked as the initial gas. if (initial == UNDEFINED && data[28 + 4 * i + 3] == 1) { @@ -326,6 +342,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) initial = data[31]; } for (unsigned int i = 0; i < ngasmixes; ++i) { + gasmix[i].id = i + 1; gasmix[i].oxygen = data[19 + 2 * i + 0]; gasmix[i].helium = data[19 + 2 * i + 1]; gasmix[i].type = 0; @@ -334,6 +351,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) } else { gasmix[i].enabled = 1; } + gasmix[i].active = 0; gasmix[i].diluent = ccr; } } @@ -342,7 +360,6 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) ERROR(abstract->context, "Invalid initial gas mix."); return DC_STATUS_DATAFORMAT; } - initial--; /* Convert to a zero based index. */ } else { WARNING(abstract->context, "No initial gas mix available."); } @@ -353,6 +370,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) parser->layout = layout; parser->ngasmixes = ngasmixes; parser->nfixed = ngasmixes; + parser->ndisabled = 0; parser->initial = initial; parser->initial_setpoint = initial_setpoint; parser->initial_cns = initial_cns; @@ -388,14 +406,17 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, const parser->layout = NULL; parser->ngasmixes = 0; parser->nfixed = 0; + parser->ndisabled = 0; parser->initial = 0; parser->initial_setpoint = 0; parser->initial_cns = 0; for (unsigned int i = 0; i < NGASMIXES; ++i) { + parser->gasmix[i].id = 0; parser->gasmix[i].oxygen = 0; parser->gasmix[i].helium = 0; parser->gasmix[i].type = 0; parser->gasmix[i].enabled = 0; + parser->gasmix[i].active = 0; parser->gasmix[i].diluent = 0; } @@ -490,7 +511,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned // Cache the profile data. if (parser->cached < PROFILE) { - rc = hw_ostc_parser_samples_foreach (abstract, NULL, NULL); + rc = hw_ostc_parser_internal_foreach (parser, NULL, NULL); if (rc != DC_STATUS_SUCCESS) return rc; } @@ -678,17 +699,12 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned static dc_status_t -hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata) +hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t callback, void *userdata) { - hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract; + dc_parser_t *abstract = (dc_parser_t *) parser; const unsigned char *data = abstract->data; unsigned int size = abstract->size; - // Cache the parser data. - dc_status_t rc = hw_ostc_parser_cache (parser); - if (rc != DC_STATUS_SUCCESS) - return rc; - unsigned int version = parser->version; unsigned int header = parser->header; const hw_ostc_layout_t *layout = parser->layout; @@ -794,7 +810,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call unsigned int time = 0; unsigned int nsamples = 0; - unsigned int tank = parser->initial != UNDEFINED ? parser->initial : 0; + unsigned int tank = parser->initial != UNDEFINED ? parser->initial - 1 : 0; unsigned int offset = header; if (version == 0x23 || version == 0x24) @@ -811,7 +827,9 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call // Initial gas mix. if (time == samplerate && parser->initial != UNDEFINED) { - sample.gasmix = parser->initial; + unsigned int idx = hw_ostc_find_gasmix_fixed (parser, parser->initial); + parser->gasmix[idx].active = 1; + sample.gasmix = idx; if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); } @@ -899,16 +917,18 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call } unsigned int o2 = data[offset]; unsigned int he = data[offset + 1]; - unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, ccr, MANUAL); + unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, ccr); if (idx >= parser->ngasmixes) { if (idx >= NGASMIXES) { ERROR (abstract->context, "Maximum number of gas mixes reached."); return DC_STATUS_NOMEMORY; } + parser->gasmix[idx].id = 0; parser->gasmix[idx].oxygen = o2; parser->gasmix[idx].helium = he; parser->gasmix[idx].type = 0; parser->gasmix[idx].enabled = 1; + parser->gasmix[idx].active = 1; parser->gasmix[idx].diluent = ccr; parser->ngasmixes = idx + 1; } @@ -925,19 +945,20 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; } - unsigned int idx = data[offset]; - if (parser->model == OSTC4 && ccr && idx > parser->nfixed) { + unsigned int id = data[offset]; + if (parser->model == OSTC4 && ccr && id > parser->nfixed) { // Fix the OSTC4 diluent index. - idx -= parser->nfixed; + id -= parser->nfixed; } - if (idx < 1 || idx > parser->nfixed) { - ERROR(abstract->context, "Invalid gas mix (%u).", idx); + if (id < 1 || id > parser->nfixed) { + ERROR(abstract->context, "Invalid gas mix (%u).", id); return DC_STATUS_DATAFORMAT; } - idx--; /* Convert to a zero based index. */ + unsigned int idx = hw_ostc_find_gasmix_fixed (parser, id); + parser->gasmix[idx].active = 1; sample.gasmix = idx; if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); - tank = idx; + tank = id - 1; offset++; length--; } @@ -964,16 +985,18 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call unsigned int o2 = data[offset]; unsigned int he = data[offset + 1]; - unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, 0, MANUAL); + unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, 0); if (idx >= parser->ngasmixes) { if (idx >= NGASMIXES) { ERROR (abstract->context, "Maximum number of gas mixes reached."); return DC_STATUS_NOMEMORY; } + parser->gasmix[idx].id = 0; parser->gasmix[idx].oxygen = o2; parser->gasmix[idx].helium = he; parser->gasmix[idx].type = 0; parser->gasmix[idx].enabled = 1; + parser->gasmix[idx].active = 1; parser->gasmix[idx].diluent = 0; parser->ngasmixes = idx + 1; } @@ -1099,16 +1122,18 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call unsigned int o2 = data[offset]; unsigned int he = data[offset + 1]; - unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, 0, MANUAL); + unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, 0); if (idx >= parser->ngasmixes) { if (idx >= NGASMIXES) { ERROR (abstract->context, "Maximum number of gas mixes reached."); return DC_STATUS_NOMEMORY; } + parser->gasmix[idx].id = 0; parser->gasmix[idx].oxygen = o2; parser->gasmix[idx].helium = he; parser->gasmix[idx].type = 0; parser->gasmix[idx].enabled = 1; + parser->gasmix[idx].active = 1; parser->gasmix[idx].diluent = 0; parser->ngasmixes = idx + 1; } @@ -1132,7 +1157,50 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call return DC_STATUS_DATAFORMAT; } + // Remove the disabled gas mixes from the fixed gas mixes. + unsigned int ndisabled = 0, nenabled = 0; + unsigned int count = parser->nfixed - parser->ndisabled; + for (unsigned int i = 0; i < count; ++i) { + if (parser->gasmix[i].enabled || parser->gasmix[i].active) { + // Move the fixed gas mix. + parser->gasmix[nenabled] = parser->gasmix[i]; + nenabled++; + } else { + ndisabled++; + } + } + + // Move all the manual gas mixes. + memmove (parser->gasmix + nenabled, parser->gasmix + count, + (parser->ngasmixes - count) * sizeof (hw_ostc_gasmix_t)); + memset (parser->gasmix + parser->ngasmixes - ndisabled, 0, + ndisabled * sizeof (hw_ostc_gasmix_t)); + + // Adjust the counts. + parser->ngasmixes -= ndisabled; + parser->ndisabled += ndisabled; + parser->cached = PROFILE; return DC_STATUS_SUCCESS; } + +static dc_status_t +hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata) +{ + hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract; + + // Cache the header data. + dc_status_t rc = hw_ostc_parser_cache (parser); + if (rc != DC_STATUS_SUCCESS) + return rc; + + // Cache the profile data. + if (parser->cached < PROFILE) { + rc = hw_ostc_parser_internal_foreach (parser, NULL, NULL); + if (rc != DC_STATUS_SUCCESS) + return rc; + } + + return hw_ostc_parser_internal_foreach (parser, callback, userdata); +}