Merge git://git.libdivecomputer.org/libdivecomputer into Subsurface-branch
Merge with upstream libdivecomputer: - workarounds for Windows libusb and hidapi issues - misc random cleanups/noise - rename DiveSystem to Ratio - make Cochran with better with FTDI - new support for: Suunto D4f, Ratio idive tank pressure, and Sherwood Insight temperature and Oceanic ndl/deco sample. * git://git.libdivecomputer.org/libdivecomputer: Workaround for a Windows libusb issue Use a fixed size packet for sending Replace the size macro with the sizeof operator Use the correct printf format for the size_t type Move platform specific macros to a common header file Use the correct data type for the return value Rename the DiveSystem vendor to Ratio Fix the Sherwood Insight temperature Implement the ndl/deco sample Change communication parameter to work better with FTDI Retry read operations on failure Add support for the Suunto D4f Implement the tank pressure
This commit is contained in:
commit
07f5777c71
@ -692,6 +692,10 @@
|
||||
RelativePath="..\include\libdivecomputer\parser.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\platform.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\rbstream.h"
|
||||
>
|
||||
|
||||
@ -63,6 +63,7 @@ libdivecomputer_la_SOURCES = \
|
||||
diverite_nitekq.h diverite_nitekq.c diverite_nitekq_parser.c \
|
||||
citizen_aqualand.h citizen_aqualand.c citizen_aqualand_parser.c \
|
||||
divesystem_idive.h divesystem_idive.c divesystem_idive_parser.c \
|
||||
platform.h \
|
||||
ringbuffer.h ringbuffer.c \
|
||||
rbstream.h rbstream.c \
|
||||
checksum.h checksum.c \
|
||||
|
||||
@ -199,8 +199,8 @@ static const cochran_device_layout_t cochran_emc14_device_layout = {
|
||||
COCHRAN_MODEL_EMC_14, // model
|
||||
32, // address_bits
|
||||
ENDIAN_LE, // endian
|
||||
806400, // baudrate
|
||||
65536, // rbstream_size
|
||||
850000, // baudrate
|
||||
32768, // rbstream_size
|
||||
0x0D2, // cf_dive_count
|
||||
0x13E, // cf_last_log
|
||||
0x142, // cf_last_interdive
|
||||
@ -224,8 +224,8 @@ static const cochran_device_layout_t cochran_emc16_device_layout = {
|
||||
COCHRAN_MODEL_EMC_16, // model
|
||||
32, // address_bits
|
||||
ENDIAN_LE, // endian
|
||||
806400, // baudrate
|
||||
65536, // rbstream_size
|
||||
850000, // baudrate
|
||||
32768, // rbstream_size
|
||||
0x0D2, // cf_dive_count
|
||||
0x13E, // cf_last_log
|
||||
0x142, // cf_last_interdive
|
||||
@ -249,8 +249,8 @@ static const cochran_device_layout_t cochran_emc20_device_layout = {
|
||||
COCHRAN_MODEL_EMC_20, // model
|
||||
32, // address_bits
|
||||
ENDIAN_LE, // endian
|
||||
806400, // baudrate
|
||||
65536, // rbstream_size
|
||||
850000, // baudrate
|
||||
32768, // rbstream_size
|
||||
0x0D2, // cf_dive_count
|
||||
0x13E, // cf_last_log
|
||||
0x142, // cf_last_interdive
|
||||
@ -372,7 +372,7 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_
|
||||
// Give the DC time to process the command.
|
||||
dc_serial_sleep(device->port, 45);
|
||||
|
||||
// Rates are odd, like 806400 for the EMC, 115200 for commander
|
||||
// Rates are odd, like 850400 for the EMC, 115200 for commander
|
||||
status = dc_serial_configure(device->port, device->layout->baudrate, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to set the high baud rate.");
|
||||
@ -523,7 +523,7 @@ cochran_commander_read (cochran_commander_device_t *device, dc_event_progress_t
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
dc_serial_sleep(device->port, 800);
|
||||
dc_serial_sleep(device->port, 550);
|
||||
|
||||
// set back to 9600 baud
|
||||
rc = cochran_commander_serial_setup(device);
|
||||
@ -539,6 +539,37 @@ cochran_commander_read (cochran_commander_device_t *device, dc_event_progress_t
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cochran_commander_read_retry (cochran_commander_device_t *device, dc_event_progress_t *progress, unsigned int address, unsigned char data[], unsigned int size)
|
||||
{
|
||||
// Save the state of the progress events.
|
||||
unsigned int saved = 0;
|
||||
if (progress) {
|
||||
saved = progress->current;
|
||||
}
|
||||
|
||||
unsigned int nretries = 0;
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
while ((rc = cochran_commander_read (device, progress, address, data, size)) != DC_STATUS_SUCCESS) {
|
||||
// Automatically discard a corrupted packet,
|
||||
// and request a new one.
|
||||
if (rc != DC_STATUS_PROTOCOL && rc != DC_STATUS_TIMEOUT)
|
||||
return rc;
|
||||
|
||||
// Abort if the maximum number of retries is reached.
|
||||
if (nretries++ >= MAXRETRIES)
|
||||
return rc;
|
||||
|
||||
// Restore the state of the progress events.
|
||||
if (progress) {
|
||||
progress->current = saved;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For corrupt dives the end-of-samples pointer is 0xFFFFFFFF
|
||||
* search for a reasonable size, e.g. using next dive start sample
|
||||
@ -798,7 +829,7 @@ cochran_commander_device_read (dc_device_t *abstract, unsigned int address, unsi
|
||||
{
|
||||
cochran_commander_device_t *device = (cochran_commander_device_t *) abstract;
|
||||
|
||||
return cochran_commander_read(device, NULL, address, data, size);
|
||||
return cochran_commander_read_retry(device, NULL, address, data, size);
|
||||
}
|
||||
|
||||
|
||||
@ -842,7 +873,7 @@ cochran_commander_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
return rc;
|
||||
|
||||
// Read the sample data, logbook and sample data are contiguous
|
||||
rc = cochran_commander_read (device, &progress, device->layout->rb_logbook_begin, dc_buffer_get_data(buffer), size);
|
||||
rc = cochran_commander_read_retry (device, &progress, device->layout->rb_logbook_begin, dc_buffer_get_data(buffer), size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the sample data.");
|
||||
return rc;
|
||||
@ -919,7 +950,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
|
||||
}
|
||||
|
||||
// Request log book
|
||||
rc = cochran_commander_read(device, &progress, layout->rb_logbook_begin, data.logbook, data.logbook_size);
|
||||
rc = cochran_commander_read_retry(device, &progress, layout->rb_logbook_begin, data.logbook, data.logbook_size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
status = rc;
|
||||
goto error;
|
||||
|
||||
@ -96,6 +96,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Suunto", "DX", DC_FAMILY_SUUNTO_D9, 0x1C}, // FTDI
|
||||
{"Suunto", "Vyper Novo", DC_FAMILY_SUUNTO_D9, 0x1D}, // FTDI
|
||||
{"Suunto", "Zoop Novo", DC_FAMILY_SUUNTO_D9, 0x1E}, // FTDI
|
||||
{"Suunto", "D4f", DC_FAMILY_SUUNTO_D9, 0x20}, // FTDI
|
||||
/* Suunto EON Steel */
|
||||
#ifdef USBHID
|
||||
{"Suunto", "EON Steel", DC_FAMILY_SUUNTO_EONSTEEL, 0}, // BLE
|
||||
@ -294,7 +295,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0},
|
||||
/* Citizen Hyper Aqualand */
|
||||
{"Citizen", "Hyper Aqualand", DC_FAMILY_CITIZEN_AQUALAND, 0},
|
||||
/* DiveSystem iDive */
|
||||
/* DiveSystem/Ratio iDive */
|
||||
{"DiveSystem", "Orca", DC_FAMILY_DIVESYSTEM_IDIVE, 0x02},
|
||||
{"DiveSystem", "iDive Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x03},
|
||||
{"DiveSystem", "iDive DAN", DC_FAMILY_DIVESYSTEM_IDIVE, 0x04},
|
||||
@ -305,17 +306,17 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"DiveSystem", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x09},
|
||||
{"DiveSystem", "iDive X3M", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0A},
|
||||
{"DiveSystem", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0B},
|
||||
{"DiveSystem", "iX3M Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22},
|
||||
{"DiveSystem", "iX3M Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23},
|
||||
{"DiveSystem", "iX3M Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24},
|
||||
{"DiveSystem", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25},
|
||||
{"DiveSystem", "iX3M Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x32},
|
||||
{"DiveSystem", "iX3M Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x34},
|
||||
{"DiveSystem", "iX3M Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x35},
|
||||
{"DiveSystem", "iDive2 Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x40},
|
||||
{"DiveSystem", "iDive2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x42},
|
||||
{"DiveSystem", "iDive2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x44},
|
||||
{"DiveSystem", "iDive2 Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x45},
|
||||
{"Ratio", "iX3M Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22},
|
||||
{"Ratio", "iX3M Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23},
|
||||
{"Ratio", "iX3M Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24},
|
||||
{"Ratio", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25},
|
||||
{"Ratio", "iX3M Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x32},
|
||||
{"Ratio", "iX3M Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x34},
|
||||
{"Ratio", "iX3M Pro Tech+",DC_FAMILY_DIVESYSTEM_IDIVE, 0x35},
|
||||
{"Ratio", "iDive Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x40},
|
||||
{"Ratio", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x42},
|
||||
{"Ratio", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x44},
|
||||
{"Ratio", "iDive Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x45},
|
||||
/* Cochran Commander */
|
||||
{"Cochran", "Commander TM", DC_FAMILY_COCHRAN_COMMANDER, 0}, // FTDI
|
||||
{"Cochran", "Commander I", DC_FAMILY_COCHRAN_COMMANDER, 1}, // FTDI
|
||||
|
||||
@ -64,6 +64,8 @@ struct divesystem_idive_parser_t {
|
||||
unsigned int ngasmixes;
|
||||
unsigned int oxygen[NGASMIXES];
|
||||
unsigned int helium[NGASMIXES];
|
||||
unsigned int beginpressure;
|
||||
unsigned int endpressure;
|
||||
};
|
||||
|
||||
static dc_status_t divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
@ -113,6 +115,8 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
parser->oxygen[i] = 0;
|
||||
parser->helium[i] = 0;
|
||||
}
|
||||
parser->beginpressure = 0;
|
||||
parser->endpressure = 0;
|
||||
|
||||
*out = (dc_parser_t*) parser;
|
||||
|
||||
@ -135,6 +139,8 @@ divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *da
|
||||
parser->oxygen[i] = 0;
|
||||
parser->helium[i] = 0;
|
||||
}
|
||||
parser->beginpressure = 0;
|
||||
parser->endpressure = 0;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
@ -173,6 +179,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
}
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_tank_t *tank = (dc_tank_t *) value;
|
||||
dc_salinity_t *water = (dc_salinity_t *) value;
|
||||
|
||||
if (value) {
|
||||
@ -191,6 +198,19 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
gasmix->oxygen = parser->oxygen[flags] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
break;
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
if (parser->beginpressure == 0 && parser->endpressure == 0)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((unsigned int *) value) = 1;
|
||||
break;
|
||||
case DC_FIELD_TANK:
|
||||
tank->type = DC_TANKVOLUME_NONE;
|
||||
tank->volume = 0.0;
|
||||
tank->workpressure = 0.0;
|
||||
tank->beginpressure = parser->beginpressure;
|
||||
tank->endpressure = parser->endpressure;
|
||||
tank->gasmix = DC_GASMIX_UNKNOWN;
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
if (parser->model >= IX3M_EASY) {
|
||||
*((double *) value) = array_uint16_le (data + 11) / 10000.0;
|
||||
@ -249,6 +269,8 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
unsigned int he_previous = 0xFFFFFFFF;
|
||||
unsigned int mode_previous = INVALID;
|
||||
unsigned int divemode = INVALID;
|
||||
unsigned int beginpressure = 0;
|
||||
unsigned int endpressure = 0;
|
||||
|
||||
unsigned int nsamples = array_uint16_le (data + 1);
|
||||
unsigned int samplesize = SZ_SAMPLE_IDIVE;
|
||||
@ -363,10 +385,26 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.cns = cns / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
|
||||
// Tank Pressure
|
||||
if (samplesize == SZ_SAMPLE_IX3M_APOS4) {
|
||||
unsigned int pressure = data[offset + 49];
|
||||
if (beginpressure == 0 && pressure != 0) {
|
||||
beginpressure = pressure;
|
||||
}
|
||||
if (beginpressure) {
|
||||
sample.pressure.tank = 0;
|
||||
sample.pressure.value = pressure;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
endpressure = pressure;
|
||||
}
|
||||
}
|
||||
|
||||
offset += samplesize;
|
||||
}
|
||||
|
||||
// Cache the data for later use.
|
||||
parser->beginpressure = beginpressure;
|
||||
parser->endpressure = endpressure;
|
||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||
parser->helium[i] = helium[i];
|
||||
parser->oxygen[i] = oxygen[i];
|
||||
|
||||
@ -30,10 +30,7 @@
|
||||
#include "serial.h"
|
||||
#include "array.h"
|
||||
#include "aes.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#include "platform.h"
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc3_device_vtable)
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
#include "common-private.h"
|
||||
#include "context-private.h"
|
||||
#include "array.h"
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef int s_ssize_t;
|
||||
@ -82,10 +83,6 @@ typedef int s_errcode_t;
|
||||
#define S_CLOSE close
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
struct dc_irda_t {
|
||||
dc_context_t *context;
|
||||
#ifdef _WIN32
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
#define REACTPRO 0x4247
|
||||
#define VEO200 0x424B
|
||||
#define VEO250 0x424C
|
||||
#define INSIGHT 0x425A
|
||||
#define REACTPROWHITE 0x4354
|
||||
|
||||
typedef struct oceanic_veo250_parser_t oceanic_veo250_parser_t;
|
||||
@ -248,7 +249,8 @@ oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
|
||||
// Temperature (°F)
|
||||
unsigned int temperature;
|
||||
if (parser->model == REACTPRO || parser->model == REACTPROWHITE) {
|
||||
if (parser->model == REACTPRO || parser->model == REACTPROWHITE ||
|
||||
parser->model == INSIGHT) {
|
||||
temperature = data[offset + 6];
|
||||
} else {
|
||||
temperature = data[offset + 7];
|
||||
@ -256,6 +258,31 @@ oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
|
||||
// NDL / Deco
|
||||
unsigned int have_deco = 0;
|
||||
unsigned int decostop = 0, decotime = 0;
|
||||
if (parser->model == REACTPRO || parser->model == REACTPROWHITE ||
|
||||
parser->model == INSIGHT) {
|
||||
decostop = (data[offset + 7] & 0xF0) >> 4;
|
||||
decotime = ((data[offset + 3] & 0xC0) << 2) | data[offset + 4];
|
||||
have_deco = 1;
|
||||
} else {
|
||||
decostop = (data[offset + 5] & 0xF0) >> 4;
|
||||
decotime = array_uint16_le(data + offset + 4) & 0x0FFF;
|
||||
have_deco = 1;
|
||||
}
|
||||
if (have_deco) {
|
||||
if (decostop) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = decostop * 10 * FEET;
|
||||
} else {
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = decotime * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
}
|
||||
|
||||
offset += PAGESIZE / 2;
|
||||
}
|
||||
|
||||
|
||||
50
src/platform.h
Normal file
50
src/platform.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2017 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_PLATFORM_H
|
||||
#define DC_PLATFORM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifdef _WIN32
|
||||
#define DC_PRINTF_SIZE "%Iu"
|
||||
#else
|
||||
#define DC_PRINTF_SIZE "%zu"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#define strcasecmp _stricmp
|
||||
#if _MSC_VER < 1800
|
||||
// The rint() function is only available in MSVC 2013 and later
|
||||
// versions. Our replacement macro isn't entirely correct, because the
|
||||
// rounding rules for halfway cases are slightly different (away from
|
||||
// zero vs to even). But for our use-case, that's not a problem.
|
||||
#define rint(x) ((x) >= 0.0 ? floor((x) + 0.5): ceil((x) - 0.5))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DC_PLATFORM_H */
|
||||
@ -26,11 +26,15 @@
|
||||
#include "scubapro_g2.h"
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "array.h"
|
||||
#include "usbhid.h"
|
||||
#include "array.h"
|
||||
#include "platform.h"
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &scubapro_g2_device_vtable)
|
||||
|
||||
#define RX_PACKET_SIZE 64
|
||||
#define TX_PACKET_SIZE 32
|
||||
|
||||
typedef struct scubapro_g2_device_t {
|
||||
dc_device_t base;
|
||||
unsigned int timestamp;
|
||||
@ -58,23 +62,22 @@ static const dc_device_vtable_t scubapro_g2_device_vtable = {
|
||||
static dc_status_t
|
||||
scubapro_g2_extract_dives (dc_device_t *device, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata);
|
||||
|
||||
#define PACKET_SIZE 64
|
||||
static int receive_data(scubapro_g2_device_t *g2, unsigned char *buffer, int size, dc_event_progress_t *progress)
|
||||
{
|
||||
dc_custom_io_t *io = _dc_context_custom_io(g2->base.context);
|
||||
while (size) {
|
||||
unsigned char buf[PACKET_SIZE] = { 0 };
|
||||
unsigned char buf[RX_PACKET_SIZE] = { 0 };
|
||||
size_t transferred = 0;
|
||||
dc_status_t rc;
|
||||
int len;
|
||||
|
||||
rc = io->packet_read(io, buf, PACKET_SIZE, &transferred);
|
||||
rc = io->packet_read(io, buf, sizeof(buf), &transferred);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR(g2->base.context, "read interrupt transfer failed");
|
||||
return -1;
|
||||
}
|
||||
if (io->packet_size == PACKET_SIZE && transferred != PACKET_SIZE) {
|
||||
ERROR(g2->base.context, "incomplete read interrupt transfer (got %zu, expected %d)", transferred, PACKET_SIZE);
|
||||
if (transferred < 1) {
|
||||
ERROR(g2->base.context, "incomplete read interrupt transfer (got empty packet)");
|
||||
return -1;
|
||||
}
|
||||
len = buf[0];
|
||||
@ -82,7 +85,7 @@ static int receive_data(scubapro_g2_device_t *g2, unsigned char *buffer, int siz
|
||||
ERROR(g2->base.context, "small packet read (got %zu, expected at least %d)", transferred, len + 1);
|
||||
return -1;
|
||||
}
|
||||
if (len >= PACKET_SIZE) {
|
||||
if (len >= sizeof(buf)) {
|
||||
ERROR(g2->base.context, "read interrupt transfer returns impossible packet size (%d)", len);
|
||||
return -1;
|
||||
}
|
||||
@ -108,11 +111,11 @@ static dc_status_t
|
||||
scubapro_g2_transfer(scubapro_g2_device_t *g2, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
|
||||
{
|
||||
dc_custom_io_t *io = _dc_context_custom_io(g2->base.context);
|
||||
unsigned char buf[PACKET_SIZE];
|
||||
unsigned char buf[TX_PACKET_SIZE] = { 0 };
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
size_t transferred = 0;
|
||||
|
||||
if (csize > PACKET_SIZE-2) {
|
||||
if (csize > sizeof(buf)-2) {
|
||||
ERROR(g2->base.context, "command too big (%d)", csize);
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
@ -128,7 +131,7 @@ scubapro_g2_transfer(scubapro_g2_device_t *g2, const unsigned char command[], un
|
||||
// No report type byte
|
||||
status = io->packet_write(io, buf+1, csize+1, &transferred);
|
||||
} else {
|
||||
status = io->packet_write(io, buf, csize+2, &transferred);
|
||||
status = io->packet_write(io, buf, sizeof(buf), &transferred);
|
||||
}
|
||||
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
#define DX 0x1C
|
||||
#define VYPERNOVO 0x1D
|
||||
#define ZOOPNOVO 0x1E
|
||||
#define D4F 0x20
|
||||
|
||||
typedef struct suunto_d9_device_t {
|
||||
suunto_common2_device_t base;
|
||||
@ -101,7 +102,8 @@ suunto_d9_device_autodetect (suunto_d9_device_t *device, unsigned int model)
|
||||
// Use the model number as a hint to speedup the detection.
|
||||
unsigned int hint = 0;
|
||||
if (model == D4i || model == D6i || model == D9tx ||
|
||||
model == DX || model == VYPERNOVO || model == ZOOPNOVO)
|
||||
model == DX || model == VYPERNOVO || model == ZOOPNOVO ||
|
||||
model == D4F)
|
||||
hint = 1;
|
||||
|
||||
for (unsigned int i = 0; i < C_ARRAY_SIZE(baudrates); ++i) {
|
||||
@ -191,7 +193,8 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam
|
||||
// Override the base class values.
|
||||
model = device->base.version[0];
|
||||
if (model == D4i || model == D6i || model == D9tx ||
|
||||
model == VYPERNOVO || model == ZOOPNOVO)
|
||||
model == VYPERNOVO || model == ZOOPNOVO ||
|
||||
model == D4F)
|
||||
device->base.layout = &suunto_d9tx_layout;
|
||||
else if (model == DX)
|
||||
device->base.layout = &suunto_dx_layout;
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
#define DX 0x1C
|
||||
#define VYPERNOVO 0x1D
|
||||
#define ZOOPNOVO 0x1E
|
||||
#define D4F 0x20
|
||||
|
||||
#define ID_D6I_V1_MIX2 0x1871C062
|
||||
#define ID_D6I_V1_MIX3 0x1871C063
|
||||
@ -140,7 +141,8 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser)
|
||||
gasmode_offset = 0x1F;
|
||||
gasmix_offset = 0x54;
|
||||
gasmix_count = 8;
|
||||
} else if (parser->model == D4i || parser->model == ZOOPNOVO) {
|
||||
} else if (parser->model == D4i || parser->model == ZOOPNOVO ||
|
||||
parser->model == D4F) {
|
||||
gasmode_offset = 0x1D;
|
||||
if (id == ID_D4I_V2)
|
||||
gasmix_offset = 0x67;
|
||||
@ -177,7 +179,7 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser)
|
||||
} else if (parser->model == HELO2 || parser->model == D4i ||
|
||||
parser->model == D6i || parser->model == D9tx ||
|
||||
parser->model == DX || parser->model == ZOOPNOVO ||
|
||||
parser->model == VYPERNOVO) {
|
||||
parser->model == VYPERNOVO || parser->model == D4F) {
|
||||
config = gasmix_offset + gasmix_count * 6;
|
||||
}
|
||||
if (config + 1 > size)
|
||||
@ -198,7 +200,7 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser)
|
||||
if (parser->model == HELO2 || parser->model == D4i ||
|
||||
parser->model == D6i || parser->model == D9tx ||
|
||||
parser->model == DX || parser->model == ZOOPNOVO ||
|
||||
parser->model == VYPERNOVO) {
|
||||
parser->model == VYPERNOVO || parser->model == D4F) {
|
||||
parser->oxygen[i] = data[gasmix_offset + 6 * i + 1];
|
||||
parser->helium[i] = data[gasmix_offset + 6 * i + 2];
|
||||
} else {
|
||||
@ -216,7 +218,7 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser)
|
||||
parser->gasmix = data[0x26];
|
||||
} else if (parser->model == D4i || parser->model == D6i ||
|
||||
parser->model == D9tx || parser->model == ZOOPNOVO ||
|
||||
parser->model == VYPERNOVO) {
|
||||
parser->model == VYPERNOVO || parser->model == D4F) {
|
||||
if (id == ID_D4I_V2 || id == ID_D6I_V2) {
|
||||
parser->gasmix = data[0x2D];
|
||||
} else {
|
||||
@ -294,7 +296,7 @@ suunto_d9_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
offset = 0x17;
|
||||
else if (parser->model == D4i || parser->model == D6i ||
|
||||
parser->model == D9tx || parser->model == ZOOPNOVO ||
|
||||
parser->model == VYPERNOVO)
|
||||
parser->model == VYPERNOVO || parser->model == D4F)
|
||||
offset = 0x13;
|
||||
|
||||
if (abstract->size < offset + 7)
|
||||
@ -305,7 +307,8 @@ suunto_d9_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
if (datetime) {
|
||||
if (parser->model == D4i || parser->model == D6i ||
|
||||
parser->model == D9tx || parser->model == DX ||
|
||||
parser->model == ZOOPNOVO || parser->model == VYPERNOVO) {
|
||||
parser->model == ZOOPNOVO || parser->model == VYPERNOVO ||
|
||||
parser->model == D4F) {
|
||||
datetime->year = p[0] + (p[1] << 8);
|
||||
datetime->month = p[2];
|
||||
datetime->day = p[3];
|
||||
@ -353,7 +356,8 @@ suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne
|
||||
*((unsigned int *) value) = array_uint16_le (data + 0x0B);
|
||||
else if (parser->model == D4i || parser->model == D6i ||
|
||||
parser->model == D9tx || parser->model == DX ||
|
||||
parser->model == ZOOPNOVO || parser->model == VYPERNOVO)
|
||||
parser->model == ZOOPNOVO || parser->model == VYPERNOVO ||
|
||||
parser->model == D4F)
|
||||
*((unsigned int *) value) = array_uint16_le (data + 0x0D);
|
||||
else if (parser->model == HELO2)
|
||||
*((unsigned int *) value) = array_uint16_le (data + 0x0D) * 60;
|
||||
@ -475,7 +479,8 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
|
||||
unsigned int interval_sample_offset = 0x18;
|
||||
if (parser->model == HELO2 || parser->model == D4i ||
|
||||
parser->model == D6i || parser->model == D9tx ||
|
||||
parser->model == ZOOPNOVO || parser->model == VYPERNOVO)
|
||||
parser->model == ZOOPNOVO || parser->model == VYPERNOVO ||
|
||||
parser->model == D4F)
|
||||
interval_sample_offset = 0x1E;
|
||||
else if (parser->model == DX)
|
||||
interval_sample_offset = 0x22;
|
||||
|
||||
@ -29,10 +29,7 @@
|
||||
#include "device-private.h"
|
||||
#include "array.h"
|
||||
#include "usbhid.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#include "platform.h"
|
||||
|
||||
typedef struct suunto_eonsteel_device_t {
|
||||
dc_device_t base;
|
||||
@ -146,7 +143,7 @@ static int receive_usbhid_packet(dc_custom_io_t *io, suunto_eonsteel_device_t *e
|
||||
return -1;
|
||||
}
|
||||
if (transferred != PACKET_SIZE) {
|
||||
ERROR(eon->base.context, "incomplete read interrupt transfer (got %zu, expected %d)", transferred, PACKET_SIZE);
|
||||
ERROR(eon->base.context, "incomplete read interrupt transfer (got " DC_PRINTF_SIZE ", expected %d)", transferred, PACKET_SIZE);
|
||||
return -1;
|
||||
}
|
||||
if (buf[0] != 0x3f) {
|
||||
|
||||
@ -36,17 +36,7 @@
|
||||
#include "context-private.h"
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strcasecmp _stricmp
|
||||
#if _MSC_VER < 1800
|
||||
// The rint() function is only available in MSVC 2013 and later
|
||||
// versions. Our replacement macro isn't entirely correct, because the
|
||||
// rounding rules for halfway cases are slightly different (away from
|
||||
// zero vs to even). But for our use-case, that's not a problem.
|
||||
#define rint(x) ((x) >= 0.0 ? floor((x) + 0.5): ceil((x) - 0.5))
|
||||
#endif
|
||||
#endif
|
||||
#include "platform.h"
|
||||
|
||||
#define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
|
||||
|
||||
|
||||
14
src/usbhid.c
14
src/usbhid.c
@ -45,6 +45,7 @@
|
||||
#include "usbhid.h"
|
||||
#include "common-private.h"
|
||||
#include "context-private.h"
|
||||
#include "platform.h"
|
||||
|
||||
struct dc_usbhid_t {
|
||||
/* Library context. */
|
||||
@ -507,15 +508,16 @@ dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *act
|
||||
nbytes = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (nbytes > size) {
|
||||
nbytes = size;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
out:
|
||||
#ifdef _WIN32
|
||||
if (nbytes > size) {
|
||||
WARNING (usbhid->context, "Number of bytes exceeds the buffer size (" DC_PRINTF_SIZE " > " DC_PRINTF_SIZE ")!", nbytes, size);
|
||||
nbytes = size;
|
||||
}
|
||||
#endif
|
||||
|
||||
HEXDUMP (usbhid->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
|
||||
|
||||
out_invalidargs:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user