diff options
author | Dirk Hohndel <dirk@hohndel.org> | 2016-04-04 22:02:03 -0700 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2016-04-04 22:33:58 -0700 |
commit | 7be962bfc2879a72c32ff67518731347dcdff6de (patch) | |
tree | d05bf7ab234a448ee37a15b608e2b939f2285d07 /subsurface-core/cochran.c | |
parent | 2d760a7bff71c46c5aeba37c40d236ea16eefea2 (diff) | |
download | subsurface-7be962bfc2879a72c32ff67518731347dcdff6de.tar.gz |
Move subsurface-core to core and qt-mobile to mobile-widgets
Having subsurface-core as a directory name really messes with
autocomplete and is obviously redundant. Simmilarly, qt-mobile caused an
autocomplete conflict and also was inconsistent with the desktop-widget
name for the directory containing the "other" UI.
And while cleaning up the resulting change in the path name for include
files, I decided to clean up those even more to make them consistent
overall.
This could have been handled in more commits, but since this requires a
make clean before the build, it seemed more sensible to do it all in one.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'subsurface-core/cochran.c')
-rw-r--r-- | subsurface-core/cochran.c | 809 |
1 files changed, 0 insertions, 809 deletions
diff --git a/subsurface-core/cochran.c b/subsurface-core/cochran.c deleted file mode 100644 index b42ed8233..000000000 --- a/subsurface-core/cochran.c +++ /dev/null @@ -1,809 +0,0 @@ -// Clang has a bug on zero-initialization of C structs. -#pragma clang diagnostic ignored "-Wmissing-field-initializers" - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include "dive.h" -#include "file.h" -#include "units.h" -#include "gettext.h" -#include "cochran.h" -#include "divelist.h" - -#include <libdivecomputer/parser.h> - -#define POUND 0.45359237 -#define FEET 0.3048 -#define INCH 0.0254 -#define GRAVITY 9.80665 -#define ATM 101325.0 -#define BAR 100000.0 -#define FSW (ATM / 33.0) -#define MSW (BAR / 10.0) -#define PSI ((POUND * GRAVITY) / (INCH * INCH)) - -// Some say 0x4a14 and 0x4b14 are the right number for this offset -// This works with CAN files from Analyst 4.01v and computers -// such as Commander, Gemini, EMC-16, and EMC-20H -#define LOG_ENTRY_OFFSET 0x4914 - -enum cochran_type { - TYPE_GEMINI, - TYPE_COMMANDER, - TYPE_EMC -}; - -struct config { - enum cochran_type type; - unsigned int logbook_size; - unsigned int sample_size; -} config; - - -// Convert 4 bytes into an INT -#define array_uint16_le(p) ((unsigned int) (p)[0] \ - + ((p)[1]<<8) ) -#define array_uint32_le(p) ((unsigned int) (p)[0] \ - + ((p)[1]<<8) + ((p)[2]<<16) \ - + ((p)[3]<<24)) - -/* - * The Cochran file format is designed to be annoying to read. It's roughly: - * - * 0x00000: room for 65534 4-byte words, giving the starting offsets - * of the dives themselves. - * - * 0x3fff8: the size of the file + 1 - * 0x3ffff: 0 (high 32 bits of filesize? Bogus: the offsets into the file - * are 32-bit, so it can't be a large file anyway) - * - * 0x40000: byte 0x46 - * 0x40001: "block 0": 256 byte encryption key - * 0x40101: the random modulus, or length of the key to use - * 0x40102: block 1: Version and date of Analyst and a feature string identifying - * the computer features and the features of the file - * 0x40138: Computer configuration page 1, 512 bytes - * 0x40338: Computer configuration page 2, 512 bytes - * 0x40538: Misc data (tissues) 1500 bytes - * 0x40b14: Ownership data 512 bytes ??? - * - * 0x4171c: Ownership data 512 bytes ??? <copy> - * - * 0x45415: Time stamp 17 bytes - * 0x45426: Computer configuration page 1, 512 bytes <copy> - * 0x45626: Computer configuration page 2, 512 bytes <copy> - * - */ -static unsigned int partial_decode(unsigned int start, unsigned int end, - const unsigned char *decode, unsigned offset, unsigned mod, - const unsigned char *buf, unsigned int size, unsigned char *dst) -{ - unsigned i, sum = 0; - - for (i = start; i < end; i++) { - unsigned char d = decode[offset++]; - if (i >= size) - break; - if (offset == mod) - offset = 0; - d += buf[i]; - if (dst) - dst[i] = d; - sum += d; - } - return sum; -} - -#ifdef COCHRAN_DEBUG - -#define hexchar(n) ("0123456789abcdef"[(n) & 15]) - -static int show_line(unsigned offset, const unsigned char *data, - unsigned size, int show_empty) -{ - unsigned char bits; - int i, off; - char buffer[120]; - - if (size > 16) - size = 16; - - bits = 0; - memset(buffer, ' ', sizeof(buffer)); - off = sprintf(buffer, "%06x ", offset); - for (i = 0; i < size; i++) { - char *hex = buffer + off + 3 * i; - char *asc = buffer + off + 50 + i; - unsigned char byte = data[i]; - - hex[0] = hexchar(byte >> 4); - hex[1] = hexchar(byte); - bits |= byte; - if (byte < 32 || byte > 126) - byte = '.'; - asc[0] = byte; - asc[1] = 0; - } - - if (bits) { - puts(buffer); - return 1; - } - if (show_empty) - puts("..."); - return 0; -} - -static void cochran_debug_write(const unsigned char *data, unsigned size) -{ - return; - - int show = 1, i; - for (i = 0; i < size; i += 16) - show = show_line(i, data + i, size - i, show); -} - -static void cochran_debug_sample(const char *s, unsigned int seconds) -{ - switch (config.type) { - case TYPE_GEMINI: - switch (seconds % 4) { - case 0: - printf("Hex: %02x %02x ", s[0], s[1]); - break; - case 1: - printf("Hex: %02x %02x ", s[0], s[1]); - break; - case 2: - printf("Hex: %02x %02x ", s[0], s[1]); - break; - case 3: - printf("Hex: %02x %02x ", s[0], s[1]); - break; - } - break; - case TYPE_COMMANDER: - switch (seconds % 2) { - case 0: - printf("Hex: %02x %02x ", s[0], s[1]); - break; - case 1: - printf("Hex: %02x %02x ", s[0], s[1]); - break; - } - break; - case TYPE_EMC: - switch (seconds % 2) { - case 0: - printf("Hex: %02x %02x %02x ", s[0], s[1], s[2]); - break; - case 1: - printf("Hex: %02x %02x %02x ", s[0], s[1], s[2]); - break; - } - break; - } - - printf ("%02dh %02dm %02ds: Depth: %-5.2f, ", seconds / 3660, - (seconds % 3660) / 60, seconds % 60, depth); -} - -#endif // COCHRAN_DEBUG - -static void cochran_parse_header(const unsigned char *decode, unsigned mod, - const unsigned char *in, unsigned size) -{ - unsigned char *buf = malloc(size); - - /* Do the "null decode" using a one-byte decode array of '\0' */ - /* Copies in plaintext, will be overwritten later */ - partial_decode(0, 0x0102, (const unsigned char *)"", 0, 1, in, size, buf); - - /* - * The header scrambling is different form the dive - * scrambling. Oh yay! - */ - partial_decode(0x0102, 0x010e, decode, 0, mod, in, size, buf); - partial_decode(0x010e, 0x0b14, decode, 0, mod, in, size, buf); - partial_decode(0x0b14, 0x1b14, decode, 0, mod, in, size, buf); - partial_decode(0x1b14, 0x2b14, decode, 0, mod, in, size, buf); - partial_decode(0x2b14, 0x3b14, decode, 0, mod, in, size, buf); - partial_decode(0x3b14, 0x5414, decode, 0, mod, in, size, buf); - partial_decode(0x5414, size, decode, 0, mod, in, size, buf); - - // Detect log type - switch (buf[0x133]) { - case '2': // Cochran Commander, version II log format - config.logbook_size = 256; - if (buf[0x132] == 0x10) { - config.type = TYPE_GEMINI; - config.sample_size = 2; // Gemini with tank PSI samples - } else { - config.type = TYPE_COMMANDER; - config.sample_size = 2; // Commander - } - break; - case '3': // Cochran EMC, version III log format - config.type = TYPE_EMC; - config.logbook_size = 512; - config.sample_size = 3; - break; - default: - printf ("Unknown log format v%c\n", buf[0x137]); - free(buf); - exit(1); - break; - } - -#ifdef COCHRAN_DEBUG - puts("Header\n======\n\n"); - cochran_debug_write(buf, size); -#endif - - free(buf); -} - -/* -* Bytes expected after a pre-dive event code -*/ -static int cochran_predive_event_bytes(unsigned char code) -{ - int x = 0; - int gem_event_bytes[15][2] = {{0x00, 10}, {0x02, 17}, {0x08, 18}, - {0x09, 18}, {0x0c, 18}, {0x0d, 18}, - {0x0e, 18}, - {-1, 0}}; - int cmdr_event_bytes[15][2] = {{0x00, 16}, {0x01, 20}, {0x02, 17}, - {0x03, 16}, {0x06, 18}, {0x07, 18}, - {0x08, 18}, {0x09, 18}, {0x0a, 18}, - {0x0b, 20}, {0x0c, 18}, {0x0d, 18}, - {0x0e, 18}, {0x10, 20}, - {-1, 0}}; - int emc_event_bytes[15][2] = {{0x00, 18}, {0x01, 22}, {0x02, 19}, - {0x03, 18}, {0x06, 20}, {0x07, 20}, - {0x0a, 20}, {0x0b, 20}, {0x0f, 18}, - {0x10, 20}, - {-1, 0}}; - - switch (config.type) { - case TYPE_GEMINI: - while (gem_event_bytes[x][0] != code && gem_event_bytes[x][0] != -1) - x++; - return gem_event_bytes[x][1]; - break; - case TYPE_COMMANDER: - while (cmdr_event_bytes[x][0] != code && cmdr_event_bytes[x][0] != -1) - x++; - return cmdr_event_bytes[x][1]; - break; - case TYPE_EMC: - while (emc_event_bytes[x][0] != code && emc_event_bytes[x][0] != -1) - x++; - return emc_event_bytes[x][1]; - break; - } - - return 0; -} - -int cochran_dive_event_bytes(unsigned char event) -{ - return (event == 0xAD || event == 0xAB) ? 4 : 0; -} - -static void cochran_dive_event(struct divecomputer *dc, const unsigned char *s, - unsigned int seconds, unsigned int *in_deco, - unsigned int *deco_ceiling, unsigned int *deco_time) -{ - switch (s[0]) { - case 0xC5: // Deco obligation begins - *in_deco = 1; - add_event(dc, seconds, SAMPLE_EVENT_DECOSTOP, - SAMPLE_FLAGS_BEGIN, 0, - QT_TRANSLATE_NOOP("gettextFromC", "deco stop")); - break; - case 0xDB: // Deco obligation ends - *in_deco = 0; - add_event(dc, seconds, SAMPLE_EVENT_DECOSTOP, - SAMPLE_FLAGS_END, 0, - QT_TRANSLATE_NOOP("gettextFromC", "deco stop")); - break; - case 0xAD: // Raise deco ceiling 10 ft - *deco_ceiling -= 10; // ft - *deco_time = (array_uint16_le(s + 3) + 1) * 60; - break; - case 0xAB: // Lower deco ceiling 10 ft - *deco_ceiling += 10; // ft - *deco_time = (array_uint16_le(s + 3) + 1) * 60; - break; - case 0xA8: // Entered Post Dive interval mode (surfaced) - break; - case 0xA9: // Exited PDI mode (re-submierged) - break; - case 0xBD: // Switched to normal PO2 setting - break; - case 0xC0: // Switched to FO2 21% mode (generally upon surface) - break; - case 0xC1: // "Ascent rate alarm - add_event(dc, seconds, SAMPLE_EVENT_ASCENT, - SAMPLE_FLAGS_BEGIN, 0, - QT_TRANSLATE_NOOP("gettextFromC", "ascent")); - break; - case 0xC2: // Low battery warning -#ifdef SAMPLE_EVENT_BATTERY - add_event(dc, seconds, SAMPLE_EVENT_BATTERY, - SAMPLE_FLAGS_NONE, 0, - QT_TRANSLATE_NOOP("gettextFromC", "battery")); -#endif - break; - case 0xC3: // CNS warning - add_event(dc, seconds, SAMPLE_EVENT_OLF, - SAMPLE_FLAGS_BEGIN, 0, - QT_TRANSLATE_NOOP("gettextFromC", "OLF")); - break; - case 0xC4: // Depth alarm begin - add_event(dc, seconds, SAMPLE_EVENT_MAXDEPTH, - SAMPLE_FLAGS_BEGIN, 0, - QT_TRANSLATE_NOOP("gettextFromC", "maxdepth")); - break; - case 0xC8: // PPO2 alarm begin - add_event(dc, seconds, SAMPLE_EVENT_PO2, - SAMPLE_FLAGS_BEGIN, 0, - QT_TRANSLATE_NOOP("gettextFromC", "pO₂")); - break; - case 0xCC: // Low cylinder 1 pressure"; - break; - case 0xCD: // Switch to deco blend setting - add_event(dc, seconds, SAMPLE_EVENT_GASCHANGE, - SAMPLE_FLAGS_NONE, 0, - QT_TRANSLATE_NOOP("gettextFromC", "gaschange")); - break; - case 0xCE: // NDL alarm begin - add_event(dc, seconds, SAMPLE_EVENT_RBT, - SAMPLE_FLAGS_BEGIN, 0, - QT_TRANSLATE_NOOP("gettextFromC", "rbt")); - break; - case 0xD0: // Breathing rate alarm begin - break; - case 0xD3: // Low gas 1 flow rate alarm begin"; - break; - case 0xD6: // Ceiling alarm begin - add_event(dc, seconds, SAMPLE_EVENT_CEILING, - SAMPLE_FLAGS_BEGIN, 0, - QT_TRANSLATE_NOOP("gettextFromC", "ceiling")); - break; - case 0xD8: // End decompression mode - *in_deco = 0; - add_event(dc, seconds, SAMPLE_EVENT_DECOSTOP, - SAMPLE_FLAGS_END, 0, - QT_TRANSLATE_NOOP("gettextFromC", "deco stop")); - break; - case 0xE1: // Ascent alarm end - add_event(dc, seconds, SAMPLE_EVENT_ASCENT, - SAMPLE_FLAGS_END, 0, - QT_TRANSLATE_NOOP("gettextFromC", "ascent")); - break; - case 0xE2: // Low transmitter battery alarm - add_event(dc, seconds, SAMPLE_EVENT_TRANSMITTER, - SAMPLE_FLAGS_BEGIN, 0, - QT_TRANSLATE_NOOP("gettextFromC", "transmitter")); - break; - case 0xE3: // Switch to FO2 mode - break; - case 0xE5: // Switched to PO2 mode - break; - case 0xE8: // PO2 too low alarm - add_event(dc, seconds, SAMPLE_EVENT_PO2, - SAMPLE_FLAGS_BEGIN, 0, - QT_TRANSLATE_NOOP("gettextFromC", "pO₂")); - break; - case 0xEE: // NDL alarm end - add_event(dc, seconds, SAMPLE_EVENT_RBT, - SAMPLE_FLAGS_END, 0, - QT_TRANSLATE_NOOP("gettextFromC", "rbt")); - break; - case 0xEF: // Switch to blend 2 - add_event(dc, seconds, SAMPLE_EVENT_GASCHANGE, - SAMPLE_FLAGS_NONE, 0, - QT_TRANSLATE_NOOP("gettextFromC", "gaschange")); - break; - case 0xF0: // Breathing rate alarm end - break; - case 0xF3: // Switch to blend 1 (often at dive start) - add_event(dc, seconds, SAMPLE_EVENT_GASCHANGE, - SAMPLE_FLAGS_NONE, 0, - QT_TRANSLATE_NOOP("gettextFromC", "gaschange")); - break; - case 0xF6: // Ceiling alarm end - add_event(dc, seconds, SAMPLE_EVENT_CEILING, - SAMPLE_FLAGS_END, 0, - QT_TRANSLATE_NOOP("gettextFromC", "ceiling")); - break; - default: - break; - } -} - -/* -* Parse sample data, extract events and build a dive -*/ -static void cochran_parse_samples(struct dive *dive, const unsigned char *log, - const unsigned char *samples, unsigned int size, - unsigned int *duration, double *max_depth, - double *avg_depth, double *min_temp) -{ - const unsigned char *s; - unsigned int offset = 0, seconds = 0; - double depth = 0, temp = 0, depth_sample = 0, psi = 0, sgc_rate = 0; - int ascent_rate = 0; - unsigned int ndl = 0; - unsigned int in_deco = 0, deco_ceiling = 0, deco_time = 0; - - struct divecomputer *dc = &dive->dc; - struct sample *sample; - - // Initialize stat variables - *max_depth = 0, *avg_depth = 0, *min_temp = 0xFF; - - // Get starting depth and temp (tank PSI???) - switch (config.type) { - case TYPE_GEMINI: - depth = (float) (log[CMD_START_DEPTH] - + log[CMD_START_DEPTH + 1] * 256) / 4; - temp = log[CMD_START_TEMP]; - psi = log[CMD_START_PSI] + log[CMD_START_PSI + 1] * 256; - sgc_rate = (float)(log[CMD_START_SGC] - + log[CMD_START_SGC + 1] * 256) / 2; - break; - case TYPE_COMMANDER: - depth = (float) (log[CMD_START_DEPTH] - + log[CMD_START_DEPTH + 1] * 256) / 4; - temp = log[CMD_START_TEMP]; - break; - - case TYPE_EMC: - depth = (float) log [EMC_START_DEPTH] / 256 - + log[EMC_START_DEPTH + 1]; - temp = log[EMC_START_TEMP]; - break; - } - - // Skip past pre-dive events - unsigned int x = 0; - if (samples[x] != 0x40) { - unsigned int c; - while ((samples[x] & 0x80) == 0 && samples[x] != 0x40 && x < size) { - c = cochran_predive_event_bytes(samples[x]) + 1; -#ifdef COCHRAN_DEBUG - printf("Predive event: ", samples[x]); - for (int y = 0; y < c; y++) printf("%02x ", samples[x + y]); - putchar('\n'); -#endif - x += c; - } - } - - // Now process samples - offset = x; - while (offset < size) { - s = samples + offset; - - // Start with an empty sample - sample = prepare_sample(dc); - sample->time.seconds = seconds; - - // Check for event - if (s[0] & 0x80) { - cochran_dive_event(dc, s, seconds, &in_deco, &deco_ceiling, &deco_time); - offset += cochran_dive_event_bytes(s[0]) + 1; - continue; - } - - // Depth is in every sample - depth_sample = (float)(s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1); - depth += depth_sample; - -#ifdef COCHRAN_DEBUG - cochran_debug_sample(s, seconds); -#endif - - switch (config.type) { - case TYPE_COMMANDER: - switch (seconds % 2) { - case 0: // Ascent rate - ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1); - break; - case 1: // Temperature - temp = s[1] / 2 + 20; - break; - } - break; - case TYPE_GEMINI: - // Gemini with tank pressure and SAC rate. - switch (seconds % 4) { - case 0: // Ascent rate - ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1); - break; - case 2: // PSI change - psi -= (float)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 4; - break; - case 1: // SGC rate - sgc_rate -= (float)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 2; - break; - case 3: // Temperature - temp = (float)s[1] / 2 + 20; - break; - } - break; - case TYPE_EMC: - switch (seconds % 2) { - case 0: // Ascent rate - ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1); - break; - case 1: // Temperature - temp = (float)s[1] / 2 + 20; - break; - } - // Get NDL and deco information - switch (seconds % 24) { - case 20: - if (in_deco) { - // Fist stop time - //first_deco_time = (s[2] + s[5] * 256 + 1) * 60; // seconds - ndl = 0; - } else { - // NDL - ndl = (s[2] + s[5] * 256 + 1) * 60; // seconds - deco_time = 0; - } - break; - case 22: - if (in_deco) { - // Total stop time - deco_time = (s[2] + s[5] * 256 + 1) * 60; // seconds - ndl = 0; - } - break; - } - } - - // Track dive stats - if (depth > *max_depth) *max_depth = depth; - if (temp < *min_temp) *min_temp = temp; - *avg_depth = (*avg_depth * seconds + depth) / (seconds + 1); - - sample->depth.mm = depth * FEET * 1000; - sample->ndl.seconds = ndl; - sample->in_deco = in_deco; - sample->stoptime.seconds = deco_time; - sample->stopdepth.mm = deco_ceiling * FEET * 1000; - sample->temperature.mkelvin = C_to_mkelvin((temp - 32) / 1.8); - sample->sensor = 0; - sample->cylinderpressure.mbar = psi * PSI / 100; - - finish_sample(dc); - - offset += config.sample_size; - seconds++; - } - (void)ascent_rate; // mark the variable as unused - - if (seconds > 0) - *duration = seconds - 1; -} - -static void cochran_parse_dive(const unsigned char *decode, unsigned mod, - const unsigned char *in, unsigned size) -{ - unsigned char *buf = malloc(size); - struct dive *dive; - struct divecomputer *dc; - struct tm tm = {0}; - uint32_t csum[5]; - - double max_depth, avg_depth, min_temp; - unsigned int duration = 0, corrupt_dive = 0; - - /* - * The scrambling has odd boundaries. I think the boundaries - * match some data structure size, but I don't know. They were - * discovered the same way we dynamically discover the decode - * size: automatically looking for least random output. - * - * The boundaries are also this confused "off-by-one" thing, - * the same way the file size is off by one. It's as if the - * cochran software forgot to write one byte at the beginning. - */ - partial_decode(0, 0x0fff, decode, 1, mod, in, size, buf); - partial_decode(0x0fff, 0x1fff, decode, 0, mod, in, size, buf); - partial_decode(0x1fff, 0x2fff, decode, 0, mod, in, size, buf); - partial_decode(0x2fff, 0x48ff, decode, 0, mod, in, size, buf); - - /* - * This is not all the descrambling you need - the above are just - * what appears to be the fixed-size blocks. The rest is also - * scrambled, but there seems to be size differences in the data, - * so this just descrambles part of it: - */ - // Decode log entry (512 bytes + random prefix) - partial_decode(0x48ff, 0x4914 + config.logbook_size, decode, - 0, mod, in, size, buf); - - unsigned int sample_size = size - 0x4914 - config.logbook_size; - int g; - - // Decode sample data - partial_decode(0x4914 + config.logbook_size, size, decode, - 0, mod, in, size, buf); - -#ifdef COCHRAN_DEBUG - // Display pre-logbook data - puts("\nPre Logbook Data\n"); - cochran_debug_write(buf, 0x4914); - - // Display log book - puts("\nLogbook Data\n"); - cochran_debug_write(buf + 0x4914, config.logbook_size + 0x400); - - // Display sample data - puts("\nSample Data\n"); -#endif - - dive = alloc_dive(); - dc = &dive->dc; - - unsigned char *log = (buf + 0x4914); - - switch (config.type) { - case TYPE_GEMINI: - case TYPE_COMMANDER: - if (config.type == TYPE_GEMINI) { - dc->model = "Gemini"; - dc->deviceid = buf[0x18c] * 256 + buf[0x18d]; // serial no - fill_default_cylinder(&dive->cylinder[0]); - dive->cylinder[0].gasmix.o2.permille = (log[CMD_O2_PERCENT] / 256 - + log[CMD_O2_PERCENT + 1]) * 10; - dive->cylinder[0].gasmix.he.permille = 0; - } else { - dc->model = "Commander"; - dc->deviceid = array_uint32_le(buf + 0x31e); // serial no - for (g = 0; g < 2; g++) { - fill_default_cylinder(&dive->cylinder[g]); - dive->cylinder[g].gasmix.o2.permille = (log[CMD_O2_PERCENT + g * 2] / 256 - + log[CMD_O2_PERCENT + g * 2 + 1]) * 10; - dive->cylinder[g].gasmix.he.permille = 0; - } - } - - tm.tm_year = log[CMD_YEAR]; - tm.tm_mon = log[CMD_MON] - 1; - tm.tm_mday = log[CMD_DAY]; - tm.tm_hour = log[CMD_HOUR]; - tm.tm_min = log[CMD_MIN]; - tm.tm_sec = log[CMD_SEC]; - tm.tm_isdst = -1; - - dive->when = dc->when = utc_mktime(&tm); - dive->number = log[CMD_NUMBER] + log[CMD_NUMBER + 1] * 256 + 1; - dc->duration.seconds = (log[CMD_BT] + log[CMD_BT + 1] * 256) * 60; - dc->surfacetime.seconds = (log[CMD_SIT] + log[CMD_SIT + 1] * 256) * 60; - dc->maxdepth.mm = (log[CMD_MAX_DEPTH] + - log[CMD_MAX_DEPTH + 1] * 256) / 4 * FEET * 1000; - dc->meandepth.mm = (log[CMD_AVG_DEPTH] + - log[CMD_AVG_DEPTH + 1] * 256) / 4 * FEET * 1000; - dc->watertemp.mkelvin = C_to_mkelvin((log[CMD_MIN_TEMP] / 32) - 1.8); - dc->surface_pressure.mbar = ATM / BAR * pow(1 - 0.0000225577 - * (double) log[CMD_ALTITUDE] * 250 * FEET, 5.25588) * 1000; - dc->salinity = 10000 + 150 * log[CMD_WATER_CONDUCTIVITY]; - - SHA1(log + CMD_NUMBER, 2, (unsigned char *)csum); - dc->diveid = csum[0]; - - if (log[CMD_MAX_DEPTH] == 0xff && log[CMD_MAX_DEPTH + 1] == 0xff) - corrupt_dive = 1; - - break; - case TYPE_EMC: - dc->model = "EMC"; - dc->deviceid = array_uint32_le(buf + 0x31e); // serial no - for (g = 0; g < 4; g++) { - fill_default_cylinder(&dive->cylinder[g]); - dive->cylinder[g].gasmix.o2.permille = - (log[EMC_O2_PERCENT + g * 2] / 256 - + log[EMC_O2_PERCENT + g * 2 + 1]) * 10; - dive->cylinder[g].gasmix.he.permille = - (log[EMC_HE_PERCENT + g * 2] / 256 - + log[EMC_HE_PERCENT + g * 2 + 1]) * 10; - } - - tm.tm_year = log[EMC_YEAR]; - tm.tm_mon = log[EMC_MON] - 1; - tm.tm_mday = log[EMC_DAY]; - tm.tm_hour = log[EMC_HOUR]; - tm.tm_min = log[EMC_MIN]; - tm.tm_sec = log[EMC_SEC]; - tm.tm_isdst = -1; - - dive->when = dc->when = utc_mktime(&tm); - dive->number = log[EMC_NUMBER] + log[EMC_NUMBER + 1] * 256 + 1; - dc->duration.seconds = (log[EMC_BT] + log[EMC_BT + 1] * 256) * 60; - dc->surfacetime.seconds = (log[EMC_SIT] + log[EMC_SIT + 1] * 256) * 60; - dc->maxdepth.mm = (log[EMC_MAX_DEPTH] + - log[EMC_MAX_DEPTH + 1] * 256) / 4 * FEET * 1000; - dc->meandepth.mm = (log[EMC_AVG_DEPTH] + - log[EMC_AVG_DEPTH + 1] * 256) / 4 * FEET * 1000; - dc->watertemp.mkelvin = C_to_mkelvin((log[EMC_MIN_TEMP] - 32) / 1.8); - dc->surface_pressure.mbar = ATM / BAR * pow(1 - 0.0000225577 - * (double) log[EMC_ALTITUDE] * 250 * FEET, 5.25588) * 1000; - dc->salinity = 10000 + 150 * (log[EMC_WATER_CONDUCTIVITY] & 0x3); - - SHA1(log + EMC_NUMBER, 2, (unsigned char *)csum); - dc->diveid = csum[0]; - - if (log[EMC_MAX_DEPTH] == 0xff && log[EMC_MAX_DEPTH + 1] == 0xff) - corrupt_dive = 1; - - break; - } - - cochran_parse_samples(dive, buf + 0x4914, buf + 0x4914 - + config.logbook_size, sample_size, - &duration, &max_depth, &avg_depth, &min_temp); - - // Check for corrupt dive - if (corrupt_dive) { - dc->maxdepth.mm = max_depth * FEET * 1000; - dc->meandepth.mm = avg_depth * FEET * 1000; - dc->watertemp.mkelvin = C_to_mkelvin((min_temp - 32) / 1.8); - dc->duration.seconds = duration; - } - - dive->downloaded = true; - record_dive(dive); - mark_divelist_changed(true); - - free(buf); -} - -int try_to_open_cochran(const char *filename, struct memblock *mem) -{ - (void) filename; - unsigned int i; - unsigned int mod; - unsigned int *offsets, dive1, dive2; - unsigned char *decode = mem->buffer + 0x40001; - - if (mem->size < 0x40000) - return 0; - - offsets = (unsigned int *) mem->buffer; - dive1 = offsets[0]; - dive2 = offsets[1]; - - if (dive1 < 0x40000 || dive2 < dive1 || dive2 > mem->size) - return 0; - - mod = decode[0x100] + 1; - cochran_parse_header(decode, mod, mem->buffer + 0x40000, dive1 - 0x40000); - - // Decode each dive - for (i = 0; i < 65534; i++) { - dive1 = offsets[i]; - dive2 = offsets[i + 1]; - if (dive2 < dive1) - break; - if (dive2 > mem->size) - break; - - cochran_parse_dive(decode, mod, mem->buffer + dive1, - dive2 - dive1); - } - - return 1; // no further processing needed -} |