2017-11-27 17:45:25 +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"
2020-10-25 12:28:55 +00:00
# include "dive.h"
2019-03-04 22:20:29 +00:00
# include "divesite.h"
2020-10-25 12:28:55 +00:00
# include "sample.h"
2018-05-11 15:25:41 +00:00
# include "subsurface-string.h"
2017-11-27 17:45:25 +00:00
# include "parse.h"
# include "divelist.h"
# include "device.h"
# include "membuffer.h"
2017-11-27 18:03:43 +00:00
# include "gettext.h"
2017-11-27 17:45:25 +00:00
2018-10-17 16:45:22 +00:00
static int divinglog_cylinder ( void * param , int columns , char * * data , char * * column )
2017-11-27 18:34:41 +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-27 18:34:41 +00:00
short dbl = 1 ;
//char get_cylinder_template[] = "select TankID,TankSize,PresS,PresE,PresW,O2,He,DblTank from Tank where LogID = %d";
if ( data [ 7 ] & & atoi ( data [ 7 ] ) > 0 )
dbl = 2 ;
2019-08-04 16:59:14 +00:00
cyl = cylinder_start ( state ) ;
2017-11-27 18:34:41 +00:00
/*
* Assuming that we have to double the cylinder size , if double
* is set
*/
if ( data [ 1 ] & & atoi ( data [ 1 ] ) > 0 )
2019-08-04 16:44:57 +00:00
cyl - > type . size . mliter = atol ( data [ 1 ] ) * 1000 * dbl ;
2017-11-27 18:34:41 +00:00
if ( data [ 2 ] & & atoi ( data [ 2 ] ) > 0 )
2019-08-04 16:44:57 +00:00
cyl - > start . mbar = atol ( data [ 2 ] ) * 1000 ;
2017-11-27 18:34:41 +00:00
if ( data [ 3 ] & & atoi ( data [ 3 ] ) > 0 )
2019-08-04 16:44:57 +00:00
cyl - > end . mbar = atol ( data [ 3 ] ) * 1000 ;
2017-11-27 18:34:41 +00:00
if ( data [ 4 ] & & atoi ( data [ 4 ] ) > 0 )
2019-08-04 16:44:57 +00:00
cyl - > type . workingpressure . mbar = atol ( data [ 4 ] ) * 1000 ;
2017-11-27 18:34:41 +00:00
if ( data [ 5 ] & & atoi ( data [ 5 ] ) > 0 )
2019-08-04 16:44:57 +00:00
cyl - > gasmix . o2 . permille = atol ( data [ 5 ] ) * 10 ;
2017-11-27 18:34:41 +00:00
if ( data [ 6 ] & & atoi ( data [ 6 ] ) > 0 )
2019-08-04 16:44:57 +00:00
cyl - > gasmix . he . permille = atol ( data [ 6 ] ) * 10 ;
2017-11-27 18:34:41 +00:00
2018-10-17 16:45:22 +00:00
cylinder_end ( state ) ;
2017-11-27 18:34:41 +00:00
return 0 ;
}
2018-10-17 16:45:22 +00:00
static int divinglog_profile ( void * param , int columns , char * * data , char * * column )
2017-11-27 18:34:41 +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-27 18:34:41 +00:00
int sinterval = 0 ;
unsigned long time ;
int len1 , len2 , len3 , len4 , len5 ;
char * ptr1 , * ptr2 , * ptr3 , * ptr4 , * ptr5 ;
short oldcyl = - 1 ;
/* We do not have samples */
if ( ! data [ 1 ] )
return 0 ;
if ( data [ 0 ] )
sinterval = atoi ( data [ 0 ] ) ;
/*
* Profile
*
* DDDDDCRASWEE
* D : Depth ( in meter with two decimals )
* C : Deco ( 1 = yes , 0 = no )
* R : RBT ( Remaining Bottom Time warning )
* A : Ascent warning
* S : Decostop ignored
* W : Work warning
* E : Extra info ( different for every computer )
*
* Example : 004500010000
* 4.5 m , no deco , no RBT warning , ascanding too fast , no decostop ignored , no work , no extra info
*
*
* Profile2
*
* TTTFFFFIRRR
*
* T : Temperature ( in ° C with one decimal )
* F : Tank pressure 1 ( in bar with one decimal )
* I : Tank ID ( 0 , 1 , 2 . . . 9 )
* R : RBT ( in min )
*
* Example : 25518051099
* 25.5 ° C , 180.5 bar , Tank 1 , 99 min RBT
*
*/
ptr1 = data [ 1 ] ;
ptr2 = data [ 2 ] ;
ptr3 = data [ 3 ] ;
ptr4 = data [ 4 ] ;
ptr5 = data [ 5 ] ;
len1 = strlen ( ptr1 ) ;
len2 = ptr2 ? strlen ( ptr2 ) : 0 ;
len3 = ptr3 ? strlen ( ptr3 ) : 0 ;
len4 = ptr4 ? strlen ( ptr4 ) : 0 ;
len5 = ptr5 ? strlen ( ptr5 ) : 0 ;
time = 0 ;
while ( len1 > = 12 ) {
2018-10-17 16:45:22 +00:00
sample_start ( state ) ;
2017-11-27 18:34:41 +00:00
2018-10-17 16:45:22 +00:00
state - > cur_sample - > time . seconds = time ;
state - > cur_sample - > in_deco = ptr1 [ 5 ] - ' 0 ' ? true : false ;
state - > cur_sample - > depth . mm = atoi_n ( ptr1 , 5 ) * 10 ;
2017-11-27 18:34:41 +00:00
if ( len2 > = 11 ) {
int temp = atoi_n ( ptr2 , 3 ) ;
int pressure = atoi_n ( ptr2 + 3 , 4 ) ;
int tank = atoi_n ( ptr2 + 7 , 1 ) ;
int rbt = atoi_n ( ptr2 + 8 , 3 ) * 60 ;
2018-10-17 16:45:22 +00:00
state - > cur_sample - > temperature . mkelvin = C_to_mkelvin ( temp / 10.0f ) ;
state - > cur_sample - > pressure [ 0 ] . mbar = pressure * 100 ;
state - > cur_sample - > rbt . seconds = rbt ;
2019-08-04 16:44:57 +00:00
if ( oldcyl ! = tank & & tank > = 0 & & tank < state - > cur_dive - > cylinders . nr ) {
2019-08-04 20:13:49 +00:00
struct gasmix mix = get_cylinder ( state - > cur_dive , tank ) - > gasmix ;
2017-11-27 18:34:41 +00:00
int o2 = get_o2 ( mix ) ;
int he = get_he ( mix ) ;
2018-10-17 16:45:22 +00:00
event_start ( state ) ;
state - > cur_event . time . seconds = time ;
strcpy ( state - > cur_event . name , " gaschange " ) ;
2017-11-27 18:34:41 +00:00
o2 = ( o2 + 5 ) / 10 ;
he = ( he + 5 ) / 10 ;
2018-10-17 16:45:22 +00:00
state - > cur_event . value = o2 + ( he < < 16 ) ;
2017-11-27 18:34:41 +00:00
2018-10-17 16:45:22 +00:00
event_end ( state ) ;
2017-11-27 18:34:41 +00:00
oldcyl = tank ;
}
ptr2 + = 11 ; len2 - = 11 ;
}
if ( len3 > = 14 ) {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > heartbeat = atoi_n ( ptr3 + 8 , 3 ) ;
2017-11-27 18:34:41 +00:00
ptr3 + = 14 ; len3 - = 14 ;
}
if ( len4 > = 9 ) {
/*
* Following value is NDL when not in deco , and
* either 0 or TTS when in deco .
*/
int val = atoi_n ( ptr4 , 3 ) ;
2018-10-17 16:45:22 +00:00
if ( state - > cur_sample - > in_deco ) {
state - > cur_sample - > ndl . seconds = 0 ;
2017-11-27 18:34:41 +00:00
if ( val )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > tts . seconds = val * 60 ;
2017-11-27 18:34:41 +00:00
} else {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > ndl . seconds = val * 60 ;
2017-11-27 18:34:41 +00:00
}
2018-10-17 16:45:22 +00:00
state - > cur_sample - > stoptime . seconds = atoi_n ( ptr4 + 3 , 3 ) * 60 ;
state - > cur_sample - > stopdepth . mm = atoi_n ( ptr4 + 6 , 3 ) * 1000 ;
2017-11-27 18:34:41 +00:00
ptr4 + = 9 ; len4 - = 9 ;
}
/*
* AAABBBCCCOOOONNNNSS
*
* A = ppO2 cell 1 ( measured )
* B = ppO2 cell 2 ( measured )
* C = ppO2 cell 3 ( measured )
* O = OTU
* N = CNS
* S = Setpoint
*
* Example : 1121131141548026411
* 1.12 bar , 1.13 bar , 1.14 bar , OTU = 154.8 , CNS = 26.4 , Setpoint = 1.1
*/
if ( len5 > = 19 ) {
int ppo2_1 = atoi_n ( ptr5 + 0 , 3 ) ;
int ppo2_2 = atoi_n ( ptr5 + 3 , 3 ) ;
int ppo2_3 = atoi_n ( ptr5 + 6 , 3 ) ;
int otu = atoi_n ( ptr5 + 9 , 4 ) ;
2018-05-22 07:07:42 +00:00
UNUSED ( otu ) ; // we seem to not store this? Do we understand its format?
2017-11-27 18:34:41 +00:00
int cns = atoi_n ( ptr5 + 13 , 4 ) ;
int setpoint = atoi_n ( ptr5 + 17 , 2 ) ;
if ( ppo2_1 > 0 )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > o2sensor [ 0 ] . mbar = ppo2_1 * 100 ;
2017-11-27 18:34:41 +00:00
if ( ppo2_2 > 0 )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > o2sensor [ 1 ] . mbar = ppo2_2 * 100 ;
2017-11-27 18:34:41 +00:00
if ( ppo2_3 > 0 )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > o2sensor [ 2 ] . mbar = ppo2_3 * 100 ;
2017-11-27 18:34:41 +00:00
if ( cns > 0 )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > cns = lrintf ( cns / 10.0f ) ;
2017-11-27 18:34:41 +00:00
if ( setpoint > 0 )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > setpoint . mbar = setpoint * 100 ;
2017-11-27 18:34:41 +00:00
ptr5 + = 19 ; len5 - = 19 ;
}
/*
* Count the number of o2 sensors
*/
2018-10-17 16:45:22 +00:00
if ( ! state - > cur_dive - > dc . no_o2sensors & & ( state - > cur_sample - > o2sensor [ 0 ] . mbar | | state - > cur_sample - > o2sensor [ 1 ] . mbar | | state - > cur_sample - > o2sensor [ 2 ] . mbar ) ) {
state - > cur_dive - > dc . no_o2sensors = state - > cur_sample - > o2sensor [ 0 ] . mbar ? 1 : 0 +
state - > cur_sample - > o2sensor [ 1 ] . mbar ? 1 : 0 +
state - > cur_sample - > o2sensor [ 2 ] . mbar ? 1 : 0 ;
2017-11-27 18:34:41 +00:00
}
2018-10-17 16:45:22 +00:00
sample_end ( state ) ;
2017-11-27 18:34:41 +00:00
/* Remaining bottom time warning */
if ( ptr1 [ 6 ] - ' 0 ' ) {
2018-10-17 16:45:22 +00:00
event_start ( state ) ;
state - > cur_event . time . seconds = time ;
strcpy ( state - > cur_event . name , " rbt " ) ;
event_end ( state ) ;
2017-11-27 18:34:41 +00:00
}
/* Ascent warning */
if ( ptr1 [ 7 ] - ' 0 ' ) {
2018-10-17 16:45:22 +00:00
event_start ( state ) ;
state - > cur_event . time . seconds = time ;
strcpy ( state - > cur_event . name , " ascent " ) ;
event_end ( state ) ;
2017-11-27 18:34:41 +00:00
}
/* Deco stop ignored */
if ( ptr1 [ 8 ] - ' 0 ' ) {
2018-10-17 16:45:22 +00:00
event_start ( state ) ;
state - > cur_event . time . seconds = time ;
strcpy ( state - > cur_event . name , " violation " ) ;
event_end ( state ) ;
2017-11-27 18:34:41 +00:00
}
/* Workload warning */
if ( ptr1 [ 9 ] - ' 0 ' ) {
2018-10-17 16:45:22 +00:00
event_start ( state ) ;
state - > cur_event . time . seconds = time ;
strcpy ( state - > cur_event . name , " workload " ) ;
event_end ( state ) ;
2017-11-27 18:34:41 +00:00
}
ptr1 + = 12 ; len1 - = 12 ;
time + = sinterval ;
}
return 0 ;
}
2018-10-17 16:45:22 +00:00
static int divinglog_dive ( void * param , int columns , char * * data , char * * column )
2017-11-27 18:34:41 +00:00
{
2018-05-22 07:07:42 +00:00
UNUSED ( columns ) ;
UNUSED ( column ) ;
2017-11-27 18:34:41 +00:00
2018-10-14 13:09:36 +00:00
int retval = 0 , diveid ;
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
sqlite3 * handle = state - > sql_handle ;
2017-11-27 18:34:41 +00:00
char get_profile_template [ ] = " select ProfileInt,Profile,Profile2,Profile3,Profile4,Profile5 from Logbook where ID = %d " ;
char get_cylinder0_template [ ] = " select 0,TankSize,PresS,PresE,PresW,O2,He,DblTank from Logbook where ID = %d " ;
char get_cylinder_template [ ] = " select TankID,TankSize,PresS,PresE,PresW,O2,He,DblTank from Tank where LogID = %d order by TankID " ;
char get_buffer [ 1024 ] ;
2018-10-17 16:45:22 +00:00
dive_start ( state ) ;
2017-11-27 18:34:41 +00:00
diveid = atoi ( data [ 13 ] ) ;
2018-10-17 16:45:22 +00:00
state - > cur_dive - > number = atoi ( data [ 0 ] ) ;
2017-11-27 18:34:41 +00:00
2018-10-17 16:45:22 +00:00
state - > cur_dive - > when = ( time_t ) ( atol ( data [ 1 ] ) ) ;
2017-11-27 18:34:41 +00:00
if ( data [ 2 ] )
2019-03-05 21:58:47 +00:00
add_dive_to_dive_site ( state - > cur_dive , find_or_create_dive_site_with_name ( data [ 2 ] , state - > sites ) ) ;
2017-11-27 18:34:41 +00:00
if ( data [ 3 ] )
2018-10-17 16:45:22 +00:00
utf8_string ( data [ 3 ] , & state - > cur_dive - > buddy ) ;
2017-11-27 18:34:41 +00:00
if ( data [ 4 ] )
2018-10-17 16:45:22 +00:00
utf8_string ( data [ 4 ] , & state - > cur_dive - > notes ) ;
2017-11-27 18:34:41 +00:00
if ( data [ 5 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . maxdepth . mm = lrint ( strtod_flags ( data [ 5 ] , NULL , 0 ) * 1000 ) ;
2017-11-27 18:34:41 +00:00
if ( data [ 6 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . duration . seconds = atoi ( data [ 6 ] ) * 60 ;
2017-11-27 18:34:41 +00:00
if ( data [ 7 ] )
2022-02-12 13:03:18 +00:00
utf8_string ( data [ 7 ] , & state - > cur_dive - > diveguide ) ;
2017-11-27 18:34:41 +00:00
if ( data [ 8 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > airtemp . mkelvin = C_to_mkelvin ( atol ( data [ 8 ] ) ) ;
2017-11-27 18:34:41 +00:00
if ( data [ 9 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > watertemp . mkelvin = C_to_mkelvin ( atol ( data [ 9 ] ) ) ;
2017-11-27 18:34:41 +00:00
if ( data [ 10 ] ) {
2022-01-02 13:24:04 +00:00
weightsystem_t ws = { { atol ( data [ 10 ] ) * 1000 } , translate ( " gettextFromC " , " unknown " ) , false } ;
2019-06-26 15:21:03 +00:00
add_cloned_weightsystem ( & state - > cur_dive - > weightsystems , ws ) ;
2017-11-27 18:34:41 +00:00
}
if ( data [ 11 ] )
2018-10-17 16:45:22 +00:00
state - > cur_dive - > suit = strdup ( data [ 11 ] ) ;
2017-11-27 18:34:41 +00:00
/* Divinglog has following visibility options: good, medium, bad */
if ( data [ 14 ] ) {
switch ( data [ 14 ] [ 0 ] ) {
case ' 0 ' :
break ;
case ' 1 ' :
2018-10-17 16:45:22 +00:00
state - > cur_dive - > visibility = 5 ;
2017-11-27 18:34:41 +00:00
break ;
case ' 2 ' :
2018-10-17 16:45:22 +00:00
state - > cur_dive - > visibility = 3 ;
2017-11-27 18:34:41 +00:00
break ;
case ' 3 ' :
2018-10-17 16:45:22 +00:00
state - > cur_dive - > visibility = 1 ;
2017-11-27 18:34:41 +00:00
break ;
default :
break ;
}
}
2018-10-17 16:45:22 +00:00
settings_start ( state ) ;
dc_settings_start ( state ) ;
2017-11-27 18:34:41 +00:00
if ( data [ 12 ] ) {
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . model = strdup ( data [ 12 ] ) ;
2017-11-27 18:34:41 +00:00
} else {
2018-10-17 16:45:22 +00:00
state - > cur_settings . dc . model = strdup ( " Divinglog import " ) ;
2017-11-27 18:34:41 +00:00
}
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_cylinder0_template , diveid ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & divinglog_cylinder , state , NULL ) ;
2017-11-27 18:34:41 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " %s " , " Database query divinglog_cylinder0 failed. \n " ) ;
return 1 ;
}
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_cylinder_template , diveid ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & divinglog_cylinder , state , NULL ) ;
2017-11-27 18:34:41 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " %s " , " Database query divinglog_cylinder failed. \n " ) ;
return 1 ;
}
if ( data [ 15 ] ) {
switch ( data [ 15 ] [ 0 ] ) {
/* OC */
case ' 0 ' :
break ;
case ' 1 ' :
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . divemode = PSCR ;
2017-11-27 18:34:41 +00:00
break ;
case ' 2 ' :
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . divemode = CCR ;
2017-11-27 18:34:41 +00:00
break ;
}
}
2018-10-17 16:45:22 +00:00
dc_settings_end ( state ) ;
settings_end ( state ) ;
2017-11-27 18:34:41 +00:00
if ( data [ 12 ] ) {
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . model = strdup ( data [ 12 ] ) ;
2017-11-27 18:34:41 +00:00
} else {
2018-10-17 16:45:22 +00:00
state - > cur_dive - > dc . model = strdup ( " Divinglog import " ) ;
2017-11-27 18:34:41 +00:00
}
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_profile_template , diveid ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & divinglog_profile , state , NULL ) ;
2017-11-27 18:34:41 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " %s " , " Database query divinglog_profile failed. \n " ) ;
return 1 ;
}
2018-10-17 16:45:22 +00:00
dive_end ( state ) ;
2017-11-27 18:34:41 +00:00
return SQLITE_OK ;
}
int parse_divinglog_buffer ( sqlite3 * handle , const char * url , const char * buffer , int size ,
2020-10-17 10:32:22 +00:00
struct dive_table * table , struct trip_table * trips , struct dive_site_table * sites ,
struct device_table * devices )
2017-11-27 18:34:41 +00:00
{
2018-05-22 07:07:42 +00:00
UNUSED ( buffer ) ;
UNUSED ( size ) ;
2017-11-27 18:34:41 +00:00
int retval ;
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 ;
2020-10-17 10:32:22 +00:00
state . devices = devices ;
2018-10-17 16:45:22 +00:00
state . sql_handle = handle ;
2017-11-27 18:34:41 +00:00
char get_dives [ ] = " select Number,strftime('%s',Divedate || ' ' || ifnull(Entrytime,'00:00')),Country || ' - ' || City || ' - ' || Place,Buddy,Comments,Depth,Divetime,Divemaster,Airtemp,Watertemp,Weight,Divesuit,Computer,ID,Visibility,SupplyType from Logbook where UUID not in (select UUID from DeletedRecords) " ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_dives , & divinglog_dive , & state , NULL ) ;
2018-10-17 16:45:22 +00:00
free_parser_state ( & state ) ;
2017-11-27 18:34:41 +00:00
if ( retval ! = SQLITE_OK ) {
fprintf ( stderr , " Database query failed '%s'. \n " , url ) ;
return 1 ;
}
return 0 ;
}