2017-04-27 18:18:03 +00:00
// SPDX-License-Identifier: GPL-2.0
2012-09-25 14:28:47 +00:00
/*
* uemis - downloader . c
*
* Copyright ( c ) Dirk Hohndel < dirk @ hohndel . org >
* released under GPL2
*
* very ( VERY ) loosely based on the algorithms found in Java code by Fabian Gast < fgast @ only640k . net >
* which was released under the BSD - STYLE BEER WARE LICENSE
* I believe that I only used the information about HOW to do this ( download data from the Uemis
* Zurich ) but did not actually use any of his copyrighted code , therefore the license under which
* he released his code does not apply to this new implementation in C
2015-09-05 17:29:43 +00:00
*
2015-09-14 08:31:29 +00:00
* Modified by Guido Lerch guido . lerch @ gmail . com in August 2015
2012-09-25 14:28:47 +00:00
*/
# include <fcntl.h>
2013-10-05 07:29:09 +00:00
# include <dirent.h>
2012-09-25 14:28:47 +00:00
# include <stdio.h>
# include <unistd.h>
# include <string.h>
2015-04-30 22:33:16 +00:00
# include <errno.h>
2012-10-11 00:42:59 +00:00
2013-10-07 23:13:13 +00:00
# include "gettext.h"
2013-06-24 22:14:07 +00:00
# include "libdivecomputer.h"
2012-09-25 14:28:47 +00:00
# include "uemis.h"
# include "divelist.h"
2018-05-11 15:25:41 +00:00
# include "core/subsurface-string.h"
2013-10-07 23:13:13 +00:00
2015-01-25 15:03:22 +00:00
# define ERR_FS_ALMOST_FULL QT_TRANSLATE_NOOP("gettextFromC", "Uemis Zurich: the file system is almost full.\nDisconnect / reconnect the dive computer\nand click \'Retry\'")
2015-09-09 09:53:30 +00:00
# define ERR_FS_FULL QT_TRANSLATE_NOOP("gettextFromC", "Uemis Zurich: the file system is full.\nDisconnect / reconnect the dive computer\nand click Retry")
2015-01-25 15:03:22 +00:00
# define ERR_FS_SHORT_WRITE QT_TRANSLATE_NOOP("gettextFromC", "Short write to req.txt file.\nIs the Uemis Zurich plugged in correctly?")
2015-09-24 17:26:35 +00:00
# define ERR_NO_FILES QT_TRANSLATE_NOOP("gettextFromC", "No dives to download.")
# define BUFLEN 2048
2012-09-25 14:28:47 +00:00
# define BUFLEN 2048
2012-10-26 03:15:39 +00:00
# define NUM_PARAM_BUFS 10
2012-12-05 05:03:56 +00:00
2015-09-05 17:33:43 +00:00
// debugging setup
2015-09-15 08:09:24 +00:00
// #define UEMIS_DEBUG 1 + 2 + 4 + 8 + 16 + 32
2015-09-05 17:29:43 +00:00
2015-09-05 18:04:58 +00:00
# define UEMIS_MAX_FILES 4000
2015-09-15 14:46:20 +00:00
# define UEMIS_MEM_FULL 1
2015-09-05 18:15:05 +00:00
# define UEMIS_MEM_OK 0
2015-09-15 14:46:20 +00:00
# define UEMIS_SPOT_BLOCK_SIZE 1
# define UEMIS_DIVE_DETAILS_SIZE 2
# define UEMIS_LOG_BLOCK_SIZE 10
# define UEMIS_CHECK_LOG 1
# define UEMIS_CHECK_DETAILS 2
# define UEMIS_CHECK_SINGLE_DIVE 3
2015-09-05 18:04:58 +00:00
2015-09-15 08:09:24 +00:00
# if UEMIS_DEBUG
2015-09-18 20:14:46 +00:00
const char * home , * user , * d_time ;
2015-09-15 08:09:24 +00:00
static int debug_round = 0 ;
# define debugfile stderr
# endif
2015-09-05 17:29:43 +00:00
# if UEMIS_DEBUG & 64 /* we are reading from a copy of the filesystem, not the device - no need to wait */
# define UEMIS_TIMEOUT 50 /* 50ns */
# define UEMIS_LONG_TIMEOUT 500 /* 500ns */
# define UEMIS_MAX_TIMEOUT 2000 /* 2ms */
2012-12-05 05:03:56 +00:00
# else
2015-09-05 17:29:43 +00:00
# define UEMIS_TIMEOUT 50000 /* 50ms */
# define UEMIS_LONG_TIMEOUT 500000 /* 500ms */
# define UEMIS_MAX_TIMEOUT 2000000 /* 2s */
2012-12-05 05:03:56 +00:00
# endif
2012-11-19 22:09:21 +00:00
2012-09-25 14:28:47 +00:00
static char * param_buff [ NUM_PARAM_BUFS ] ;
static char * reqtxt_path ;
static int reqtxt_file ;
static int filenr ;
static int number_of_files ;
static char * mbuf = NULL ;
static int mbuf_size = 0 ;
2012-11-29 00:11:19 +00:00
2015-09-05 18:24:10 +00:00
static int max_mem_used = - 1 ;
static int next_table_index = 0 ;
2015-09-17 14:46:02 +00:00
static int dive_to_read = 0 ;
2018-01-28 19:20:02 +00:00
static uint32_t mindiveid ;
2015-09-05 18:24:10 +00:00
2018-01-18 19:38:19 +00:00
/* Linked list to remember already executed divespot download requests */
struct divespot_mapping {
int divespot_id ;
2018-10-23 10:48:33 +00:00
struct dive_site * dive_site ;
2018-01-18 19:38:19 +00:00
struct divespot_mapping * next ;
} ;
static struct divespot_mapping * divespot_mapping = NULL ;
static void erase_divespot_mapping ( )
{
struct divespot_mapping * tmp ;
while ( divespot_mapping ! = NULL ) {
tmp = divespot_mapping ;
divespot_mapping = tmp - > next ;
free ( tmp ) ;
}
divespot_mapping = NULL ;
}
2018-10-23 10:48:33 +00:00
static void add_to_divespot_mapping ( int divespot_id , struct dive_site * ds )
2018-01-18 19:38:19 +00:00
{
struct divespot_mapping * ndm = ( struct divespot_mapping * ) calloc ( 1 , sizeof ( struct divespot_mapping ) ) ;
struct divespot_mapping * * pdm = & divespot_mapping ;
struct divespot_mapping * cdm = * pdm ;
while ( cdm & & cdm - > next )
cdm = cdm - > next ;
ndm - > divespot_id = divespot_id ;
2018-10-23 10:48:33 +00:00
ndm - > dive_site = ds ;
2018-01-18 19:38:19 +00:00
ndm - > next = NULL ;
if ( cdm )
cdm - > next = ndm ;
else
cdm = * pdm = ndm ;
}
static bool is_divespot_mappable ( int divespot_id )
{
struct divespot_mapping * dm = divespot_mapping ;
while ( dm ) {
if ( dm - > divespot_id = = divespot_id )
return true ;
dm = dm - > next ;
}
return false ;
}
2018-10-23 10:42:01 +00:00
static struct dive_site * get_dive_site_by_divespot_id ( int divespot_id )
2018-01-18 19:38:19 +00:00
{
struct divespot_mapping * dm = divespot_mapping ;
while ( dm ) {
if ( dm - > divespot_id = = divespot_id )
2018-10-23 10:48:33 +00:00
return dm - > dive_site ;
2018-01-18 19:38:19 +00:00
dm = dm - > next ;
}
2018-10-23 10:42:01 +00:00
return NULL ;
2018-01-18 19:38:19 +00:00
}
2012-11-29 00:11:19 +00:00
/* helper function to parse the Uemis data structures */
static void uemis_ts ( char * buffer , void * _when )
{
struct tm tm ;
timestamp_t * when = _when ;
memset ( & tm , 0 , sizeof ( tm ) ) ;
2014-02-28 04:09:57 +00:00
sscanf ( buffer , " %d-%d-%dT%d:%d:%d " ,
& tm . tm_year , & tm . tm_mon , & tm . tm_mday ,
& tm . tm_hour , & tm . tm_min , & tm . tm_sec ) ;
tm . tm_mon - = 1 ;
2012-11-29 00:11:19 +00:00
* when = utc_mktime ( & tm ) ;
}
/* float minutes */
static void uemis_duration ( char * buffer , duration_t * duration )
{
2017-03-08 06:41:41 +00:00
duration - > seconds = lrint ( ascii_strtod ( buffer , NULL ) * 60 ) ;
2012-11-29 00:11:19 +00:00
}
/* int cm */
static void uemis_depth ( char * buffer , depth_t * depth )
{
depth - > mm = atoi ( buffer ) * 10 ;
}
static void uemis_get_index ( char * buffer , int * idx )
{
* idx = atoi ( buffer ) ;
}
/* space separated */
2015-09-07 18:48:45 +00:00
static void uemis_add_string ( const char * buffer , char * * text , const char * delimit )
2012-11-29 00:11:19 +00:00
{
2012-12-29 02:30:02 +00:00
/* do nothing if this is an empty buffer (Uemis sometimes returns a single
* space for empty buffers ) */
2018-01-07 14:42:28 +00:00
if ( empty_string ( buffer ) | | ( * buffer = = ' ' & & * ( buffer + 1 ) = = ' \0 ' ) )
2012-11-29 00:11:19 +00:00
return ;
if ( ! * text ) {
* text = strdup ( buffer ) ;
} else {
char * buf = malloc ( strlen ( buffer ) + strlen ( * text ) + 2 ) ;
strcpy ( buf , * text ) ;
2015-09-07 18:48:45 +00:00
strcat ( buf , delimit ) ;
2012-11-29 00:11:19 +00:00
strcat ( buf , buffer ) ;
free ( * text ) ;
* text = buf ;
}
}
/* still unclear if it ever reports lbs */
static void uemis_get_weight ( char * buffer , weightsystem_t * weight , int diveid )
{
weight - > weight . grams = uemis_get_weight_unit ( diveid ) ?
2017-03-09 16:07:30 +00:00
lbs_to_grams ( ascii_strtod ( buffer , NULL ) ) :
lrint ( ascii_strtod ( buffer , NULL ) * 1000 ) ;
2014-02-28 04:09:57 +00:00
weight - > description = strdup ( translate ( " gettextFromC " , " unknown " ) ) ;
2012-11-29 00:11:19 +00:00
}
2013-01-18 20:56:54 +00:00
static struct dive * uemis_start_dive ( uint32_t deviceid )
2012-11-29 00:11:19 +00:00
{
struct dive * dive = alloc_dive ( ) ;
dive - > dc . model = strdup ( " Uemis Zurich " ) ;
dive - > dc . deviceid = deviceid ;
return dive ;
}
2015-09-08 17:04:41 +00:00
static struct dive * get_dive_by_uemis_diveid ( device_data_t * devdata , uint32_t object_id )
2015-09-05 18:00:54 +00:00
{
for ( int i = 0 ; i < devdata - > download_table - > nr ; i + + ) {
if ( object_id = = devdata - > download_table - > dives [ i ] - > dc . diveid )
return devdata - > download_table - > dives [ i ] ;
}
return NULL ;
}
2012-09-25 14:28:47 +00:00
/* send text to the importer progress bar */
static void uemis_info ( const char * fmt , . . . )
{
2013-03-04 01:53:43 +00:00
static char buffer [ 256 ] ;
2012-09-25 14:28:47 +00:00
va_list ap ;
va_start ( ap , fmt ) ;
vsnprintf ( buffer , sizeof ( buffer ) , fmt , ap ) ;
va_end ( ap ) ;
progress_bar_text = buffer ;
2015-11-08 22:55:46 +00:00
if ( verbose )
fprintf ( stderr , " Uemis downloader: %s \n " , buffer ) ;
2012-09-25 14:28:47 +00:00
}
static long bytes_available ( int file )
{
long result ;
long now = lseek ( file , 0 , SEEK_CUR ) ;
2015-06-22 13:46:01 +00:00
if ( now = = - 1 )
return 0 ;
2012-09-25 14:28:47 +00:00
result = lseek ( file , 0 , SEEK_END ) ;
lseek ( file , now , SEEK_SET ) ;
2014-03-06 02:27:33 +00:00
if ( now = = - 1 | | result = = - 1 )
return 0 ;
2012-09-25 14:28:47 +00:00
return result ;
}
static int number_of_file ( char * path )
{
int count = 0 ;
2013-12-19 13:00:56 +00:00
# ifdef WIN32
struct _wdirent * entry ;
_WDIR * dirp = ( _WDIR * ) subsurface_opendir ( path ) ;
# else
struct dirent * entry ;
DIR * dirp = ( DIR * ) subsurface_opendir ( path ) ;
# endif
2013-10-05 07:29:09 +00:00
2013-12-19 13:00:56 +00:00
while ( dirp ) {
# ifdef WIN32
entry = _wreaddir ( dirp ) ;
if ( ! entry )
break ;
# else
entry = readdir ( dirp ) ;
if ( ! entry )
break ;
2015-10-21 12:51:11 +00:00
if ( strstr ( entry - > d_name , " .TXT " ) | | strstr ( entry - > d_name , " .txt " ) ) /* If the entry is a regular file */
2013-10-07 04:04:25 +00:00
# endif
2014-02-28 04:09:57 +00:00
count + + ;
2013-10-05 07:29:09 +00:00
}
2013-12-19 13:00:56 +00:00
# ifdef WIN32
_wclosedir ( dirp ) ;
# else
2013-10-05 07:29:09 +00:00
closedir ( dirp ) ;
2013-12-19 13:00:56 +00:00
# endif
2012-09-25 14:28:47 +00:00
return count ;
}
2013-10-05 07:29:09 +00:00
static char * build_filename ( const char * path , const char * name )
{
2013-11-07 04:06:06 +00:00
int len = strlen ( path ) + strlen ( name ) + 2 ;
2013-10-05 07:29:09 +00:00
char * buf = malloc ( len ) ;
# if WIN32
2014-05-07 18:15:39 +00:00
snprintf ( buf , len , " %s \\ %s " , path , name ) ;
2013-10-05 07:29:09 +00:00
# else
snprintf ( buf , len , " %s/%s " , path , name ) ;
# endif
return buf ;
}
2012-09-25 14:28:47 +00:00
/* Check if there's a req.txt file and get the starting filenr from it.
* Test for the maximum number of ANS files ( I believe this is always
* 4000 but in case there are differences depending on firmware , this
* code is easy enough */
2013-10-05 07:29:09 +00:00
static bool uemis_init ( const char * path )
2012-09-25 14:28:47 +00:00
{
char * ans_path ;
int i ;
2018-01-18 19:38:19 +00:00
erase_divespot_mapping ( ) ;
2012-09-25 14:28:47 +00:00
if ( ! path )
2014-01-15 18:54:41 +00:00
return false ;
2012-09-25 14:28:47 +00:00
/* let's check if this is indeed a Uemis DC */
2014-02-28 04:09:57 +00:00
reqtxt_path = build_filename ( path , " req.txt " ) ;
2015-06-25 03:59:49 +00:00
reqtxt_file = subsurface_open ( reqtxt_path , O_RDONLY | O_CREAT , 0666 ) ;
2015-06-22 05:16:23 +00:00
if ( reqtxt_file < 0 ) {
2012-12-05 05:03:56 +00:00
# if UEMIS_DEBUG & 1
2012-11-19 22:08:14 +00:00
fprintf ( debugfile , " :EE req.txt can't be opened \n " ) ;
# endif
2014-01-15 18:54:41 +00:00
return false ;
2012-11-19 22:08:14 +00:00
}
2012-09-25 14:28:47 +00:00
if ( bytes_available ( reqtxt_file ) > 5 ) {
char tmp [ 6 ] ;
2018-01-27 22:33:05 +00:00
if ( read ( reqtxt_file , tmp , 5 ) ! = 5 )
return false ;
2012-09-25 14:28:47 +00:00
tmp [ 5 ] = ' \0 ' ;
2012-12-05 05:03:56 +00:00
# if UEMIS_DEBUG & 2
2012-09-25 14:28:47 +00:00
fprintf ( debugfile , " ::r req.txt \" %s \" \n " , tmp ) ;
# endif
if ( sscanf ( tmp + 1 , " %d " , & filenr ) ! = 1 )
2014-01-15 18:54:41 +00:00
return false ;
2013-01-29 21:10:46 +00:00
} else {
2012-11-19 23:09:50 +00:00
filenr = 0 ;
2012-12-05 05:03:56 +00:00
# if UEMIS_DEBUG & 2
2012-09-25 14:28:47 +00:00
fprintf ( debugfile , " ::r req.txt skipped as there were fewer than 5 bytes \n " ) ;
# endif
2012-11-19 23:09:50 +00:00
}
2014-02-28 04:09:57 +00:00
close ( reqtxt_file ) ;
2012-09-25 14:28:47 +00:00
/* It would be nice if we could simply go back to the first set of
2012-11-29 00:11:19 +00:00
* ANS files . But with a FAT filesystem that isn ' t possible */
2013-10-05 07:29:09 +00:00
ans_path = build_filename ( path , " ANS " ) ;
2012-09-25 14:28:47 +00:00
number_of_files = number_of_file ( ans_path ) ;
2013-10-05 07:29:09 +00:00
free ( ans_path ) ;
2012-09-25 14:28:47 +00:00
/* initialize the array in which we collect the answers */
for ( i = 0 ; i < NUM_PARAM_BUFS ; i + + )
param_buff [ i ] = " " ;
2014-01-15 18:54:41 +00:00
return true ;
2012-09-25 14:28:47 +00:00
}
static void str_append_with_delim ( char * s , char * t )
{
int len = strlen ( s ) ;
snprintf ( s + len , BUFLEN - len , " %s{ " , t ) ;
}
2015-11-15 18:15:40 +00:00
/* The communication protocol with the DC is truly funky.
2012-09-25 14:28:47 +00:00
* After you write your request to the req . txt file you call this function .
* It writes the number of the next ANS file at the beginning of the req . txt
* file ( prefixed by ' n ' or ' r ' ) and then again at the very end of it , after
* the full request ( this time without the prefix ) .
* Then it syncs ( not needed on Windows ) and closes the file . */
static void trigger_response ( int file , char * command , int nr , long tailpos )
{
char fl [ 10 ] ;
snprintf ( fl , 8 , " %s%04d " , command , nr ) ;
2012-12-05 05:03:56 +00:00
# if UEMIS_DEBUG & 4
2014-02-28 04:09:57 +00:00
fprintf ( debugfile , " :tr %s (after seeks) \n " , fl ) ;
2012-09-25 14:28:47 +00:00
# endif
2014-03-06 02:27:33 +00:00
if ( lseek ( file , 0 , SEEK_SET ) = = - 1 )
goto fs_error ;
if ( write ( file , fl , strlen ( fl ) ) = = - 1 )
goto fs_error ;
if ( lseek ( file , tailpos , SEEK_SET ) = = - 1 )
goto fs_error ;
if ( write ( file , fl + 1 , strlen ( fl + 1 ) ) = = - 1 )
goto fs_error ;
2012-09-25 14:28:47 +00:00
# ifndef WIN32
fsync ( file ) ;
# endif
2014-03-06 02:27:33 +00:00
fs_error :
2012-09-25 14:28:47 +00:00
close ( file ) ;
}
static char * next_token ( char * * buf )
{
char * q , * p = strchr ( * buf , ' { ' ) ;
2012-09-27 03:37:57 +00:00
if ( p )
* p = ' \0 ' ;
else
p = * buf + strlen ( * buf ) - 1 ;
2012-09-25 14:28:47 +00:00
q = * buf ;
* buf = p + 1 ;
return q ;
}
2015-11-15 18:15:40 +00:00
/* poor man's tokenizer that understands a quoted delimiter ('{') */
2012-09-25 14:28:47 +00:00
static char * next_segment ( char * buf , int * offset , int size )
{
int i = * offset ;
int seg_size ;
2014-01-15 18:54:41 +00:00
bool done = false ;
2012-09-25 14:28:47 +00:00
char * segment ;
while ( ! done ) {
if ( i < size ) {
2013-12-11 13:26:49 +00:00
if ( i < size - 1 & & buf [ i ] = = ' \\ ' & &
2014-02-28 04:09:57 +00:00
( buf [ i + 1 ] = = ' \\ ' | | buf [ i + 1 ] = = ' { ' ) )
2012-09-25 14:28:47 +00:00
memcpy ( buf + i , buf + i + 1 , size - i - 1 ) ;
else if ( buf [ i ] = = ' { ' )
2014-01-15 18:54:41 +00:00
done = true ;
2012-09-25 14:28:47 +00:00
i + + ;
} else {
2014-01-15 18:54:41 +00:00
done = true ;
2012-09-25 14:28:47 +00:00
}
}
seg_size = i - * offset - 1 ;
if ( seg_size < 0 )
seg_size = 0 ;
segment = malloc ( seg_size + 1 ) ;
memcpy ( segment , buf + * offset , seg_size ) ;
segment [ seg_size ] = ' \0 ' ;
* offset = i ;
return segment ;
}
/* a dynamically growing buffer to store the potentially massive responses.
* The binary data block can be more than 100 k in size ( base64 encoded ) */
2012-09-27 07:16:42 +00:00
static void buffer_add ( char * * buffer , int * buffer_size , char * buf )
2012-09-25 14:28:47 +00:00
{
2012-10-26 03:15:39 +00:00
if ( ! buf )
return ;
2014-02-28 04:09:57 +00:00
if ( ! * buffer ) {
2012-10-26 03:15:39 +00:00
* buffer = strdup ( buf ) ;
* buffer_size = strlen ( * buffer ) + 1 ;
} else {
* buffer_size + = strlen ( buf ) ;
* buffer = realloc ( * buffer , * buffer_size ) ;
strcat ( * buffer , buf ) ;
}
2015-09-17 14:46:02 +00:00
# if UEMIS_DEBUG & 8
2014-02-28 04:09:57 +00:00
fprintf ( debugfile , " added \" %s \" to buffer - new length %d \n " , buf , * buffer_size ) ;
2012-09-25 14:28:47 +00:00
# endif
2012-10-26 03:15:39 +00:00
}
2012-09-25 14:28:47 +00:00
/* are there more ANS files we can check? */
2013-10-05 07:29:09 +00:00
static bool next_file ( int max )
2012-09-25 14:28:47 +00:00
{
if ( filenr > = max )
2014-01-15 18:54:41 +00:00
return false ;
2012-09-25 14:28:47 +00:00
filenr + + ;
2014-01-15 18:54:41 +00:00
return true ;
2012-09-25 14:28:47 +00:00
}
2014-08-17 21:44:43 +00:00
/* try and do a quick decode - without trying to get to fancy in case the data
* straddles a block boundary . . .
* we are parsing something that looks like this :
* object_id { int { 2 { date { ts { 2011 - 04 - 05 T12 : 38 : 04 { duration { float { 12.000 . . .
*/
2014-02-28 04:09:57 +00:00
static char * first_object_id_val ( char * buf )
2012-09-25 14:28:47 +00:00
{
2012-12-05 21:43:36 +00:00
char * object , * bufend ;
2012-12-05 20:32:16 +00:00
if ( ! buf )
return NULL ;
2012-12-05 21:43:36 +00:00
bufend = buf + strlen ( buf ) ;
2012-09-25 14:28:47 +00:00
object = strstr ( buf , " object_id " ) ;
2012-12-08 04:02:14 +00:00
if ( object & & object + 14 < bufend ) {
2012-12-05 20:32:16 +00:00
/* get the value */
2014-08-17 21:44:43 +00:00
char tmp [ 36 ] ;
2012-09-25 14:28:47 +00:00
char * p = object + 14 ;
char * t = tmp ;
2015-09-05 17:33:43 +00:00
# if UEMIS_DEBUG & 4
2012-12-05 21:43:36 +00:00
char debugbuf [ 50 ] ;
strncpy ( debugbuf , object , 49 ) ;
debugbuf [ 49 ] = ' \0 ' ;
fprintf ( debugfile , " buf |%s| \n " , debugbuf ) ;
# endif
while ( p < bufend & & * p ! = ' { ' & & t < tmp + 9 )
* t + + = * p + + ;
if ( * p = = ' { ' ) {
2014-08-17 21:44:43 +00:00
/* found the object_id - let's quickly look for the date */
if ( strncmp ( p , " {date{ts{ " , 9 ) = = 0 & & strstr ( p , " {duration{ " ) ! = NULL ) {
/* cool - that was easy */
* t + + = ' , ' ;
* t + + = ' ' ;
/* skip the 9 characters we just found and take the date, ignoring the seconds
* and replace the silly ' T ' in the middle with a space */
strncpy ( t , p + 9 , 16 ) ;
if ( * ( t + 10 ) = = ' T ' )
* ( t + 10 ) = ' ' ;
t + = 16 ;
}
2012-09-25 14:28:47 +00:00
* t = ' \0 ' ;
2012-12-05 21:43:36 +00:00
return strdup ( tmp ) ;
2012-09-25 14:28:47 +00:00
}
2012-12-05 20:32:16 +00:00
}
return NULL ;
}
/* ultra-simplistic; it doesn't deal with the case when the object_id is
* split across two chunks . It also doesn ' t deal with the discrepancy between
* object_id and dive number as understood by the dive computer */
2013-10-06 15:55:58 +00:00
static void show_progress ( char * buf , const char * what )
2012-12-05 20:32:16 +00:00
{
char * val = first_object_id_val ( buf ) ;
if ( val ) {
2014-02-28 04:09:57 +00:00
/* let the user know what we are working on */
2015-09-17 14:46:02 +00:00
# if UEMIS_DEBUG & 8
2015-09-15 08:09:24 +00:00
fprintf ( debugfile , " reading %s \n %s \n %s \n " , what , val , buf ) ;
2012-12-05 21:43:36 +00:00
# endif
2014-08-17 21:44:43 +00:00
uemis_info ( translate ( " gettextFromC " , " %s %s " ) , what , val ) ;
2012-12-05 20:32:16 +00:00
free ( val ) ;
2012-09-25 14:28:47 +00:00
}
}
2012-11-19 22:09:21 +00:00
static void uemis_increased_timeout ( int * timeout )
{
if ( * timeout < UEMIS_MAX_TIMEOUT )
* timeout + = UEMIS_LONG_TIMEOUT ;
usleep ( * timeout ) ;
}
2019-03-17 20:58:11 +00:00
static char * build_ans_path ( const char * path , int filenumber )
2018-11-18 10:33:50 +00:00
{
char * intermediate , * ans_path , fl [ 13 ] ;
2019-03-17 20:58:11 +00:00
/* Clamp filenumber into the 0..9999 range. This is never necessary,
* as filenumber can never go above UEMIS_MAX_FILES , but gcc doesn ' t
2018-11-18 10:33:50 +00:00
* recognize that and produces very noisy warnings . */
2019-03-17 20:58:11 +00:00
filenumber = filenumber < 0 ? 0 : filenumber % 10000 ;
2018-11-18 10:33:50 +00:00
2019-03-17 20:58:11 +00:00
snprintf ( fl , 13 , " ANS%d.TXT " , filenumber ) ;
2018-11-18 10:33:50 +00:00
intermediate = build_filename ( path , " ANS " ) ;
ans_path = build_filename ( intermediate , fl ) ;
free ( intermediate ) ;
return ans_path ;
}
2012-09-25 14:28:47 +00:00
/* send a request to the dive computer and collect the answer */
2013-10-05 07:29:09 +00:00
static bool uemis_get_answer ( const char * path , char * request , int n_param_in ,
2014-02-28 04:09:57 +00:00
int n_param_out , const char * * error_text )
2012-09-25 14:28:47 +00:00
{
int i = 0 , file_length ;
char sb [ BUFLEN ] ;
char fl [ 13 ] ;
2012-09-27 07:16:42 +00:00
char tmp [ 101 ] ;
2014-02-28 04:09:57 +00:00
const char * what = translate ( " gettextFromC " , " data " ) ;
2014-01-15 18:54:41 +00:00
bool searching = true ;
bool assembling_mbuf = false ;
bool ismulti = false ;
bool found_answer = false ;
bool more_files = true ;
bool answer_in_mbuf = false ;
2012-09-25 14:28:47 +00:00
char * ans_path ;
int ans_file ;
2012-11-19 22:09:21 +00:00
int timeout = UEMIS_LONG_TIMEOUT ;
2012-09-25 14:28:47 +00:00
2013-12-19 13:00:51 +00:00
reqtxt_file = subsurface_open ( reqtxt_path , O_RDWR | O_CREAT , 0666 ) ;
2017-12-30 17:32:12 +00:00
if ( reqtxt_file < 0 ) {
2015-04-30 22:33:16 +00:00
* error_text = " can't open req.txt " ;
2015-09-05 17:33:43 +00:00
# ifdef UEMIS_DEBUG
fprintf ( debugfile , " open %s failed with errno %d \n " , reqtxt_path , errno ) ;
# endif
2015-04-30 22:33:16 +00:00
return false ;
}
2012-09-25 14:28:47 +00:00
snprintf ( sb , BUFLEN , " n%04d12345678 " , filenr ) ;
str_append_with_delim ( sb , request ) ;
for ( i = 0 ; i < n_param_in ; i + + )
str_append_with_delim ( sb , param_buff [ i ] ) ;
2014-02-28 04:09:57 +00:00
if ( ! strcmp ( request , " getDivelogs " ) | | ! strcmp ( request , " getDeviceData " ) | | ! strcmp ( request , " getDirectory " ) | |
! strcmp ( request , " getDivespot " ) | | ! strcmp ( request , " getDive " ) ) {
2014-01-15 18:54:41 +00:00
answer_in_mbuf = true ;
2012-09-25 14:28:47 +00:00
str_append_with_delim ( sb , " " ) ;
2014-02-28 04:09:57 +00:00
if ( ! strcmp ( request , " getDivelogs " ) )
2017-02-20 09:30:01 +00:00
what = translate ( " gettextFromC " , " dive log # " ) ;
2012-11-29 00:11:19 +00:00
else if ( ! strcmp ( request , " getDivespot " ) )
2017-02-20 09:36:49 +00:00
what = translate ( " gettextFromC " , " dive spot # " ) ;
2012-11-29 00:11:19 +00:00
else if ( ! strcmp ( request , " getDive " ) )
2014-08-17 21:44:43 +00:00
what = translate ( " gettextFromC " , " details for # " ) ;
2012-09-25 14:28:47 +00:00
}
str_append_with_delim ( sb , " " ) ;
file_length = strlen ( sb ) ;
snprintf ( fl , 10 , " %08d " , file_length - 13 ) ;
memcpy ( sb + 5 , fl , strlen ( fl ) ) ;
2015-09-05 17:33:43 +00:00
# if UEMIS_DEBUG & 4
2014-02-28 04:09:57 +00:00
fprintf ( debugfile , " ::w req.txt \" %s \" \n " , sb ) ;
2012-09-25 14:28:47 +00:00
# endif
2016-03-10 03:06:14 +00:00
int written = write ( reqtxt_file , sb , strlen ( sb ) ) ;
if ( written = = - 1 | | ( size_t ) written ! = strlen ( sb ) ) {
2014-02-28 04:09:57 +00:00
* error_text = translate ( " gettextFromC " , ERR_FS_SHORT_WRITE ) ;
2014-01-15 18:54:41 +00:00
return false ;
2012-09-25 14:28:47 +00:00
}
2014-02-28 04:09:57 +00:00
if ( ! next_file ( number_of_files ) ) {
* error_text = translate ( " gettextFromC " , ERR_FS_FULL ) ;
2014-01-15 18:54:41 +00:00
more_files = false ;
2012-09-25 14:28:47 +00:00
}
trigger_response ( reqtxt_file , " n " , filenr , file_length ) ;
2012-11-19 22:09:21 +00:00
usleep ( timeout ) ;
2015-12-03 17:47:09 +00:00
free ( mbuf ) ;
2012-09-25 14:28:47 +00:00
mbuf = NULL ;
mbuf_size = 0 ;
while ( searching | | assembling_mbuf ) {
2012-11-19 22:11:08 +00:00
if ( import_thread_cancelled )
2014-01-15 18:54:41 +00:00
return false ;
2015-09-05 18:04:58 +00:00
progress_bar_fraction = filenr / ( double ) UEMIS_MAX_FILES ;
2018-11-18 10:33:50 +00:00
ans_path = build_ans_path ( path , filenr - 1 ) ;
2013-12-19 13:00:51 +00:00
ans_file = subsurface_open ( ans_path , O_RDONLY , 0666 ) ;
2017-12-30 17:32:12 +00:00
if ( ans_file < 0 ) {
* error_text = " can't open Uemis response file " ;
# ifdef UEMIS_DEBUG
fprintf ( debugfile , " open %s failed with errno %d \n " , ans_path , errno ) ;
# endif
2018-11-19 11:35:45 +00:00
free ( ans_path ) ;
2017-12-30 17:32:12 +00:00
return false ;
}
2018-11-19 11:35:45 +00:00
if ( read ( ans_file , tmp , 100 ) < 0 ) {
free ( ans_path ) ;
2018-01-27 22:33:05 +00:00
return false ;
2018-11-19 11:35:45 +00:00
}
2012-09-25 14:28:47 +00:00
close ( ans_file ) ;
2012-12-05 05:03:56 +00:00
# if UEMIS_DEBUG & 8
2014-02-28 04:09:57 +00:00
tmp [ 100 ] = ' \0 ' ;
2012-09-25 14:28:47 +00:00
fprintf ( debugfile , " ::t %s \" %s \" \n " , ans_path , tmp ) ;
2012-12-05 20:32:16 +00:00
# elif UEMIS_DEBUG & 4
2012-11-19 22:08:14 +00:00
char pbuf [ 4 ] ;
pbuf [ 0 ] = tmp [ 0 ] ;
pbuf [ 1 ] = tmp [ 1 ] ;
pbuf [ 2 ] = tmp [ 2 ] ;
pbuf [ 3 ] = 0 ;
fprintf ( debugfile , " ::t %s \" %s... \" \n " , ans_path , pbuf ) ;
2012-09-25 14:28:47 +00:00
# endif
2013-10-05 07:29:09 +00:00
free ( ans_path ) ;
2012-09-25 14:28:47 +00:00
if ( tmp [ 0 ] = = ' 1 ' ) {
2014-01-15 18:54:41 +00:00
searching = false ;
2012-09-25 14:28:47 +00:00
if ( tmp [ 1 ] = = ' m ' ) {
2014-01-15 18:54:41 +00:00
assembling_mbuf = true ;
ismulti = true ;
2012-09-25 14:28:47 +00:00
}
if ( tmp [ 2 ] = = ' e ' )
2014-01-15 18:54:41 +00:00
assembling_mbuf = false ;
2012-09-25 14:28:47 +00:00
if ( assembling_mbuf ) {
2014-02-28 04:09:57 +00:00
if ( ! next_file ( number_of_files ) ) {
* error_text = translate ( " gettextFromC " , ERR_FS_FULL ) ;
2014-01-15 18:54:41 +00:00
more_files = false ;
assembling_mbuf = false ;
2012-09-25 14:28:47 +00:00
}
2013-12-19 13:00:51 +00:00
reqtxt_file = subsurface_open ( reqtxt_path , O_RDWR | O_CREAT , 0666 ) ;
2017-12-30 17:32:12 +00:00
if ( reqtxt_file < 0 ) {
2015-06-22 13:46:01 +00:00
* error_text = " can't open req.txt " ;
fprintf ( stderr , " open %s failed with errno %d \n " , reqtxt_path , errno ) ;
return false ;
}
2012-09-25 14:28:47 +00:00
trigger_response ( reqtxt_file , " n " , filenr , file_length ) ;
}
} else {
2014-02-28 04:09:57 +00:00
if ( ! next_file ( number_of_files - 1 ) ) {
* error_text = translate ( " gettextFromC " , ERR_FS_FULL ) ;
2014-01-15 18:54:41 +00:00
more_files = false ;
assembling_mbuf = false ;
searching = false ;
2012-09-25 14:28:47 +00:00
}
2013-12-19 13:00:51 +00:00
reqtxt_file = subsurface_open ( reqtxt_path , O_RDWR | O_CREAT , 0666 ) ;
2017-12-30 17:32:12 +00:00
if ( reqtxt_file < 0 ) {
2015-06-22 13:46:01 +00:00
* error_text = " can't open req.txt " ;
fprintf ( stderr , " open %s failed with errno %d \n " , reqtxt_path , errno ) ;
return false ;
}
2012-09-25 14:28:47 +00:00
trigger_response ( reqtxt_file , " r " , filenr , file_length ) ;
2012-11-19 22:09:21 +00:00
uemis_increased_timeout ( & timeout ) ;
2012-09-25 14:28:47 +00:00
}
if ( ismulti & & more_files & & tmp [ 0 ] = = ' 1 ' ) {
int size ;
2018-11-18 10:33:50 +00:00
ans_path = build_ans_path ( path , assembling_mbuf ? filenr - 2 : filenr - 1 ) ;
2013-12-19 13:00:51 +00:00
ans_file = subsurface_open ( ans_path , O_RDONLY , 0666 ) ;
2017-12-30 17:32:12 +00:00
if ( ans_file < 0 ) {
* error_text = " can't open Uemis response file " ;
# ifdef UEMIS_DEBUG
fprintf ( debugfile , " open %s failed with errno %d \n " , ans_path , errno ) ;
# endif
2018-11-19 11:35:45 +00:00
free ( ans_path ) ;
2017-12-30 17:32:12 +00:00
return false ;
}
2015-06-22 03:24:07 +00:00
free ( ans_path ) ;
2012-09-25 14:28:47 +00:00
size = bytes_available ( ans_file ) ;
if ( size > 3 ) {
2014-03-06 02:27:33 +00:00
char * buf ;
int r ;
if ( lseek ( ans_file , 3 , SEEK_CUR ) = = - 1 )
goto fs_error ;
buf = malloc ( size - 2 ) ;
2014-05-01 21:14:50 +00:00
if ( ( r = read ( ans_file , buf , size - 3 ) ) ! = size - 3 ) {
2014-03-06 02:27:33 +00:00
free ( buf ) ;
goto fs_error ;
}
buf [ r ] = ' \0 ' ;
2012-09-27 07:16:42 +00:00
buffer_add ( & mbuf , & mbuf_size , buf ) ;
2012-11-29 00:11:19 +00:00
show_progress ( buf , what ) ;
2012-09-25 14:28:47 +00:00
free ( buf ) ;
2012-09-27 07:16:42 +00:00
param_buff [ 3 ] + + ;
2012-09-25 14:28:47 +00:00
}
close ( ans_file ) ;
2012-11-19 22:09:21 +00:00
timeout = UEMIS_TIMEOUT ;
2012-09-27 07:16:42 +00:00
usleep ( UEMIS_TIMEOUT ) ;
2012-09-25 14:28:47 +00:00
}
}
if ( more_files ) {
int size = 0 , j = 0 ;
char * buf = NULL ;
if ( ! ismulti ) {
2018-11-18 10:33:50 +00:00
ans_path = build_ans_path ( path , filenr - 1 ) ;
2013-12-19 13:00:51 +00:00
ans_file = subsurface_open ( ans_path , O_RDONLY , 0666 ) ;
2017-12-30 17:32:12 +00:00
if ( ans_file < 0 ) {
* error_text = " can't open Uemis response file " ;
# ifdef UEMIS_DEBUG
fprintf ( debugfile , " open %s failed with errno %d \n " , ans_path , errno ) ;
# endif
2018-11-19 11:35:45 +00:00
free ( ans_path ) ;
2017-12-30 17:32:12 +00:00
return false ;
}
2012-09-25 14:28:47 +00:00
size = bytes_available ( ans_file ) ;
if ( size > 3 ) {
2014-03-06 02:27:33 +00:00
int r ;
if ( lseek ( ans_file , 3 , SEEK_CUR ) = = - 1 )
goto fs_error ;
2012-09-25 14:28:47 +00:00
buf = malloc ( size - 2 ) ;
2014-03-06 02:27:33 +00:00
if ( ( r = read ( ans_file , buf , size - 3 ) ) ! = size - 3 ) {
free ( buf ) ;
goto fs_error ;
}
buf [ r ] = ' \0 ' ;
2012-11-29 00:11:19 +00:00
buffer_add ( & mbuf , & mbuf_size , buf ) ;
show_progress ( buf , what ) ;
2012-12-05 05:03:56 +00:00
# if UEMIS_DEBUG & 8
2018-11-18 10:33:50 +00:00
fprintf ( debugfile , " ::r %s \" %s \" \n " , ans_path , buf ) ;
2012-09-25 14:28:47 +00:00
# endif
}
2012-09-27 07:16:42 +00:00
size - = 3 ;
2018-11-18 10:33:50 +00:00
free ( ans_path ) ;
2012-09-25 14:28:47 +00:00
close ( ans_file ) ;
} else {
2014-01-15 18:54:41 +00:00
ismulti = false ;
2012-09-25 14:28:47 +00:00
}
2012-12-05 05:03:56 +00:00
# if UEMIS_DEBUG & 8
2014-02-28 04:09:57 +00:00
fprintf ( debugfile , " :r: %s \n " , buf ) ;
2012-09-25 14:28:47 +00:00
# endif
if ( ! answer_in_mbuf )
for ( i = 0 ; i < n_param_out & & j < size ; i + + )
param_buff [ i ] = next_segment ( buf , & j , size ) ;
2014-01-15 18:54:41 +00:00
found_answer = true ;
2012-09-30 03:57:48 +00:00
free ( buf ) ;
2012-09-25 14:28:47 +00:00
}
2012-12-05 05:03:56 +00:00
# if UEMIS_DEBUG & 1
2012-09-25 14:28:47 +00:00
for ( i = 0 ; i < n_param_out ; i + + )
2014-02-28 04:09:57 +00:00
fprintf ( debugfile , " ::: %d: %s \n " , i , param_buff [ i ] ) ;
2012-09-25 14:28:47 +00:00
# endif
return found_answer ;
2014-03-06 02:27:33 +00:00
fs_error :
2015-09-05 17:29:43 +00:00
close ( ans_file ) ;
2014-03-06 02:27:33 +00:00
return false ;
2012-09-25 14:28:47 +00:00
}
2015-09-05 18:09:10 +00:00
static bool parse_divespot ( char * buf )
2012-11-29 00:11:19 +00:00
{
char * bp = buf + 1 ;
char * tp = next_token ( & bp ) ;
char * tag , * type , * val ;
2013-03-04 01:53:43 +00:00
char locationstring [ 1024 ] = " " ;
2012-11-29 00:11:19 +00:00
int divespot , len ;
2013-04-08 02:50:26 +00:00
double latitude = 0.0 , longitude = 0.0 ;
2012-11-29 00:11:19 +00:00
2015-09-05 18:09:10 +00:00
// dive spot got deleted, so fail here
if ( strstr ( bp , " deleted{bool{true " ) )
return false ;
// not a dive spot, fail here
2012-11-29 00:11:19 +00:00
if ( strcmp ( tp , " divespot " ) )
2015-09-05 18:09:10 +00:00
return false ;
2012-11-29 00:11:19 +00:00
do
tag = next_token ( & bp ) ;
while ( * tag & & strcmp ( tag , " object_id " ) ) ;
2014-02-28 04:09:57 +00:00
if ( ! * tag )
2015-09-05 18:09:10 +00:00
return false ;
2014-03-04 05:24:52 +00:00
next_token ( & bp ) ;
2012-11-29 00:11:19 +00:00
val = next_token ( & bp ) ;
divespot = atoi ( val ) ;
do {
tag = next_token ( & bp ) ;
type = next_token ( & bp ) ;
val = next_token ( & bp ) ;
if ( ! strcmp ( type , " string " ) & & * val & & strcmp ( val , " " ) ) {
len = strlen ( locationstring ) ;
snprintf ( locationstring + len , sizeof ( locationstring ) - len ,
2014-02-28 04:09:57 +00:00
" %s%s " , len ? " , " : " " , val ) ;
2012-11-29 00:11:19 +00:00
} else if ( ! strcmp ( type , " float " ) ) {
if ( ! strcmp ( tag , " longitude " ) )
2013-10-05 07:29:09 +00:00
longitude = ascii_strtod ( val , NULL ) ;
2012-11-29 00:11:19 +00:00
else if ( ! strcmp ( tag , " latitude " ) )
2013-10-05 07:29:09 +00:00
latitude = ascii_strtod ( val , NULL ) ;
2012-11-29 00:11:19 +00:00
}
} while ( tag & & * tag ) ;
2015-09-05 18:09:10 +00:00
2015-03-19 20:20:03 +00:00
uemis_set_divelocation ( divespot , locationstring , longitude , latitude ) ;
2015-09-05 18:09:10 +00:00
return true ;
2012-11-29 00:11:19 +00:00
}
2015-09-05 17:29:43 +00:00
static char * suit [ ] = { " " , QT_TRANSLATE_NOOP ( " gettextFromC " , " wetsuit " ) , QT_TRANSLATE_NOOP ( " gettextFromC " , " semidry " ) , QT_TRANSLATE_NOOP ( " gettextFromC " , " drysuit " ) } ;
static char * suit_type [ ] = { " " , QT_TRANSLATE_NOOP ( " gettextFromC " , " shorty " ) , QT_TRANSLATE_NOOP ( " gettextFromC " , " vest " ) , QT_TRANSLATE_NOOP ( " gettextFromC " , " long john " ) , QT_TRANSLATE_NOOP ( " gettextFromC " , " jacket " ) , QT_TRANSLATE_NOOP ( " gettextFromC " , " full suit " ) , QT_TRANSLATE_NOOP ( " gettextFromC " , " 2 pcs full suit " ) } ;
static char * suit_thickness [ ] = { " " , " 0.5-2mm " , " 2-3mm " , " 3-5mm " , " 5-7mm " , " 8mm+ " , QT_TRANSLATE_NOOP ( " gettextFromC " , " membrane " ) } ;
2012-11-29 00:11:19 +00:00
static void parse_tag ( struct dive * dive , char * tag , char * val )
{
/* we can ignore computer_id, water and gas as those are redundant
* with the binary data and would just get overwritten */
2015-09-05 17:33:43 +00:00
# if UEMIS_DEBUG & 4
if ( strcmp ( tag , " file_content " ) )
fprintf ( debugfile , " Adding to dive %d : %s = %s \n " , dive - > dc . diveid , tag , val ) ;
# endif
2014-02-28 04:09:57 +00:00
if ( ! strcmp ( tag , " date " ) ) {
2012-11-29 00:11:19 +00:00
uemis_ts ( val , & dive - > when ) ;
2013-02-04 04:50:14 +00:00
} else if ( ! strcmp ( tag , " duration " ) ) {
2013-01-23 18:25:31 +00:00
uemis_duration ( val , & dive - > dc . duration ) ;
2013-02-04 04:50:14 +00:00
} else if ( ! strcmp ( tag , " depth " ) ) {
2013-01-23 18:25:31 +00:00
uemis_depth ( val , & dive - > dc . maxdepth ) ;
2013-02-04 04:50:14 +00:00
} else if ( ! strcmp ( tag , " file_content " ) ) {
2012-11-29 00:11:19 +00:00
uemis_parse_divelog_binary ( val , dive ) ;
2013-02-04 04:50:14 +00:00
} else if ( ! strcmp ( tag , " altitude " ) ) {
2013-01-23 18:25:31 +00:00
uemis_get_index ( val , & dive - > dc . surface_pressure . mbar ) ;
2013-02-04 04:50:14 +00:00
} else if ( ! strcmp ( tag , " f32Weight " ) ) {
2012-11-29 00:11:19 +00:00
uemis_get_weight ( val , & dive - > weightsystem [ 0 ] , dive - > dc . diveid ) ;
2013-02-04 04:50:14 +00:00
} else if ( ! strcmp ( tag , " notes " ) ) {
2015-09-18 20:14:46 +00:00
uemis_add_string ( val , & dive - > notes , " " ) ;
2013-02-04 04:50:14 +00:00
} else if ( ! strcmp ( tag , " u8DiveSuit " ) ) {
if ( * suit [ atoi ( val ) ] )
2015-09-07 18:48:45 +00:00
uemis_add_string ( translate ( " gettextFromC " , suit [ atoi ( val ) ] ) , & dive - > suit , " " ) ;
2013-02-04 04:50:14 +00:00
} else if ( ! strcmp ( tag , " u8DiveSuitType " ) ) {
if ( * suit_type [ atoi ( val ) ] )
2015-09-07 18:48:45 +00:00
uemis_add_string ( translate ( " gettextFromC " , suit_type [ atoi ( val ) ] ) , & dive - > suit , " " ) ;
2013-02-04 04:50:14 +00:00
} else if ( ! strcmp ( tag , " u8SuitThickness " ) ) {
if ( * suit_thickness [ atoi ( val ) ] )
2015-09-07 18:48:45 +00:00
uemis_add_string ( translate ( " gettextFromC " , suit_thickness [ atoi ( val ) ] ) , & dive - > suit , " " ) ;
} else if ( ! strcmp ( tag , " nickname " ) ) {
uemis_add_string ( val , & dive - > buddy , " , " ) ;
2013-02-04 04:50:14 +00:00
}
2012-11-29 00:11:19 +00:00
}
2015-09-05 18:21:14 +00:00
static bool uemis_delete_dive ( device_data_t * devdata , uint32_t diveid )
{
struct dive * dive = NULL ;
if ( devdata - > download_table - > dives [ devdata - > download_table - > nr - 1 ] - > dc . diveid = = diveid ) {
/* we hit the last one in the array */
dive = devdata - > download_table - > dives [ devdata - > download_table - > nr - 1 ] ;
} else {
for ( int i = 0 ; i < devdata - > download_table - > nr - 1 ; i + + ) {
if ( devdata - > download_table - > dives [ i ] - > dc . diveid = = diveid ) {
dive = devdata - > download_table - > dives [ i ] ;
for ( int x = i ; x < devdata - > download_table - > nr - 1 ; x + + )
devdata - > download_table - > dives [ i ] = devdata - > download_table - > dives [ x + 1 ] ;
}
}
}
if ( dive ) {
devdata - > download_table - > dives [ - - devdata - > download_table - > nr ] = NULL ;
free ( dive - > dc . sample ) ;
free ( ( void * ) dive - > notes ) ;
free ( ( void * ) dive - > divemaster ) ;
free ( ( void * ) dive - > buddy ) ;
free ( ( void * ) dive - > suit ) ;
taglist_free ( dive - > tag_list ) ;
free ( dive ) ;
return true ;
}
return false ;
}
2017-02-20 09:30:01 +00:00
/* This function is called for both dive log and dive information that we get
* from the SDA ( what an insane design , btw ) . The object_id in the dive log
2012-11-29 00:11:19 +00:00
* matches the logfilenr in the dive information ( which has its own , often
* different object_id ) - we use this as the diveid .
2017-02-20 09:30:01 +00:00
* We create the dive when parsing the dive log and then later , when we parse
2012-11-29 00:11:19 +00:00
* the dive information we locate the already created dive via its diveid .
* Most things just get parsed and converted into our internal data structures ,
* but the dive location API is even more crazy . We just get an id that is an
* index into yet another data store that we read out later . In order to
* correctly populate the location and gps data from that we need to remember
2017-02-20 09:36:49 +00:00
* the addresses of those fields for every dive that references the dive spot . */
2016-03-10 03:06:14 +00:00
static bool process_raw_buffer ( device_data_t * devdata , uint32_t deviceid , char * inbuf , char * * max_divenr , int * for_dive )
2012-09-25 14:28:47 +00:00
{
char * buf = strdup ( inbuf ) ;
char * tp , * bp , * tag , * type , * val ;
2014-01-15 18:54:41 +00:00
bool done = false ;
2012-09-25 14:28:47 +00:00
int inbuflen = strlen ( inbuf ) ;
char * endptr = buf + inbuflen ;
2015-09-10 04:19:07 +00:00
bool is_log = false , is_dive = false ;
2012-10-26 03:15:39 +00:00
char * sections [ 10 ] ;
2016-03-10 03:06:14 +00:00
size_t s , nr_sections = 0 ;
2012-11-29 00:11:19 +00:00
struct dive * dive = NULL ;
2015-09-07 18:51:49 +00:00
char dive_no [ 10 ] ;
2012-09-25 14:28:47 +00:00
2015-09-17 14:46:02 +00:00
# if UEMIS_DEBUG & 8
2014-05-05 21:36:55 +00:00
fprintf ( debugfile , " p_r_b %s \n " , inbuf ) ;
# endif
2013-02-08 01:53:32 +00:00
if ( for_dive )
* for_dive = - 1 ;
2012-09-25 14:28:47 +00:00
bp = buf + 1 ;
tp = next_token ( & bp ) ;
2012-10-26 03:15:39 +00:00
if ( strcmp ( tp , " divelog " ) = = 0 ) {
2017-02-20 09:30:01 +00:00
/* this is a dive log */
2015-09-05 18:24:10 +00:00
is_log = true ;
2012-10-26 03:15:39 +00:00
tp = next_token ( & bp ) ;
2014-05-05 21:36:55 +00:00
/* is it a valid entry or nothing ? */
if ( strcmp ( tp , " 1.0 " ) ! = 0 | | strstr ( inbuf , " divelog{1.0{{{{ " ) ) {
2013-12-10 23:53:29 +00:00
free ( buf ) ;
2014-05-05 21:36:55 +00:00
return false ;
2013-12-10 23:53:29 +00:00
}
2012-10-26 03:15:39 +00:00
} else if ( strcmp ( tp , " dive " ) = = 0 ) {
/* this is dive detail */
2015-09-05 18:24:10 +00:00
is_dive = true ;
2012-10-26 03:15:39 +00:00
tp = next_token ( & bp ) ;
2014-02-28 04:09:57 +00:00
if ( strcmp ( tp , " 1.0 " ) ! = 0 ) {
2013-12-10 23:53:29 +00:00
free ( buf ) ;
2014-05-05 21:36:55 +00:00
return false ;
2013-12-10 23:53:29 +00:00
}
2012-10-26 03:15:39 +00:00
} else {
/* don't understand the buffer */
2013-12-10 23:53:29 +00:00
free ( buf ) ;
2014-05-05 21:36:55 +00:00
return false ;
2012-10-26 03:15:39 +00:00
}
2015-09-05 18:24:10 +00:00
if ( is_log ) {
2012-11-29 00:11:19 +00:00
dive = uemis_start_dive ( deviceid ) ;
2014-05-05 21:36:55 +00:00
} else {
/* remember, we don't know if this is the right entry,
* so first test if this is even a valid entry */
if ( strstr ( inbuf , " deleted{bool{true " ) ) {
2015-09-05 17:33:43 +00:00
# if UEMIS_DEBUG & 2
2014-05-05 21:36:55 +00:00
fprintf ( debugfile , " p_r_b entry deleted \n " ) ;
# endif
/* oops, this one isn't valid, suggest to try the previous one */
2015-03-19 19:32:31 +00:00
free ( buf ) ;
2014-05-05 21:36:55 +00:00
return false ;
}
2015-09-07 18:51:49 +00:00
/* quickhack and workaround to capture the original dive_no
2015-11-15 18:15:40 +00:00
* I am doing this so I don ' t have to change the original design
2015-09-07 18:51:49 +00:00
* but when parsing a dive we never parse the dive number because
2015-11-15 18:15:40 +00:00
* at the time it ' s being read the * dive variable is not set because
2015-09-07 18:51:49 +00:00
* the dive_no tag comes before the object_id in the uemis ans file
*/
2015-10-02 01:49:00 +00:00
dive_no [ 0 ] = ' \0 ' ;
2015-09-07 18:51:49 +00:00
char * dive_no_buf = strdup ( inbuf ) ;
char * dive_no_ptr = strstr ( dive_no_buf , " dive_no{int{ " ) + 12 ;
2015-10-02 01:49:00 +00:00
if ( dive_no_ptr ) {
char * dive_no_end = strstr ( dive_no_ptr , " { " ) ;
if ( dive_no_end ) {
* dive_no_end = ' \0 ' ;
strncpy ( dive_no , dive_no_ptr , 9 ) ;
dive_no [ 9 ] = ' \0 ' ;
}
}
2015-09-07 18:51:49 +00:00
free ( dive_no_buf ) ;
2014-05-05 21:36:55 +00:00
}
2012-09-25 14:28:47 +00:00
while ( ! done ) {
2012-10-26 03:15:39 +00:00
/* the valid buffer ends with a series of delimiters */
if ( bp > = endptr - 2 | | ! strcmp ( bp , " {{ " ) )
break ;
2012-09-25 14:28:47 +00:00
tag = next_token ( & bp ) ;
2012-10-26 03:15:39 +00:00
/* 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 ;
}
2012-09-25 14:28:47 +00:00
type = next_token ( & bp ) ;
2012-10-26 03:15:39 +00:00
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 ;
2012-12-05 05:03:56 +00:00
# if UEMIS_DEBUG & 4
2012-10-26 03:15:39 +00:00
fprintf ( debugfile , " Expect to find section %s \n " , sections [ nr_sections ] ) ;
# endif
2017-12-26 23:49:19 +00:00
if ( nr_sections < sizeof ( sections ) / sizeof ( * sections ) - 1 )
2012-10-26 03:15:39 +00:00
nr_sections + + ;
continue ;
}
2012-09-25 14:28:47 +00:00
val = next_token ( & bp ) ;
2015-09-05 17:33:43 +00:00
# if UEMIS_DEBUG & 8
if ( strlen ( val ) < 20 )
fprintf ( debugfile , " Parsed %s, %s, %s \n ************************* \n " , tag , type , val ) ;
# endif
2015-09-05 18:24:10 +00:00
if ( is_log & & strcmp ( tag , " object_id " ) = = 0 ) {
2012-09-25 14:28:47 +00:00
free ( * max_divenr ) ;
* max_divenr = strdup ( val ) ;
2012-11-29 00:11:19 +00:00
dive - > dc . diveid = atoi ( val ) ;
2015-09-05 17:33:43 +00:00
# if UEMIS_DEBUG % 2
fprintf ( debugfile , " Adding new dive from log with object_id %d. \n " , atoi ( val ) ) ;
# endif
2015-09-05 18:24:10 +00:00
} else if ( is_dive & & strcmp ( tag , " logfilenr " ) = = 0 ) {
2012-11-29 00:11:19 +00:00
/* this one tells us which dive we are adding data to */
2015-09-05 18:00:54 +00:00
dive = get_dive_by_uemis_diveid ( devdata , atoi ( val ) ) ;
2015-09-07 18:51:49 +00:00
if ( strcmp ( dive_no , " 0 " ) )
dive - > number = atoi ( dive_no ) ;
2013-02-08 01:53:32 +00:00
if ( for_dive )
* for_dive = atoi ( val ) ;
2015-09-05 18:24:10 +00:00
} else if ( ! is_log & & dive & & ! strcmp ( tag , " divespot_id " ) ) {
2015-09-10 15:29:19 +00:00
int divespot_id = atoi ( val ) ;
if ( divespot_id ! = - 1 ) {
2018-10-24 14:03:52 +00:00
struct dive_site * ds = create_dive_site ( " from Uemis " , dive - > when ) ;
2018-10-26 15:03:54 +00:00
dive - > dive_site = ds ;
2018-10-24 14:03:52 +00:00
uemis_mark_divelocation ( dive - > dc . diveid , divespot_id , ds ) ;
2015-09-10 15:29:19 +00:00
}
2015-09-05 17:33:43 +00:00
# if UEMIS_DEBUG & 2
2018-10-26 15:03:54 +00:00
fprintf ( debugfile , " Created divesite %d for diveid : %d \n " , dive - > dive_site - > uuid , dive - > dc . diveid ) ;
2015-09-05 17:33:43 +00:00
# endif
2012-11-29 00:11:19 +00:00
} else if ( dive ) {
parse_tag ( dive , tag , val ) ;
2012-09-25 14:28:47 +00:00
}
2015-09-05 18:24:10 +00:00
if ( is_log & & ! strcmp ( tag , " file_content " ) )
2014-01-15 18:54:41 +00:00
done = true ;
2012-09-27 03:37:57 +00:00
/* done with one dive (got the file_content tag), but there could be more:
* a ' { ' indicates the end of the record - but we need to see another " {{ "
* later in the buffer to know that the next record is complete ( it could
* be a short read because of some error */
if ( done & & + + bp < endptr & & * bp ! = ' { ' & & strstr ( bp , " {{ " ) ) {
2014-01-15 18:54:41 +00:00
done = false ;
2019-01-13 08:58:04 +00:00
record_dive_to_table ( dive , devdata - > download_table ) ;
2014-01-15 18:54:41 +00:00
mark_divelist_changed ( true ) ;
2012-11-29 00:11:19 +00:00
dive = uemis_start_dive ( deviceid ) ;
2012-09-25 14:28:47 +00:00
}
}
2015-09-05 18:24:10 +00:00
if ( is_log ) {
2012-11-29 00:11:19 +00:00
if ( dive - > dc . diveid ) {
2019-01-13 08:58:04 +00:00
record_dive_to_table ( dive , devdata - > download_table ) ;
2014-01-15 18:54:41 +00:00
mark_divelist_changed ( true ) ;
2012-11-29 00:11:19 +00:00
} else { /* partial dive */
free ( dive ) ;
2014-05-05 21:36:55 +00:00
free ( buf ) ;
return false ;
2012-11-29 00:11:19 +00:00
}
2012-10-26 03:15:39 +00:00
}
2012-09-25 14:28:47 +00:00
free ( buf ) ;
2014-05-05 21:36:55 +00:00
return true ;
2012-09-25 14:28:47 +00:00
}
2018-10-04 09:48:40 +00:00
static char * uemis_get_divenr ( char * deviceidstr , struct dive_table * table , int force )
2012-09-25 14:28:47 +00:00
{
2013-01-18 20:56:54 +00:00
uint32_t deviceid , maxdiveid = 0 ;
int i ;
2012-11-29 05:02:03 +00:00
char divenr [ 10 ] ;
2012-11-29 00:11:19 +00:00
deviceid = atoi ( deviceidstr ) ;
2018-01-28 19:20:02 +00:00
mindiveid = 0xFFFFFFFF ;
2015-09-20 04:09:58 +00:00
/*
* If we are are retrying after a disconnect / reconnect , we
* will look up the highest dive number in the dives we
* already have .
*
* Also , if " force_download " is true , do this even if we
2018-10-04 09:48:40 +00:00
* don ' t have any dives ( maxdiveid will remain ~ 0 ) .
*
* Otherwise , use the global dive table .
2015-09-20 04:09:58 +00:00
*/
2018-10-04 09:48:40 +00:00
if ( ! force & & ! table - > nr )
2015-09-20 04:09:58 +00:00
table = & dive_table ;
for ( i = 0 ; i < table - > nr ; i + + ) {
struct dive * d = table - > dives [ i ] ;
2014-05-13 22:32:45 +00:00
struct divecomputer * dc ;
2015-09-20 04:09:58 +00:00
if ( ! d )
continue ;
2015-09-05 18:24:10 +00:00
for_each_dc ( d , dc ) {
2012-12-29 19:28:35 +00:00
if ( dc - > model & & ! strcmp ( dc - > model , " Uemis Zurich " ) & &
2018-01-28 19:20:02 +00:00
( dc - > deviceid = = 0 | | dc - > deviceid = = 0x7fffffff | | dc - > deviceid = = deviceid ) ) {
if ( dc - > diveid > maxdiveid )
maxdiveid = dc - > diveid ;
if ( dc - > diveid < mindiveid )
mindiveid = dc - > diveid ;
}
2012-12-29 02:21:34 +00:00
}
2012-09-25 14:28:47 +00:00
}
2015-09-20 04:09:58 +00:00
snprintf ( divenr , 10 , " %d " , maxdiveid ) ;
2012-11-29 05:02:03 +00:00
return strdup ( divenr ) ;
2012-09-25 14:28:47 +00:00
}
2015-09-15 08:09:24 +00:00
# if UEMIS_DEBUG
2015-09-05 18:22:22 +00:00
static int bufCnt = 0 ;
2015-09-15 08:09:24 +00:00
static bool do_dump_buffer_to_file ( char * buf , char * prefix )
2015-09-05 18:22:22 +00:00
{
char path [ 100 ] ;
char date [ 40 ] ;
char obid [ 40 ] ;
2018-01-27 22:33:05 +00:00
bool success ;
2015-09-05 18:22:22 +00:00
if ( ! buf )
return false ;
if ( strstr ( buf , " date{ts{ " ) )
strncpy ( date , strstr ( buf , " date{ts{ " ) , sizeof ( date ) ) ;
else
2015-09-10 04:19:05 +00:00
strncpy ( date , " date{ts{no-date{ " , sizeof ( date ) ) ;
2015-09-05 18:22:22 +00:00
if ( ! strstr ( buf , " object_id{int{ " ) )
return false ;
strncpy ( obid , strstr ( buf , " object_id{int{ " ) , sizeof ( obid ) ) ;
char * ptr1 = strstr ( date , " date{ts{ " ) ;
char * ptr2 = strstr ( obid , " object_id{int{ " ) ;
char * pdate = next_token ( & ptr1 ) ;
pdate = next_token ( & ptr1 ) ;
pdate = next_token ( & ptr1 ) ;
char * pobid = next_token ( & ptr2 ) ;
pobid = next_token ( & ptr2 ) ;
pobid = next_token ( & ptr2 ) ;
2015-09-15 08:09:24 +00:00
snprintf ( path , sizeof ( path ) , " /%s/%s/UEMIS Dump/%s_%s_Uemis_dump_%s_in_round_%d_%d.txt " , home , user , prefix , pdate , pobid , debug_round , bufCnt ) ;
2015-09-05 18:22:22 +00:00
int dumpFile = subsurface_open ( path , O_RDWR | O_CREAT , 0666 ) ;
if ( dumpFile = = - 1 )
return false ;
2018-01-27 22:33:05 +00:00
success = write ( dumpFile , buf , strlen ( buf ) ) = = strlen ( buf ) ;
2015-09-05 18:22:22 +00:00
close ( dumpFile ) ;
bufCnt + + ;
2018-01-27 22:33:05 +00:00
return success ;
2015-09-05 18:22:22 +00:00
}
2015-09-15 08:09:24 +00:00
# endif
2015-09-05 18:22:22 +00:00
2015-09-05 18:15:05 +00:00
/* do some more sophisticated calculations here to try and predict if the next round of
* divelog / divedetail reads will fit into the UEMIS buffer ,
* filenr holds now the uemis filenr after having read several logs including the dive details ,
* fCapacity will five us the average number of files needed for all currently loaded data
* remember the maximum file usage per dive
2015-11-15 18:15:40 +00:00
* return : UEMIS_MEM_OK if there is enough memory for a full round
2015-09-05 18:15:05 +00:00
* UEMIS_MEM_CRITICAL if the memory is good for reading the dive logs
2015-11-15 18:15:40 +00:00
* UEMIS_MEM_FULL if the memory is exhausted
2015-09-05 18:15:05 +00:00
*/
2015-09-15 14:46:20 +00:00
static int get_memory ( struct dive_table * td , int checkpoint )
2015-09-05 18:15:05 +00:00
{
2015-09-15 14:46:20 +00:00
if ( td - > nr < = 0 )
2015-09-05 18:15:05 +00:00
return UEMIS_MEM_OK ;
2015-09-15 14:46:20 +00:00
switch ( checkpoint ) {
case UEMIS_CHECK_LOG :
if ( filenr / td - > nr > max_mem_used )
max_mem_used = filenr / td - > nr ;
/* check if a full block of dive logs + dive details and dive spot fit into the UEMIS buffer */
2015-11-10 02:00:16 +00:00
# if UEMIS_DEBUG & 4
fprintf ( debugfile , " max_mem_used %d (from td->nr %d) * block_size %d > max_files %d - filenr %d? \n " , max_mem_used , td - > nr , UEMIS_LOG_BLOCK_SIZE , UEMIS_MAX_FILES , filenr ) ;
# endif
2015-09-15 14:46:20 +00:00
if ( max_mem_used * UEMIS_LOG_BLOCK_SIZE > UEMIS_MAX_FILES - filenr )
return UEMIS_MEM_FULL ;
break ;
case UEMIS_CHECK_DETAILS :
/* check if the next set of dive details and dive spot fit into the UEMIS buffer */
if ( ( UEMIS_DIVE_DETAILS_SIZE + UEMIS_SPOT_BLOCK_SIZE ) * UEMIS_LOG_BLOCK_SIZE > UEMIS_MAX_FILES - filenr )
return UEMIS_MEM_FULL ;
break ;
case UEMIS_CHECK_SINGLE_DIVE :
if ( UEMIS_DIVE_DETAILS_SIZE + UEMIS_SPOT_BLOCK_SIZE > UEMIS_MAX_FILES - filenr )
return UEMIS_MEM_FULL ;
break ;
2015-09-05 18:15:05 +00:00
}
return UEMIS_MEM_OK ;
}
2018-10-03 20:03:39 +00:00
/* we misuse the hidden_by_filter flag to mark a dive as deleted.
* this will be picked up by some cleaning statement later . */
2015-09-05 18:24:10 +00:00
static void do_delete_dives ( struct dive_table * td , int idx )
{
for ( int x = idx ; x < td - > nr ; x + + )
2018-10-03 20:03:39 +00:00
td - > dives [ x ] - > hidden_by_filter = true ;
2015-09-05 18:24:10 +00:00
}
2015-09-10 14:12:57 +00:00
static bool load_uemis_divespot ( const char * mountpath , int divespot_id )
{
2018-11-18 10:33:50 +00:00
char divespotnr [ 32 ] ;
2015-09-10 14:12:57 +00:00
snprintf ( divespotnr , sizeof ( divespotnr ) , " %d " , divespot_id ) ;
param_buff [ 2 ] = divespotnr ;
# if UEMIS_DEBUG & 2
fprintf ( debugfile , " getDivespot %d \n " , divespot_id ) ;
# endif
bool success = uemis_get_answer ( mountpath , " getDivespot " , 3 , 0 , NULL ) ;
if ( mbuf & & success ) {
2015-09-10 19:23:47 +00:00
# if UEMIS_DEBUG & 16
2015-09-15 08:09:24 +00:00
do_dump_buffer_to_file ( mbuf , " Spot " ) ;
2015-09-10 14:12:57 +00:00
# endif
return parse_divespot ( mbuf ) ;
}
return false ;
}
2015-09-14 08:42:00 +00:00
static void get_uemis_divespot ( const char * mountpath , int divespot_id , struct dive * dive )
{
2018-10-26 15:03:54 +00:00
struct dive_site * nds = dive - > dive_site ;
2018-01-18 19:38:19 +00:00
if ( is_divespot_mappable ( divespot_id ) ) {
2018-10-23 10:42:01 +00:00
struct dive_site * ds = get_dive_site_by_divespot_id ( divespot_id ) ;
2018-10-26 15:03:54 +00:00
dive - > dive_site = ds ;
2018-01-18 19:38:19 +00:00
} else if ( nds & & nds - > name & & strstr ( nds - > name , " from Uemis " ) ) {
2015-09-18 19:22:26 +00:00
if ( load_uemis_divespot ( mountpath , divespot_id ) ) {
/* get the divesite based on the diveid, this should give us
* the newly created site
*/
2018-10-23 10:42:01 +00:00
struct dive_site * ods ;
2015-09-14 08:42:00 +00:00
/* with the divesite name we got from parse_dive, that is called on load_uemis_divespot
* we search all existing divesites if we have one with the same name already . The function
* returns the first found which is luckily not the newly created .
*/
2018-10-23 10:42:01 +00:00
ods = get_dive_site_by_name ( nds - > name ) ;
2015-09-14 08:42:00 +00:00
if ( ods ) {
2015-11-15 18:15:40 +00:00
/* if the uuid's are the same, the new site is a duplicate and can be deleted */
2015-09-14 08:42:00 +00:00
if ( nds - > uuid ! = ods - > uuid ) {
2018-10-23 17:11:13 +00:00
delete_dive_site ( nds ) ;
2018-10-26 15:03:54 +00:00
dive - > dive_site = ods ;
2015-09-14 08:42:00 +00:00
}
}
2018-10-26 15:03:54 +00:00
add_to_divespot_mapping ( divespot_id , dive - > dive_site ) ;
2015-09-18 19:22:26 +00:00
} else {
2015-11-15 18:15:40 +00:00
/* if we can't load the dive site details, delete the site we
2015-09-18 19:22:26 +00:00
* created in process_raw_buffer
*/
2018-10-26 15:03:54 +00:00
delete_dive_site ( dive - > dive_site ) ;
2015-09-14 08:42:00 +00:00
}
}
}
2017-07-17 23:50:03 +00:00
static bool get_matching_dive ( int idx , char * newmax , int * uemis_mem_status , device_data_t * data , const char * mountpath , const char deviceidnr )
2015-09-14 20:04:10 +00:00
{
struct dive * dive = data - > download_table - > dives [ idx ] ;
char log_file_no_to_find [ 20 ] ;
char dive_to_read_buf [ 10 ] ;
bool found = false ;
2015-11-10 01:58:36 +00:00
bool found_below = false ;
bool found_above = false ;
2015-09-17 14:46:02 +00:00
int deleted_files = 0 ;
2018-01-28 19:20:02 +00:00
int fail_count = 0 ;
2015-09-14 20:04:10 +00:00
snprintf ( log_file_no_to_find , sizeof ( log_file_no_to_find ) , " logfilenr{int{%d " , dive - > dc . diveid ) ;
2015-11-10 02:00:16 +00:00
# if UEMIS_DEBUG & 2
2017-02-20 09:30:01 +00:00
fprintf ( debugfile , " Looking for dive details to go with dive log id %d \n " , dive - > dc . diveid ) ;
2015-11-10 02:00:16 +00:00
# endif
2015-09-14 20:04:10 +00:00
while ( ! found ) {
2015-09-16 07:10:56 +00:00
if ( import_thread_cancelled )
break ;
2015-09-17 14:46:02 +00:00
snprintf ( dive_to_read_buf , sizeof ( dive_to_read_buf ) , " %d " , dive_to_read ) ;
2015-09-14 20:04:10 +00:00
param_buff [ 2 ] = dive_to_read_buf ;
( void ) uemis_get_answer ( mountpath , " getDive " , 3 , 0 , NULL ) ;
# if UEMIS_DEBUG & 16
2015-09-15 08:09:24 +00:00
do_dump_buffer_to_file ( mbuf , " Dive " ) ;
2015-09-14 20:04:10 +00:00
# endif
2015-09-15 14:46:20 +00:00
* uemis_mem_status = get_memory ( data - > download_table , UEMIS_CHECK_SINGLE_DIVE ) ;
if ( * uemis_mem_status = = UEMIS_MEM_OK ) {
2017-02-20 09:30:01 +00:00
/* if the memory isn's completely full we can try to read more dive log vs. dive details
2015-09-14 20:04:10 +00:00
* UEMIS_MEM_CRITICAL means not enough space for a full round but the dive details
2017-02-20 09:36:49 +00:00
* and the dive spots should fit into the UEMIS memory
2015-09-14 20:04:10 +00:00
* The match we do here is to map the object_id to the logfilenr , we do this
2017-02-20 09:30:01 +00:00
* by iterating through the last set of loaded dive logs and then find the corresponding
2015-09-14 20:04:10 +00:00
* dive with the matching logfilenr */
if ( mbuf ) {
if ( strstr ( mbuf , log_file_no_to_find ) ) {
2017-02-20 09:30:01 +00:00
/* we found the logfilenr that matches our object_id from the dive log we were looking for
2015-11-15 18:15:40 +00:00
* we mark the search successful even if the dive has been deleted . */
2015-09-14 20:04:10 +00:00
found = true ;
if ( strstr ( mbuf , " deleted{bool{true " ) = = NULL ) {
2016-03-10 03:06:14 +00:00
process_raw_buffer ( data , deviceidnr , mbuf , & newmax , NULL ) ;
2015-09-14 20:04:10 +00:00
/* remember the last log file number as it is very likely that subsequent dives
* have the same or higher logfile number .
* UEMIS unfortunately deletes dives by deleting the dive details and not the logs . */
# if UEMIS_DEBUG & 2
2015-09-15 08:09:24 +00:00
d_time = get_dive_date_c_string ( dive - > when ) ;
2017-02-20 09:30:01 +00:00
fprintf ( debugfile , " Matching dive log id %d from %s with dive details %d \n " , dive - > dc . diveid , d_time , dive_to_read ) ;
2015-09-14 20:04:10 +00:00
# endif
int divespot_id = uemis_get_divespot_id_by_diveid ( dive - > dc . diveid ) ;
2015-09-18 19:37:23 +00:00
if ( divespot_id > = 0 )
get_uemis_divespot ( mountpath , divespot_id , dive ) ;
2015-09-14 20:04:10 +00:00
} else {
/* in this case we found a deleted file, so let's increment */
# if UEMIS_DEBUG & 2
2015-09-15 08:09:24 +00:00
d_time = get_dive_date_c_string ( dive - > when ) ;
2017-02-20 09:30:01 +00:00
fprintf ( debugfile , " TRY matching dive log id %d from %s with dive details %d but details are deleted \n " , dive - > dc . diveid , d_time , dive_to_read ) ;
2015-09-14 20:04:10 +00:00
# endif
2015-09-17 14:46:02 +00:00
deleted_files + + ;
2015-09-14 20:04:10 +00:00
/* mark this log entry as deleted and cleanup later, otherwise we mess up our array */
2018-10-03 20:03:39 +00:00
dive - > hidden_by_filter = true ;
2015-09-14 20:04:10 +00:00
# if UEMIS_DEBUG & 2
2015-11-10 01:57:02 +00:00
fprintf ( debugfile , " Deleted dive from %s, with id %d from table -- newmax is %s \n " , d_time , dive - > dc . diveid , newmax ) ;
2015-09-14 20:04:10 +00:00
# endif
}
} else {
2015-09-17 14:46:02 +00:00
uint32_t nr_found = 0 ;
char * logfilenr = strstr ( mbuf , " logfilenr " ) ;
2018-01-19 05:18:36 +00:00
if ( logfilenr & & strstr ( mbuf , " act{ " ) ) {
2015-09-17 14:46:02 +00:00
sscanf ( logfilenr , " logfilenr{int{%u " , & nr_found ) ;
2015-12-06 21:38:38 +00:00
if ( nr_found > = dive - > dc . diveid | | nr_found = = 0 ) {
2015-11-10 01:58:36 +00:00
found_above = true ;
2015-09-17 14:46:02 +00:00
dive_to_read = dive_to_read - 2 ;
2015-11-10 01:58:36 +00:00
} else {
found_below = true ;
}
2015-09-17 14:46:02 +00:00
if ( dive_to_read < - 1 )
dive_to_read = - 1 ;
2018-01-28 19:20:02 +00:00
} else if ( ! strstr ( mbuf , " act{ " ) & & + + fail_count = = 10 ) {
if ( verbose )
fprintf ( stderr , " Uemis downloader: Cannot access dive details - searching from start \n " ) ;
dive_to_read = - 1 ;
2015-09-17 14:46:02 +00:00
}
2015-09-14 20:04:10 +00:00
}
}
2015-11-10 01:58:36 +00:00
if ( found_above & & found_below )
break ;
2015-09-17 14:46:02 +00:00
dive_to_read + + ;
2015-09-14 20:04:10 +00:00
} else {
2017-02-20 09:30:01 +00:00
/* At this point the memory of the UEMIS is full, let's cleanup all dive log files were
2015-09-14 20:04:10 +00:00
* we could not match the details to . */
do_delete_dives ( data - > download_table , idx ) ;
return false ;
}
}
/* decrement iDiveToRead by the amount of deleted entries found to assure
* we are not missing any valid matches when processing subsequent logs */
2015-09-17 14:46:02 +00:00
dive_to_read = ( dive_to_read - deleted_files > 0 ? dive_to_read - deleted_files : 0 ) ;
deleted_files = 0 ;
2015-09-14 20:04:10 +00:00
return true ;
}
2014-10-12 10:57:32 +00:00
const char * do_uemis_import ( device_data_t * data )
2012-09-25 14:28:47 +00:00
{
2014-10-12 10:57:32 +00:00
const char * mountpath = data - > devname ;
short force_download = data - > force_download ;
2012-09-25 14:28:47 +00:00
char * newmax = NULL ;
2015-04-22 03:29:20 +00:00
int first , start , end = - 2 ;
2013-01-18 20:56:54 +00:00
uint32_t deviceidnr ;
2012-09-30 03:57:48 +00:00
char * deviceid = NULL ;
2013-10-06 15:55:58 +00:00
const char * result = NULL ;
2012-09-27 07:16:42 +00:00
char * endptr ;
2016-03-10 03:06:14 +00:00
bool success , once = true ;
2015-09-05 18:24:10 +00:00
int match_dive_and_log = 0 ;
int uemis_mem_status = UEMIS_MEM_OK ;
2015-09-15 08:09:24 +00:00
# if UEMIS_DEBUG
home = getenv ( " HOME " ) ;
user = getenv ( " LOGNAME " ) ;
# endif
2014-11-25 15:47:24 +00:00
uemis_info ( translate ( " gettextFromC " , " Initialise communication " ) ) ;
2015-03-23 18:22:55 +00:00
if ( ! uemis_init ( mountpath ) ) {
free ( reqtxt_path ) ;
2014-02-28 04:09:57 +00:00
return translate ( " gettextFromC " , " Uemis init failed " ) ;
2015-03-23 18:22:55 +00:00
}
2015-09-05 18:24:10 +00:00
2014-02-28 04:09:57 +00:00
if ( ! uemis_get_answer ( mountpath , " getDeviceId " , 0 , 1 , & result ) )
2012-09-30 03:57:48 +00:00
goto bail ;
2012-09-25 14:28:47 +00:00
deviceid = strdup ( param_buff [ 0 ] ) ;
2012-11-29 00:11:19 +00:00
deviceidnr = atoi ( deviceid ) ;
2015-09-05 18:24:10 +00:00
2012-09-25 14:28:47 +00:00
/* param_buff[0] is still valid */
2014-02-28 04:09:57 +00:00
if ( ! uemis_get_answer ( mountpath , " initSession " , 1 , 6 , & result ) )
2012-09-30 03:57:48 +00:00
goto bail ;
2015-09-05 18:24:10 +00:00
2014-02-28 04:09:57 +00:00
uemis_info ( translate ( " gettextFromC " , " Start download " ) ) ;
if ( ! uemis_get_answer ( mountpath , " processSync " , 0 , 2 , & result ) )
2012-09-30 03:57:48 +00:00
goto bail ;
2015-09-05 18:24:10 +00:00
2012-11-19 22:11:08 +00:00
/* before starting the long download, check if user pressed cancel */
if ( import_thread_cancelled )
goto bail ;
2015-09-05 18:24:10 +00:00
2012-09-25 14:28:47 +00:00
param_buff [ 1 ] = " notempty " ;
2018-10-04 09:48:40 +00:00
newmax = uemis_get_divenr ( deviceid , data - > download_table , force_download ) ;
2015-11-08 22:55:46 +00:00
if ( verbose )
2018-01-28 19:20:02 +00:00
fprintf ( stderr , " Uemis downloader: start looking at dive nr %s \n " , newmax ) ;
2015-09-05 18:24:10 +00:00
2015-04-22 03:29:20 +00:00
first = start = atoi ( newmax ) ;
2018-01-28 19:20:02 +00:00
dive_to_read = mindiveid < first ? first - mindiveid : first ;
2012-09-27 03:37:57 +00:00
for ( ; ; ) {
2015-09-05 18:24:10 +00:00
# if UEMIS_DEBUG & 2
2015-09-15 08:09:24 +00:00
debug_round + + ;
2015-09-05 18:24:10 +00:00
# endif
2014-05-05 21:36:55 +00:00
# if UEMIS_DEBUG & 4
fprintf ( debugfile , " d_u_i inner loop start %d end %d newmax %s \n " , start , end , newmax ) ;
# endif
2015-09-05 18:24:10 +00:00
/* start at the last filled download table index */
2015-09-16 07:22:11 +00:00
match_dive_and_log = data - > download_table - > nr ;
2015-09-05 18:24:10 +00:00
sprintf ( newmax , " %d " , start ) ;
2012-09-27 03:37:57 +00:00
param_buff [ 2 ] = newmax ;
2012-09-27 07:16:42 +00:00
param_buff [ 3 ] = 0 ;
2012-09-30 03:57:48 +00:00
success = uemis_get_answer ( mountpath , " getDivelogs " , 3 , 0 , & result ) ;
2015-09-15 14:46:20 +00:00
uemis_mem_status = get_memory ( data - > download_table , UEMIS_CHECK_DETAILS ) ;
2015-12-03 17:47:46 +00:00
/* first, remove any leading garbage... this needs to start with a '{' */
char * realmbuf = mbuf ;
if ( mbuf )
realmbuf = strchr ( mbuf , ' { ' ) ;
if ( success & & realmbuf & & uemis_mem_status ! = UEMIS_MEM_FULL ) {
2015-09-10 19:23:47 +00:00
# if UEMIS_DEBUG & 16
2017-02-20 09:30:01 +00:00
do_dump_buffer_to_file ( realmbuf , " Dive logs " ) ;
2015-09-05 18:24:10 +00:00
# endif
/* process the buffer we have assembled */
2016-03-10 03:06:14 +00:00
if ( ! process_raw_buffer ( data , deviceidnr , realmbuf , & newmax , NULL ) ) {
2014-05-05 21:36:55 +00:00
/* if no dives were downloaded, mark end appropriately */
if ( end = = - 2 )
end = start - 1 ;
success = false ;
}
2015-09-05 18:24:10 +00:00
if ( once ) {
2015-12-03 17:47:46 +00:00
char * t = first_object_id_val ( realmbuf ) ;
2015-09-05 18:24:10 +00:00
if ( t & & atoi ( t ) > start )
start = atoi ( t ) ;
free ( t ) ;
once = false ;
}
/* clean up mbuf */
2015-12-03 17:47:46 +00:00
endptr = strstr ( realmbuf , " {{{ " ) ;
2015-09-05 18:24:10 +00:00
if ( endptr )
* ( endptr + 2 ) = ' \0 ' ;
/* last object_id we parsed */
sscanf ( newmax , " %d " , & end ) ;
2014-05-05 21:36:55 +00:00
# if UEMIS_DEBUG & 4
2015-09-05 18:24:10 +00:00
fprintf ( debugfile , " d_u_i after download and parse start %d end %d newmax %s progress %4.2f \n " , start , end , newmax , progress_bar_fraction ) ;
# endif
/* The way this works is that I am reading the current dive from what has been loaded during the getDiveLogs call to the UEMIS.
2017-02-20 09:30:01 +00:00
* As the object_id of the dive log entry and the object_id of the dive details are not necessarily the same , the match needs
2015-09-05 18:24:10 +00:00
* to happen based on the logfilenr .
* What the following part does is to optimize the mapping by using
2015-11-15 18:15:40 +00:00
* dive_to_read = the dive details entry that need to be read using the object_id
2015-09-05 18:24:10 +00:00
* logFileNoToFind = map the logfilenr of the dive details with the object_id = diveid from the get dive logs */
2015-09-14 20:04:10 +00:00
for ( int i = match_dive_and_log ; i < data - > download_table - > nr ; i + + ) {
2015-09-18 20:14:46 +00:00
bool success = get_matching_dive ( i , newmax , & uemis_mem_status , data , mountpath , deviceidnr ) ;
2015-09-14 20:04:10 +00:00
if ( ! success )
2015-09-05 18:24:10 +00:00
break ;
2015-09-16 07:10:56 +00:00
if ( import_thread_cancelled )
break ;
2015-04-22 03:29:20 +00:00
}
2015-09-05 18:24:10 +00:00
start = end ;
/* Do some memory checking here */
2015-09-15 14:46:20 +00:00
uemis_mem_status = get_memory ( data - > download_table , UEMIS_CHECK_LOG ) ;
2015-11-10 02:00:16 +00:00
if ( uemis_mem_status ! = UEMIS_MEM_OK ) {
# if UEMIS_DEBUG & 4
fprintf ( debugfile , " d_u_i out of memory, bailing \n " ) ;
# endif
2015-04-22 03:29:20 +00:00
break ;
2015-11-10 02:00:16 +00:00
}
2015-09-05 18:24:10 +00:00
/* if the user clicked cancel, exit gracefully */
2015-11-10 02:00:16 +00:00
if ( import_thread_cancelled ) {
# if UEMIS_DEBUG & 4
2015-11-15 18:15:40 +00:00
fprintf ( debugfile , " d_u_i thread canceled, bailing \n " ) ;
2015-11-10 02:00:16 +00:00
# endif
2015-09-05 18:24:10 +00:00
break ;
2015-11-10 02:00:16 +00:00
}
2015-09-05 18:24:10 +00:00
/* if we got an error or got nothing back, stop trying */
2015-11-10 02:00:16 +00:00
if ( ! success | | ! param_buff [ 3 ] ) {
# if UEMIS_DEBUG & 4
fprintf ( debugfile , " d_u_i after download nothing found, giving up \n " ) ;
# endif
2015-09-05 18:24:10 +00:00
break ;
2015-11-10 02:00:16 +00:00
}
2015-09-05 18:24:10 +00:00
# if UEMIS_DEBUG & 2
2015-09-15 08:09:24 +00:00
if ( debug_round ! = - 1 )
2015-11-10 02:00:16 +00:00
if ( debug_round - - = = 0 ) {
fprintf ( debugfile , " d_u_i debug_round is now 0, bailing \n " ) ;
2015-09-05 18:24:10 +00:00
goto bail ;
2015-11-10 02:00:16 +00:00
}
2015-09-05 18:24:10 +00:00
# endif
} else {
2017-02-20 09:30:01 +00:00
/* some of the loading from the UEMIS failed at the dive log level
2017-02-20 09:36:49 +00:00
* if the memory status = full , we can ' t even load the dive spots and / or buddies .
2017-02-20 09:30:01 +00:00
* The loaded block of dive logs is useless and all new loaded dive logs need to
2015-09-05 18:24:10 +00:00
* be deleted from the download_table .
*/
if ( uemis_mem_status = = UEMIS_MEM_FULL )
do_delete_dives ( data - > download_table , match_dive_and_log ) ;
2015-11-10 02:00:16 +00:00
# if UEMIS_DEBUG & 4
fprintf ( debugfile , " d_u_i out of memory, bailing instead of processing \n " ) ;
# endif
2012-09-27 03:37:57 +00:00
break ;
}
2012-09-25 14:28:47 +00:00
}
2015-09-05 18:24:10 +00:00
2014-05-05 21:36:55 +00:00
if ( end = = - 2 & & sscanf ( newmax , " %d " , & end ) ! = 1 )
2012-10-26 03:15:39 +00:00
end = start ;
2015-09-05 18:24:10 +00:00
2012-12-05 05:03:56 +00:00
# if UEMIS_DEBUG & 2
2015-09-05 18:24:10 +00:00
fprintf ( debugfile , " Done: read from object_id %d to %d \n " , first , end ) ;
2012-10-26 03:15:39 +00:00
# endif
2015-09-05 18:24:10 +00:00
/* Regardless on where we are with the memory situation, it's time now
* to see if we have to clean some dead bodies from our download table */
next_table_index = 0 ;
2015-09-14 08:31:29 +00:00
while ( next_table_index < data - > download_table - > nr ) {
2018-10-03 20:03:39 +00:00
if ( data - > download_table - > dives [ next_table_index ] - > hidden_by_filter )
2015-09-05 18:24:10 +00:00
uemis_delete_dive ( data , data - > download_table - > dives [ next_table_index ] - > dc . diveid ) ;
else
next_table_index + + ;
}
2015-09-15 14:46:20 +00:00
if ( uemis_mem_status ! = UEMIS_MEM_OK )
result = translate ( " gettextFromC " , ERR_FS_ALMOST_FULL ) ;
2012-11-19 22:11:08 +00:00
bail :
2014-02-28 04:09:57 +00:00
( void ) uemis_get_answer ( mountpath , " terminateSync " , 0 , 3 , & result ) ;
if ( ! strcmp ( param_buff [ 0 ] , " error " ) ) {
if ( ! strcmp ( param_buff [ 2 ] , " Out of Memory " ) )
result = translate ( " gettextFromC " , ERR_FS_FULL ) ;
2012-09-27 03:37:57 +00:00
else
result = param_buff [ 2 ] ;
}
2012-09-30 03:57:48 +00:00
free ( deviceid ) ;
2015-03-23 18:22:55 +00:00
free ( reqtxt_path ) ;
2015-09-24 17:26:35 +00:00
if ( ! data - > download_table - > nr )
result = translate ( " gettextFromC " , ERR_NO_FILES ) ;
2012-09-27 03:37:57 +00:00
return result ;
2012-09-25 14:28:47 +00:00
}