2017-11-28 19:31:27 +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
# include "dive.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-28 19:31:27 +00:00
# include "parse.h"
# include "divelist.h"
core: introduce divelog structure
The parser API was very annoying, as a number of tables
to-be-filled were passed in as pointers. The goal of this
commit is to collect all these tables in a single struct.
This should make it (more or less) clear what is actually
written into the divelog files.
Moreover, it should now be rather easy to search for
instances, where the global logfile is accessed (and it
turns out that there are many!).
The divelog struct does not contain the tables as substructs,
but only collects pointers. The idea is that the "divelog.h"
file can be included without all the other files describing
the numerous tables.
To make it easier to use from C++ parts of the code, the
struct implements a constructor and a destructor. Sadly,
we can't use smart pointers, since the pointers are accessed
from C code. Therfore the constructor and destructor are
quite complex.
The whole commit is large, but was mostly an automatic
conversion.
One oddity of note: the divelog structure also contains
the "autogroup" flag, since that is saved in the divelog.
This actually fixes a bug: Before, when importing dives
from a different log, the autogroup flag was overwritten.
This was probably not intended and does not happen anymore.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2022-11-08 20:31:08 +00:00
# include "divelog.h"
2017-11-28 19:31:27 +00:00
# include "device.h"
2024-03-24 20:03:08 +00:00
# include "errorhelper.h"
2017-11-28 19:31:27 +00:00
# include "membuffer.h"
# include "gettext.h"
2020-10-25 13:10:52 +00:00
# include <stdlib.h>
2024-02-29 06:29:11 +00:00
static int shearwater_cylinders ( void * param , int , char * * data , char * * )
2017-11-28 19:31:27 +00:00
{
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:31:27 +00:00
2024-04-23 07:06:28 +00:00
int o2 = lrint ( permissive_strtod ( data [ 0 ] , NULL ) * 1000 ) ;
int he = lrint ( permissive_strtod ( data [ 1 ] , NULL ) * 1000 ) ;
2017-11-28 19:31:27 +00:00
/* Shearwater allows entering only 99%, not 100%
* so assume 99 % to be pure oxygen */
if ( o2 = = 990 & & he = = 0 )
o2 = 1000 ;
2019-08-04 16:59:14 +00:00
cyl = cylinder_start ( state ) ;
2019-08-04 16:44:57 +00:00
cyl - > gasmix . o2 . permille = o2 ;
cyl - > gasmix . he . permille = he ;
2018-10-17 16:45:22 +00:00
cylinder_end ( state ) ;
2017-11-28 19:31:27 +00:00
return 0 ;
}
2024-02-29 06:29:11 +00:00
static int shearwater_changes ( void * param , int columns , char * * data , char * * )
2017-11-28 19:31:27 +00:00
{
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:31:27 +00:00
if ( columns ! = 3 ) {
return 1 ;
}
if ( ! data [ 0 ] | | ! data [ 1 ] | | ! data [ 2 ] ) {
return 2 ;
}
2024-04-23 07:06:28 +00:00
int o2 = lrint ( permissive_strtod ( data [ 1 ] , NULL ) * 1000 ) ;
int he = lrint ( permissive_strtod ( data [ 2 ] , NULL ) * 1000 ) ;
2017-11-28 19:31:27 +00:00
/* Shearwater allows entering only 99%, not 100%
* so assume 99 % to be pure oxygen */
if ( o2 = = 990 & & he = = 0 )
o2 = 1000 ;
// Find the cylinder index
2024-05-28 19:31:11 +00:00
auto it = std : : find_if ( state - > cur_dive - > cylinders . begin ( ) , state - > cur_dive - > cylinders . end ( ) ,
[ o2 , he ] ( auto & cyl )
{ return cyl . gasmix . o2 . permille = = o2 & & cyl . gasmix . he . permille = = he ; } ) ;
if ( it = = state - > cur_dive - > cylinders . end ( ) ) {
2017-11-28 19:31:27 +00:00
// Cylinder not found, creating a new one
2019-08-04 16:59:14 +00:00
cyl = cylinder_start ( state ) ;
2019-08-04 16:44:57 +00:00
cyl - > gasmix . o2 . permille = o2 ;
cyl - > gasmix . he . permille = he ;
2018-10-17 16:45:22 +00:00
cylinder_end ( state ) ;
2024-05-28 19:31:11 +00:00
it = std : : prev ( state - > cur_dive - > cylinders . end ( ) ) ;
2017-11-28 19:31:27 +00:00
}
2024-05-28 19:31:11 +00:00
add_gas_switch_event ( state - > cur_dive . get ( ) , get_dc ( state ) , state - > sample_rate ? atoi ( data [ 0 ] ) / state - > sample_rate * 10 : atoi ( data [ 0 ] ) ,
it - state - > cur_dive - > cylinders . begin ( ) ) ;
2017-11-28 19:31:27 +00:00
return 0 ;
}
2024-02-29 06:29:11 +00:00
static int shearwater_profile_sample ( void * param , int , char * * data , char * * )
2017-11-28 19:31:27 +00:00
{
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
2018-05-27 13:56:09 +00:00
int d6 , d7 ;
2017-11-28 19:31:27 +00:00
2018-10-17 16:45:22 +00:00
sample_start ( state ) ;
2020-09-19 10:25:47 +00:00
/*
* If we have sample_rate , we use self calculated sample number
* to count the sample time .
* If we do not have sample_rate , we try to use the sample time
* provided by Shearwater as is .
*/
if ( data [ 9 ] & & state - > sample_rate )
state - > cur_sample - > time . seconds = atoi ( data [ 9 ] ) * state - > sample_rate ;
else if ( data [ 0 ] )
state - > cur_sample - > time . seconds = atoi ( data [ 0 ] ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 1 ] )
2024-04-23 07:06:28 +00:00
state - > cur_sample - > depth . mm = state - > metric ? lrint ( permissive_strtod ( data [ 1 ] , NULL ) * 1000 ) : feet_to_mm ( permissive_strtod ( data [ 1 ] , NULL ) ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 2 ] )
2024-04-23 07:06:28 +00:00
state - > cur_sample - > temperature . mkelvin = state - > metric ? C_to_mkelvin ( permissive_strtod ( data [ 2 ] , NULL ) ) : F_to_mkelvin ( permissive_strtod ( data [ 2 ] , NULL ) ) ;
2024-05-28 19:31:11 +00:00
if ( data [ 3 ] )
2024-04-23 07:06:28 +00:00
state - > cur_sample - > setpoint . mbar = lrint ( permissive_strtod ( data [ 3 ] , NULL ) * 1000 ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 4 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > ndl . seconds = atoi ( data [ 4 ] ) * 60 ;
2017-11-28 19:31:27 +00:00
if ( data [ 5 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > cns = atoi ( data [ 5 ] ) ;
2018-05-27 06:06:09 +00:00
if ( data [ 6 ] ) {
2018-05-27 13:56:09 +00:00
d6 = atoi ( data [ 6 ] ) ;
if ( d6 > 0 ) {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > stopdepth . mm = state - > metric ? d6 * 1000 : feet_to_mm ( d6 ) ;
state - > cur_sample - > in_deco = 1 ;
2018-05-27 06:06:09 +00:00
} else if ( data [ 7 ] ) {
2018-05-27 13:56:09 +00:00
d7 = atoi ( data [ 7 ] ) ;
if ( d7 > 0 ) {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > stopdepth . mm = state - > metric ? d7 * 1000 : feet_to_mm ( d7 ) ;
2018-05-27 14:17:15 +00:00
if ( data [ 8 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > stoptime . seconds = atoi ( data [ 8 ] ) * 60 ;
state - > cur_sample - > in_deco = 1 ;
2018-05-27 06:06:09 +00:00
} else {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > in_deco = 0 ;
2018-05-27 06:06:09 +00:00
}
} else {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > in_deco = 0 ;
2018-05-27 06:06:09 +00:00
}
}
2017-11-28 19:31:27 +00:00
/* We don't actually have data[3], but it should appear in the
* SQL query at some point .
if ( data [ 3 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > pressure [ 0 ] . mbar = state - > metric ? atoi ( data [ 3 ] ) * 1000 : psi_to_mbar ( atoi ( data [ 3 ] ) ) ;
2017-11-28 19:31:27 +00:00
*/
2018-10-17 16:45:22 +00:00
sample_end ( state ) ;
2017-11-28 19:31:27 +00:00
return 0 ;
}
2024-02-29 06:29:11 +00:00
static int shearwater_ai_profile_sample ( void * param , int , char * * data , char * * )
2017-11-28 19:31:27 +00:00
{
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
2018-05-27 13:56:09 +00:00
int d6 , d9 ;
2017-11-28 19:31:27 +00:00
2018-10-17 16:45:22 +00:00
sample_start ( state ) ;
2020-09-19 10:25:47 +00:00
/*
* If we have sample_rate , we use self calculated sample number
* to count the sample time .
* If we do not have sample_rate , we try to use the sample time
* provided by Shearwater as is .
*/
if ( data [ 11 ] & & state - > sample_rate )
state - > cur_sample - > time . seconds = atoi ( data [ 11 ] ) * state - > sample_rate ;
else if ( data [ 0 ] )
state - > cur_sample - > time . seconds = atoi ( data [ 0 ] ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 1 ] )
2024-04-23 07:06:28 +00:00
state - > cur_sample - > depth . mm = state - > metric ? lrint ( permissive_strtod ( data [ 1 ] , NULL ) * 1000 ) : feet_to_mm ( permissive_strtod ( data [ 1 ] , NULL ) ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 2 ] )
2024-04-23 07:06:28 +00:00
state - > cur_sample - > temperature . mkelvin = state - > metric ? C_to_mkelvin ( permissive_strtod ( data [ 2 ] , NULL ) ) : F_to_mkelvin ( permissive_strtod ( data [ 2 ] , NULL ) ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 3 ] ) {
2024-04-23 07:06:28 +00:00
state - > cur_sample - > setpoint . mbar = lrint ( permissive_strtod ( data [ 3 ] , NULL ) * 1000 ) ;
2017-11-28 19:31:27 +00:00
}
if ( data [ 4 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > ndl . seconds = atoi ( data [ 4 ] ) * 60 ;
2017-11-28 19:31:27 +00:00
if ( data [ 5 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > cns = atoi ( data [ 5 ] ) ;
2018-05-27 06:06:09 +00:00
if ( data [ 6 ] ) {
2018-05-27 13:56:09 +00:00
d6 = atoi ( data [ 6 ] ) ;
if ( d6 > 0 ) {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > stopdepth . mm = state - > metric ? d6 * 1000 : feet_to_mm ( d6 ) ;
state - > cur_sample - > in_deco = 1 ;
2018-05-27 06:06:09 +00:00
} else if ( data [ 9 ] ) {
2018-05-27 13:56:09 +00:00
d9 = atoi ( data [ 9 ] ) ;
if ( d9 > 0 ) {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > stopdepth . mm = state - > metric ? d9 * 1000 : feet_to_mm ( d9 ) ;
2018-05-27 14:17:15 +00:00
if ( data [ 10 ] )
2018-10-17 16:45:22 +00:00
state - > cur_sample - > stoptime . seconds = atoi ( data [ 10 ] ) * 60 ;
state - > cur_sample - > in_deco = 1 ;
2018-05-27 06:06:09 +00:00
} else {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > in_deco = 0 ;
2018-05-27 06:06:09 +00:00
}
} else {
2018-10-17 16:45:22 +00:00
state - > cur_sample - > in_deco = 0 ;
2018-05-27 06:06:09 +00:00
}
}
2017-11-28 19:31:27 +00:00
2020-09-10 13:46:52 +00:00
/*
* I have seen sample log where the sample pressure had to be multiplied by 2. However ,
* currently this seems to be corrected in ShearWater , so we are no longer taking this into
* account .
*
* Also , missing values might be nowadays 8184 , even though an old log I have received has
* 8190. Thus discarding values over 8180 here .
*/
if ( data [ 7 ] & & atoi ( data [ 7 ] ) < 8180 ) {
state - > cur_sample - > pressure [ 0 ] . mbar = psi_to_mbar ( atoi ( data [ 7 ] ) ) ;
2017-11-28 19:31:27 +00:00
}
2020-09-10 13:46:52 +00:00
if ( data [ 8 ] & & atoi ( data [ 8 ] ) < 8180 )
state - > cur_sample - > pressure [ 1 ] . mbar = psi_to_mbar ( atoi ( data [ 8 ] ) ) ;
2018-10-17 16:45:22 +00:00
sample_end ( state ) ;
2017-11-28 19:31:27 +00:00
return 0 ;
}
2024-02-29 06:29:11 +00:00
static int shearwater_mode ( void * param , int , char * * data , char * * )
2017-11-28 19:31:27 +00:00
{
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
2017-11-28 19:31:27 +00:00
if ( data [ 0 ] )
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . divemode = atoi ( data [ 0 ] ) = = 0 ? CCR : OC ;
2017-11-28 19:31:27 +00:00
return 0 ;
}
2024-02-29 06:29:11 +00:00
static int shearwater_dive ( void * param , int , char * * data , char * * )
2017-11-28 19:31:27 +00:00
{
int retval = 0 ;
2018-10-17 16:45:22 +00:00
struct parser_state * state = ( struct parser_state * ) param ;
sqlite3 * handle = state - > sql_handle ;
2018-12-29 19:31:12 +00:00
char get_profile_template [ ] = " select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,firstStopDepth,firstStopTime from dive_log_records where diveLogId=%ld " ;
char get_profile_template_ai [ ] = " select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,aiSensor0_PressurePSI,aiSensor1_PressurePSI,firstStopDepth,firstStopTime from dive_log_records where diveLogId = %ld " ;
char get_cylinder_template [ ] = " select fractionO2,fractionHe from dive_log_records where diveLogId = %ld group by fractionO2,fractionHe " ;
char get_changes_template [ ] = " select a.currentTime,a.fractionO2,a.fractionHe from dive_log_records as a,dive_log_records as b where (a.id - 1) = b.id and (a.fractionO2 != b.fractionO2 or a.fractionHe != b.fractionHe) and a.diveLogId=b.divelogId and a.diveLogId = %ld " ;
char get_mode_template [ ] = " select distinct currentCircuitSetting from dive_log_records where diveLogId = %ld " ;
2017-11-28 19:31:27 +00:00
char get_buffer [ 1024 ] ;
2018-10-17 16:45:22 +00:00
dive_start ( state ) ;
state - > cur_dive - > number = atoi ( data [ 0 ] ) ;
2017-11-28 19:31:27 +00:00
2018-10-17 16:45:22 +00:00
state - > cur_dive - > when = ( time_t ) ( atol ( data [ 1 ] ) ) ;
2017-11-28 19:31:27 +00:00
2018-12-29 19:31:12 +00:00
long int dive_id = atol ( data [ 11 ] ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 2 ] )
2024-05-16 18:11:21 +00:00
add_dive_site ( data [ 2 ] , state - > cur_dive . get ( ) , state ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 3 ] )
2024-05-29 18:40:18 +00:00
utf8_string_std ( data [ 3 ] , & state - > cur_dive - > buddy ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 4 ] )
2024-05-29 18:40:18 +00:00
utf8_string_std ( data [ 4 ] , & state - > cur_dive - > notes ) ;
2017-11-28 19:31:27 +00:00
2018-10-17 16:45:22 +00:00
state - > metric = atoi ( data [ 5 ] ) = = 1 ? 0 : 1 ;
2017-11-28 19:31:27 +00:00
/* TODO: verify that metric calculation is correct */
if ( data [ 6 ] )
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . maxdepth . mm = state - > metric ? lrint ( permissive_strtod ( data [ 6 ] , NULL ) * 1000 ) : feet_to_mm ( permissive_strtod ( data [ 6 ] , NULL ) ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 7 ] )
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . duration . seconds = atoi ( data [ 7 ] ) * 60 ;
2017-11-28 19:31:27 +00:00
if ( data [ 8 ] )
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . surface_pressure . mbar = atoi ( data [ 8 ] ) ;
2017-11-28 19:31:27 +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:31:27 +00:00
if ( data [ 9 ] )
2024-02-29 06:56:27 +00:00
utf8_string_std ( data [ 9 ] , & state - > cur_settings . dc . serial_nr ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 10 ] ) {
switch ( atoi ( data [ 10 ] ) ) {
case 2 :
2024-05-18 15:03:19 +00:00
state - > cur_settings . dc . model = " Shearwater Petrel/Perdix " ;
2017-11-28 19:31:27 +00:00
break ;
case 4 :
2024-05-18 15:03:19 +00:00
state - > cur_settings . dc . model = " Shearwater Predator " ;
2017-11-28 19:31:27 +00:00
break ;
default :
2024-05-18 15:03:19 +00:00
state - > cur_settings . dc . model = " Shearwater import " ;
2017-11-28 19:31:27 +00:00
break ;
}
}
2018-10-17 16:45:22 +00:00
state - > cur_settings . dc . deviceid = atoi ( data [ 9 ] ) ;
2017-11-28 19:31:27 +00:00
2018-10-17 16:45:22 +00:00
dc_settings_end ( state ) ;
settings_end ( state ) ;
2017-11-28 19:31:27 +00:00
if ( data [ 10 ] ) {
switch ( atoi ( data [ 10 ] ) ) {
case 2 :
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . model = " Shearwater Petrel/Perdix " ;
2017-11-28 19:31:27 +00:00
break ;
case 4 :
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . model = " Shearwater Predator " ;
2017-11-28 19:31:27 +00:00
break ;
default :
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . model = " Shearwater import " ;
2017-11-28 19:31:27 +00:00
break ;
}
}
if ( data [ 11 ] ) {
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_mode_template , dive_id ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & shearwater_mode , state , NULL ) ;
2017-11-28 19:31:27 +00:00
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query shearwater_mode failed. " ) ;
2017-11-28 19:31:27 +00:00
return 1 ;
}
}
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_cylinder_template , dive_id ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & shearwater_cylinders , state , NULL ) ;
2017-11-28 19:31:27 +00:00
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query shearwater_cylinders failed. " ) ;
2017-11-28 19:31:27 +00:00
return 1 ;
}
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_changes_template , dive_id ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & shearwater_changes , state , NULL ) ;
2017-11-28 19:31:27 +00:00
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query shearwater_changes failed. " ) ;
2017-11-28 19:31:27 +00:00
return 1 ;
}
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_profile_template_ai , dive_id ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & shearwater_ai_profile_sample , state , NULL ) ;
2017-11-28 19:31:27 +00:00
if ( retval ! = SQLITE_OK ) {
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_profile_template , dive_id ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & shearwater_profile_sample , state , NULL ) ;
2017-11-28 19:31:27 +00:00
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query shearwater_profile_sample failed. " ) ;
2017-11-28 19:31:27 +00:00
return 1 ;
}
}
2018-10-17 16:45:22 +00:00
dive_end ( state ) ;
2017-11-28 19:31:27 +00:00
return SQLITE_OK ;
}
2024-02-29 06:29:11 +00:00
static int shearwater_cloud_dive ( void * param , int , char * * data , char * * )
2018-12-29 19:32:55 +00:00
{
int retval = 0 ;
struct parser_state * state = ( struct parser_state * ) param ;
sqlite3 * handle = state - > sql_handle ;
2020-09-19 10:25:47 +00:00
/*
* Since Shearwater reported sample time can be totally bogus ,
* we need to calculate the sample number by ourselves . The
* calculated sample number is multiplied by sample interval
* giving us correct sample time .
*/
char get_profile_template [ ] = " select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,firstStopDepth,firstStopTime,(select count(0) from dive_log_records r where r.id < d.id and r.diveLogId = %ld and r.currentTime > 0) as row from dive_log_records d where d.diveLogId=%ld and d.currentTime > 0 " ;
char get_profile_template_ai [ ] = " select currentTime,currentDepth,waterTemp,averagePPO2,currentNdl,CNSPercent,decoCeiling,aiSensor0_PressurePSI,aiSensor1_PressurePSI,firstStopDepth,firstStopTime,(select count(0) from dive_log_records r where r.id < d.id and r.diveLogId = %ld and r.currentTime > 0) as row from dive_log_records d where d.diveLogId = %ld and d.currentTime > 0 " ;
2018-12-29 19:32:55 +00:00
char get_cylinder_template [ ] = " select fractionO2 / 100,fractionHe / 100 from dive_log_records where diveLogId = %ld group by fractionO2,fractionHe " ;
2020-09-12 18:38:46 +00:00
char get_first_gas_template [ ] = " select currentTime, fractionO2 / 100, fractionHe / 100 from dive_log_records where diveLogId = %ld limit 1 " ;
2020-09-08 18:25:26 +00:00
char get_changes_template [ ] = " select a.currentTime,a.fractionO2 / 100,a.fractionHe /100 from dive_log_records as a,dive_log_records as b where (a.id - 1) = b.id and (a.fractionO2 != b.fractionO2 or a.fractionHe != b.fractionHe) and a.diveLogId=b.divelogId and a.diveLogId = %ld and a.fractionO2 > 0 and b.fractionO2 > 0 " ;
2018-12-29 19:32:55 +00:00
char get_mode_template [ ] = " select distinct currentCircuitSetting from dive_log_records where diveLogId = %ld " ;
char get_buffer [ 1024 ] ;
dive_start ( state ) ;
state - > cur_dive - > number = atoi ( data [ 0 ] ) ;
state - > cur_dive - > when = ( time_t ) ( atol ( data [ 1 ] ) ) ;
long int dive_id = atol ( data [ 11 ] ) ;
2018-12-29 20:31:52 +00:00
if ( data [ 12 ] )
2019-01-03 04:56:48 +00:00
state - > sample_rate = atoi ( data [ 12 ] ) ;
2018-12-29 20:31:52 +00:00
else
2019-01-03 04:56:48 +00:00
state - > sample_rate = 0 ;
2018-12-29 19:32:55 +00:00
if ( data [ 2 ] )
2024-05-16 18:11:21 +00:00
add_dive_site ( data [ 2 ] , state - > cur_dive . get ( ) , state ) ;
2018-12-29 19:32:55 +00:00
if ( data [ 3 ] )
2024-05-29 18:40:18 +00:00
utf8_string_std ( data [ 3 ] , & state - > cur_dive - > buddy ) ;
2018-12-29 19:32:55 +00:00
if ( data [ 4 ] )
2024-05-29 18:40:18 +00:00
utf8_string_std ( data [ 4 ] , & state - > cur_dive - > notes ) ;
2018-12-29 19:32:55 +00:00
state - > metric = atoi ( data [ 5 ] ) = = 1 ? 0 : 1 ;
/* TODO: verify that metric calculation is correct */
if ( data [ 6 ] )
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . maxdepth . mm = state - > metric ? lrint ( permissive_strtod ( data [ 6 ] , NULL ) * 1000 ) : feet_to_mm ( permissive_strtod ( data [ 6 ] , NULL ) ) ;
2018-12-29 19:32:55 +00:00
if ( data [ 7 ] )
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . duration . seconds = atoi ( data [ 7 ] ) ;
2018-12-29 19:32:55 +00:00
if ( data [ 8 ] )
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . surface_pressure . mbar = atoi ( data [ 8 ] ) ;
2018-12-29 19:32:55 +00:00
/*
* TODO : the deviceid hash should be calculated here .
*/
settings_start ( state ) ;
dc_settings_start ( state ) ;
if ( data [ 9 ] )
2024-02-29 06:56:27 +00:00
utf8_string_std ( data [ 9 ] , & state - > cur_settings . dc . serial_nr ) ;
2018-12-29 19:32:55 +00:00
if ( data [ 10 ] ) {
switch ( atoi ( data [ 10 ] ) ) {
case 2 :
2024-05-18 15:03:19 +00:00
state - > cur_settings . dc . model = " Shearwater Petrel/Perdix " ;
2018-12-29 19:32:55 +00:00
break ;
case 4 :
2024-05-18 15:03:19 +00:00
state - > cur_settings . dc . model = " Shearwater Predator " ;
2018-12-29 19:32:55 +00:00
break ;
default :
2024-05-18 15:03:19 +00:00
state - > cur_settings . dc . model = " Shearwater import " ;
2018-12-29 19:32:55 +00:00
break ;
}
}
state - > cur_settings . dc . deviceid = atoi ( data [ 9 ] ) ;
dc_settings_end ( state ) ;
settings_end ( state ) ;
if ( data [ 10 ] ) {
switch ( atoi ( data [ 10 ] ) ) {
case 2 :
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . model = " Shearwater Petrel/Perdix " ;
2018-12-29 19:32:55 +00:00
break ;
case 4 :
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . model = " Shearwater Predator " ;
2018-12-29 19:32:55 +00:00
break ;
default :
2024-05-27 15:09:48 +00:00
state - > cur_dive - > dcs [ 0 ] . model = " Shearwater import " ;
2018-12-29 19:32:55 +00:00
break ;
}
}
if ( data [ 11 ] ) {
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_mode_template , dive_id ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & shearwater_mode , state , NULL ) ;
2018-12-29 19:32:55 +00:00
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query shearwater_mode failed. " ) ;
2018-12-29 19:32:55 +00:00
return 1 ;
}
}
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_cylinder_template , dive_id ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & shearwater_cylinders , state , NULL ) ;
2018-12-29 19:32:55 +00:00
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query shearwater_cylinders failed. " ) ;
2018-12-29 19:32:55 +00:00
return 1 ;
}
2020-09-12 18:38:46 +00:00
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_first_gas_template , dive_id ) ;
retval = sqlite3_exec ( handle , get_buffer , & shearwater_changes , state , NULL ) ;
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query shearwater_changes failed. " ) ;
2020-09-12 18:38:46 +00:00
return 1 ;
}
2018-12-29 19:32:55 +00:00
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_changes_template , dive_id ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & shearwater_changes , state , NULL ) ;
2018-12-29 19:32:55 +00:00
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query shearwater_changes failed. " ) ;
2018-12-29 19:32:55 +00:00
return 1 ;
}
2020-09-19 10:25:47 +00:00
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_profile_template_ai , dive_id , dive_id ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & shearwater_ai_profile_sample , state , NULL ) ;
2018-12-29 19:32:55 +00:00
if ( retval ! = SQLITE_OK ) {
2020-09-19 10:25:47 +00:00
snprintf ( get_buffer , sizeof ( get_buffer ) - 1 , get_profile_template , dive_id , dive_id ) ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_buffer , & shearwater_profile_sample , state , NULL ) ;
2018-12-29 19:32:55 +00:00
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query shearwater_profile_sample failed. " ) ;
2018-12-29 19:32:55 +00:00
return 1 ;
}
}
dive_end ( state ) ;
return SQLITE_OK ;
}
2024-05-04 16:45:55 +00:00
int parse_shearwater_buffer ( sqlite3 * handle , const char * url , const char * , int , struct divelog * log )
2017-11-28 19:31:27 +00:00
{
int retval ;
2018-10-17 16:45:22 +00:00
struct parser_state state ;
2022-11-12 07:57:56 +00:00
state . log = log ;
2018-10-17 16:45:22 +00:00
state . sql_handle = handle ;
2017-11-28 19:31:27 +00:00
2018-12-29 20:31:52 +00:00
// So far have not seen any sample rate in Shearwater Desktop
2019-01-03 04:56:48 +00:00
state . sample_rate = 0 ;
2018-12-29 20:31:52 +00:00
2017-11-28 19:31:27 +00:00
char get_dives [ ] = " select l.number,timestamp,location||' / '||site,buddy,notes,imperialUnits,maxDepth,maxTime,startSurfacePressure,computerSerial,computerModel,i.diveId FROM dive_info AS i JOIN dive_logs AS l ON i.diveId=l.diveId " ;
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_dives , & shearwater_dive , & state , NULL ) ;
2017-11-28 19:31:27 +00:00
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query failed '%s'. " , url ) ;
2017-11-28 19:31:27 +00:00
return 1 ;
}
return 0 ;
}
2024-05-04 16:45:55 +00:00
int parse_shearwater_cloud_buffer ( sqlite3 * handle , const char * url , const char * , int , struct divelog * log )
2018-12-29 19:32:55 +00:00
{
int retval ;
struct parser_state state ;
2022-11-12 07:57:56 +00:00
state . log = log ;
2018-12-29 19:32:55 +00:00
state . sql_handle = handle ;
2020-09-19 10:25:47 +00:00
char get_dives [ ] = " select l.number,strftime('%s', DiveDate),location||' / '||site,buddy,notes,imperialUnits,maxDepth,DiveLengthTime,startSurfacePressure,computerSerial,computerModel,d.diveId,l.sampleRateMs / 1000 FROM dive_details AS d JOIN dive_logs AS l ON d.diveId=l.diveId " ;
2018-12-29 19:32:55 +00:00
2019-10-26 21:11:44 +00:00
retval = sqlite3_exec ( handle , get_dives , & shearwater_cloud_dive , & state , NULL ) ;
2018-12-29 19:32:55 +00:00
if ( retval ! = SQLITE_OK ) {
2024-03-24 20:03:08 +00:00
report_info ( " Database query failed '%s'. " , url ) ;
2018-12-29 19:32:55 +00:00
return 1 ;
}
return 0 ;
}