diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86552e10..b8b29689 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: CC: ${{ matrix.compiler }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install dependencies run: | sudo apt-get update @@ -32,10 +32,10 @@ jobs: run: | make install DESTDIR=$PWD/artifacts tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr/local - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: - name: ${{ github.job }}-${{ matrix.compiler }} path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz + archive: false mac: @@ -52,7 +52,7 @@ jobs: CC: ${{ matrix.compiler }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install dependencies run: brew install autoconf automake libtool hidapi libusb - run: autoreconf --install --force @@ -63,10 +63,10 @@ jobs: run: | make install DESTDIR=$PWD/artifacts tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr/local - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: - name: ${{ github.job }}-${{ matrix.compiler }} path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz + archive: false windows: @@ -80,7 +80,7 @@ jobs: arch: [i686, x86_64] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install dependencies run: | sudo apt-get update @@ -122,10 +122,10 @@ jobs: run: | make install DESTDIR=$PWD/artifacts tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr/local - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: - name: ${{ github.job }}-${{ matrix.arch }} path: ${{ github.job }}-${{ matrix.arch }}.tar.gz + archive: false msvc: @@ -142,7 +142,7 @@ jobs: CONFIGURATION: Release steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: msys2/setup-msys2@v2 with: install: autoconf automake libtool pkg-config make gcc @@ -151,11 +151,11 @@ jobs: ./configure make -C src revision.h shell: msys2 {0} - - uses: microsoft/setup-msbuild@v2 + - uses: microsoft/setup-msbuild@v3 - run: msbuild -m -p:Platform=${{ matrix.platform }} -p:Configuration=${{ env.CONFIGURATION }} contrib/msvc/libdivecomputer.vcxproj - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: - name: ${{ github.job }}-${{ matrix.platform }} + name: ${{ github.job }}-${{ matrix.platform }}.zip path: contrib/msvc/${{ matrix.platform }}/${{ env.CONFIGURATION }}/bin android: @@ -165,13 +165,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - run: | autoreconf --install --force ./configure make -C src revision.h - run: $ANDROID_NDK/ndk-build -C contrib/android NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: - name: ${{ github.job }} + name: ${{ github.job }}.zip path: contrib/android/libs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f8f2b342..f9b2d789 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ jobs: name: Release runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Version number id: version diff --git a/doc/man/dc_parser_samples_foreach.3 b/doc/man/dc_parser_samples_foreach.3 index 69a637f2..459aca8a 100644 --- a/doc/man/dc_parser_samples_foreach.3 +++ b/doc/man/dc_parser_samples_foreach.3 @@ -117,7 +117,6 @@ structure set to .Dv SAMPLE_EVENT_PO2 , .Dv SAMPLE_EVENT_AIRTIME , .Dv SAMPLE_EVENT_RGBM , -.Dv SAMPLE_EVENT_HEADING , or .Dv SAMPLE_EVENT_TISSUELEVEL . .It Dv DC_SAMPLE_RBT diff --git a/examples/common.c b/examples/common.c index 7aacd90e..0950ecb6 100644 --- a/examples/common.c +++ b/examples/common.c @@ -79,7 +79,7 @@ static const backend_table_t g_backends[] = { {"iconhd", DC_FAMILY_MARES_ICONHD, 0x14}, {"ostc", DC_FAMILY_HW_OSTC, 0}, {"frog", DC_FAMILY_HW_FROG, 0}, - {"ostc3", DC_FAMILY_HW_OSTC3, 0x11}, + {"ostc3", DC_FAMILY_HW_OSTC3, 0}, {"edy", DC_FAMILY_CRESSI_EDY, 0x08}, {"leonardo", DC_FAMILY_CRESSI_LEONARDO, 1}, {"goa", DC_FAMILY_CRESSI_GOA, 2}, diff --git a/include/libdivecomputer/parser.h b/include/libdivecomputer/parser.h index 88eb912a..8c3e075a 100644 --- a/include/libdivecomputer/parser.h +++ b/include/libdivecomputer/parser.h @@ -99,7 +99,7 @@ typedef enum parser_sample_event_t { SAMPLE_EVENT_PO2, SAMPLE_EVENT_AIRTIME, SAMPLE_EVENT_RGBM, - SAMPLE_EVENT_HEADING, + SAMPLE_EVENT_HEADING, /* Deprecated: replaced by DC_SAMPLE_BEARING. */ SAMPLE_EVENT_TISSUELEVEL, SAMPLE_EVENT_GASCHANGE2, /* Deprecated: replaced by DC_SAMPLE_GASMIX. */ SAMPLE_EVENT_STRING, diff --git a/src/deepsix_excursion_parser.c b/src/deepsix_excursion_parser.c index eae86b37..cd6f7943 100644 --- a/src/deepsix_excursion_parser.c +++ b/src/deepsix_excursion_parser.c @@ -743,16 +743,18 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca sample.deco.type = DC_DECO_DECOSTOP; sample.deco.depth = pressure_to_depth(deco_depth, atmospheric, density); sample.deco.time = deco_time; + sample.deco.tts = deco_ndl_tts; } else if (deco_flags & SAFETYSTOP) { sample.deco.type = DC_DECO_SAFETYSTOP; sample.deco.depth = pressure_to_depth(deco_depth, atmospheric, density); sample.deco.time = deco_time; + sample.deco.tts = 0; } else { sample.deco.type = DC_DECO_NDL; sample.deco.depth = 0; sample.deco.time = deco_ndl_tts; + sample.deco.tts = 0; } - sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, &sample, userdata); break; default: diff --git a/src/descriptor.c b/src/descriptor.c index 29c665fc..863cb7c7 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -63,6 +63,7 @@ static int dc_filter_oceans (const dc_descriptor_t *descriptor, dc_transport_t t static int dc_filter_divesoft (const dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_cressi (const dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_halcyon (const dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); +static int dc_filter_seac (const dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); // Not merged upstream yet static int dc_filter_garmin (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); @@ -339,12 +340,12 @@ static const dc_descriptor_t g_descriptors[] = { {"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x1B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw}, /* Historic models */ {"Heinrichs Weikamp", "OSTC 4", DC_FAMILY_HW_OSTC3, 0x3B43, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw}, - {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x05, DC_TRANSPORT_SERIAL, NULL}, - {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x07, DC_TRANSPORT_SERIAL, NULL}, + {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x05, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw}, + {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x07, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw}, {"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x12, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw}, {"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x13, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw}, {"Heinrichs Weikamp", "OSTC 2 TR", DC_FAMILY_HW_OSTC3, 0x33, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw}, - {"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0x0A, DC_TRANSPORT_SERIAL, NULL}, + {"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0x0A, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH | DC_TRANSPORT_BLE, dc_filter_hw}, {"Heinrichs Weikamp", "OSTC 2N", DC_FAMILY_HW_OSTC, 2, DC_TRANSPORT_SERIAL, NULL}, {"Heinrichs Weikamp", "OSTC 2C", DC_FAMILY_HW_OSTC, 3, DC_TRANSPORT_SERIAL, NULL}, {"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, DC_TRANSPORT_SERIAL, NULL}, @@ -491,7 +492,7 @@ static const dc_descriptor_t g_descriptors[] = { /* Seac Screen */ {"Seac", "Action", DC_FAMILY_SEAC_SCREEN, 0x01, DC_TRANSPORT_SERIAL, NULL}, {"Seac", "Screen", DC_FAMILY_SEAC_SCREEN, 0x02, DC_TRANSPORT_SERIAL, NULL}, - {"Seac", "Tablet", DC_FAMILY_SEAC_SCREEN, 0x10, DC_TRANSPORT_SERIAL, NULL}, + {"Seac", "Tablet", DC_FAMILY_SEAC_SCREEN, 0x10, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_seac}, /* Deepblu Cosmiq */ {"Deepblu", "Cosmiq+", DC_FAMILY_DEEPBLU_COSMIQ, 0, DC_TRANSPORT_BLE, dc_filter_deepblu}, /* Oceans S1 */ @@ -982,6 +983,20 @@ dc_filter_halcyon (const dc_descriptor_t *descriptor, dc_transport_t transport, return 1; } +static int +dc_filter_seac (const dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata) +{ + static const char * const bluetooth[] = { + "Tablet", + }; + + if (transport == DC_TRANSPORT_BLE) { + return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix_with_number); + } + + return 1; +} + dc_status_t dc_descriptor_iterator_new (dc_iterator_t **out, dc_context_t *context) { diff --git a/src/divesoft_freedom_parser.c b/src/divesoft_freedom_parser.c index 714cd7fa..5bb2e54f 100644 --- a/src/divesoft_freedom_parser.c +++ b/src/divesoft_freedom_parser.c @@ -949,12 +949,7 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba if (callback) callback(DC_SAMPLE_PPO2, &sample, userdata); } - if (id == POINT_2) { - unsigned int orientation = array_uint32_le (data + offset + 8); - unsigned int heading = orientation & 0x1FF; - sample.bearing = heading; - if (callback) callback (DC_SAMPLE_BEARING, &sample, userdata); - } else if (id == POINT_1 || id == POINT_1_OLD) { + if (id == POINT_1 || id == POINT_1_OLD) { unsigned int misc = array_uint32_le (data + offset + 8); unsigned int ceiling = array_uint16_le (data + offset + 12); unsigned int setpoint = data[offset + 15]; @@ -1019,8 +1014,14 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba sample.cns = array_uint16_le (data + offset + 6) / 100.0; if (callback) callback(DC_SAMPLE_CNS, &sample, userdata); } else if (event == EVENT_SETPOINT_MANUAL || event == EVENT_SETPOINT_AUTO) { - sample.setpoint = data[6] / 100.0; + sample.setpoint = data[offset + 6] / 100.0; if (callback) callback(DC_SAMPLE_SETPOINT, &sample, userdata); + } else if (event == EVENT_WAYPOINT) { + unsigned int heading = array_uint16_le (data + offset + 8); + if ((heading & 0x8000) == 0) { + sample.bearing = heading; + if (callback) callback (DC_SAMPLE_BEARING, &sample, userdata); + } } } else if (type == LREC_MEASURE) { // Measurement record. diff --git a/src/halcyon_symbios.c b/src/halcyon_symbios.c index 3eabf806..07d6c45e 100644 --- a/src/halcyon_symbios.c +++ b/src/halcyon_symbios.c @@ -469,13 +469,15 @@ halcyon_symbios_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba // Emit a device info event. dc_event_devinfo_t devinfo; devinfo.model = info[5]; - devinfo.firmware = 0; + devinfo.firmware = array_uint24_be (info + 16); devinfo.serial = array_uint32_le (info); device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); - DEBUG (abstract->context, "Device: serial=%u, hw=%u, model=%u, bt=%u.%u, battery=%u, pressure=%u, errorbits=%u", + DEBUG (abstract->context, "Device: model=%u, serial=%u, firmware=%u.%u.%u, hw=%u, bt=%u.%u, battery=%u, pressure=%u, errorbits=%u", + info[5], array_uint32_le (info), - info[4], info[5], info[6], info[7], + info[16], info[17], info[18], + info[4], info[6], info[7], array_uint16_le (info + 8), array_uint16_le (info + 10), array_uint32_le (info + 12)); diff --git a/src/halcyon_symbios_parser.c b/src/halcyon_symbios_parser.c index 485e4701..b7e51307 100644 --- a/src/halcyon_symbios_parser.c +++ b/src/halcyon_symbios_parser.c @@ -49,6 +49,8 @@ #define ID_GAS_CONFIG 0x11 #define ID_TANK_TRANSMITTER 0x12 #define ID_GF_INFO 0x13 +#define ID_SGC 0x14 +#define ID_GF_DATA 0x15 #define ISCONFIG(type) ( \ (type) == ID_LOG_VERSION || \ @@ -64,9 +66,10 @@ #define EPOCH 1609459200 /* 2021-01-01 00:00:00 */ #define OC 0 -#define CC 1 -#define GAUGE 2 +#define CCR 1 +#define CCR_FSP 2 #define SIDEMOUNT 3 +#define GAUGE 4 #define NGASMIXES 10 #define NTANKS 10 @@ -248,7 +251,8 @@ halcyon_symbios_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u case SIDEMOUNT: *((dc_divemode_t *) value) = DC_DIVEMODE_OC; break; - case CC: + case CCR: + case CCR_FSP: *((dc_divemode_t *) value) = DC_DIVEMODE_CCR; break; case GAUGE: @@ -332,6 +336,8 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac 8, /* ID_GAS_CONFIG */ 8, /* ID_TANK_TRANSMITTER */ 6, /* ID_GF_INFO */ + 4, /* ID_SGC */ + 8, /* ID_GF_DATA */ }; unsigned int logversion = 0; @@ -372,6 +378,15 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac return DC_STATUS_DATAFORMAT; } + // Since log version 1.9, the ID_GF_INFO record has been deprecated and + // replaced with the larger ID_GF_DATA record. Unfortunately some + // earlier firmware versions produced records with the new type, but + // with the old size. This has been fixed in log version 1.12. + // Correct the record type to workaround this bug. + if (type == ID_GF_DATA && length == lengths[ID_GF_INFO]) { + type = ID_GF_INFO; + } + if (type < C_ARRAY_SIZE(lengths)) { if (length != lengths[type]) { ERROR (abstract->context, "Unexpected record size (%u %u).", length, lengths[type]); @@ -416,12 +431,12 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac unsigned int DC_ATTR_UNUSED battery = array_uint16_le(data + offset + 20); time_start = array_uint32_le(data + offset + 24); unsigned int serial = array_uint32_le(data + offset + 28); - DEBUG (abstract->context, "Device: model=%u, hw=%u.%u, fw=%u.%u.%u, deco=%u.%u, serial=%u", + DEBUG (abstract->context, "Device: model=%u, serial=%u, firmware=%u.%u.%u, hw=%u.%u, deco=%u.%u", model, - hw_major, hw_minor, + serial, fw_major, fw_minor, fw_bugfix, - deco_major, deco_minor, - serial); + hw_major, hw_minor, + deco_major, deco_minor); } else if (type == ID_GAS_SWITCH) { unsigned int id = UNDEFINED; unsigned int o2 = data[offset + 2]; @@ -497,7 +512,7 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac // Add a new tank if necessary. if (idx >= ntanks) { - if (ngasmixes >= NTANKS) { + if (ntanks >= NTANKS) { ERROR (abstract->context, "Maximum number of tanks reached."); return DC_STATUS_NOMEMORY; } @@ -601,7 +616,7 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac // Add a new tank if necessary. if (idx >= ntanks) { - if (ngasmixes >= NTANKS) { + if (ntanks >= NTANKS) { ERROR (abstract->context, "Maximum number of tanks reached."); return DC_STATUS_NOMEMORY; } @@ -623,7 +638,7 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac sample.pressure.value = pressure / 10.0; if (callback) callback(DC_SAMPLE_PRESSURE, &sample, userdata); } else if (type == ID_COMPASS) { - unsigned int heading = array_uint16_le (data + offset + 4); + unsigned int heading = array_uint16_le (data + offset + 2); sample.bearing = heading; if (callback) callback(DC_SAMPLE_BEARING, &sample, userdata); } else if (type == ID_TRIM) { @@ -682,7 +697,7 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac // Add a new tank if necessary. if (idx >= ntanks) { - if (ngasmixes >= NTANKS) { + if (ntanks >= NTANKS) { ERROR (abstract->context, "Maximum number of tanks reached."); return DC_STATUS_NOMEMORY; } @@ -703,11 +718,17 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac sample.pressure.tank = tank_idx; sample.pressure.value = pressure / 10.0; if (callback) callback(DC_SAMPLE_PRESSURE, &sample, userdata); - } else if (type == ID_GF_INFO) { + } else if (type == ID_GF_INFO || type == ID_GF_DATA) { unsigned int DC_ATTR_UNUSED gf_now = array_uint16_le (data + offset + 2); unsigned int DC_ATTR_UNUSED gf_surface = array_uint16_le (data + offset + 4); + if (type == ID_GF_DATA) { + unsigned int DC_ATTR_UNUSED leading_tissue_gf_now = data[offset + 6]; + unsigned int DC_ATTR_UNUSED leading_tissue_gf_surface = data[offset + 7]; + } + } else if (type == ID_SGC) { + unsigned int DC_ATTR_UNUSED sgc = array_uint16_le (data + offset + 2); } else { - WARNING (abstract->context, "Unknown record (type=%u, size=%u", type, length); + WARNING (abstract->context, "Unknown record (type=%u, size=%u)", type, length); } offset += length; diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index f511e39d..cc77b098 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -83,7 +83,6 @@ #define INVALID 0xFFFFFFFF #define UNKNOWN 0x00 #define OSTC3 0x0A -#define OSTC4_5_PREFIX 0x3B #define SPORT 0x12 #define CR 0x05 #define MODEL_OSTC4 0x43 @@ -204,12 +203,6 @@ hw_ostc3_strncpy (unsigned char *data, unsigned int size, const char *text) return 0; } -bool is_ostc4_family(unsigned int hardware) -{ - // Check if the hardware is an OSTC 4 or 5. - return (hardware >> 8) == OSTC4_5_PREFIX; -} - static dc_status_t hw_ostc3_read (hw_ostc3_device_t *device, dc_event_progress_t *progress, unsigned char data[], size_t size) { @@ -249,7 +242,7 @@ hw_ostc3_write (hw_ostc3_device_t *device, dc_event_progress_t *progress, const size_t nbytes = 0; while (nbytes < size) { // Set the maximum packet size. - size_t length = is_ostc4_family(device->hardware) ? 64 : 1024; + size_t length = ISHWOS4(device->hardware) ? 64 : 1024; // Limit the packet size to the total size. if (nbytes + length > size) @@ -661,6 +654,25 @@ hw_ostc3_device_init (hw_ostc3_device_t *device, hw_ostc3_state_t state) device->model = hardware2[4]; device->serial = array_uint16_le (version + 0); + DEBUG (abstract->context, "Device: hardware=%04x, feature=%04x, model=%02x", + device->hardware, device->feature, device->model); + + if (ISHWOS4(device->hardware)) { + DEBUG (abstract->context, "Device: serial=%u, firmware=%u (%u.%u.%u.%u)", + device->serial, + device->firmware, + (device->firmware >> 11) & 0x1F, + (device->firmware >> 6) & 0x1F, + (device->firmware >> 1) & 0x1F, + (device->firmware ) & 0x01); + } else { + DEBUG (abstract->context, "Device: serial=%u, firmware=%u (%u.%u)", + device->serial, + device->firmware, + (device->firmware >> 8) & 0xFF, + (device->firmware ) & 0xFF); + } + return DC_STATUS_SUCCESS; } @@ -835,7 +847,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi // Get the internal dive number. unsigned int current = array_uint16_le (header + offset + logbook->number); - if (current > maximum || is_ostc4_family(device->hardware)) { + if (current > maximum || ISHWOS4(device->hardware)) { maximum = current; latest = i; } @@ -937,7 +949,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi } // Detect invalid profile data. - unsigned int delta = is_ostc4_family(device->hardware) ? 3 : 0; + unsigned int delta = ISHWOS4(device->hardware) ? 3 : 0; if (length < RB_LOGBOOK_SIZE_FULL + 2 || profile[length - 2] != 0xFD || profile[length - 1] != 0xFD) { // A valid profile should have at least a correct 2 byte @@ -1055,7 +1067,7 @@ hw_ostc3_device_config_read (dc_device_t *abstract, unsigned int config, unsigne if (rc != DC_STATUS_SUCCESS) return rc; - if (is_ostc4_family(device->hardware) ? size != SZ_CONFIG : size > SZ_CONFIG) { + if (ISHWOS4(device->hardware) ? size != SZ_CONFIG : size > SZ_CONFIG) { ERROR (abstract->context, "Invalid parameter specified."); return DC_STATUS_INVALIDARGS; } @@ -1081,7 +1093,7 @@ hw_ostc3_device_config_write (dc_device_t *abstract, unsigned int config, const if (rc != DC_STATUS_SUCCESS) return rc; - if (is_ostc4_family(device->hardware) ? size != SZ_CONFIG : size > SZ_CONFIG) { + if (ISHWOS4(device->hardware) ? size != SZ_CONFIG : size > SZ_CONFIG) { ERROR (abstract->context, "Invalid parameter specified."); return DC_STATUS_INVALIDARGS; } @@ -1648,7 +1660,7 @@ hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename, bool forc return status; } - if (is_ostc4_family(device->hardware)) { + if (ISHWOS4(device->hardware)) { return hw_ostc3_device_fwupdate4 (abstract, filename, forceUpdate); } else { if (forceUpdate) { @@ -1677,7 +1689,7 @@ hw_ostc3_device_read (dc_device_t *abstract, unsigned int address, unsigned char return status; } - if (is_ostc4_family(device->hardware)) { + if (ISHWOS4(device->hardware)) { return DC_STATUS_UNSUPPORTED; } @@ -1714,7 +1726,7 @@ hw_ostc3_device_write (dc_device_t *abstract, unsigned int address, const unsign return status; } - if (is_ostc4_family(device->hardware)) { + if (ISHWOS4(device->hardware)) { return DC_STATUS_UNSUPPORTED; } @@ -1756,7 +1768,7 @@ hw_ostc3_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) return rc; } - if (is_ostc4_family(device->hardware)) { + if (ISHWOS4(device->hardware)) { return DC_STATUS_UNSUPPORTED; } diff --git a/src/hw_ostc3.h b/src/hw_ostc3.h index 389329b6..7de52715 100644 --- a/src/hw_ostc3.h +++ b/src/hw_ostc3.h @@ -32,14 +32,15 @@ extern "C" { #endif /* __cplusplus */ +#define OSTC4_5_PREFIX 0x3B +#define ISHWOS4(hardware) (((hardware) >> 8) == OSTC4_5_PREFIX) + dc_status_t hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); dc_status_t hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model, unsigned int serial); -bool is_ostc4_family(unsigned int hardware); - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index a73f0aff..5a9c71f0 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -78,7 +78,8 @@ #define OSTC3_ZHL16_GF 1 #define OSTC4_VPM 2 -#define OSTC4 0x3B +#define OSTC4 0x43 +#define OSTC5 0x44 #define OSTC3FW(major,minor) ( \ (((major) & 0xFF) << 8) | \ @@ -776,7 +777,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned case 3: /* firmware */ string->desc = STRING_KEY_FIRMWARE_VERSION; /* OSTC4 stores firmware as XXXX XYYY YYZZ ZZZB, -> X.Y.Z beta? */ - if (is_ostc4_family(parser->model)) { + if (ISHWOS4(parser->model)) { int firmwareOnDevice = array_uint16_le (data + layout->firmware); unsigned char X = 0, Y = 0, Z = 0, beta = 0; X = (firmwareOnDevice & 0xF800) >> 11; @@ -835,7 +836,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned snprintf(buf, BUFLEN, "%d", parser->last_scrubber_time_minutes); break; case 8: - if (!is_ostc4_family(parser->model)) { + if (!ISHWOS4(parser->model)) { return DC_STATUS_UNSUPPORTED; } @@ -958,7 +959,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t // Get the firmware version. unsigned int firmware = 0; - if (is_ostc4_family(parser->model)) { + if (ISHWOS4(parser->model)) { firmware = array_uint16_le (data + layout->firmware); DEBUG (abstract->context, "Device: firmware=%u (%u.%u.%u.%u)", firmware, @@ -1091,7 +1092,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t } unsigned int o2 = data[offset]; unsigned int diluent; - if (is_ostc4_family(parser->model)) { + if (ISHWOS4(parser->model)) { // all manually added gas mixes on OSTC4 are OC gases diluent = 0; } else { @@ -1299,7 +1300,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t // 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 && !is_ostc4_family(parser->model) && + if (info[i].type == PPO2 && parser->hwos && !ISHWOS4(parser->model) && ((firmware >= OSTC3FW(3,3) && firmware <= OSTC3FW(3,8)) || (firmware >= OSTC3FW(10,57) && firmware <= OSTC3FW(10,63)))) { WARNING (abstract->context, "Reset invalid ppO2 divisor to zero."); @@ -1323,7 +1324,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t 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 (is_ostc4_family(parser->model) && firmware < OSTC4FW(1,0,8,0)) + if (ISHWOS4(parser->model) && firmware < OSTC4FW(1,0,8,0)) break; if (data[offset]) { sample.deco.type = DC_DECO_DECOSTOP; @@ -1368,7 +1369,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t 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 && !is_ostc4_family(parser->model) && + if (parser->hwos && !ISHWOS4(parser->model) && (firmware >= OSTC3FW(10,40) && firmware <= OSTC3FW(10,50))) { sample.pressure.value /= 10.0; } diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index ea3fa563..05e2021a 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -92,6 +92,7 @@ #define CMD_OBJ_INIT 0xBF #define CMD_OBJ_EVEN 0xAC #define CMD_OBJ_ODD 0xFE +#define CMD_SET_TIME 0xB0 #define OBJ_DEVICE 0x2000 #define OBJ_DEVICE_MODEL 0x02 @@ -134,6 +135,7 @@ static dc_status_t mares_iconhd_device_set_fingerprint (dc_device_t *abstract, c static dc_status_t mares_iconhd_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static dc_status_t mares_iconhd_device_dump (dc_device_t *abstract, dc_buffer_t *buffer); static dc_status_t mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata); +static dc_status_t mares_iconhd_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime); static dc_status_t mares_iconhd_device_close (dc_device_t *abstract); static const dc_device_vtable_t mares_iconhd_device_vtable = { @@ -144,7 +146,7 @@ static const dc_device_vtable_t mares_iconhd_device_vtable = { NULL, /* write */ mares_iconhd_device_dump, /* dump */ mares_iconhd_device_foreach, /* foreach */ - NULL, /* timesync */ + mares_iconhd_device_timesync, /* timesync */ mares_iconhd_device_close /* close */ }; @@ -1175,3 +1177,36 @@ mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, return mares_iconhd_device_foreach_raw (abstract, callback, userdata); } } + + +static dc_status_t +mares_iconhd_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime) +{ + dc_status_t status = DC_STATUS_SUCCESS; + mares_iconhd_device_t *device = (mares_iconhd_device_t *) abstract; + + // Convert to local time. + dc_datetime_t local = *datetime; + local.timezone = DC_TIMEZONE_NONE; + + dc_ticks_t ticks = dc_datetime_mktime (&local); + if (ticks == -1) { + ERROR (abstract->context, "Invalid date/time value specified."); + return DC_STATUS_INVALIDARGS; + } + + const unsigned char timestamp[] = { + (ticks ) & 0xFF, + (ticks >> 8) & 0xFF, + (ticks >> 16) & 0xFF, + (ticks >> 24) & 0xFF, + }; + + status = mares_iconhd_transfer (device, CMD_SET_TIME, timestamp, sizeof (timestamp), NULL, 0, NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to set the local time."); + return status; + } + + return status; +} diff --git a/src/seac_screen.c b/src/seac_screen.c index 06ac942a..9632f097 100644 --- a/src/seac_screen.c +++ b/src/seac_screen.c @@ -28,6 +28,7 @@ #include "device-private.h" #include "ringbuffer.h" #include "rbstream.h" +#include "packet.h" #include "checksum.h" #include "array.h" @@ -101,6 +102,7 @@ static dc_status_t seac_screen_device_set_fingerprint (dc_device_t *abstract, co static dc_status_t seac_screen_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static dc_status_t seac_screen_device_dump (dc_device_t *abstract, dc_buffer_t *buffer); static dc_status_t seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata); +static dc_status_t seac_screen_device_close (dc_device_t *abstract); static const dc_device_vtable_t seac_screen_device_vtable = { sizeof(seac_screen_device_t), @@ -111,7 +113,7 @@ static const dc_device_vtable_t seac_screen_device_vtable = { seac_screen_device_dump, /* dump */ seac_screen_device_foreach, /* foreach */ NULL, /* timesync */ - NULL, /* close */ + seac_screen_device_close, /* close */ }; static const seac_screen_commands_t cmds_screen = { @@ -307,6 +309,7 @@ seac_screen_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t { dc_status_t status = DC_STATUS_SUCCESS; seac_screen_device_t *device = NULL; + dc_transport_t transport = dc_iostream_get_transport (iostream); if (out == NULL) return DC_STATUS_INVALIDARGS; @@ -319,24 +322,35 @@ seac_screen_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t } // Set the default values. - device->iostream = iostream; device->cmds = NULL; device->layout = NULL; device->fingerprint = 0; memset (device->info, 0, sizeof (device->info)); + // Create the packet stream. + if (transport == DC_TRANSPORT_BLE) { + status = dc_packet_open (&device->iostream, context, iostream, 244, 244); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to create the packet stream."); + goto error_free; + } + } else { + device->iostream = iostream; + } + // Set the serial communication protocol (115200 8N1). status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - goto error_free; + goto error_free_iostream; } - // Set the timeout for receiving data (1000ms). - status = dc_iostream_set_timeout (device->iostream, 1000); + // Set the timeout for receiving data. + int timeout = transport == DC_TRANSPORT_BLE ? 6000 : 1000; + status = dc_iostream_set_timeout (device->iostream, timeout); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - goto error_free; + goto error_free_iostream; } // Make sure everything is in a sane state. @@ -351,7 +365,7 @@ seac_screen_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t status = seac_screen_transfer (device, CMD_HWINFO, NULL, 0, device->info, SZ_HWINFO); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to read the hardware info."); - goto error_free; + goto error_free_iostream; } HEXDUMP (context, DC_LOGLEVEL_DEBUG, "Hardware", device->info, SZ_HWINFO); @@ -360,7 +374,7 @@ seac_screen_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t status = seac_screen_transfer (device, CMD_SWINFO, NULL, 0, device->info + SZ_HWINFO, SZ_SWINFO); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to read the software info."); - goto error_free; + goto error_free_iostream; } HEXDUMP (context, DC_LOGLEVEL_DEBUG, "Software", device->info + SZ_HWINFO, SZ_SWINFO); @@ -378,11 +392,29 @@ seac_screen_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t return DC_STATUS_SUCCESS; +error_free_iostream: + if (transport == DC_TRANSPORT_BLE) { + dc_iostream_close (device->iostream); + } error_free: dc_device_deallocate ((dc_device_t *) device); return status; } +static dc_status_t +seac_screen_device_close (dc_device_t *abstract) +{ + seac_screen_device_t *device = (seac_screen_device_t *) abstract; + dc_transport_t transport = dc_iostream_get_transport (device->iostream); + + // Close the packet stream. + if (transport == DC_TRANSPORT_BLE) { + return dc_iostream_close (device->iostream); + } + + return DC_STATUS_SUCCESS; +} + static dc_status_t seac_screen_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size) { diff --git a/src/shearwater_common.c b/src/shearwater_common.c index 0a863f19..dd5748ea 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -730,6 +730,7 @@ dc_status_t shearwater_common_get_model(shearwater_common_device_t *device, unsi *model = PETREL2; break; case 0xB407: + case 0xB429: *model = PETREL3; break; case 0x0606: @@ -744,23 +745,29 @@ dc_status_t shearwater_common_get_model(shearwater_common_device_t *device, unsi *model = PERDIX; break; case 0x0C0D: + case 0x425B: case 0x7C2D: case 0x8D6C: - case 0x425B: *model = PERDIXAI; break; case 0x704C: + case 0x924C: + case 0x9C64: case 0xC407: + case 0xC429: case 0xC964: - case 0x9C64: *model = PERDIX2; break; - case 0x0F0F: case 0x1F0A: - case 0x1F0F: + case 0x0F0F: + case 0x1F10: + case 0x1F1A: *model = TERIC; break; case 0x1512: + case 0x1613: + case 0x2623: + case 0x63A5: *model = PEREGRINE; break; case 0x1712: diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 5b000807..eeab1e5d 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -95,6 +95,7 @@ #define AI_OFF 0 #define AI_HPCCR 4 #define AI_ON 5 +#define AI_ON_GPS 6 #define GF 0 #define VPMB 1 @@ -108,7 +109,6 @@ #define NFIXED 10 #define NTANKS 6 #define NRECORDS 10 -#define MAXSTRINGS 32 #define PREDATOR 2 #define PETREL 3 @@ -1098,7 +1098,7 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ } break; case DC_FIELD_LOCATION: - if (parser->opening[9] == UNDEFINED || parser->logversion < 17) + if (parser->opening[9] == UNDEFINED || parser->aimode != AI_ON_GPS) return DC_STATUS_UNSUPPORTED; latitude = (signed int) array_uint32_be (data + parser->opening[9] + 21); longitude = (signed int) array_uint32_be (data + parser->opening[9] + 25); diff --git a/src/usb.c b/src/usb.c index d7074cb9..abe22fa4 100644 --- a/src/usb.c +++ b/src/usb.c @@ -190,7 +190,11 @@ dc_usb_session_new (dc_usb_session_t **out, dc_context_t *context) session->refcount = 1; +#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x0100010A) + int rc = libusb_init_context (&session->handle, NULL, 0); +#else int rc = libusb_init (&session->handle); +#endif if (rc != LIBUSB_SUCCESS) { ERROR (context, "Failed to initialize usb support (%s).", libusb_error_name (rc)); diff --git a/src/usbhid.c b/src/usbhid.c index b7818e04..1fd2dfda 100644 --- a/src/usbhid.c +++ b/src/usbhid.c @@ -240,7 +240,11 @@ dc_usbhid_session_new (dc_usbhid_session_t **out, dc_context_t *context) session->refcount = 1; #if defined(USE_LIBUSB) +#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x0100010A) + int rc = libusb_init_context (&session->handle, NULL, 0); +#else int rc = libusb_init (&session->handle); +#endif if (rc != LIBUSB_SUCCESS) { ERROR (context, "Failed to initialize usb support (%s).", libusb_error_name (rc));