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:
Linus Torvalds 2017-10-05 15:02:56 -07:00
commit 07f5777c71
15 changed files with 220 additions and 74 deletions

View File

@ -692,6 +692,10 @@
RelativePath="..\include\libdivecomputer\parser.h"
>
</File>
<File
RelativePath="..\src\platform.h"
>
</File>
<File
RelativePath="..\src\rbstream.h"
>

View File

@ -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 \

View File

@ -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;

View File

@ -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

View File

@ -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];

View File

@ -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)

View File

@ -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

View File

@ -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
View 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 */

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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)))

View File

@ -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: