diff --git a/CHANGELOG.md b/CHANGELOG.md
index 272871122..17deea5ff 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,4 @@
+import: add option to synchronise dive computer time when downloading dives
core: fix bug when save sea water salinity given by DC
desktop: add option to force firmware update on OSTC4
desktop: add column for dive notes to the dive list table
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 2f12c5d50..deef9350a 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -374,6 +374,13 @@ of the dive computer (at least for those not charging while connected via USB).
- Do *not* check the checkboxes labelled _Save libdivecomputer logfile_ and
_Save libdivecomputer dumpfile_. These are only used as diagnostic tools
when there are problems with downloads(see below).
+
+ - With some dive computers it is possible to adjust the clock on the dive
+ computer based on the PC clock. This can be very helpful when dealing with
+ daylight savings time changes, or when travelling between different time
+ zones. In order to synchronise the dive computer clock with the PC clock
+ every time dives are imported, check _Sync dive computer time_.
+
- Then select the _Download_ button.
With communication established, you can see how the data are
retrieved from the dive computer.
@@ -398,6 +405,7 @@ of the dive computer (at least for those not charging while connected via USB).
(Puck Pro)". Refer to the text in the box below.
+
****
*PROBLEMS WITH DATA DOWNLOAD FROM A DIVE COMPUTER?*
[icon="images/icons/important.png"]
diff --git a/cli-downloader.cpp b/cli-downloader.cpp
index 3eef0b2d5..3e38a2e9c 100644
--- a/cli-downloader.cpp
+++ b/cli-downloader.cpp
@@ -29,6 +29,7 @@ void cliDownloader(const char *vendor, const char *product, const char *device)
data->setForceDownload(false);
data->setSaveLog(true);
data->setSaveDump(false);
+ data->setSyncTime(false);
diveImportedModel.startDownload();
diveImportedModel.waitForDownload();
diff --git a/core/downloadfromdcthread.cpp b/core/downloadfromdcthread.cpp
index 3128a36c5..7b5707372 100644
--- a/core/downloadfromdcthread.cpp
+++ b/core/downloadfromdcthread.cpp
@@ -227,6 +227,7 @@ DCDeviceData::DCDeviceData()
#if defined(Q_OS_ANDROID)
data.androidUsbDeviceDescriptor = nullptr;
#endif
+ data.sync_time = false;
}
DCDeviceData *DCDeviceData::instance()
@@ -291,6 +292,11 @@ int DCDeviceData::diveId() const
return data.diveid;
}
+bool DCDeviceData::syncTime() const
+{
+ return data.sync_time;
+}
+
void DCDeviceData::setVendor(const QString &vendor)
{
data.vendor = copy_qstring(vendor);
@@ -350,6 +356,11 @@ void DCDeviceData::setDiveId(int diveId)
data.diveid = diveId;
}
+void DCDeviceData::setSyncTime(bool syncTime)
+{
+ data.sync_time = syncTime;
+}
+
void DCDeviceData::setSaveDump(bool save)
{
data.libdc_dump = save;
diff --git a/core/downloadfromdcthread.h b/core/downloadfromdcthread.h
index 871a79556..324c39cf5 100644
--- a/core/downloadfromdcthread.h
+++ b/core/downloadfromdcthread.h
@@ -32,6 +32,7 @@ public:
bool forceDownload() const;
bool saveLog() const;
int diveId() const;
+ bool syncTime() const;
/* this needs to be a pointer to make the C-API happy */
device_data_t *internalData();
@@ -54,6 +55,7 @@ public:
#if defined(Q_OS_ANDROID)
void setUsbDevice(const android_usb_serial_device_descriptor &usbDescriptor);
#endif
+ void setSyncTime(bool syncTime);
private:
#if defined(Q_OS_ANDROID)
struct android_usb_serial_device_descriptor androidUsbDescriptor;
diff --git a/core/libdivecomputer.c b/core/libdivecomputer.c
index f1fd8f526..c5031cb52 100644
--- a/core/libdivecomputer.c
+++ b/core/libdivecomputer.c
@@ -1413,6 +1413,14 @@ dc_status_t divecomputer_device_open(device_data_t *data)
return DC_STATUS_UNSUPPORTED;
}
+static dc_status_t sync_divecomputer_time(dc_device_t *device)
+{
+ dc_datetime_t now;
+ dc_datetime_localtime(&now, dc_datetime_now());
+
+ return dc_device_timesync(device, &now);
+}
+
const char *do_libdivecomputer_import(device_data_t *data)
{
dc_status_t rc;
@@ -1463,6 +1471,28 @@ const char *do_libdivecomputer_import(device_data_t *data)
dev_info(data, "Starting import ...");
err = do_device_import(data);
/* TODO: Show the logfile to the user on error. */
+ dev_info(data, "Import complete");
+
+ if (!err && data->sync_time) {
+ dev_info(data, "Syncing dive computer time ...");
+ rc = sync_divecomputer_time(data->device);
+
+ switch (rc) {
+ case DC_STATUS_SUCCESS:
+ dev_info(data, "Time sync complete");
+
+ break;
+ case DC_STATUS_UNSUPPORTED:
+ dev_info(data, "Time sync not supported by dive computer");
+
+ break;
+ default:
+ dev_info(data, "Time sync failed");
+
+ break;
+ }
+ }
+
dc_device_close(data->device);
data->device = NULL;
if (!data->log->dives->nr)
diff --git a/core/libdivecomputer.h b/core/libdivecomputer.h
index c93daaedd..30f0f9c76 100644
--- a/core/libdivecomputer.h
+++ b/core/libdivecomputer.h
@@ -46,6 +46,7 @@ typedef struct {
bool libdc_log;
bool libdc_dump;
bool bluetooth_mode;
+ bool sync_time;
FILE *libdc_logfile;
struct divelog *log;
void *androidUsbDeviceDescriptor;
diff --git a/core/pref.c b/core/pref.c
index 85a5ec243..42188ecb4 100644
--- a/core/pref.c
+++ b/core/pref.c
@@ -93,6 +93,7 @@ struct preferences default_prefs = {
.extract_video_thumbnails = true,
.extract_video_thumbnails_position = 20, // The first fifth seems like a reasonable place
.three_m_based_grid = false,
+ .sync_dc_time = false,
};
/* copy a preferences block, including making copies of all included strings */
diff --git a/core/pref.h b/core/pref.h
index e0c10cda4..1738e20b8 100644
--- a/core/pref.h
+++ b/core/pref.h
@@ -96,6 +96,7 @@ struct preferences {
dive_computer_prefs_t dive_computer2;
dive_computer_prefs_t dive_computer3;
dive_computer_prefs_t dive_computer4;
+ bool sync_dc_time;
// ********** Display *************
bool display_invalid_dives;
diff --git a/core/settings/qPrefDiveComputer.cpp b/core/settings/qPrefDiveComputer.cpp
index 0ee74254a..57c060808 100644
--- a/core/settings/qPrefDiveComputer.cpp
+++ b/core/settings/qPrefDiveComputer.cpp
@@ -29,6 +29,8 @@ void qPrefDiveComputer::loadSync(bool doSync)
DISK_DC(2)
DISK_DC(3)
DISK_DC(4)
+
+ disk_sync_dc_time(doSync);
}
// these are the 'active' settings
@@ -54,3 +56,5 @@ HANDLE_PREFERENCE_TXT_EXT_ALT(DiveComputer, "dive_computer_vendor1", vendor, div
HANDLE_PREFERENCE_TXT_EXT_ALT(DiveComputer, "dive_computer_vendor2", vendor, dive_computer, 2)
HANDLE_PREFERENCE_TXT_EXT_ALT(DiveComputer, "dive_computer_vendor3", vendor, dive_computer, 3)
HANDLE_PREFERENCE_TXT_EXT_ALT(DiveComputer, "dive_computer_vendor4", vendor, dive_computer, 4)
+
+HANDLE_PREFERENCE_BOOL(DiveComputer, "sync_dive_computer_time", sync_dc_time);
diff --git a/core/settings/qPrefDiveComputer.h b/core/settings/qPrefDiveComputer.h
index e3cb4df11..644a547e9 100644
--- a/core/settings/qPrefDiveComputer.h
+++ b/core/settings/qPrefDiveComputer.h
@@ -35,6 +35,8 @@ class qPrefDiveComputer : public QObject {
Q_PROPERTY(QString vendor3 READ vendor3 WRITE set_vendor3 NOTIFY vendor3Changed)
Q_PROPERTY(QString vendor4 READ vendor4 WRITE set_vendor4 NOTIFY vendor4Changed)
+ Q_PROPERTY(bool sync_dc_time READ sync_dc_time WRITE set_sync_dc_time NOTIFY sync_dc_timeChanged)
+
public:
static qPrefDiveComputer *instance();
@@ -49,6 +51,8 @@ public:
IMPLEMENT5GETTERS(product)
IMPLEMENT5GETTERS(vendor)
+ static bool sync_dc_time() { return prefs.sync_dc_time; }
+
public slots:
static void set_device(const QString &device);
static void set_device1(const QString &device);
@@ -74,6 +78,8 @@ public slots:
static void set_vendor3(const QString &vendor);
static void set_vendor4(const QString &vendor);
+ static void set_sync_dc_time(bool value);
+
signals:
void deviceChanged(const QString &device);
void device1Changed(const QString &device);
@@ -99,6 +105,8 @@ signals:
void vendor3Changed(const QString &vendor);
void vendor4Changed(const QString &vendor);
+ void sync_dc_timeChanged(bool value);
+
private:
qPrefDiveComputer() {}
@@ -127,6 +135,8 @@ private:
static void disk_vendor2(bool doSync);
static void disk_vendor3(bool doSync);
static void disk_vendor4(bool doSync);
+
+ static void disk_sync_dc_time(bool doSync);
};
#endif
diff --git a/core/uemis-downloader.c b/core/uemis-downloader.c
index df9f9e3c1..95c635e80 100644
--- a/core/uemis-downloader.c
+++ b/core/uemis-downloader.c
@@ -1518,6 +1518,9 @@ const char *do_uemis_import(device_data_t *data)
if (uemis_mem_status != UEMIS_MEM_OK)
result = translate("gettextFromC", ERR_FS_ALMOST_FULL);
+ if (data->sync_time)
+ uemis_info(translate("gettextFromC", "Time sync not supported by dive computer"));
+
bail:
(void)uemis_get_answer(mountpath, "terminateSync", 0, 3, &result);
if (!strcmp(param_buff[0], "error")) {
diff --git a/desktop-widgets/downloadfromdivecomputer.cpp b/desktop-widgets/downloadfromdivecomputer.cpp
index 7636a5661..b2d2824d6 100644
--- a/desktop-widgets/downloadfromdivecomputer.cpp
+++ b/desktop-widgets/downloadfromdivecomputer.cpp
@@ -60,6 +60,7 @@ DownloadFromDCWidget::DownloadFromDCWidget(QWidget *parent) : QDialog(parent, QF
ui.vendor->setModel(&vendorModel);
ui.search->setEnabled(is_vendor_searchable(ui.vendor->currentText()));
ui.product->setModel(&productModel);
+ ui.syncDiveComputerTime->setChecked(prefs.sync_dc_time);
progress_bar_text = "";
@@ -72,6 +73,7 @@ DownloadFromDCWidget::DownloadFromDCWidget(QWidget *parent) : QDialog(parent, QF
connect(ui.logToFile, SIGNAL(stateChanged(int)), this, SLOT(checkLogFile(int)));
connect(ui.selectAllButton, SIGNAL(clicked()), diveImportedModel, SLOT(selectAll()));
connect(ui.unselectAllButton, SIGNAL(clicked()), diveImportedModel, SLOT(selectNone()));
+ connect(ui.syncDiveComputerTime, &QAbstractButton::toggled, qPrefDiveComputer::instance(), &qPrefDiveComputer::set_sync_dc_time);
connect(timer, SIGNAL(timeout()), this, SLOT(updateProgressBar()));
connect(close, SIGNAL(activated()), this, SLOT(close()));
connect(quit, SIGNAL(activated()), parent, SLOT(close()));
@@ -419,6 +421,7 @@ void DownloadFromDCWidget::on_downloadCancelRetryButton_clicked()
data->setForceDownload(ui.forceDownload->isChecked());
data->setSaveLog(ui.logToFile->isChecked());
data->setSaveDump(ui.dumpToFile->isChecked());
+ data->setSyncTime(ui.syncDiveComputerTime->isChecked());
qPrefDiveComputer::set_vendor(data->vendor());
qPrefDiveComputer::set_product(data->product());
@@ -582,6 +585,7 @@ void DownloadFromDCWidget::markChildrenAsDisabled()
ui.unselectAllButton->setEnabled(false);
ui.bluetoothMode->setEnabled(false);
ui.chooseBluetoothDevice->setEnabled(false);
+ ui.syncDiveComputerTime->setEnabled(false);
}
void DownloadFromDCWidget::markChildrenAsEnabled()
@@ -605,6 +609,7 @@ void DownloadFromDCWidget::markChildrenAsEnabled()
ui.bluetoothMode->setEnabled(true);
ui.chooseBluetoothDevice->setEnabled(true);
#endif
+ ui.syncDiveComputerTime->setEnabled(true);
}
#if defined(BT_SUPPORT)
diff --git a/desktop-widgets/downloadfromdivecomputer.h b/desktop-widgets/downloadfromdivecomputer.h
index 68763701c..24c956890 100644
--- a/desktop-widgets/downloadfromdivecomputer.h
+++ b/desktop-widgets/downloadfromdivecomputer.h
@@ -85,6 +85,7 @@ private:
BtDeviceSelectionDialog *btDeviceSelectionDialog;
BTDiscovery *btd;
#endif
+ void setSyncDiveComputerTime(bool value);
public:
bool preferDownloaded();
diff --git a/desktop-widgets/downloadfromdivecomputer.ui b/desktop-widgets/downloadfromdivecomputer.ui
index fee199399..e429009f8 100644
--- a/desktop-widgets/downloadfromdivecomputer.ui
+++ b/desktop-widgets/downloadfromdivecomputer.ui
@@ -185,6 +185,16 @@
+ -
+
+
+ Sync dive computer time
+
+
+ Adjust the time on the dive computer to match the time on the PC (if supported by the dive computer model).
+
+
+
-
diff --git a/mobile-widgets/qml/DownloadFromDiveComputer.qml b/mobile-widgets/qml/DownloadFromDiveComputer.qml
index 3346ad5c0..163241a20 100644
--- a/mobile-widgets/qml/DownloadFromDiveComputer.qml
+++ b/mobile-widgets/qml/DownloadFromDiveComputer.qml
@@ -397,7 +397,7 @@ Kirigami.Page {
}
RowLayout {
- id: downloadOptions
+ id: forceDownloadOption
Layout.fillWidth: true
Layout.topMargin: 0
spacing: Kirigami.Units.smallSpacing
@@ -421,6 +421,31 @@ Kirigami.Page {
}
}
+ RowLayout {
+ id: syncTimeOption
+ Layout.fillWidth: true
+ Layout.topMargin: 0
+ spacing: Kirigami.Units.smallSpacing
+ TemplateCheckBox {
+ id: syncTimeWithDiveComputer
+ checked: Backend.sync_dc_time
+ enabled: syncTimeLabel.visible
+ visible: enabled
+ height: syncTimeLabel.height - Kirigami.Units.smallSpacing;
+ width: height
+ onClicked: {
+ Backend.sync_dc_time = checked
+ }
+ }
+ TemplateLabel {
+ id: syncTimeLabel
+ text: qsTr("Sync dive computer time")
+ visible: comboVendor.currentIndex != -1 && comboProduct.currentIndex != -1 &&
+ comboConnection.currentIndex != -1
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ }
+ }
+
ListView {
id: dlList
Layout.topMargin: Kirigami.Units.smallSpacing * 4
diff --git a/mobile-widgets/qmlinterface.cpp b/mobile-widgets/qmlinterface.cpp
index e70c73cb9..52ac9f194 100644
--- a/mobile-widgets/qmlinterface.cpp
+++ b/mobile-widgets/qmlinterface.cpp
@@ -79,6 +79,9 @@ QMLInterface::QMLInterface()
this, &QMLInterface::verbatim_planChanged);
connect(qPrefDivePlanner::instance(), &qPrefDivePlanner::display_variationsChanged,
this, &QMLInterface::display_variationsChanged);
+
+ connect(qPrefDiveComputer::instance(), &qPrefDiveComputer::sync_dc_timeChanged,
+ this, &QMLInterface::sync_dc_timeChanged);
}
void QMLInterface::setup(QQmlContext *ct)
diff --git a/mobile-widgets/qmlinterface.h b/mobile-widgets/qmlinterface.h
index efa34cdc0..76f182f15 100644
--- a/mobile-widgets/qmlinterface.h
+++ b/mobile-widgets/qmlinterface.h
@@ -2,10 +2,12 @@
#ifndef QMLINTERFACE_H
#define QMLINTERFACE_H
#include "core/qthelper.h"
+#include "core/downloadfromdcthread.h"
#include "core/settings/qPrefCloudStorage.h"
#include "core/settings/qPrefUnit.h"
#include "core/settings/qPrefDivePlanner.h"
#include "core/settings/qPrefTechnicalDetails.h"
+#include "core/settings/qPrefDiveComputer.h"
#include "qt-models/diveplannermodel.h"
#include "backend-shared/plannershared.h"
@@ -78,6 +80,8 @@ class QMLInterface : public QObject {
Q_PROPERTY(bool verbatim_plan READ verbatim_plan WRITE set_verbatim_plan NOTIFY verbatim_planChanged);
Q_PROPERTY(bool display_variations READ display_variations WRITE set_display_variations NOTIFY display_variationsChanged);
+ Q_PROPERTY(bool sync_dc_time READ sync_dc_time WRITE set_sync_dc_time NOTIFY sync_dc_timeChanged);
+
public:
// function to do the needed setup
static void setup(QQmlContext *ct);
@@ -212,6 +216,8 @@ public:
bool verbatim_plan() { return prefs.verbatim_plan; }
bool display_variations() { return prefs.display_variations; }
+ bool sync_dc_time() { return prefs.sync_dc_time; }
+
public slots:
void set_cloud_verification_status(CLOUD_STATUS value) { qPrefCloudStorage::set_cloud_verification_status(value); }
void set_duration_units(DURATION value) { qPrefUnits::set_duration_units((units::DURATION)value); }
@@ -258,6 +264,10 @@ public slots:
void set_display_transitions(bool value) { DivePlannerPointsModel::instance()->setDisplayTransitions(value); }
void set_verbatim_plan(bool value) { DivePlannerPointsModel::instance()->setVerbatim(value); }
void set_display_variations(bool value) { DivePlannerPointsModel::instance()->setDisplayVariations(value); }
+ void set_sync_dc_time(bool value) {
+ qPrefDiveComputer::set_sync_dc_time(value);
+ DCDeviceData::instance()->setSyncTime(value);
+ }
QString firstDiveDate() { return get_first_dive_date_string(); }
QString lastDiveDate() { return get_last_dive_date_string(); }
@@ -307,6 +317,8 @@ signals:
void display_transitionsChanged(bool value);
void verbatim_planChanged(bool value);
void display_variationsChanged(bool value);
+
+ void sync_dc_timeChanged(bool value);
private:
QMLInterface();
};