Merge branch 'master' of git://github.com/libdivecomputer/libdivecomputer into Subsurface-NG
Merge upstream libdivecomputer updates from Jef. Misc small updates all over, the biggest thing (code wise) is probably the Ratio firmware update support. * 'master' of git://github.com/libdivecomputer/libdivecomputer: Fix the Oceanic Geo 4.0 memory layout Ignore all empty logbook entries Add a workaround for the hwOS ppO2 firmware bug Use macros to encode the firmware version Use symbolic constants for the sample types Remove the obsolete hwos parameter Limit the tank pressure workaround to hwOS devices Fix the OSTC tank pressure decoding Fix the Scubapro G2 HUD udev rule Add the Mares Genius to the bluetooth filter Add firmware upgrade support for the Ratio computers
This commit is contained in:
commit
5290984316
@ -17,7 +17,7 @@ SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3201", GROUP="plugde
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3211", GROUP="plugdev"
|
||||
|
||||
# Scubapro G2 HUD
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="0x4201", GROUP="plugdev"
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="4201", GROUP="plugdev"
|
||||
|
||||
# Scubapro Aladin Square
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="c251", ATTR{idProduct}=="2006", GROUP="plugdev"
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/hw_ostc.h>
|
||||
#include <libdivecomputer/hw_ostc3.h>
|
||||
#include <libdivecomputer/divesystem_idive.h>
|
||||
|
||||
#include "dctool.h"
|
||||
#include "common.h"
|
||||
@ -93,6 +94,9 @@ fwupdate (dc_context_t *context, dc_descriptor_t *descriptor, dc_transport_t tra
|
||||
case DC_FAMILY_HW_OSTC3:
|
||||
rc = hw_ostc3_device_fwupdate (device, hexfile);
|
||||
break;
|
||||
case DC_FAMILY_DIVESYSTEM_IDIVE:
|
||||
rc = divesystem_idive_device_fwupdate (device, hexfile);
|
||||
break;
|
||||
default:
|
||||
rc = DC_STATUS_UNSUPPORTED;
|
||||
break;
|
||||
|
||||
@ -28,4 +28,5 @@ libdivecomputer_HEADERS = \
|
||||
hw_ostc.h \
|
||||
hw_frog.h \
|
||||
hw_ostc3.h \
|
||||
atomics_cobalt.h
|
||||
atomics_cobalt.h \
|
||||
divesystem_idive.h
|
||||
|
||||
38
include/libdivecomputer/divesystem_idive.h
Normal file
38
include/libdivecomputer/divesystem_idive.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2019 Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef DC_DIVESYSTEM_IDIVE_H
|
||||
#define DC_DIVESYSTEM_IDIVE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "device.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_device_fwupdate (dc_device_t *abstract, const char *filename);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DC_DIVESYSTEM_IDIVE_H */
|
||||
@ -584,10 +584,11 @@ static int dc_filter_mares (dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"Mares bluelink pro",
|
||||
"Mares Genius",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
@ -21,10 +21,12 @@
|
||||
|
||||
#include <string.h> // memcmp, memcpy
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <stdio.h>
|
||||
|
||||
#include "divesystem_idive.h"
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "platform.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
|
||||
@ -39,6 +41,7 @@
|
||||
#define MAXPACKET 0xFF
|
||||
#define START 0x55
|
||||
#define ACK 0x06
|
||||
#define WAIT 0x13
|
||||
#define NAK 0x15
|
||||
|
||||
#define CMD_IDIVE_ID 0x10
|
||||
@ -51,6 +54,12 @@
|
||||
#define CMD_IX3M_HEADER 0x79
|
||||
#define CMD_IX3M_SAMPLE 0x7A
|
||||
#define CMD_IX3M_TIMESYNC 0x13
|
||||
#define CMD_IX3M_BOOTLOADER 0x0A
|
||||
|
||||
#define BOOTLOADER_PROBE 0x78
|
||||
#define BOOTLOADER_UPLOAD_A 0x40
|
||||
#define BOOTLOADER_UPLOAD_B 0x23
|
||||
#define BOOTLOADER_ACK 0x46
|
||||
|
||||
#define ERR_INVALID_CMD 0x10
|
||||
#define ERR_INVALID_LENGTH 0x20
|
||||
@ -80,6 +89,11 @@ typedef struct divesystem_idive_commands_t {
|
||||
unsigned int nsamples;
|
||||
} divesystem_idive_commands_t;
|
||||
|
||||
typedef struct divesystem_idive_signature_t {
|
||||
const char *name;
|
||||
unsigned int delay;
|
||||
} divesystem_idive_signature_t;
|
||||
|
||||
typedef struct divesystem_idive_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
@ -127,6 +141,14 @@ static const divesystem_idive_commands_t ix3m_apos4 = {
|
||||
3,
|
||||
};
|
||||
|
||||
static const divesystem_idive_signature_t signatures[] = {
|
||||
{"dsh01", 50}, // IX3M GPS
|
||||
{"dsh30", 50}, // IX3M Pro
|
||||
{"dsh20", 5}, // iDive Sport
|
||||
{"dsh23", 5}, // iDive Color
|
||||
{"acx", 5}, // WPT
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model)
|
||||
{
|
||||
@ -652,3 +674,262 @@ divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *da
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesystem_idive_firmware_readfile (dc_buffer_t *buffer, dc_context_t *context, const char *filename)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_buffer_t *tmp = NULL;
|
||||
FILE *fp = NULL;
|
||||
|
||||
if (!dc_buffer_clear (buffer)) {
|
||||
ERROR (context, "Invalid arguments.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Allocate a temporary buffer.
|
||||
tmp = dc_buffer_new (0x20000);
|
||||
if (tmp == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Open the file.
|
||||
fp = fopen (filename, "rb");
|
||||
if (fp == NULL) {
|
||||
ERROR (context, "Failed to open the file.");
|
||||
status = DC_STATUS_IO;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Read the entire file into the buffer.
|
||||
size_t n = 0;
|
||||
unsigned char block[4096] = {0};
|
||||
while ((n = fread (block, 1, sizeof (block), fp)) > 0) {
|
||||
if (!dc_buffer_append (tmp, block, n)) {
|
||||
ERROR (context, "Insufficient buffer space available.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_close;
|
||||
}
|
||||
}
|
||||
|
||||
// Resize the output buffer.
|
||||
size_t nbytes = dc_buffer_get_size (tmp);
|
||||
if (!dc_buffer_resize (buffer, nbytes / 2)) {
|
||||
ERROR (context, "Insufficient buffer space available.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
// Convert to binary data.
|
||||
int rc = array_convert_hex2bin (
|
||||
dc_buffer_get_data (tmp), dc_buffer_get_size (tmp),
|
||||
dc_buffer_get_data (buffer), dc_buffer_get_size (buffer));
|
||||
if (rc != 0) {
|
||||
ERROR (context, "Unexpected data format.");
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error_close;
|
||||
}
|
||||
|
||||
error_close:
|
||||
fclose (fp);
|
||||
error_free:
|
||||
dc_buffer_free (tmp);
|
||||
error_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesystem_idive_firmware_send (divesystem_idive_device_t *device, const divesystem_idive_signature_t *signature, const unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
unsigned int nretries = 0;
|
||||
while (1) {
|
||||
// Send the frame.
|
||||
status = dc_iostream_write (device->iostream, data, size, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the frame.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the response until an ACK or NAK byte is received.
|
||||
unsigned int state = 0;
|
||||
while (state == 0) {
|
||||
// Receive the response.
|
||||
unsigned char response = 0;
|
||||
status = dc_iostream_read (device->iostream, &response, 1, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the response.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Process the response.
|
||||
switch (response) {
|
||||
case ACK:
|
||||
case NAK:
|
||||
state = response;
|
||||
break;
|
||||
case WAIT:
|
||||
dc_iostream_sleep (device->iostream, signature->delay);
|
||||
break;
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case 'K':
|
||||
case 'X':
|
||||
break;
|
||||
default:
|
||||
WARNING (abstract->context, "Unexpected response byte received (%02x)", response);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Exit if ACK received.
|
||||
if (state == ACK)
|
||||
break;
|
||||
|
||||
// Abort if the maximum number of retries is reached.
|
||||
if (nretries++ >= MAXRETRIES) {
|
||||
ERROR (abstract->context, "Maximum number of retries reached.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_device_fwupdate (dc_device_t *abstract, const char *filename)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
divesystem_idive_device_t *device = (divesystem_idive_device_t *) abstract;
|
||||
unsigned int errcode = 0;
|
||||
|
||||
// Allocate memory for the firmware data.
|
||||
dc_buffer_t *buffer = dc_buffer_new (0);
|
||||
if (buffer == NULL) {
|
||||
ERROR (abstract->context, "Failed to allocate memory for the firmware data.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Read the firmware file.
|
||||
status = divesystem_idive_firmware_readfile (buffer, abstract->context, filename);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the firmware file.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Cache the data and size.
|
||||
const unsigned char *data = dc_buffer_get_data (buffer);
|
||||
size_t size = dc_buffer_get_size (buffer);
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
progress.maximum = size;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Activate the bootloader.
|
||||
const unsigned char bootloader[] = {CMD_IX3M_BOOTLOADER, 0xC9, 0x4B};
|
||||
status = divesystem_idive_transfer (device, bootloader, sizeof (bootloader), NULL, 0, &errcode);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to activate the bootloader.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Give the device some time to enter the bootloader.
|
||||
dc_iostream_sleep (device->iostream, 2000);
|
||||
|
||||
// Wait for the bootloader.
|
||||
const divesystem_idive_signature_t *signature = NULL;
|
||||
while (signature == NULL) {
|
||||
// Discard garbage data.
|
||||
dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT);
|
||||
|
||||
// Probe for the bootloader.
|
||||
const unsigned char probe[] = {BOOTLOADER_PROBE};
|
||||
status = dc_iostream_write (device->iostream, probe, sizeof (probe), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to activate the bootloader.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Read the signature string.
|
||||
size_t n = 0;
|
||||
unsigned char name[5] = {0};
|
||||
status = dc_iostream_read (device->iostream, name, sizeof (name), &n);
|
||||
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_TIMEOUT) {
|
||||
ERROR (abstract->context, "Failed to read the signature string.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Verify the signature string.
|
||||
for (size_t i = 0; i < C_ARRAY_SIZE (signatures); ++i) {
|
||||
if (n == strlen (signatures[i].name) && memcmp (name, signatures[i].name, n) == 0) {
|
||||
signature = signatures + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send the start upload command.
|
||||
const unsigned char upload[] = {BOOTLOADER_UPLOAD_A, BOOTLOADER_UPLOAD_B};
|
||||
status = dc_iostream_write (device->iostream, upload, sizeof(upload), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the start upload command.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Receive the ack.
|
||||
unsigned char ack[1] = {0};
|
||||
status = dc_iostream_read (device->iostream, ack, sizeof(ack), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the ack byte.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Verify the ack.
|
||||
if (ack[0] != BOOTLOADER_ACK) {
|
||||
ERROR (abstract->context, "Invalid ack byte (%02x).", ack[0]);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Upload the firmware.
|
||||
unsigned int offset = 0;
|
||||
while (offset + 2 <= size) {
|
||||
// Get the number of bytes in the current frame.
|
||||
unsigned int len = array_uint16_be (data + offset) + 2;
|
||||
if (offset + len > size) {
|
||||
ERROR (abstract->context, "Invalid frame size (%u %u " DC_PRINTF_SIZE ")", offset, len, size);
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Send the frame.
|
||||
status = divesystem_idive_firmware_send (device, signature, data + offset, len);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the frame.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current += len;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
offset += len;
|
||||
}
|
||||
|
||||
error_free:
|
||||
dc_buffer_free (buffer);
|
||||
error_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
#include <libdivecomputer/divesystem_idive.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial, unsigned int hwos);
|
||||
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -713,7 +713,6 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
||||
// The device maintains an internal counter which is incremented for every
|
||||
// dive, and the current value at the time of the dive is stored in the
|
||||
// dive header. Thus the most recent dive will have the highest value.
|
||||
unsigned int count = 0;
|
||||
unsigned int latest = 0;
|
||||
unsigned int maximum = 0;
|
||||
for (unsigned int i = 0; i < RB_LOGBOOK_COUNT; ++i) {
|
||||
@ -729,24 +728,21 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
||||
maximum = current;
|
||||
latest = i;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
// Calculate the total and maximum size.
|
||||
unsigned int ndives = 0;
|
||||
unsigned int size = 0;
|
||||
unsigned int maxsize = 0;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
unsigned char dive[RB_LOGBOOK_COUNT] = {0};
|
||||
for (unsigned int i = 0; i < RB_LOGBOOK_COUNT; ++i) {
|
||||
unsigned int idx = (latest + RB_LOGBOOK_COUNT - i) % RB_LOGBOOK_COUNT;
|
||||
unsigned int offset = idx * logbook->size;
|
||||
|
||||
// Uninitialized header entries should no longer be present at this
|
||||
// stage, unless the dives are interleaved with empty entries. But
|
||||
// that's something we don't support at all.
|
||||
// Ignore uninitialized header entries.
|
||||
if (array_isequal (header + offset, logbook->size, 0xFF)) {
|
||||
WARNING (abstract->context, "Unexpected empty header found.");
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate the profile length.
|
||||
@ -770,6 +766,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
||||
if (length > maxsize)
|
||||
maxsize = length;
|
||||
size += length;
|
||||
dive[ndives] = idx;
|
||||
ndives++;
|
||||
}
|
||||
|
||||
@ -793,7 +790,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
||||
|
||||
// Download the dives.
|
||||
for (unsigned int i = 0; i < ndives; ++i) {
|
||||
unsigned int idx = (latest + RB_LOGBOOK_COUNT - i) % RB_LOGBOOK_COUNT;
|
||||
unsigned int idx = dive[i];
|
||||
unsigned int offset = idx * logbook->size;
|
||||
|
||||
// Calculate the profile length.
|
||||
|
||||
@ -49,6 +49,14 @@
|
||||
#define HEADER 1
|
||||
#define PROFILE 2
|
||||
|
||||
#define TEMPERATURE 0
|
||||
#define DECO 1
|
||||
#define GF 2
|
||||
#define PPO2 3
|
||||
#define DECOPLAN 4
|
||||
#define CNS 5
|
||||
#define TANK 6
|
||||
|
||||
#define OSTC_ZHL16_OC 0
|
||||
#define OSTC_GAUGE 1
|
||||
#define OSTC_ZHL16_CC 2
|
||||
@ -75,6 +83,16 @@
|
||||
|
||||
#define UNSUPPORTED 0xFFFFFFFF
|
||||
|
||||
#define OSTC3FW(major,minor) ( \
|
||||
(((major) & 0xFF) << 8) | \
|
||||
((minor) & 0xFF))
|
||||
|
||||
#define OSTC4FW(major,minor,micro,beta) ( \
|
||||
(((major) & 0x1F) << 11) | \
|
||||
(((minor) & 0x1F) >> 6) | \
|
||||
(((micro) & 0x1F) << 1) | \
|
||||
((beta) & 0x01))
|
||||
|
||||
typedef struct hw_ostc_sample_info_t {
|
||||
unsigned int type;
|
||||
unsigned int divisor;
|
||||
@ -370,9 +388,9 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
||||
|
||||
|
||||
dc_status_t
|
||||
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int hwos)
|
||||
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial)
|
||||
{
|
||||
return hw_ostc_parser_create_internal (out, context, serial, hwos, 0);
|
||||
return hw_ostc_parser_create_internal (out, context, serial, 0, 0);
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
@ -757,21 +775,21 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
|
||||
if (info[i].divisor) {
|
||||
switch (info[i].type) {
|
||||
case 0: // Temperature
|
||||
case 1: // Deco / NDL
|
||||
case 6: // Tank pressure
|
||||
case TEMPERATURE:
|
||||
case DECO:
|
||||
case TANK:
|
||||
if (info[i].size != 2) {
|
||||
ERROR(abstract->context, "Unexpected sample size.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case 3: // ppO2
|
||||
case PPO2:
|
||||
if (info[i].size != 3 && info[i].size != 9) {
|
||||
ERROR(abstract->context, "Unexpected sample size.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case 5: // CNS
|
||||
case CNS:
|
||||
if (info[i].size != 1 && info[i].size != 2) {
|
||||
ERROR(abstract->context, "Unexpected sample size.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
@ -978,6 +996,17 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
for (unsigned int i = 0; i < nconfig; ++i) {
|
||||
if (info[i].divisor && (nsamples % info[i].divisor) == 0) {
|
||||
if (length < info[i].size) {
|
||||
// Due to a bug in the hwOS Tech firmware v3.03 to v3.07, and
|
||||
// the hwOS Sport firmware v10.57 to v10.63, the ppO2 divisor
|
||||
// is sometimes not correctly reset to zero when no ppO2
|
||||
// samples are being recorded.
|
||||
if (info[i].type == PPO2 && parser->hwos && parser->model != OSTC4 &&
|
||||
((firmware >= OSTC3FW(3,3) && firmware <= OSTC3FW(3,7)) ||
|
||||
(firmware >= OSTC3FW(10,57) && firmware <= OSTC3FW(10,63)))) {
|
||||
WARNING (abstract->context, "Reset invalid ppO2 divisor to zero.");
|
||||
info[i].divisor = 0;
|
||||
continue;
|
||||
}
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
@ -986,15 +1015,15 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
unsigned int count = 0;
|
||||
unsigned int value = 0;
|
||||
switch (info[i].type) {
|
||||
case 0: // Temperature (0.1 °C).
|
||||
case TEMPERATURE:
|
||||
value = array_uint16_le (data + offset);
|
||||
sample.temperature = value / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
break;
|
||||
case 1: // Deco / NDL
|
||||
case DECO:
|
||||
// Due to a firmware bug, the deco/ndl info is incorrect for
|
||||
// all OSTC4 dives with a firmware older than version 1.0.8.
|
||||
if (parser->model == OSTC4 && firmware < 0x0810)
|
||||
if (parser->model == OSTC4 && firmware < OSTC4FW(1,0,8,0))
|
||||
break;
|
||||
if (data[offset]) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
@ -1006,7 +1035,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
sample.deco.time = data[offset + 1] * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
break;
|
||||
case 3: // ppO2 (0.01 bar).
|
||||
case PPO2:
|
||||
for (unsigned int j = 0; j < 3; ++j) {
|
||||
if (info[i].size == 3) {
|
||||
ppo2[j] = data[offset + j];
|
||||
@ -1023,18 +1052,24 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5: // CNS
|
||||
case CNS:
|
||||
if (info[i].size == 2)
|
||||
sample.cns = array_uint16_le (data + offset) / 100.0;
|
||||
else
|
||||
sample.cns = data[offset] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
break;
|
||||
case 6: // Tank pressure
|
||||
case TANK:
|
||||
value = array_uint16_le (data + offset);
|
||||
if (value != 0) {
|
||||
sample.pressure.tank = tank;
|
||||
sample.pressure.value = value / 10.0;
|
||||
sample.pressure.value = value;
|
||||
// The hwOS Sport firmware used a resolution of
|
||||
// 0.1 bar between versions 10.40 and 10.50.
|
||||
if (parser->hwos && parser->model != OSTC4 &&
|
||||
(firmware >= OSTC3FW(10,40) && firmware <= OSTC3FW(10,50))) {
|
||||
sample.pressure.value /= 10.0;
|
||||
}
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -144,3 +144,4 @@ hw_ostc3_device_config_reset
|
||||
hw_ostc3_device_fwupdate
|
||||
atomics_cobalt_device_version
|
||||
atomics_cobalt_device_set_simulation
|
||||
divesystem_idive_device_fwupdate
|
||||
|
||||
@ -124,7 +124,8 @@ static const oceanic_common_version_t oceanic_atom2b_version[] = {
|
||||
{"AQUAI300 \0\0 512K"},
|
||||
{"HOLLDG03 \0\0 512K"},
|
||||
{"AQUAI100 \0\0 512K"},
|
||||
{"AQUA300C \0\0 \0\0\0\0"},
|
||||
{"AQUA300C \0\0 512K"},
|
||||
{"OCEGEO40 \0\0 512K"},
|
||||
};
|
||||
|
||||
static const oceanic_common_version_t oceanic_atom2c_version[] = {
|
||||
@ -139,7 +140,6 @@ static const oceanic_common_version_t oceanic_default_version[] = {
|
||||
{"ELITET31 \0\0 512K"},
|
||||
{"DATAMASK \0\0 512K"},
|
||||
{"COMPMASK \0\0 512K"},
|
||||
{"OCEGEO40 \0\0 512K"},
|
||||
};
|
||||
|
||||
static const oceanic_common_version_t sherwood_wisdom_version[] = {
|
||||
|
||||
@ -134,7 +134,7 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa
|
||||
rc = mares_iconhd_parser_create (&parser, context, model);
|
||||
break;
|
||||
case DC_FAMILY_HW_OSTC:
|
||||
rc = hw_ostc_parser_create (&parser, context, serial, 0);
|
||||
rc = hw_ostc_parser_create (&parser, context, serial);
|
||||
break;
|
||||
case DC_FAMILY_HW_FROG:
|
||||
case DC_FAMILY_HW_OSTC3:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user