diff --git a/src/Makefile.am b/src/Makefile.am index 9a56bc1..05e1cf9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,7 +67,7 @@ libdivecomputer_la_LIBADD = -lws2_32 endif libdivecomputer_la_SOURCES += \ irda.h irda.c \ - uwatec_smart.h uwatec_smart.c uwatec_smart_parser.c uwatec_galileo_parser.c + uwatec_smart.h uwatec_smart.c uwatec_smart_parser.c endif libdivecomputer_la_DEPENDENCIES = libdivecomputer.exp diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 812855e..2468d32 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -9,7 +9,6 @@ reefnet_sensusultra_parser_create reefnet_sensusultra_parser_set_calibration uwatec_memomouse_parser_create uwatec_smart_parser_create -uwatec_galileo_parser_create suunto_vyper_parser_create suunto_spyder_parser_create suunto_d9_parser_create diff --git a/src/parser.h b/src/parser.h index 4d8766b..8cfc01d 100644 --- a/src/parser.h +++ b/src/parser.h @@ -34,8 +34,7 @@ typedef enum parser_type_t { PARSER_TYPE_REEFNET_SENSUSPRO, PARSER_TYPE_REEFNET_SENSUSULTRA, PARSER_TYPE_UWATEC_MEMOMOUSE, - PARSER_TYPE_UWATEC_SMART, - PARSER_TYPE_UWATEC_GALILEO + PARSER_TYPE_UWATEC_SMART } parser_type_t; typedef enum parser_status_t { @@ -94,8 +93,7 @@ typedef enum parser_sample_flags_t { typedef enum parser_sample_vendor_t { SAMPLE_VENDOR_NONE, SAMPLE_VENDOR_UWATEC_ALADIN, - SAMPLE_VENDOR_UWATEC_SMART, - SAMPLE_VENDOR_UWATEC_GALILEO + SAMPLE_VENDOR_UWATEC_SMART } parser_sample_vendor_t; typedef union parser_sample_value_t { diff --git a/src/uwatec_galileo_parser.c b/src/uwatec_galileo_parser.c deleted file mode 100644 index f99ecda..0000000 --- a/src/uwatec_galileo_parser.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2008 Jef Driesen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ - -#include -#include // memcmp -#include - -#include "uwatec_smart.h" -#include "parser-private.h" -#include "units.h" -#include "utils.h" - -#define WARNING(expr) \ -{ \ - message ("%s:%d: %s\n", __FILE__, __LINE__, expr); \ -} - -#define NBITS 8 -#define NELEMENTS(x) ( sizeof(x) / sizeof((x)[0]) ) - -typedef struct uwatec_galileo_parser_t uwatec_galileo_parser_t; - -struct uwatec_galileo_parser_t { - parser_t base; - unsigned int model; -}; - -static parser_status_t uwatec_galileo_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size); -static parser_status_t uwatec_galileo_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata); -static parser_status_t uwatec_galileo_parser_destroy (parser_t *abstract); - -static const parser_backend_t uwatec_galileo_parser_backend = { - PARSER_TYPE_UWATEC_GALILEO, - uwatec_galileo_parser_set_data, /* set_data */ - uwatec_galileo_parser_samples_foreach, /* samples_foreach */ - uwatec_galileo_parser_destroy /* destroy */ -}; - - -static int -parser_is_uwatec_galileo (parser_t *abstract) -{ - if (abstract == NULL) - return 0; - - return abstract->backend == &uwatec_galileo_parser_backend; -} - - -parser_status_t -uwatec_galileo_parser_create (parser_t **out, unsigned int model) -{ - if (out == NULL) - return PARSER_STATUS_ERROR; - - // Allocate memory. - uwatec_galileo_parser_t *parser = malloc (sizeof (uwatec_galileo_parser_t)); - if (parser == NULL) { - WARNING ("Failed to allocate memory."); - return PARSER_STATUS_MEMORY; - } - - // Initialize the base class. - parser_init (&parser->base, &uwatec_galileo_parser_backend); - - // Set the default values. - parser->model = model; - - *out = (parser_t*) parser; - - return PARSER_STATUS_SUCCESS; -} - - -static parser_status_t -uwatec_galileo_parser_destroy (parser_t *abstract) -{ - if (! parser_is_uwatec_galileo (abstract)) - return PARSER_STATUS_TYPE_MISMATCH; - - // Free memory. - free (abstract); - - return PARSER_STATUS_SUCCESS; -} - - -static parser_status_t -uwatec_galileo_parser_set_data (parser_t *abstract, const unsigned char *data, unsigned int size) -{ - if (! parser_is_uwatec_galileo (abstract)) - return PARSER_STATUS_TYPE_MISMATCH; - - return PARSER_STATUS_SUCCESS; -} - - -static unsigned int -uwatec_galileo_fixsignbit (unsigned int x, unsigned int n) -{ - assert (n > 0); - - unsigned int signbit = (1 << (n - 1)); - unsigned int mask = (0xFFFFFFFF << n); - - // When turning a two's-complement number with a certain number - // of bits into one with more bits, the sign bit must be repeated - // in all the extra bits. - if ((x & signbit) == signbit) - return x | mask; - else - return x & ~mask; -} - - -static unsigned int -uwatec_galileo_identify (const unsigned char data[], unsigned int size) -{ - assert (size > 0); - - unsigned char value = data[0]; - - if ((value & 0x80) == 0) // Delta Depth - return 0; - - if ((value & 0xE0) == 0x80) // Delta RBT - return 1; - - switch (value & 0xF0) { - case 0xA0: // Delta Tank Pressure - return 2; - case 0xB0: // Delta Temperature - return 3; - case 0xC0: // Time - return 4; - case 0xD0: // Delta Heart Rate - return 5; - case 0xE0: // Alarms - return 6; - case 0xF0: - switch (value & 0xFF) { - case 0xF0: // More Alarms - return 7; - case 0xF1: // Absolute Depth - return 8; - case 0xF2: // Absolute RBT - return 9; - case 0xF3: // Absolute Temperature - return 10; - case 0xF4: // Absolute Pressure T1 - return 11; - case 0xF5: // Absolute Pressure T2 - return 12; - case 0xF6: // Absolute Pressure T3 - return 13; - case 0xF7: // Absolute Heart Rate - return 14; - case 0xF8: // Compass Bearing - return 15; - case 0xF9: // Even More Alarms - return 16; - } - break; - } - - assert (0); - - return (unsigned int) -1; -} - - -typedef enum { - DELTA_TANK_PRESSURE_DEPTH, - DELTA_RBT, - DELTA_TEMPERATURE, - DELTA_TANK_PRESSURE, - DELTA_DEPTH, - DELTA_HEARTRATE, - BEARING, - ALARMS, - TIME, - ABSOLUTE_DEPTH, - ABSOLUTE_TEMPERATURE, - ABSOLUTE_TANK_1_PRESSURE, - ABSOLUTE_TANK_2_PRESSURE, - ABSOLUTE_TANK_D_PRESSURE, - ABSOLUTE_RBT, - ABSOLUTE_HEARTRATE -} uwatec_galileo_sample_t; - -typedef struct uwatec_galileo_sample_info_t { - uwatec_galileo_sample_t type; - unsigned int ntypebits; - unsigned int extrabytes; -} uwatec_galileo_sample_info_t; - -static const -uwatec_galileo_sample_info_t uwatec_galileo_sol_table [] = { - {DELTA_DEPTH, 1, 0}, // 0ddd dddd - {DELTA_RBT, 3, 0}, // 100d dddd - {DELTA_TANK_PRESSURE, 4, 0}, // 1010 dddd - {DELTA_TEMPERATURE, 4, 0}, // 1011 dddd - {TIME, 4, 0}, // 1100 dddd - {DELTA_HEARTRATE, 4, 0}, // 1101 dddd - {ALARMS, 4, 0}, // 1110 dddd - {ALARMS, 8, 1}, // 1111 0000 dddddddd - {ABSOLUTE_DEPTH, 8, 2}, // 1111 0001 dddddddd dddddddd - {ABSOLUTE_RBT, 8, 1}, // 1111 0010 dddddddd - {ABSOLUTE_TEMPERATURE, 8, 2}, // 1111 0011 dddddddd dddddddd - {ABSOLUTE_TANK_1_PRESSURE, 8, 2}, // 1111 0100 dddddddd dddddddd - {ABSOLUTE_TANK_2_PRESSURE, 8, 2}, // 1111 0101 dddddddd dddddddd - {ABSOLUTE_TANK_D_PRESSURE, 8, 2}, // 1111 0110 dddddddd dddddddd - {ABSOLUTE_HEARTRATE, 8, 1}, // 1111 0111 dddddddd - {BEARING, 8, 2}, // 1111 1000 dddddddd dddddddd - {ALARMS, 8, 1}, // 1111 1001 dddddddd -}; - -static parser_status_t -uwatec_galileo_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata) -{ - uwatec_galileo_parser_t *parser = (uwatec_galileo_parser_t*) abstract; - - if (! parser_is_uwatec_galileo (abstract)) - return PARSER_STATUS_TYPE_MISMATCH; - - const unsigned char *data = abstract->data; - unsigned int size = abstract->size; - - const uwatec_galileo_sample_info_t *table = NULL; - unsigned int entries = 0; - unsigned int header = 0; - - // Load the correct table. - switch (parser->model) { - case 0x11: // Galileo Sol - header = 152; - table = uwatec_galileo_sol_table; - entries = NELEMENTS (uwatec_galileo_sol_table); - break; - default: - return PARSER_STATUS_ERROR; - } - - int complete = 1; - int calibrated = 0; - - unsigned int time = 0; - unsigned int rbt = 0; - unsigned int tank = 0; - double depth = 0, depth_calibration = 0; - double temperature = 0; - double pressure = 0; - unsigned int heartrate = 0; - unsigned char alarms = 0; - - unsigned int offset = header; - while (offset < size) { - parser_sample_value_t sample = {0}; - - // Process the type bits in the bitstream. - unsigned int id = uwatec_galileo_identify (data + offset, size - offset); - assert (id < entries); - - // Skip the processed type bytes. - offset += table[id].ntypebits / NBITS; - - // Process the remaining data bits. - unsigned int nbits = 0; - unsigned int value = 0; - unsigned int n = table[id].ntypebits % NBITS; - if (n > 0) { - nbits = NBITS - n; - value = data[offset] & (0xFF >> n); - offset++; - } - - // Process the extra data bytes. - assert (offset + table[id].extrabytes <= size); - for (unsigned int i = 0; i < table[id].extrabytes; ++i) { - nbits += NBITS; - value <<= NBITS; - value += data[offset]; - offset++; - } - - // Fix the sign bit. - signed int svalue = uwatec_galileo_fixsignbit (value, nbits); - - if (complete && table[id].type != TIME) { - complete = 0; - sample.time = time; - if (callback) callback (SAMPLE_TYPE_TIME, sample, userdata); - } - - // Parse the value. - switch (table[id].type) { - case DELTA_TANK_PRESSURE_DEPTH: - pressure += ((signed char) ((svalue >> NBITS) & 0xFF)) / 4.0; - depth += ((signed char) (svalue & 0xFF)) / 50.0; - sample.pressure.tank = tank; - sample.pressure.value = pressure; - if (callback) callback (SAMPLE_TYPE_PRESSURE, sample, userdata); - sample.depth = depth - depth_calibration; - if (callback) callback (SAMPLE_TYPE_DEPTH, sample, userdata); - complete = 1; - time += 4; - break; - case DELTA_RBT: - rbt += svalue; - sample.rbt = rbt; - if (callback) callback (SAMPLE_TYPE_RBT, sample, userdata); - break; - case DELTA_TEMPERATURE: - temperature += svalue / 2.5; - sample.temperature = temperature; - if (callback) callback (SAMPLE_TYPE_TEMPERATURE, sample, userdata); - break; - case DELTA_TANK_PRESSURE: - pressure += svalue / 4.0; - sample.pressure.tank = tank; - sample.pressure.value = pressure; - if (callback) callback (SAMPLE_TYPE_PRESSURE, sample, userdata); - break; - case DELTA_DEPTH: - depth += svalue / 50.0; - sample.depth = depth - depth_calibration; - if (callback) callback (SAMPLE_TYPE_DEPTH, sample, userdata); - complete = 1; - time += 4; - break; - case DELTA_HEARTRATE: - heartrate += svalue; - sample.heartbeat = heartrate; - if (callback) callback (SAMPLE_TYPE_HEARTBEAT, sample, userdata); - break; - case BEARING: - sample.bearing = value; - if (callback) callback (SAMPLE_TYPE_BEARING, sample, userdata); - break; - case ALARMS: - alarms = value; - sample.vendor.type = SAMPLE_VENDOR_UWATEC_GALILEO; - sample.vendor.size = sizeof (alarms); - sample.vendor.data = &alarms; - if (callback) callback (SAMPLE_TYPE_VENDOR, sample, userdata); - break; - case TIME: - complete = 1; - time += value * 4; - break; - case ABSOLUTE_DEPTH: - depth = value / 50.0; - if (!calibrated) { - calibrated = 1; - depth_calibration = depth; - } - sample.depth = depth - depth_calibration; - if (callback) callback (SAMPLE_TYPE_DEPTH, sample, userdata); - complete = 1; - time += 4; - break; - case ABSOLUTE_TEMPERATURE: - temperature = value / 2.5; - sample.temperature = temperature; - if (callback) callback (SAMPLE_TYPE_TEMPERATURE, sample, userdata); - break; - case ABSOLUTE_TANK_D_PRESSURE: - tank = 2; - pressure = value / 4.0; - sample.pressure.tank = tank; - sample.pressure.value = pressure; - if (callback) callback (SAMPLE_TYPE_PRESSURE, sample, userdata); - break; - case ABSOLUTE_TANK_2_PRESSURE: - tank = 1; - pressure = value / 4.0; - sample.pressure.tank = tank; - sample.pressure.value = pressure; - if (callback) callback (SAMPLE_TYPE_PRESSURE, sample, userdata); - break; - case ABSOLUTE_TANK_1_PRESSURE: - tank = 0; - pressure = value / 4.0; - sample.pressure.tank = tank; - sample.pressure.value = pressure; - if (callback) callback (SAMPLE_TYPE_PRESSURE, sample, userdata); - break; - case ABSOLUTE_RBT: - rbt = value; - sample.rbt = rbt; - if (callback) callback (SAMPLE_TYPE_RBT, sample, userdata); - break; - case ABSOLUTE_HEARTRATE: - heartrate = value; - sample.heartbeat = heartrate; - if (callback) callback (SAMPLE_TYPE_HEARTBEAT, sample, userdata); - break; - default: - WARNING ("Unknown sample type."); - break; - } - } - - assert (offset == size); - - return PARSER_STATUS_SUCCESS; -} diff --git a/src/uwatec_smart.h b/src/uwatec_smart.h index 310cd73..ef7328d 100644 --- a/src/uwatec_smart.h +++ b/src/uwatec_smart.h @@ -49,9 +49,6 @@ uwatec_smart_extract_dives (const unsigned char data[], unsigned int size, dive_ parser_status_t uwatec_smart_parser_create (parser_t **parser, unsigned int model); -parser_status_t -uwatec_galileo_parser_create (parser_t **parser, unsigned int model); - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 3d76bc1..4929674 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -133,6 +133,62 @@ uwatec_smart_identify (const unsigned char data[], unsigned int size) } +static unsigned int +uwatec_galileo_identify (const unsigned char data[], unsigned int size) +{ + assert (size > 0); + + unsigned char value = data[0]; + + if ((value & 0x80) == 0) // Delta Depth + return 0; + + if ((value & 0xE0) == 0x80) // Delta RBT + return 1; + + switch (value & 0xF0) { + case 0xA0: // Delta Tank Pressure + return 2; + case 0xB0: // Delta Temperature + return 3; + case 0xC0: // Time + return 4; + case 0xD0: // Delta Heart Rate + return 5; + case 0xE0: // Alarms + return 6; + case 0xF0: + switch (value & 0xFF) { + case 0xF0: // More Alarms + return 7; + case 0xF1: // Absolute Depth + return 8; + case 0xF2: // Absolute RBT + return 9; + case 0xF3: // Absolute Temperature + return 10; + case 0xF4: // Absolute Pressure T1 + return 11; + case 0xF5: // Absolute Pressure T2 + return 12; + case 0xF6: // Absolute Pressure T3 + return 13; + case 0xF7: // Absolute Heart Rate + return 14; + case 0xF8: // Compass Bearing + return 15; + case 0xF9: // Even More Alarms + return 16; + } + break; + } + + assert (0); + + return (unsigned int) -1; +} + + static unsigned int uwatec_smart_fixsignbit (unsigned int x, unsigned int n) { @@ -157,6 +213,8 @@ typedef enum { DELTA_TEMPERATURE, DELTA_TANK_PRESSURE, DELTA_DEPTH, + DELTA_HEARTRATE, + BEARING, ALARMS, TIME, ABSOLUTE_DEPTH, @@ -164,7 +222,8 @@ typedef enum { ABSOLUTE_TANK_1_PRESSURE, ABSOLUTE_TANK_2_PRESSURE, ABSOLUTE_TANK_D_PRESSURE, - ABSOLUTE_RBT + ABSOLUTE_RBT, + ABSOLUTE_HEARTRATE } uwatec_smart_sample_t; typedef struct uwatec_smart_sample_info_t { @@ -233,6 +292,26 @@ uwatec_smart_sample_info_t uwatec_smart_tec_table [] = { {ABSOLUTE_RBT, 14, 1, 1}, // 11111111 111110dd dddddddd }; +static const +uwatec_smart_sample_info_t uwatec_galileo_sol_table [] = { + {DELTA_DEPTH, 1, 0, 0}, // 0ddd dddd + {DELTA_RBT, 3, 0, 0}, // 100d dddd + {DELTA_TANK_PRESSURE, 4, 0, 0}, // 1010 dddd + {DELTA_TEMPERATURE, 4, 0, 0}, // 1011 dddd + {TIME, 4, 0, 0}, // 1100 dddd + {DELTA_HEARTRATE, 4, 0, 0}, // 1101 dddd + {ALARMS, 4, 0, 0}, // 1110 dddd + {ALARMS, 8, 0, 1}, // 1111 0000 dddddddd + {ABSOLUTE_DEPTH, 8, 0, 2}, // 1111 0001 dddddddd dddddddd + {ABSOLUTE_RBT, 8, 0, 1}, // 1111 0010 dddddddd + {ABSOLUTE_TEMPERATURE, 8, 0, 2}, // 1111 0011 dddddddd dddddddd + {ABSOLUTE_TANK_1_PRESSURE, 8, 0, 2}, // 1111 0100 dddddddd dddddddd + {ABSOLUTE_TANK_2_PRESSURE, 8, 0, 2}, // 1111 0101 dddddddd dddddddd + {ABSOLUTE_TANK_D_PRESSURE, 8, 0, 2}, // 1111 0110 dddddddd dddddddd + {ABSOLUTE_HEARTRATE, 8, 0, 1}, // 1111 0111 dddddddd + {BEARING, 8, 0, 2}, // 1111 1000 dddddddd dddddddd + {ALARMS, 8, 0, 1}, // 1111 1001 dddddddd +}; static parser_status_t uwatec_smart_parser_samples_foreach (parser_t *abstract, sample_callback_t callback, void *userdata) @@ -256,6 +335,11 @@ uwatec_smart_parser_samples_foreach (parser_t *abstract, sample_callback_t callb table = uwatec_smart_pro_table; entries = NELEMENTS (uwatec_smart_pro_table); break; + case 0x11: // Galileo Sol + header = 152; + table = uwatec_galileo_sol_table; + entries = NELEMENTS (uwatec_galileo_sol_table); + break; case 0x12: // Aladin Tec, Prime header = 108; table = uwatec_smart_aladin_table; @@ -285,15 +369,23 @@ uwatec_smart_parser_samples_foreach (parser_t *abstract, sample_callback_t callb double depth = 0, depth_calibration = 0; double temperature = 0; double pressure = 0; + unsigned int heartrate = 0; unsigned char alarms = 0; unsigned int offset = header; while (offset < size) { parser_sample_value_t sample = {0}; - // Count the number of type bits in the bitstream. - unsigned int id = uwatec_smart_identify (data + offset, size - offset); - assert (id < entries); + // Process the type bits in the bitstream. + unsigned int id = 0; + if (parser->model == 0x11) { + // Uwatec Galileo + id = uwatec_galileo_identify (data + offset, size - offset); + } else { + // Uwatec Smart + id = uwatec_smart_identify (data + offset, size - offset); + } + assert (id < entries); // Skip the processed type bytes. offset += table[id].ntypebits / NBITS; @@ -368,6 +460,15 @@ uwatec_smart_parser_samples_foreach (parser_t *abstract, sample_callback_t callb complete = 1; time += 4; break; + case DELTA_HEARTRATE: + heartrate += svalue; + sample.heartbeat = heartrate; + if (callback) callback (SAMPLE_TYPE_HEARTBEAT, sample, userdata); + break; + case BEARING: + sample.bearing = value; + if (callback) callback (SAMPLE_TYPE_BEARING, sample, userdata); + break; case ALARMS: alarms = value; sample.vendor.type = SAMPLE_VENDOR_UWATEC_SMART; @@ -421,6 +522,11 @@ uwatec_smart_parser_samples_foreach (parser_t *abstract, sample_callback_t callb sample.rbt = rbt; if (callback) callback (SAMPLE_TYPE_RBT, sample, userdata); break; + case ABSOLUTE_HEARTRATE: + heartrate = value; + sample.heartbeat = heartrate; + if (callback) callback (SAMPLE_TYPE_HEARTBEAT, sample, userdata); + break; default: WARNING ("Unknown sample type."); break;