mirror of
				https://github.com/subsurface/subsurface.git
				synced 2025-02-19 22:16:15 +00:00 
			
		
		
		
	Merge branch 'uemis-next'
No reason to keep this in a separate branch. If we decide to make a 2.1.1 release we'll simply cherry pick only the fixes.
This commit is contained in:
		
						commit
						d88c69b97a
					
				
					 4 changed files with 275 additions and 30 deletions
				
			
		
							
								
								
									
										4
									
								
								main.c
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								main.c
									
										
									
									
									
								
							|  | @ -242,7 +242,9 @@ int main(int argc, char **argv) | |||
| 
 | ||||
| 	init_ui(&argc, &argv); | ||||
| 
 | ||||
| #ifdef DEBUGFILE | ||||
| #if DEBUGFILE > 1 | ||||
| 	debugfile = stderr; | ||||
| #elif defined(DEBUGFILE) | ||||
| 	debugfilename = (char *)subsurface_default_filename(); | ||||
| 	strncpy(debugfilename + strlen(debugfilename) - 3, "log", 3); | ||||
| 	if (g_mkdir_with_parents(g_path_get_dirname(debugfilename), 0664) != 0 || | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ | |||
| #define ERR_FS_FULL N_("Uemis Zurich: File System is full\nDisconnect/reconnect the dive computer\nand try again") | ||||
| #define ERR_FS_SHORT_WRITE N_("Short write to req.txt file\nIs the Uemis Zurich plugged in correctly?") | ||||
| #define BUFLEN 2048 | ||||
| #define NUM_PARAM_BUFS 6 | ||||
| #define NUM_PARAM_BUFS 10 | ||||
| #define UEMIS_TIMEOUT 100000 | ||||
| static char *param_buff[NUM_PARAM_BUFS]; | ||||
| static char *reqtxt_path; | ||||
|  | @ -223,19 +223,197 @@ static char *next_segment(char *buf, int *offset, int size) | |||
|  * The binary data block can be more than 100k in size (base64 encoded) */ | ||||
| static void buffer_add(char **buffer, int *buffer_size, char *buf) | ||||
| { | ||||
| 	if (buf) { | ||||
| 		if (! *buffer) { | ||||
| 			*buffer = strdup(buf); | ||||
| 			*buffer_size = strlen(*buffer) + 1; | ||||
| 		} else { | ||||
| 			*buffer_size += strlen(buf); | ||||
| 			*buffer = realloc(*buffer, *buffer_size); | ||||
| 			strcat(*buffer, buf); | ||||
| 		} | ||||
| #if UEMIS_DEBUG > 5 | ||||
| 		fprintf(debugfile,"added \"%s\" to buffer - new length %d\n", buf, *buffer_size); | ||||
| #endif | ||||
| 	if (!buf) | ||||
| 		return; | ||||
| 	if (! *buffer) { | ||||
| 		*buffer = strdup(buf); | ||||
| 		*buffer_size = strlen(*buffer) + 1; | ||||
| 	} else { | ||||
| 		*buffer_size += strlen(buf); | ||||
| 		*buffer = realloc(*buffer, *buffer_size); | ||||
| 		strcat(*buffer, buf); | ||||
| 	} | ||||
| #if UEMIS_DEBUG > 5 | ||||
| 	fprintf(debugfile,"added \"%s\" to buffer - new length %d\n", buf, *buffer_size); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| #define PATTERN1 "<val key=\"%s\">%s" | ||||
| #define PATTERN2 "\n<int>%d</int>" | ||||
| static gboolean get_tag_int_value(char *buffer, char *tag, int *value, char **next_ptr) | ||||
| { | ||||
| 	char *ptr = buffer; | ||||
| 	int len; | ||||
| 	char *format; | ||||
| 
 | ||||
| 	if (!ptr || !value) | ||||
| 		return FALSE; | ||||
| 	len = strlen(PATTERN1) + strlen(PATTERN2) + strlen(tag); | ||||
| 	format = malloc(len); | ||||
| 	snprintf(format, len, PATTERN1, tag, ""); | ||||
| 	ptr = strstr(ptr, format); | ||||
| 	if (!ptr) | ||||
| 		return FALSE; | ||||
| 	snprintf(format, len, PATTERN1, tag, PATTERN2); | ||||
| 	if (sscanf(ptr, format, value) != 1) | ||||
| 		return FALSE; | ||||
| 	if (next_ptr) | ||||
| 		*next_ptr = ptr + 1; | ||||
| 	return TRUE; | ||||
| } | ||||
| 
 | ||||
| static gboolean get_tag_string_value(char *buffer, char *tag, char **value) | ||||
| { | ||||
| 	char *eptr, *ptr = buffer; | ||||
| 	int len; | ||||
| 	char *format; | ||||
| 
 | ||||
| 	if (!ptr || !value) | ||||
| 		return FALSE; | ||||
| 	len = strlen(PATTERN1) + strlen(tag); | ||||
| 	format = malloc(len); | ||||
| 	snprintf(format, len, PATTERN1, tag, ""); | ||||
| 	ptr = strstr(ptr, format); | ||||
| 	if (!ptr) | ||||
| 		return FALSE; | ||||
| 	eptr = strstr(ptr, "</string>"); | ||||
| 	if (!eptr) | ||||
| 		return FALSE; | ||||
| 	*eptr = '\0'; | ||||
| 	*value = strdup(ptr + strlen(format) + 9); | ||||
| 	*eptr = '<'; | ||||
| 	return TRUE; | ||||
| } | ||||
| 
 | ||||
| #define PATTERN4 "\n<float>%lf</float>" | ||||
| static gboolean get_tag_double_value(char *buffer, char *tag, double *value, char **next_ptr) | ||||
| { | ||||
| 	char *ptr = buffer; | ||||
| 	int len; | ||||
| 	char *format; | ||||
| 
 | ||||
| 	if (!ptr || !value) | ||||
| 		return FALSE; | ||||
| 	len = strlen(PATTERN1) + strlen(PATTERN4) + strlen(tag); | ||||
| 	format = malloc(len); | ||||
| 	snprintf(format, len, PATTERN1, tag, ""); | ||||
| 	ptr = strstr(ptr, format); | ||||
| 	if (!ptr) | ||||
| 		return FALSE; | ||||
| 	snprintf(format, len, PATTERN1, tag, PATTERN4); | ||||
| 	if (sscanf(ptr, format, value) != 1) | ||||
| 		return FALSE; | ||||
| 	if (next_ptr) | ||||
| 		*next_ptr = ptr + 1; | ||||
| 	return TRUE; | ||||
| } | ||||
| 
 | ||||
| static char *get_xml_for_int(char *buf, char *tag) | ||||
| { | ||||
| 	int value; | ||||
| 	char *xml; | ||||
| 	if (get_tag_int_value(buf, tag, &value, NULL)) { | ||||
| 		int len = 20 + 2 * strlen(tag); | ||||
| 		xml = malloc(len); | ||||
| 		snprintf(xml, len, "<%s>%d</%s>\n", tag, value, tag); | ||||
| 	} | ||||
| 	return xml; | ||||
| } | ||||
| 
 | ||||
| static const char *suit[] = { "", "wetsuit", "semidry", "drysuit" }; | ||||
| static const char *suit_type[] = { "", "shorty", "vest", "long john", "jacket", "full suit", "2 pcs full suit" }; | ||||
| static const char *suit_thickness[] = { "", "0.5-2mm", "2-3mm", "3-5mm", "5-7mm", "8mm+", "membrane" }; | ||||
| static char *convert_dive_details(char *buf, uint8_t *hdr) | ||||
| { | ||||
| 	char *conv_buffer = NULL; | ||||
| 	int conv_size = 0; | ||||
| 	char *ptr, *eptr; | ||||
| 	double doublevalue; | ||||
| 	double weight; | ||||
| 	char *stringvalue; | ||||
| 	char textbuf[200]; | ||||
| 	int suit_idx, suit_type_idx, suit_thickness_idx; | ||||
| 
 | ||||
| 	/* we want to throw away what is duplicate and clean up and
 | ||||
| 	 * parse the userful entries */ | ||||
| 	ptr = strstr(buf, "<val key=\"logfilenr\">"); | ||||
| 	if (!ptr) | ||||
| 		return NULL; | ||||
| 	eptr = strstr(ptr + 1, "<val"); | ||||
| 	*eptr = '\0'; | ||||
| 	buffer_add(&conv_buffer, &conv_size, ptr); | ||||
| 	*eptr = '<'; | ||||
| 	buffer_add(&conv_buffer, &conv_size, get_xml_for_int(eptr, "altitude")); | ||||
| 	buffer_add(&conv_buffer, &conv_size, get_xml_for_int(eptr, "decoindex")); | ||||
| 	buffer_add(&conv_buffer, &conv_size, get_xml_for_int(eptr, "consumption")); | ||||
| 	if (get_tag_double_value(eptr, "f32Weight", &doublevalue, NULL)) { | ||||
| 		weight = hdr[24] ? lbs_to_grams(doublevalue) / 1000.0 : doublevalue; | ||||
| 		snprintf(textbuf, sizeof(textbuf), | ||||
| 			"<weightsystem weight='%.3lf' description='unknown' />\n", weight); | ||||
| 		buffer_add(&conv_buffer, &conv_size, textbuf); | ||||
| 	} | ||||
| 	if (get_tag_string_value(eptr, "notes", &stringvalue)) { | ||||
| 		buffer_add(&conv_buffer, &conv_size, "<notes>"); | ||||
| 		buffer_add(&conv_buffer, &conv_size, stringvalue); | ||||
| 		buffer_add(&conv_buffer, &conv_size, "</notes>\n"); | ||||
| 	} | ||||
| 	if (get_tag_int_value(eptr, "u8DiveSuit", &suit_idx, NULL) && | ||||
| 	    get_tag_int_value(eptr, "u8DiveSuitType", &suit_type_idx, NULL) && | ||||
| 	    get_tag_int_value(eptr, "u8SuitThickness", &suit_thickness_idx, NULL) && | ||||
| 	    suit_idx >= 0 && suit_idx < sizeof(suit) && | ||||
| 	    suit_type_idx >= 0 && suit_type_idx < sizeof(suit_type) && | ||||
| 	    suit_thickness_idx >= 0 && suit_thickness_idx < sizeof(suit_thickness)) { | ||||
| 		snprintf(textbuf, sizeof(textbuf), "<suit>%s %s %s</suit>\n", | ||||
| 			suit[suit_idx], suit_type[suit_type_idx], suit_thickness[suit_thickness_idx]); | ||||
| 		buffer_add(&conv_buffer, &conv_size, textbuf); | ||||
| 	} | ||||
| 	return conv_buffer; | ||||
| } | ||||
| 
 | ||||
| /* this is more interesting - insert the additional data in the dive
 | ||||
|  * it belongs to - no idea why Uemis splits out the dive data in this | ||||
|  * odd way, but we have to re-assemble it here */ | ||||
| static void buffer_insert(char **buffer, int *buffer_size, char *buf) | ||||
| { | ||||
| 	char *ptr, *endptr, *b64, *cbuf; | ||||
| 	int obj_dive; | ||||
| 	int obj_log; | ||||
| 	int offset, len; | ||||
| 	uint8_t hdr[24]; | ||||
| 
 | ||||
| 	/* since we want to insert into the buffer... if there's
 | ||||
| 	 * nothing there, this makes absolutely no sense so just | ||||
| 	 * bail */ | ||||
| 	if (!buf || !*buffer) | ||||
| 		return; | ||||
| 	endptr = *buffer + strlen(*buffer); | ||||
| 	/* now figure out the object_id of buf and find the matching
 | ||||
| 	 * spot in buffer */ | ||||
| 	if (!get_tag_int_value(buf, "logfilenr", &obj_dive, NULL)) | ||||
| 		return; | ||||
| 	ptr = *buffer; | ||||
| 	while (ptr < endptr) { | ||||
| 		if (!get_tag_int_value(ptr, "object_id", &obj_log, &ptr)) | ||||
| 			return; | ||||
| 		if (obj_dive == obj_log) | ||||
| 			break; | ||||
| 	} | ||||
| 	ptr = strstr(ptr, "<val key=\"file_content\">"); | ||||
| 	if (!ptr) | ||||
| 		return; | ||||
| 	/* this is where the base64 data starts; we need to extract
 | ||||
| 	 * some info from that in order to make sense of the data in | ||||
| 	 * the dive info */ | ||||
| 	b64 = strstr(ptr, "<bin>") + 5; | ||||
| 	decode(b64, hdr, 32); | ||||
| 	cbuf = convert_dive_details(buf, hdr); | ||||
| 	offset = ptr - *buffer; | ||||
| 	len = strlen(cbuf); | ||||
| 	*buffer_size += len; | ||||
| 	*buffer = realloc(*buffer, *buffer_size); | ||||
| 	ptr = *buffer + offset; | ||||
| 	memmove(ptr + len, ptr, strlen(*buffer) - offset); | ||||
| 	memmove(ptr, cbuf, len); | ||||
| } | ||||
| 
 | ||||
| /* are there more ANS files we can check? */ | ||||
|  | @ -291,7 +469,7 @@ static gboolean uemis_get_answer(const char *path, char *request, int n_param_in | |||
| 	str_append_with_delim(sb, request); | ||||
| 	for (i = 0; i < n_param_in; i++) | ||||
| 		str_append_with_delim(sb, param_buff[i]); | ||||
| 	if (! strcmp(request, "getDivelogs") || ! strcmp(request, "getDeviceData")) { | ||||
| 	if (! strcmp(request, "getDivelogs") || ! strcmp(request, "getDeviceData") || ! strcmp(request, "getDirectory")) { | ||||
| 		answer_in_mbuf = TRUE; | ||||
| 		str_append_with_delim(sb, ""); | ||||
| 	} | ||||
|  | @ -414,9 +592,9 @@ static gboolean uemis_get_answer(const char *path, char *request, int n_param_in | |||
| 	return found_answer; | ||||
| } | ||||
| 
 | ||||
| /* Turn what we get from the dive computer into something
 | ||||
|  * that we can pass to the parse_xml function. | ||||
|  * The last 'object_id' that we see is returned as our current | ||||
| /* Turn what we get from the dive computer into something that we can
 | ||||
|  * pass to the parse_xml function.  If this is a divelog, then the | ||||
|  * last 'object_id' that we see is returned as our current | ||||
|  * approximation of a last dive number */ | ||||
| static char *process_raw_buffer(char *inbuf, char **max_divenr) | ||||
| { | ||||
|  | @ -427,34 +605,71 @@ static char *process_raw_buffer(char *inbuf, char **max_divenr) | |||
| 	char *endptr = buf + inbuflen; | ||||
| 	char *conv_buffer = NULL; | ||||
| 	int conv_buffer_size = 0; | ||||
| 	gboolean log = FALSE; | ||||
| 	char *sections[10]; | ||||
| 	int s, nr_sections = 0; | ||||
| 
 | ||||
| 	bp = buf + 1; | ||||
| 	tp = next_token(&bp); | ||||
| 	if (strcmp(tp,"divelog") != 0) | ||||
| 	if (strcmp(tp, "divelog") == 0) { | ||||
| 		/* this is a divelog */ | ||||
| 		log = TRUE; | ||||
| 		tp = next_token(&bp); | ||||
| 		if (strcmp(tp,"1.0") != 0) | ||||
| 			return NULL; | ||||
| 	} else if (strcmp(tp, "dive") == 0) { | ||||
| 		/* this is dive detail */ | ||||
| 		tp = next_token(&bp); | ||||
| 		if (strcmp(tp,"1.0") != 0) | ||||
| 			return NULL; | ||||
| 	} else { | ||||
| 		/* don't understand the buffer */ | ||||
| 		return NULL; | ||||
| 	tp = next_token(&bp); | ||||
| 	if (strcmp(tp,"1.0") != 0) | ||||
| 		return NULL; | ||||
| 	buffer_add(&conv_buffer, &conv_buffer_size, | ||||
| 		"<dive type=\"uemis\" ref=\"divelog\" version=\"1.0\">\n"); | ||||
| 	} | ||||
| 	if (log) | ||||
| 		buffer_add(&conv_buffer, &conv_buffer_size, | ||||
| 			"<dive type=\"uemis\" ref=\"divelog\" version=\"1.0\">\n"); | ||||
| 	while (!done) { | ||||
| 		char *tmp; | ||||
| 		int tmp_size; | ||||
| 
 | ||||
| 		/* the valid buffer ends with a series of delimiters */ | ||||
| 		if (bp >= endptr - 2 || !strcmp(bp, "{{")) | ||||
| 			break; | ||||
| 		tag = next_token(&bp); | ||||
| 		/* we also end if we get an empty tag */ | ||||
| 		if (*tag == '\0') | ||||
| 			break; | ||||
| 		for (s = 0; s < nr_sections; s++) | ||||
| 			if (!strcmp(tag, sections[s])) { | ||||
| 				tag = next_token(&bp); | ||||
| 				break; | ||||
| 			} | ||||
| 		type = next_token(&bp); | ||||
| 		if (!strcmp(type, "1.0")) { | ||||
| 			/* this tells us the sections that will follow; the tag here
 | ||||
| 			 * is of the format dive-<section> */ | ||||
| 			sections[nr_sections] = strchr(tag, '-') + 1; | ||||
| #if UEMIS_DEBUG > 2 | ||||
| 			fprintf(debugfile, "Expect to find section %s\n", sections[nr_sections]); | ||||
| #endif | ||||
| 			if (nr_sections < sizeof(sections) - 1) | ||||
| 				nr_sections++; | ||||
| 			continue; | ||||
| 		} | ||||
| 		val = next_token(&bp); | ||||
| 		if (! strcmp(tag, "object_id")) { | ||||
| 		if (log && ! strcmp(tag, "object_id")) { | ||||
| 			free(*max_divenr); | ||||
| 			*max_divenr = strdup(val); | ||||
| 		} | ||||
| 		if (! strcmp(tag, "file_content")) { | ||||
| 			tmp_size = 44 + strlen(tag) + strlen(val); | ||||
| 			tmp_size = 45 + strlen(tag) + strlen(val); | ||||
| 			done = TRUE; | ||||
| 		} else { | ||||
| 			tmp_size = 27 + strlen(tag) + 2 * strlen(type) + strlen(val); | ||||
| 			tmp_size = 28 + strlen(tag) + 2 * strlen(type) + strlen(val); | ||||
| 		} | ||||
| 		tmp = malloc(tmp_size); | ||||
| 		snprintf(tmp, tmp_size,"<val key=\"%s\">\n<%s>%s</%s>\n</val>\n", | ||||
| 		snprintf(tmp, tmp_size, "<val key=\"%s\">\n<%s>%s</%s>\n</val>\n", | ||||
| 			tag, type, val, type); | ||||
| 		buffer_add(&conv_buffer, &conv_buffer_size, tmp); | ||||
| 		free(tmp); | ||||
|  | @ -468,8 +683,13 @@ static char *process_raw_buffer(char *inbuf, char **max_divenr) | |||
| 				"</dive>\n<dive type=\"uemis\" ref=\"divelog\" version=\"1.0\">\n"); | ||||
| 		} | ||||
| 	} | ||||
| 	buffer_add(&conv_buffer, &conv_buffer_size, "</dive>\n"); | ||||
| 	if (log) { | ||||
| 		buffer_add(&conv_buffer, &conv_buffer_size, "</dive>\n"); | ||||
| 	} | ||||
| 	free(buf); | ||||
| #if UEMIS_DEBUG > 2 | ||||
| 	fprintf(debugfile,"converted to \"%s\"\n", conv_buffer); | ||||
| #endif | ||||
| 	return strdup(conv_buffer); | ||||
| } | ||||
| 
 | ||||
|  | @ -548,6 +768,8 @@ static char *do_uemis_download(struct argument_block *args) | |||
| 	char **xml_buffer = args->xml_buffer; | ||||
| 	int xml_buffer_size; | ||||
| 	char *newmax = NULL; | ||||
| 	int start, end, i; | ||||
| 	char objectid[10]; | ||||
| 	char *deviceid = NULL; | ||||
| 	char *result = NULL; | ||||
| 	char *endptr; | ||||
|  | @ -571,6 +793,8 @@ static char *do_uemis_download(struct argument_block *args) | |||
| 		goto bail; | ||||
| 	param_buff[1] = "notempty"; | ||||
| 	newmax = get_divenr(*max_dive_data, deviceid); | ||||
| 	if (sscanf(newmax, "%d", &start) != 1) | ||||
| 		start = 0; | ||||
| 	for (;;) { | ||||
| 		param_buff[2] = newmax; | ||||
| 		param_buff[3] = 0; | ||||
|  | @ -598,7 +822,25 @@ static char *do_uemis_download(struct argument_block *args) | |||
| 			*(endptr + 2) = '\0'; | ||||
| 	} | ||||
| 	*args->max_dive_data = update_max_dive_data(*max_dive_data, deviceid, newmax); | ||||
| 	if (sscanf(newmax, "%d", &end) != 1) | ||||
| 		end = start; | ||||
| #if UEMIS_DEBUG > 2 | ||||
| 	fprintf(debugfile, "done: read from object_id %d to %d\n", start, end); | ||||
| #endif | ||||
| 	free(newmax); | ||||
| 	for (i = start; i < end; i++) { | ||||
| 		snprintf(objectid, sizeof(objectid), "%d", i); | ||||
| 		param_buff[2] = objectid; | ||||
| 		param_buff[3] = 0; | ||||
| 		success = uemis_get_answer(mountpath, "getDive", 3, 0, &result); | ||||
| 		if (mbuf) { | ||||
| 			char *next_detail = process_raw_buffer(mbuf, &newmax); | ||||
| 			buffer_insert(xml_buffer, &xml_buffer_size, next_detail); | ||||
| 			free(next_detail); | ||||
| 		} | ||||
| 		if (!success) | ||||
| 			break; | ||||
| 	} | ||||
| 	if (! uemis_get_answer(mountpath, "terminateSync", 0, 3, &result)) | ||||
| 		goto bail; | ||||
| 	if (! strcmp(param_buff[0], "error")) { | ||||
|  |  | |||
							
								
								
									
										2
									
								
								uemis.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								uemis.c
									
										
									
									
									
								
							|  | @ -43,7 +43,7 @@ static void decodeblock( unsigned char in[4], unsigned char out[3] ) { | |||
| /*
 | ||||
|  * decode a base64 encoded stream discarding padding, line breaks and noise | ||||
|  */ | ||||
| static void decode( uint8_t *inbuf, uint8_t *outbuf, int inbuf_len ) { | ||||
| void decode( uint8_t *inbuf, uint8_t *outbuf, int inbuf_len ) { | ||||
| 	uint8_t in[4], out[3], v; | ||||
| 	int i,len,indx_in=0,indx_out=0; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										1
									
								
								uemis.h
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								uemis.h
									
										
									
									
									
								
							|  | @ -8,6 +8,7 @@ | |||
| #include <stdint.h> | ||||
| 
 | ||||
| void uemis_parse_divelog_binary(char *base64, void *divep); | ||||
| void decode(uint8_t *in, uint8_t *out, int len); | ||||
| 
 | ||||
| typedef struct { | ||||
| 	uint16_t	dive_time; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue