| 
									
										
										
										
											2017-04-27 20:18:03 +02:00
										 |  |  | // SPDX-License-Identifier: GPL-2.0
 | 
					
						
							| 
									
										
										
										
											2017-03-11 22:08:31 +02:00
										 |  |  | #ifdef __clang__
 | 
					
						
							| 
									
										
										
										
											2016-03-09 15:16:41 -03:00
										 |  |  | // Clang has a bug on zero-initialization of C structs.
 | 
					
						
							|  |  |  | #pragma clang diagnostic ignored "-Wmissing-field-initializers"
 | 
					
						
							| 
									
										
										
										
											2017-03-11 22:08:31 +02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-03-09 15:16:41 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2012-01-27 14:02:50 -08:00
										 |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <sys/types.h>
 | 
					
						
							|  |  |  | #include <sys/stat.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "dive.h"
 | 
					
						
							|  |  |  | #include "file.h"
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | #include "units.h"
 | 
					
						
							|  |  |  | #include "gettext.h"
 | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | #include "cochran.h"
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | #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
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | #define array_uint16_le(p) ((unsigned int) (p)[0] \
 | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 			    + ((p)[1]<<8) ) | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | #define array_uint32_le(p) ((unsigned int) (p)[0] \
 | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 			    + ((p)[1]<<8) + ((p)[2]<<16) \ | 
					
						
							|  |  |  | 			    + ((p)[3]<<24)) | 
					
						
							| 
									
										
										
										
											2012-01-27 18:27:30 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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) | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  |  * 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> | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static unsigned int partial_decode(unsigned int start, unsigned int end, | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 				   const unsigned char *decode, unsigned offset, unsigned mod, | 
					
						
							|  |  |  | 				   const unsigned char *buf, unsigned int size, unsigned char *dst) | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned i, sum = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-27 20:09:57 -08:00
										 |  |  | 	for (i = start; i < end; i++) { | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 		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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | #ifdef COCHRAN_DEBUG
 | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-27 20:09:57 -08:00
										 |  |  | #define hexchar(n) ("0123456789abcdef"[(n) & 15])
 | 
					
						
							| 
									
										
										
										
											2012-01-27 14:02:50 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | static int show_line(unsigned offset, const unsigned char *data, | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 		     unsigned size, int show_empty) | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-01-27 14:02:50 -08:00
										 |  |  | 	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++) { | 
					
						
							| 
									
										
										
										
											2014-02-27 20:09:57 -08:00
										 |  |  | 		char *hex = buffer + off + 3 * i; | 
					
						
							| 
									
										
										
										
											2012-01-27 14:02:50 -08:00
										 |  |  | 		char *asc = buffer + off + 50 + i; | 
					
						
							|  |  |  | 		unsigned char byte = data[i]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-27 20:09:57 -08:00
										 |  |  | 		hex[0] = hexchar(byte >> 4); | 
					
						
							| 
									
										
										
										
											2012-01-27 14:02:50 -08:00
										 |  |  | 		hex[1] = hexchar(byte); | 
					
						
							|  |  |  | 		bits |= byte; | 
					
						
							|  |  |  | 		if (byte < 32 || byte > 126) | 
					
						
							|  |  |  | 			byte = '.'; | 
					
						
							|  |  |  | 		asc[0] = byte; | 
					
						
							|  |  |  | 		asc[1] = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-27 15:11:34 -08:00
										 |  |  | 	if (bits) { | 
					
						
							| 
									
										
										
										
											2012-01-27 14:02:50 -08:00
										 |  |  | 		puts(buffer); | 
					
						
							| 
									
										
										
										
											2012-01-27 15:11:34 -08:00
										 |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (show_empty) | 
					
						
							|  |  |  | 		puts("..."); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2012-01-27 14:02:50 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | static void cochran_debug_write(const unsigned char *data, unsigned size) | 
					
						
							| 
									
										
										
										
											2012-01-27 14:02:50 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	int show = 1,  i; | 
					
						
							| 
									
										
										
										
											2012-01-27 15:11:34 -08:00
										 |  |  | 	for (i = 0; i < size; i += 16) | 
					
						
							|  |  |  | 		show = show_line(i, data + i, size - i, show); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | static void cochran_debug_sample(const char *s, unsigned int sample_cnt) | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 	switch (config.type) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	case TYPE_GEMINI: | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 		switch (sample_cnt % 4) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		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: | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 		switch (sample_cnt % 2) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		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: | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 		switch (sample_cnt % 2) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 	printf ("%02dh %02dm %02ds: Depth: %-5.2f, ", sample_cnt / 3660, | 
					
						
							|  |  |  | 		(sample_cnt % 3660) / 60, sample_cnt % 60, depth); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif  // COCHRAN_DEBUG
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | static void cochran_parse_header(const unsigned char *decode, unsigned mod, | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 				 const unsigned char *in, unsigned size) | 
					
						
							| 
									
										
										
										
											2012-01-27 15:11:34 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	unsigned char *buf = malloc(size); | 
					
						
							| 
									
										
										
										
											2012-01-27 15:11:34 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Do the "null decode" using a one-byte decode array of '\0' */ | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	/* Copies in plaintext, will be overwritten later */ | 
					
						
							| 
									
										
										
										
											2015-05-28 14:59:08 +02:00
										 |  |  | 	partial_decode(0, 0x0102, (const unsigned char *)"", 0, 1, in, size, buf); | 
					
						
							| 
									
										
										
										
											2012-01-27 15:11:34 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * The header scrambling is different form the dive | 
					
						
							|  |  |  | 	 * scrambling. Oh yay! | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	partial_decode(0x0102, 0x010e, decode, 0, mod, in, size, buf); | 
					
						
							| 
									
										
										
										
											2012-01-27 17:36:42 -08:00
										 |  |  | 	partial_decode(0x010e, 0x0b14, decode, 0, mod, in, size, buf); | 
					
						
							| 
									
										
										
										
											2012-01-27 15:11:34 -08:00
										 |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	partial_decode(0x5414,  size, decode, 0, mod, in, size, buf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Detect log type
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 	switch (buf[0x133]) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	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]); | 
					
						
							| 
									
										
										
										
											2015-03-23 20:17:27 +02:00
										 |  |  | 		free(buf); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		exit(1); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-01-27 15:11:34 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | #ifdef COCHRAN_DEBUG
 | 
					
						
							|  |  |  | 	puts("Header\n======\n\n"); | 
					
						
							|  |  |  | 	cochran_debug_write(buf, size); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2012-01-27 15:11:34 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	free(buf); | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-18 16:52:41 -07:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | * Bytes expected after a pre-dive event code | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | static int cochran_predive_event_bytes(unsigned char code) | 
					
						
							| 
									
										
										
										
											2012-06-18 16:52:41 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	int x = 0; | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 	int cmdr_event_bytes[15][2] = {{0x00, 16}, {0x01, 20}, {0x02, 17}, | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 				       {0x03, 16}, {0x06, 18}, {0x07, 18}, | 
					
						
							|  |  |  | 				       {0x08, 18}, {0x09, 18}, {0x0a, 18}, | 
					
						
							|  |  |  | 				       {0x0b, 18}, {0x0c, 18}, {0x0d, 18}, | 
					
						
							|  |  |  | 				       {0x0e, 18}, {0x10, 20}, | 
					
						
							|  |  |  | 				       {-1,  0}}; | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 	int emc_event_bytes[15][2] =  {{0x00, 18}, {0x01, 22}, {0x02, 19}, | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 				       {0x03, 18}, {0x06, 20}, {0x07, 20}, | 
					
						
							|  |  |  | 				       {0x0a, 20}, {0x0b, 20}, {0x0f, 18}, | 
					
						
							|  |  |  | 				       {0x10, 20}, | 
					
						
							|  |  |  | 				       {-1,  0}}; | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (config.type) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	case TYPE_GEMINI: | 
					
						
							|  |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2012-06-18 16:52:41 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2012-06-18 16:52:41 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | int cochran_dive_event_bytes(unsigned char event) | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 	return (event == 0xAD || event == 0xAB) ? 4 : 0; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void cochran_dive_event(struct divecomputer *dc, const unsigned char *s, | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 			       unsigned int seconds, unsigned int *in_deco, | 
					
						
							|  |  |  | 			       unsigned int *deco_ceiling, unsigned int *deco_time) | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 	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
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | #ifdef SAMPLE_EVENT_BATTERY
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 		add_event(dc, seconds, SAMPLE_EVENT_BATTERY, | 
					
						
							|  |  |  | 			SAMPLE_FLAGS_NONE, 0, | 
					
						
							|  |  |  | 			QT_TRANSLATE_NOOP("gettextFromC", "battery")); | 
					
						
							| 
									
										
										
										
											2012-01-27 18:27:30 -08:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 		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, | 
					
						
							| 
									
										
										
										
											2015-01-25 17:00:19 +02:00
										 |  |  | 			QT_TRANSLATE_NOOP("gettextFromC", "pO₂")); | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 		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, | 
					
						
							| 
									
										
										
										
											2015-01-25 17:00:19 +02:00
										 |  |  | 			QT_TRANSLATE_NOOP("gettextFromC", "pO₂")); | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 		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; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  | * Parse sample data, extract events and build a dive | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | static void cochran_parse_samples(struct dive *dive, const unsigned char *log, | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 				  const unsigned char *samples, unsigned int size, | 
					
						
							|  |  |  | 				  unsigned int *duration, double *max_depth, | 
					
						
							|  |  |  | 				  double *avg_depth, double *min_temp) | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	const unsigned char *s; | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 	unsigned int offset = 0, profile_period = 1, sample_cnt = 0; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	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???)
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 	switch (config.type) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	case TYPE_GEMINI: | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 		profile_period = log[CMD_PROFILE_PERIOD]; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case TYPE_COMMANDER: | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		depth = (float) (log[CMD_START_DEPTH] | 
					
						
							|  |  |  | 			+ log[CMD_START_DEPTH + 1] * 256) / 4; | 
					
						
							|  |  |  | 		temp = log[CMD_START_TEMP]; | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 		profile_period = log[CMD_PROFILE_PERIOD]; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case TYPE_EMC: | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		depth = (float) log [EMC_START_DEPTH] / 256 | 
					
						
							|  |  |  | 			+ log[EMC_START_DEPTH + 1]; | 
					
						
							|  |  |  | 		temp = log[EMC_START_TEMP]; | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 		profile_period = log[EMC_PROFILE_PERIOD]; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Skip past pre-dive events
 | 
					
						
							|  |  |  | 	unsigned int x = 0; | 
					
						
							| 
									
										
										
										
											2017-05-26 19:58:06 -04:00
										 |  |  | 	unsigned int c; | 
					
						
							|  |  |  | 	while (x < size && (samples[x] & 0x80) == 0 && samples[x] != 0x40) { | 
					
						
							|  |  |  | 		c = cochran_predive_event_bytes(samples[x]) + 1; | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | #ifdef COCHRAN_DEBUG
 | 
					
						
							|  |  |  | 		printf("Predive event: "); | 
					
						
							|  |  |  | 		for (unsigned int y = 0; y < c && x + y < size; y++) printf("%02x ", samples[x + y]); | 
					
						
							| 
									
										
										
										
											2017-05-26 19:58:06 -04:00
										 |  |  | 		putchar('\n'); | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 			x += c; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Now process samples
 | 
					
						
							|  |  |  | 	offset = x; | 
					
						
							| 
									
										
										
										
											2017-05-26 19:58:06 -04:00
										 |  |  | 	while (offset + config.sample_size < size) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		s = samples + offset; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Start with an empty sample
 | 
					
						
							|  |  |  | 		sample = prepare_sample(dc); | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 		sample->time.seconds = sample_cnt * profile_period; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// Check for event
 | 
					
						
							|  |  |  | 		if (s[0] & 0x80) { | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 			cochran_dive_event(dc, s, sample_cnt * profile_period, &in_deco, &deco_ceiling, &deco_time); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 			offset += cochran_dive_event_bytes(s[0]) + 1; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Depth is in every sample
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 		depth_sample = (float)(s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		depth += depth_sample; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef COCHRAN_DEBUG
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 		cochran_debug_sample(s, sample_cnt); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 		switch (config.type) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		case TYPE_COMMANDER: | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 			switch (sample_cnt % 2) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 			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.
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 			switch (sample_cnt % 4) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 			case 0:	// Ascent rate
 | 
					
						
							|  |  |  | 				ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case 2:	// PSI change
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 				psi -= (float)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 4; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			case 1:	// SGC rate
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 				sgc_rate -= (float)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 2; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			case 3:	// Temperature
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 				temp = (float)s[1] / 2 + 20; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case TYPE_EMC: | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 			switch (sample_cnt % 2) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 			case 0:	// Ascent rate
 | 
					
						
							|  |  |  | 				ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1); | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case 1:	// Temperature
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 				temp = (float)s[1] / 2 + 20; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// Get NDL and deco information
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 			switch (sample_cnt % 24) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 			case 20: | 
					
						
							| 
									
										
										
										
											2017-05-26 19:58:06 -04:00
										 |  |  | 				if (offset + 5 < size) { | 
					
						
							|  |  |  | 					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; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			case 22: | 
					
						
							| 
									
										
										
										
											2017-05-26 19:58:06 -04:00
										 |  |  | 				if (offset + 5 < size) { | 
					
						
							|  |  |  | 					if (in_deco) { | 
					
						
							|  |  |  | 						// Total stop time
 | 
					
						
							|  |  |  | 						deco_time = (s[2] + s[5] * 256 + 1) * 60; // seconds
 | 
					
						
							|  |  |  | 						ndl = 0; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Track dive stats
 | 
					
						
							|  |  |  | 		if (depth > *max_depth) *max_depth = depth; | 
					
						
							|  |  |  | 		if (temp < *min_temp) *min_temp = temp; | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 		*avg_depth = (*avg_depth * sample_cnt + depth) / (sample_cnt + 1); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-09 23:07:30 +07:00
										 |  |  | 		sample->depth.mm = lrint(depth * FEET * 1000); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		sample->ndl.seconds = ndl; | 
					
						
							|  |  |  | 		sample->in_deco = in_deco; | 
					
						
							|  |  |  | 		sample->stoptime.seconds = deco_time; | 
					
						
							| 
									
										
										
										
											2017-03-09 23:07:30 +07:00
										 |  |  | 		sample->stopdepth.mm = lrint(deco_ceiling * FEET * 1000); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		sample->temperature.mkelvin = C_to_mkelvin((temp - 32) / 1.8); | 
					
						
							| 
									
										
											  
											
												Start cleaning up sensor indexing for multiple sensors
This is a very timid start at making us actually use multiple sensors
without the magical special case for just CCR oxygen tracking.
It mainly does:
 - turn the "sample->sensor" index into an array of two indexes, to
   match the pressures themselves.
 - get rid of dive->{oxygen_cylinder_index,diluent_cylinder_index},
   since a CCR dive should now simply set the sample->sensor[] indices
   correctly instead.
 - in a couple of places, start actually looping over the sensors rather
   than special-case the O2 case (although often the small "loops" are
   just unrolled, since it's just two cases.
but in many cases we still end up only covering the zero sensor case,
because the CCR O2 sensor code coverage was fairly limited.
It's entirely possible (even likely) that this migth break some existing
case: it tries to be a fairly direct ("stupid") translation of the old
code, but unlike the preparatory patch this does actually does change
some semantics.
For example, right now the git loader code assumes that if the git save
data contains a o2pressure entry, it just hardcodes the O2 sensor index
to 1.
In fact, one issue is going to simply be that our file formats do not
have that multiple sensor format, but instead had very clearly encoded
things as being the CCR O2 pressure sensor.
But this is hopefully close to usable, and I will need feedback (and
maybe test cases) from people who have existing CCR dives with pressure
data.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
											
										 
											2017-07-20 19:49:45 -07:00
										 |  |  | 		sample->sensor[0] = 0; | 
					
						
							| 
									
										
										
										
											2017-07-20 14:39:02 -07:00
										 |  |  | 		sample->pressure[0].mbar = lrint(psi * PSI / 100); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		finish_sample(dc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		offset += config.sample_size; | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 		sample_cnt++; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:15 +02:00
										 |  |  | 	(void)ascent_rate; // mark the variable as unused
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 20:46:22 -04:00
										 |  |  | 	if (sample_cnt > 0) | 
					
						
							|  |  |  | 		*duration = sample_cnt * profile_period - 1; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void cochran_parse_dive(const unsigned char *decode, unsigned mod, | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 			       const unsigned char *in, unsigned size) | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * 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. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2014-02-27 20:09:57 -08:00
										 |  |  | 	partial_decode(0, 0x0fff, decode, 1, mod, in, size, buf); | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 	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: | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2017-05-26 19:58:06 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (size < 0x4914 + config.logbook_size) { | 
					
						
							|  |  |  | 		// Analyst calls this a "Corrupt Beginning Summary"
 | 
					
						
							|  |  |  | 		free(buf); | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	// Decode log entry (512 bytes + random prefix)
 | 
					
						
							|  |  |  | 	partial_decode(0x48ff, 0x4914 + config.logbook_size, decode, | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 		0, mod, in, size, buf); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	unsigned int sample_size = size - 0x4914 - config.logbook_size; | 
					
						
							|  |  |  | 	int g; | 
					
						
							| 
									
										
										
										
											2017-05-31 22:08:48 -04:00
										 |  |  | 	unsigned int sample_pre_offset = 0, sample_end_offset = 0; | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	// Decode sample data
 | 
					
						
							|  |  |  | 	partial_decode(0x4914 + config.logbook_size, size, decode, | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 		0, mod, in, size, buf); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | #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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 	unsigned char *log = (buf + 0x4914); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 	switch (config.type) { | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	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]); | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 			dive->cylinder[0].gasmix.o2.permille = (log[CMD_O2_PERCENT] / 256 | 
					
						
							|  |  |  | 				+ log[CMD_O2_PERCENT + 1]) * 10; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 			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]); | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 				dive->cylinder[g].gasmix.o2.permille = (log[CMD_O2_PERCENT + g * 2] / 256 | 
					
						
							|  |  |  | 					+ log[CMD_O2_PERCENT + g * 2 + 1]) * 10; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 				dive->cylinder[g].gasmix.he.permille = 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		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]; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		tm.tm_isdst = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dive->when = dc->when = utc_mktime(&tm); | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2017-03-09 23:07:30 +07:00
										 |  |  | 		dc->maxdepth.mm = lrint((log[CMD_MAX_DEPTH] + | 
					
						
							|  |  |  | 			log[CMD_MAX_DEPTH + 1] * 256) / 4 * FEET * 1000); | 
					
						
							|  |  |  | 		dc->meandepth.mm = lrint((log[CMD_AVG_DEPTH] + | 
					
						
							|  |  |  | 			log[CMD_AVG_DEPTH + 1] * 256) / 4 * FEET * 1000); | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		dc->watertemp.mkelvin = C_to_mkelvin((log[CMD_MIN_TEMP] / 32) - 1.8); | 
					
						
							| 
									
										
										
										
											2017-03-09 23:07:30 +07:00
										 |  |  | 		dc->surface_pressure.mbar = lrint(ATM / BAR * pow(1 - 0.0000225577 | 
					
						
							|  |  |  | 			* (double) log[CMD_ALTITUDE] * 250 * FEET, 5.25588) * 1000); | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		dc->salinity = 10000 + 150 * log[CMD_WATER_CONDUCTIVITY]; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		SHA1(log + CMD_NUMBER, 2, (unsigned char *)csum); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		dc->diveid = csum[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		if (log[CMD_MAX_DEPTH] == 0xff && log[CMD_MAX_DEPTH + 1] == 0xff) | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 			corrupt_dive = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 22:08:48 -04:00
										 |  |  | 		sample_pre_offset = array_uint32_le(log + CMD_PREDIVE_OFFSET); | 
					
						
							|  |  |  | 		sample_end_offset = array_uint32_le(log + CMD_END_OFFSET); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		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]); | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		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]; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		tm.tm_isdst = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dive->when = dc->when = utc_mktime(&tm); | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2017-03-09 23:07:30 +07:00
										 |  |  | 		dc->maxdepth.mm = lrint((log[EMC_MAX_DEPTH] + | 
					
						
							|  |  |  | 			log[EMC_MAX_DEPTH + 1] * 256) / 4 * FEET * 1000); | 
					
						
							|  |  |  | 		dc->meandepth.mm = lrint((log[EMC_AVG_DEPTH] + | 
					
						
							| 
									
										
										
										
											2017-05-27 07:37:58 -07:00
										 |  |  | 			log[EMC_AVG_DEPTH + 1] * 256) / 4 * FEET * 1000); | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		dc->watertemp.mkelvin = C_to_mkelvin((log[EMC_MIN_TEMP] - 32) / 1.8); | 
					
						
							| 
									
										
										
										
											2017-03-09 23:07:30 +07:00
										 |  |  | 		dc->surface_pressure.mbar = lrint(ATM / BAR * pow(1 - 0.0000225577 | 
					
						
							|  |  |  | 			* (double) log[EMC_ALTITUDE] * 250 * FEET, 5.25588) * 1000); | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		dc->salinity = 10000 + 150 * (log[EMC_WATER_CONDUCTIVITY] & 0x3); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		SHA1(log + EMC_NUMBER, 2, (unsigned char *)csum); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		dc->diveid = csum[0]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-29 11:14:44 -04:00
										 |  |  | 		if (log[EMC_MAX_DEPTH] == 0xff && log[EMC_MAX_DEPTH + 1] == 0xff) | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 			corrupt_dive = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 22:08:48 -04:00
										 |  |  | 		sample_pre_offset = array_uint32_le(log + EMC_PREDIVE_OFFSET); | 
					
						
							|  |  |  | 		sample_end_offset = array_uint32_le(log + EMC_END_OFFSET); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-31 22:08:48 -04:00
										 |  |  | 	// Use the log information to determine actual profile sample size
 | 
					
						
							|  |  |  | 	// Otherwise we will get surface time at end of dive.
 | 
					
						
							|  |  |  | 	if (sample_pre_offset < sample_end_offset && sample_end_offset != 0xffffffff) | 
					
						
							|  |  |  | 		sample_size = sample_end_offset - sample_pre_offset; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	cochran_parse_samples(dive, buf + 0x4914, buf + 0x4914 | 
					
						
							| 
									
										
										
										
											2014-10-28 13:35:14 +02:00
										 |  |  | 		+ config.logbook_size, sample_size, | 
					
						
							|  |  |  | 		&duration, &max_depth, &avg_depth, &min_temp); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Check for corrupt dive
 | 
					
						
							|  |  |  | 	if (corrupt_dive) { | 
					
						
							| 
									
										
										
										
											2017-03-09 23:07:30 +07:00
										 |  |  | 		dc->maxdepth.mm = lrint(max_depth * FEET * 1000); | 
					
						
							|  |  |  | 		dc->meandepth.mm = lrint(avg_depth * FEET * 1000); | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 		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); | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	free(buf); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | int try_to_open_cochran(const char *filename, struct memblock *mem) | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-03-07 16:54:14 -03:00
										 |  |  | 	(void) filename; | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 	unsigned int i; | 
					
						
							|  |  |  | 	unsigned int mod; | 
					
						
							|  |  |  | 	unsigned int *offsets, dive1, dive2; | 
					
						
							|  |  |  | 	unsigned char *decode = mem->buffer + 0x40001; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mem->size < 0x40000) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-28 14:59:08 +02:00
										 |  |  | 	offsets = (unsigned int *) mem->buffer; | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 	dive1 = offsets[0]; | 
					
						
							|  |  |  | 	dive2 = offsets[1]; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 	if (dive1 < 0x40000 || dive2 < dive1 || dive2 > mem->size) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	mod = decode[0x100] + 1; | 
					
						
							|  |  |  | 	cochran_parse_header(decode, mod, mem->buffer + 0x40000, dive1 - 0x40000); | 
					
						
							| 
									
										
										
										
											2012-01-27 15:11:34 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	// Decode each dive
 | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 	for (i = 0; i < 65534; i++) { | 
					
						
							|  |  |  | 		dive1 = offsets[i]; | 
					
						
							| 
									
										
										
										
											2014-02-27 20:09:57 -08:00
										 |  |  | 		dive2 = offsets[i + 1]; | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 		if (dive2 < dive1) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		if (dive2 > mem->size) | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		cochran_parse_dive(decode, mod, mem->buffer + dive1, | 
					
						
							|  |  |  | 						dive2 - dive1); | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-17 21:03:37 -04:00
										 |  |  | 	return 1; // no further processing needed
 | 
					
						
							| 
									
										
										
										
											2012-01-27 12:43:40 -08:00
										 |  |  | } |