2017-11-28 19:24:53 +00:00
// SPDX-License-Identifier: GPL-2.0
# ifdef __clang__
// Clang has a bug on zero-initialization of C structs.
# pragma clang diagnostic ignored "-Wmissing-field-initializers"
# endif
2018-05-22 07:07:42 +00:00
# include "ssrf.h"
2017-11-28 19:24:53 +00:00
# include "dive.h"
2018-05-11 15:25:41 +00:00
# include "subsurface-string.h"
2017-11-28 19:24:53 +00:00
# include "parse.h"
# include "divelist.h"
# include "device.h"
# include "membuffer.h"
# include "gettext.h"
2019-05-30 16:29:36 +00:00
# include "tag.h"
2017-11-28 19:24:53 +00:00
2018-10-17 16:45:22 +00:00
static int dm4_events ( void * param , int columns , char * * data , char * * column )
2017-11-28 19:24:53 +00:00
{
2018-05-22 07:07:42 +00:00
UNUSED ( columns ) ;
UNUSED ( column ) ;
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
2017-11-28 19:24:53 +00:00
2018-10-17 16:45:22 +00:00
event_start ( state ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 1 ] )
2018-10-17 16:45:22 +00:00
state - > cur_event . time . seconds = atoi ( data [ 1 ] ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 2 ] ) {
switch ( atoi ( data [ 2 ] ) ) {
case 1 :
/* 1 Mandatory Safety Stop */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " safety stop (mandatory) " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 3 :
/* 3 Deco */
/* What is Subsurface's term for going to
* deco ? */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " deco " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 4 :
/* 4 Ascent warning */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " ascent " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 5 :
/* 5 Ceiling broken */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " violation " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 6 :
/* 6 Mandatory safety stop ceiling error */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " violation " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 7 :
/* 7 Below deco floor */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " below floor " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 8 :
/* 8 Dive time alarm */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " divetime " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 9 :
/* 9 Depth alarm */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " maxdepth " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 10 :
/* 10 OLF 80% */
case 11 :
/* 11 OLF 100% */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " OLF " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 12 :
/* 12 High pO₂ */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " PO2 " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 13 :
/* 13 Air time */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " airtime " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 17 :
/* 17 Ascent warning */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " ascent " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 18 :
/* 18 Ceiling error */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " ceiling " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 19 :
/* 19 Surfaced */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " surface " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 20 :
/* 20 Deco */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " deco " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 22 :
case 32 :
/* 22 Mandatory safety stop violation */
/* 32 Deep stop violation */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " violation " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 30 :
/* Tissue level warning */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " tissue warning " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 37 :
/* Tank pressure alarm */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " tank pressure " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 257 :
/* 257 Dive active */
/* This seems to be given after surface when
* descending again . */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " surface " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 258 :
/* 258 Bookmark */
if ( data [ 3 ] ) {
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " heading " ) ;
state - > cur_event . value = atoi ( data [ 3 ] ) ;
2017-11-28 19:24:53 +00:00
} else {
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " bookmark " ) ;
2017-11-28 19:24:53 +00:00
}
break ;
case 259 :
/* Deep stop */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " Deep stop " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 260 :
/* Deep stop */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " Deep stop cleared " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 266 :
/* Mandatory safety stop activated */
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " safety stop (mandatory) " ) ;
2017-11-28 19:24:53 +00:00
break ;
case 267 :
/* Mandatory safety stop deactivated */
/* DM5 shows this only on event list, not on the
* profile so skipping as well for now */
break ;
default :
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " unknown " ) ;
state - > cur_event . value = atoi ( data [ 2 ] ) ;
2017-11-28 19:24:53 +00:00
break ;
}
}
2018-10-17 16:45:22 +00:00
event_end ( state ) ;
2017-11-28 19:24:53 +00:00
return 0 ;
}
2018-10-17 16:45:22 +00:00
static int dm4_tags ( void * param , int columns , char * * data , char * * column )
2017-11-28 19:24:53 +00:00
{
2018-05-22 07:07:42 +00:00
UNUSED ( columns ) ;
UNUSED ( column ) ;
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
2017-11-28 19:24:53 +00:00
if ( data [ 0 ] )
2018-10-17 16:45:22 +00:00
taglist_add_tag ( & state - > cur_dive - > tag_list , data [ 0 ] ) ;
2017-11-28 19:24:53 +00:00
return 0 ;
}
2018-10-17 16:45:22 +00:00
static int dm4_dive ( void * param , int columns , char * * data , char * * column )
2017-11-28 19:24:53 +00:00
{
2018-05-22 07:07:42 +00:00
UNUSED ( columns ) ;
UNUSED ( column ) ;
2017-12-17 17:12:08 +00:00
int i ;
2017-11-28 19:24:53 +00:00
int interval , retval = 0 ;
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
sqlite3 * handle = state - > sql_handle ;
2017-11-28 19:24:53 +00:00
float * profileBlob ;
unsigned char * tempBlob ;
int * pressureBlob ;
char get_events_template [ ] = " select * from Mark where DiveId = %d " ;
char get_tags_template [ ] = " select Text from DiveTag where DiveId = %d " ;
char get_events [ 64 ] ;
2019-08-04 16:44:57 +00:00
cylinder_t * cyl ;
2017-11-28 19:24:53 +00:00
2018-10-17 16:45:22 +00:00
dive_start ( state ) ;
state - > cur_dive - > number = atoi ( data [ 0 ] ) ;
2017-11-28 19:24:53 +00:00
2018-10-17 16:45:22 +00:00
state - > cur_dive - > when = ( time_t ) ( atol ( data [ 1 ] ) ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 2 ] )
2018-10-17 16:45:22 +00:00
utf8_string ( data [ 2 ] , & state - > cur_dive - > notes ) ;
2017-11-28 19:24:53 +00:00
/*
* DM4 stores Duration and DiveTime . It looks like DiveTime is
* 10 to 60 seconds shorter than Duration . However , I have no
* idea what is the difference and which one should be used .
* Duration = data [ 3 ]
* DiveTime = data [ 15 ]
*/
if ( data [ 3 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > duration . seconds = atoi ( data [ 3 ] ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 15 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . duration . seconds = atoi ( data [ 15 ] ) ;
2017-11-28 19:24:53 +00:00
/*
* TODO : the deviceid hash should be calculated here .
*/
2018-10-17 16:45:22 +00:00
settings_start ( state ) ;
dc_settings_start ( state ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 4 ] )
2018-10-17 16:45:22 +00:00
utf8_string ( data [ 4 ] , & state - > cur_settings . dc . serial_nr ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 5 ] )
2018-10-17 16:45:22 +00:00
utf8_string ( data [ 5 ] , & state - > cur_settings . dc . model ) ;
2017-11-28 19:24:53 +00:00
2018-10-17 16:45:22 +00:00
state - > cur_settings . dc . deviceid = 0xffffffff ;
dc_settings_end ( state ) ;
settings_end ( state ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 6 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . maxdepth . mm = lrint ( strtod_flags ( data [ 6 ] , NULL , 0 ) * 1000 ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 8 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . airtemp . mkelvin = C_to_mkelvin ( atoi ( data [ 8 ] ) ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 9 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . watertemp . mkelvin = C_to_mkelvin ( atoi ( data [ 9 ] ) ) ;
2017-11-28 19:24:53 +00:00
/*
* TODO : handle multiple cylinders
*/
2019-08-04 16:59:14 +00:00
cyl = cylinder_start ( state ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 22 ] & & atoi ( data [ 22 ] ) > 0 )
2019-08-04 16:44:57 +00:00
cyl - > start . mbar = atoi ( data [ 22 ] ) ;
2017-11-28 19:24:53 +00:00
else if ( data [ 10 ] & & atoi ( data [ 10 ] ) > 0 )
2019-08-04 16:44:57 +00:00
cyl - > start . mbar = atoi ( data [ 10 ] ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 23 ] & & atoi ( data [ 23 ] ) > 0 )
2019-08-04 16:44:57 +00:00
cyl - > end . mbar = ( atoi ( data [ 23 ] ) ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 11 ] & & atoi ( data [ 11 ] ) > 0 )
2019-08-04 16:44:57 +00:00
cyl - > end . mbar = ( atoi ( data [ 11 ] ) ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 12 ] )
2019-08-04 16:44:57 +00:00
cyl - > type . size . mliter = lrint ( ( strtod_flags ( data [ 12 ] , NULL , 0 ) ) * 1000 ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 13 ] )
2019-08-04 16:44:57 +00:00
cyl - > type . workingpressure . mbar = ( atoi ( data [ 13 ] ) ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 20 ] )
2019-08-04 16:44:57 +00:00
cyl - > gasmix . o2 . permille = atoi ( data [ 20 ] ) * 10 ;
2017-11-28 19:24:53 +00:00
if ( data [ 21 ] )
2019-08-04 16:44:57 +00:00
cyl - > gasmix . he . permille = atoi ( data [ 21 ] ) * 10 ;
2018-10-17 16:45:22 +00:00
cylinder_end ( state ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 14 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . surface_pressure . mbar = ( atoi ( data [ 14 ] ) * 1000 ) ;
2017-11-28 19:24:53 +00:00
interval = data [ 16 ] ? atoi ( data [ 16 ] ) : 0 ;
profileBlob = ( float * ) data [ 17 ] ;
tempBlob = ( unsigned char * ) data [ 18 ] ;
pressureBlob = ( int * ) data [ 19 ] ;
2018-10-17 16:45:22 +00:00
for ( i = 0 ; interval & & i * interval < state - > cur_dive - > duration . seconds ; i + + ) {
sample_start ( state ) ;
state - > cur_sample - > time . seconds = i * interval ;
2017-11-28 19:24:53 +00:00
if ( profileBlob )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > depth . mm = lrintf ( profileBlob [ i ] * 1000.0f ) ;
2017-11-28 19:24:53 +00:00
else
2018-10-17 16:45:22 +00:00
state - > cur_sample - > depth . mm = state - > cur_dive - > dc . maxdepth . mm ;
2017-11-28 19:24:53 +00:00
if ( data [ 18 ] & & data [ 18 ] [ 0 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > temperature . mkelvin = C_to_mkelvin ( tempBlob [ i ] ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 19 ] & & data [ 19 ] [ 0 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > pressure [ 0 ] . mbar = pressureBlob [ i ] ;
sample_end ( state ) ;
2017-11-28 19:24:53 +00:00
}
2018-10-17 16:45:22 +00:00
snprintf ( get_events , sizeof ( get_events ) - 1 , get_events_template , state - > cur_dive - > number ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_events , & dm4_events , state , NULL ) ;
2017-11-28 19:24:53 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " %s " , " Database query dm4_events failed. \n " ) ;
return 1 ;
}
2018-10-17 16:45:22 +00:00
snprintf ( get_events , sizeof ( get_events ) - 1 , get_tags_template , state - > cur_dive - > number ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_events , & dm4_tags , state , NULL ) ;
2017-11-28 19:24:53 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " %s " , " Database query dm4_tags failed. \n " ) ;
return 1 ;
}
2018-10-17 16:45:22 +00:00
dive_end ( state ) ;
2017-11-28 19:24:53 +00:00
/*
for ( i = 0 ; i < columns ; + + i ) {
fprintf ( stderr , " %s \t " , column [ i ] ) ;
}
fprintf ( stderr , " \n " ) ;
for ( i = 0 ; i < columns ; + + i ) {
fprintf ( stderr , " %s \t " , data [ i ] ) ;
}
fprintf ( stderr , " \n " ) ;
//exit(0);
*/
return SQLITE_OK ;
}
int parse_dm4_buffer ( sqlite3 * handle , const char * url , const char * buffer , int size ,
2019-02-28 21:45:17 +00:00
struct dive_table * table , struct trip_table * trips , struct dive_site_table * sites )
2017-11-28 19:24:53 +00:00
{
2018-05-22 07:07:42 +00:00
UNUSED ( buffer ) ;
UNUSED ( size ) ;
2017-11-28 19:24:53 +00:00
int retval ;
char * err = NULL ;
2018-10-17 16:45:22 +00:00
struct parser_state state ;
init_parser_state ( & state ) ;
state . target_table = table ;
2018-11-26 23:25:15 +00:00
state . trips = trips ;
2019-02-28 21:45:17 +00:00
state . sites = sites ;
2018-10-17 16:45:22 +00:00
state . sql_handle = handle ;
2017-11-28 19:24:53 +00:00
/* StartTime is converted from Suunto's nano seconds to standard
* time . We also need epoch , not seconds since year 1. */
char get_dives [ ] = " select D.DiveId,StartTime/10000000-62135596800,Note,Duration,SourceSerialNumber,Source,MaxDepth,SampleInterval,StartTemperature,BottomTemperature,D.StartPressure,D.EndPressure,Size,CylinderWorkPressure,SurfacePressure,DiveTime,SampleInterval,ProfileBlob,TemperatureBlob,PressureBlob,Oxygen,Helium,MIX.StartPressure,MIX.EndPressure FROM Dive AS D JOIN DiveMixture AS MIX ON D.DiveId=MIX.DiveId " ;
2018-10-17 16:45:22 +00:00
retval = sqlite3_exec ( handle , get_dives , & dm4_dive , & state , & err ) ;
free_parser_state ( & state ) ;
2017-11-28 19:24:53 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " Database query failed '%s'. \n " , url ) ;
return 1 ;
}
return 0 ;
}
2018-10-17 16:45:22 +00:00
static int dm5_cylinders ( void * param , int columns , char * * data , char * * column )
2017-11-28 19:24:53 +00:00
{
2018-05-22 07:07:42 +00:00
UNUSED ( columns ) ;
UNUSED ( column ) ;
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
2019-08-04 16:44:57 +00:00
cylinder_t * cyl ;
2017-11-28 19:24:53 +00:00
2019-08-04 16:59:14 +00:00
cyl = cylinder_start ( state ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 7 ] & & atoi ( data [ 7 ] ) > 0 & & atoi ( data [ 7 ] ) < 350000 )
2019-08-04 16:44:57 +00:00
cyl - > start . mbar = atoi ( data [ 7 ] ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 8 ] & & atoi ( data [ 8 ] ) > 0 & & atoi ( data [ 8 ] ) < 350000 )
2019-08-04 16:44:57 +00:00
cyl - > end . mbar = ( atoi ( data [ 8 ] ) ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 6 ] ) {
/* DM5 shows tank size of 12 liters when the actual
* value is 0 ( and using metric units ) . So we just use
* the same 12 liters when size is not available */
2019-08-04 16:44:57 +00:00
if ( strtod_flags ( data [ 6 ] , NULL , 0 ) = = 0.0 & & cyl - > start . mbar )
cyl - > type . size . mliter = 12000 ;
2017-11-28 19:24:53 +00:00
else
2019-08-04 16:44:57 +00:00
cyl - > type . size . mliter = lrint ( ( strtod_flags ( data [ 6 ] , NULL , 0 ) ) * 1000 ) ;
2017-11-28 19:24:53 +00:00
}
if ( data [ 2 ] )
2019-08-04 16:44:57 +00:00
cyl - > gasmix . o2 . permille = atoi ( data [ 2 ] ) * 10 ;
2017-11-28 19:24:53 +00:00
if ( data [ 3 ] )
2019-08-04 16:44:57 +00:00
cyl - > gasmix . he . permille = atoi ( data [ 3 ] ) * 10 ;
2018-10-17 16:45:22 +00:00
cylinder_end ( state ) ;
2017-11-28 19:24:53 +00:00
return 0 ;
}
2018-10-17 16:45:22 +00:00
static int dm5_gaschange ( void * param , int columns , char * * data , char * * column )
2017-11-28 19:24:53 +00:00
{
2018-05-22 07:07:42 +00:00
UNUSED ( columns ) ;
UNUSED ( column ) ;
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
2017-11-28 19:24:53 +00:00
2018-10-17 16:45:22 +00:00
event_start ( state ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 0 ] )
2018-10-17 16:45:22 +00:00
state - > cur_event . time . seconds = atoi ( data [ 0 ] ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 1 ] ) {
2018-10-17 16:45:22 +00:00
strcpy ( state - > cur_event . name , " gaschange " ) ;
state - > cur_event . value = lrint ( strtod_flags ( data [ 1 ] , NULL , 0 ) ) ;
2017-11-28 19:24:53 +00:00
}
/* He part of the mix */
if ( data [ 2 ] )
2018-10-17 16:45:22 +00:00
state - > cur_event . value + = lrint ( strtod_flags ( data [ 2 ] , NULL , 0 ) ) < < 16 ;
event_end ( state ) ;
2017-11-28 19:24:53 +00:00
return 0 ;
}
2018-10-17 16:45:22 +00:00
static int dm5_dive ( void * param , int columns , char * * data , char * * column )
2017-11-28 19:24:53 +00:00
{
2018-05-22 07:07:42 +00:00
UNUSED ( columns ) ;
UNUSED ( column ) ;
2017-12-17 17:12:08 +00:00
int i ;
2018-04-07 04:46:37 +00:00
int tempformat = 0 ;
2017-11-28 19:24:53 +00:00
int interval , retval = 0 , block_size ;
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
sqlite3 * handle = state - > sql_handle ;
2017-11-28 19:24:53 +00:00
unsigned const char * sampleBlob ;
char get_events_template [ ] = " select * from Mark where DiveId = %d " ;
char get_tags_template [ ] = " select Text from DiveTag where DiveId = %d " ;
char get_cylinders_template [ ] = " select * from DiveMixture where DiveId = %d " ;
char get_gaschange_template [ ] = " select GasChangeTime,Oxygen,Helium from DiveGasChange join DiveMixture on DiveGasChange.DiveMixtureId=DiveMixture.DiveMixtureId where DiveId = %d " ;
char get_events [ 512 ] ;
2018-10-17 16:45:22 +00:00
dive_start ( state ) ;
state - > cur_dive - > number = atoi ( data [ 0 ] ) ;
2017-11-28 19:24:53 +00:00
2018-10-17 16:45:22 +00:00
state - > cur_dive - > when = ( time_t ) ( atol ( data [ 1 ] ) ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 2 ] )
2018-10-17 16:45:22 +00:00
utf8_string ( data [ 2 ] , & state - > cur_dive - > notes ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 3 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > duration . seconds = atoi ( data [ 3 ] ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 15 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . duration . seconds = atoi ( data [ 15 ] ) ;
2017-11-28 19:24:53 +00:00
/*
* TODO : the deviceid hash should be calculated here .
*/
2018-10-17 16:45:22 +00:00
settings_start ( state ) ;
dc_settings_start ( state ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 4 ] ) {
2018-10-17 16:45:22 +00:00
utf8_string ( data [ 4 ] , & state - > cur_settings . dc . serial_nr ) ;
state - > cur_settings . dc . deviceid = atoi ( data [ 4 ] ) ;
2017-11-28 19:24:53 +00:00
}
if ( data [ 5 ] )
2018-10-17 16:45:22 +00:00
utf8_string ( data [ 5 ] , & state - > cur_settings . dc . model ) ;
2017-11-28 19:24:53 +00:00
2018-10-17 16:45:22 +00:00
dc_settings_end ( state ) ;
settings_end ( state ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 6 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . maxdepth . mm = lrint ( strtod_flags ( data [ 6 ] , NULL , 0 ) * 1000 ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 8 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . airtemp . mkelvin = C_to_mkelvin ( atoi ( data [ 8 ] ) ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 9 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . watertemp . mkelvin = C_to_mkelvin ( atoi ( data [ 9 ] ) ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 4 ] ) {
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . deviceid = atoi ( data [ 4 ] ) ;
2017-11-28 19:24:53 +00:00
}
if ( data [ 5 ] )
2018-10-17 16:45:22 +00:00
utf8_string ( data [ 5 ] , & state - > cur_dive - > dc . model ) ;
2017-11-28 19:24:53 +00:00
2018-10-17 16:45:22 +00:00
snprintf ( get_events , sizeof ( get_events ) - 1 , get_cylinders_template , state - > cur_dive - > number ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_events , & dm5_cylinders , state , NULL ) ;
2017-11-28 19:24:53 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " %s " , " Database query dm5_cylinders failed. \n " ) ;
return 1 ;
}
if ( data [ 14 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . surface_pressure . mbar = ( atoi ( data [ 14 ] ) / 100 ) ;
2017-11-28 19:24:53 +00:00
interval = data [ 16 ] ? atoi ( data [ 16 ] ) : 0 ;
2018-04-07 04:41:04 +00:00
/*
* sampleBlob [ 0 ] version number , indicates the size of one sample
*
* Following ones describe single sample , bugs in interpretation of the binary blob are likely :
*
* sampleBlob [ 3 ] depth
* sampleBlob [ 7 - 9 ] pressure
* sampleBlob [ 11 ] temperature - either full Celsius or float , might be different field for some version of DM
*/
2017-11-28 19:24:53 +00:00
sampleBlob = ( unsigned const char * ) data [ 24 ] ;
if ( sampleBlob ) {
switch ( sampleBlob [ 0 ] ) {
2018-04-07 04:45:30 +00:00
case 1 :
// Log is converted from DM4 to DM5
block_size = 16 ;
break ;
2017-11-28 19:24:53 +00:00
case 2 :
block_size = 19 ;
break ;
case 3 :
block_size = 23 ;
break ;
case 4 :
2018-04-07 04:46:37 +00:00
// Temperature is stored in float
tempformat = 1 ;
2017-11-28 19:24:53 +00:00
block_size = 26 ;
break ;
2018-06-16 00:03:16 +00:00
case 5 :
// Temperature is stored in float
tempformat = 1 ;
block_size = 30 ;
break ;
2017-11-28 19:24:53 +00:00
default :
block_size = 16 ;
break ;
}
}
2018-10-17 16:45:22 +00:00
for ( i = 0 ; interval & & sampleBlob & & i * interval < state - > cur_dive - > duration . seconds ; i + + ) {
2017-11-28 19:24:53 +00:00
float * depth = ( float * ) & sampleBlob [ i * block_size + 3 ] ;
int32_t pressure = ( sampleBlob [ i * block_size + 9 ] < < 16 ) + ( sampleBlob [ i * block_size + 8 ] < < 8 ) + sampleBlob [ i * block_size + 7 ] ;
2018-10-17 16:45:22 +00:00
sample_start ( state ) ;
state - > cur_sample - > time . seconds = i * interval ;
state - > cur_sample - > depth . mm = lrintf ( depth [ 0 ] * 1000.0f ) ;
2018-04-07 04:46:37 +00:00
if ( tempformat = = 1 ) {
float * temp = ( float * ) & ( sampleBlob [ i * block_size + 11 ] ) ;
2018-10-17 16:45:22 +00:00
state - > cur_sample - > temperature . mkelvin = C_to_mkelvin ( * temp ) ;
2018-04-07 04:46:37 +00:00
} else {
2018-04-07 05:15:15 +00:00
if ( ( sampleBlob [ i * block_size + 11 ] ) ! = 0x7F ) {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > temperature . mkelvin = C_to_mkelvin ( sampleBlob [ i * block_size + 11 ] ) ;
2018-04-07 05:15:15 +00:00
}
2018-04-07 04:46:37 +00:00
}
2017-11-28 19:24:53 +00:00
/*
2018-04-07 04:46:37 +00:00
* Limit cylinder pressures to somewhat sensible values
2017-11-28 19:24:53 +00:00
*/
if ( pressure > = 0 & & pressure < 350000 )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > pressure [ 0 ] . mbar = pressure ;
sample_end ( state ) ;
2017-11-28 19:24:53 +00:00
}
/*
* Log was converted from DM4 , thus we need to parse the profile
* from DM4 format
*/
if ( i = = 0 ) {
float * profileBlob ;
unsigned char * tempBlob ;
int * pressureBlob ;
profileBlob = ( float * ) data [ 17 ] ;
tempBlob = ( unsigned char * ) data [ 18 ] ;
pressureBlob = ( int * ) data [ 19 ] ;
2018-10-17 16:45:22 +00:00
for ( i = 0 ; interval & & i * interval < state - > cur_dive - > duration . seconds ; i + + ) {
sample_start ( state ) ;
state - > cur_sample - > time . seconds = i * interval ;
2017-11-28 19:24:53 +00:00
if ( profileBlob )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > depth . mm = lrintf ( profileBlob [ i ] * 1000.0f ) ;
2017-11-28 19:24:53 +00:00
else
2018-10-17 16:45:22 +00:00
state - > cur_sample - > depth . mm = state - > cur_dive - > dc . maxdepth . mm ;
2017-11-28 19:24:53 +00:00
if ( data [ 18 ] & & data [ 18 ] [ 0 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > temperature . mkelvin = C_to_mkelvin ( tempBlob [ i ] ) ;
2017-11-28 19:24:53 +00:00
if ( data [ 19 ] & & data [ 19 ] [ 0 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > pressure [ 0 ] . mbar = pressureBlob [ i ] ;
sample_end ( state ) ;
2017-11-28 19:24:53 +00:00
}
}
2018-10-17 16:45:22 +00:00
snprintf ( get_events , sizeof ( get_events ) - 1 , get_gaschange_template , state - > cur_dive - > number ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_events , & dm5_gaschange , state , NULL ) ;
2017-11-28 19:24:53 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " %s " , " Database query dm5_gaschange failed. \n " ) ;
return 1 ;
}
2018-10-17 16:45:22 +00:00
snprintf ( get_events , sizeof ( get_events ) - 1 , get_events_template , state - > cur_dive - > number ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_events , & dm4_events , state , NULL ) ;
2017-11-28 19:24:53 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " %s " , " Database query dm4_events failed. \n " ) ;
return 1 ;
}
2018-10-17 16:45:22 +00:00
snprintf ( get_events , sizeof ( get_events ) - 1 , get_tags_template , state - > cur_dive - > number ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_events , & dm4_tags , state , NULL ) ;
2017-11-28 19:24:53 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " %s " , " Database query dm4_tags failed. \n " ) ;
return 1 ;
}
2018-10-17 16:45:22 +00:00
dive_end ( state ) ;
2017-11-28 19:24:53 +00:00
return SQLITE_OK ;
}
int parse_dm5_buffer ( sqlite3 * handle , const char * url , const char * buffer , int size ,
2019-02-28 21:45:17 +00:00
struct dive_table * table , struct trip_table * trips , struct dive_site_table * sites )
2017-11-28 19:24:53 +00:00
{
2018-05-22 07:07:42 +00:00
UNUSED ( buffer ) ;
UNUSED ( size ) ;
2017-11-28 19:24:53 +00:00
int retval ;
char * err = NULL ;
2018-10-17 16:45:22 +00:00
struct parser_state state ;
init_parser_state ( & state ) ;
state . target_table = table ;
2018-11-26 23:25:15 +00:00
state . trips = trips ;
2019-02-28 21:45:17 +00:00
state . sites = sites ;
2018-10-17 16:45:22 +00:00
state . sql_handle = handle ;
2017-11-28 19:24:53 +00:00
/* StartTime is converted from Suunto's nano seconds to standard
* time . We also need epoch , not seconds since year 1. */
char get_dives [ ] = " select DiveId,StartTime/10000000-62135596800,Note,Duration,coalesce(SourceSerialNumber,SerialNumber),Source,MaxDepth,SampleInterval,StartTemperature,BottomTemperature,StartPressure,EndPressure,'','',SurfacePressure,DiveTime,SampleInterval,ProfileBlob,TemperatureBlob,PressureBlob,'','','','',SampleBlob FROM Dive where Deleted is null " ;
2018-10-17 16:45:22 +00:00
retval = sqlite3_exec ( handle , get_dives , & dm5_dive , & state , & err ) ;
free_parser_state ( & state ) ;
2017-11-28 19:24:53 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " Database query failed '%s'. \n " , url ) ;
return 1 ;
}
return 0 ;
}