From fccf5e2d426c49a4c8799be1374e7a9c73d63990 Mon Sep 17 00:00:00 2001 From: Michael Keller Date: Thu, 3 Sep 2026 11:33:50 +1200 Subject: [PATCH 1/4] Shearwater: expose FWID via devinfo_hw_id, restore ID_MODEL as model source ID_MODEL (RDBI 0x8060, Product-Version byte) is now the sole authoritative model source on live Shearwater download, aligning with upstream libdc. The previous shearwater_common_get_model() FWID->model mapping is removed from the model-resolution path. The raw FWID (ID_HARDWARE, RDBI 0x8050) is read best-effort in shearwater_petrel_device_foreach() and exposed to consumers through a new generic field on dc_event_devinfo_t: unsigned int devinfo_hw_id; Value 0 means unknown or not available (all non-Shearwater drivers, Predator memory-dump path, and any RDBI failure). This lets consumers distinguish e.g. Petrel 1 vs Petrel 2 hardware on a live download without libdc mapping the FWID to a synthetic model number. shearwater_petrel_device_timesync() is also updated to read ID_MODEL directly rather than calling the now-removed shearwater_common_get_model(). Only the two Shearwater drivers that use devinfo_hw_id (shearwater_petrel.c and shearwater_predator.c) zero-initialise dc_event_devinfo_t; all other drivers retain their existing plain declaration since they explicitly assign all fields before use. // AI-generated (Claude) Signed-off-by: Michael Keller --- include/libdivecomputer/device.h | 7 +++ src/shearwater_common.c | 96 +++++++++++++------------------- src/shearwater_common.h | 5 +- src/shearwater_petrel.c | 39 +++++++++---- src/shearwater_predator.c | 5 +- src/shearwater_predator_parser.c | 5 ++ 6 files changed, 88 insertions(+), 69 deletions(-) diff --git a/include/libdivecomputer/device.h b/include/libdivecomputer/device.h index 8810a652..874a5d56 100644 --- a/include/libdivecomputer/device.h +++ b/include/libdivecomputer/device.h @@ -52,6 +52,13 @@ typedef struct dc_event_devinfo_t { unsigned int model; unsigned int firmware; unsigned int serial; + /* Generic hardware identifier, 0 = unknown/not available. + * On live download from devices that support it, this is populated + * with the device's hardware type identifier (e.g. Shearwater FWID + * from RDBI 0x8050). It supplements the coarse model field for + * consumer-side sub-model differentiation. Consumers that do not use + * this field are unaffected; the model field remains authoritative. */ + unsigned int devinfo_hw_id; } dc_event_devinfo_t; typedef struct dc_event_clock_t { diff --git a/src/shearwater_common.c b/src/shearwater_common.c index 22ae3ca6..16a46efb 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -763,30 +763,32 @@ shearwater_common_timesync_utc (shearwater_common_device_t *device, const dc_dat return status; } -dc_status_t shearwater_common_get_model(shearwater_common_device_t *device, unsigned int *model) +/* Fork-local FWID->product mapping for consumer-side sub-model refinement. + * + * ID_MODEL (RDBI 0x8060) is the authoritative model source for libdc; this + * table supplements it on live download when a finer FWID distinction is + * needed (e.g. Petrel 1 vs Petrel 2, which both report ID_MODEL=PETREL=3). + * Best-effort only: the FWID (ID_HARDWARE, RDBI 0x8050) can change across + * firmware updates and the stored log format does not carry it. + * + * Do NOT use this as the primary model source. The FWID is passed to the + * consumer via devinfo.devinfo_hw_id and this table is provided for the + * consumer to map it back to a human-readable product name. + * + * Entries with "(Petrel 2 hardware)" below are Petrel 2 hardware IDs; + * their authoritative ID_MODEL value is PETREL (3), not a distinct constant. + */ +static unsigned int +shearwater_fwid_to_product_version (unsigned int fwid) { - // Read the hardware type. - unsigned char rsp_hardware[2] = {0}; - dc_status_t status = shearwater_common_rdbi (device, ID_HARDWARE, rsp_hardware, sizeof(rsp_hardware), NULL); - if (status != DC_STATUS_SUCCESS) { - ERROR (device->base.context, "Failed to read the hardware type."); - return status; - } - - // Convert and map to the model number. - unsigned int hardware = array_uint16_be (rsp_hardware); - - DEBUG(device->base.context, "Hardware type: 0x%04x", hardware); - - switch (hardware) { + switch (fwid) { case 0x0101: case 0x0202: - *model = PREDATOR; - break; + return PREDATOR; case 0x0404: case 0x0909: - *model = PETREL; - break; + return PETREL; + /* Petrel 2 hardware — reports ID_MODEL=PETREL (3) */ case 0x0505: case 0x0808: case 0x0838: @@ -795,77 +797,59 @@ dc_status_t shearwater_common_get_model(shearwater_common_device_t *device, unsi case 0x7828: case 0x7B2C: case 0x8838: - *model = PETREL2; - break; + return PETREL; case 0xB407: case 0xB429: case 0xB469: case 0x3C3D: - *model = PETREL3; - break; + return PETREL3; case 0x0606: case 0x0A0A: - *model = NERD; - break; + return NERD; case 0x0E0D: case 0x7E2D: - *model = NERD2; - break; + return NERD2; case 0x0707: - *model = PERDIX; - break; + return PERDIX; case 0x0C0D: case 0x425B: case 0x7C2D: case 0x8D6C: - *model = PERDIXAI; - break; + return PERDIXAI; case 0x704C: case 0x924C: case 0x9C64: case 0xC407: case 0xC429: case 0xC964: - *model = PERDIX2; - break; + return PERDIX2; case 0x39C2: case 0x4AB1: - *model = PERDIX3; - break; + return PERDIX3; case 0x1F0A: case 0x1F0F: case 0x0F0F: case 0x1F10: case 0x1F1A: - *model = TERIC; - break; + return TERIC; case 0x1512: case 0x1613: case 0x2623: case 0x63A5: - *model = PEREGRINE; - break; + return PEREGRINE; case 0x1712: case 0x813A: - *model = PEREGRINE_TX; - break; + return PEREGRINE_TX; case 0xC0E0: - *model = TERN; - break; + return TERN; default: - // Unknown hardware type: fall back to reading the model number directly from the device. - WARNING (device->base.context, "Unknown hardware type 0x%04x, falling back to ID_MODEL.", hardware); - { - unsigned char rsp_model = 0; - dc_status_t rc = shearwater_common_rdbi (device, ID_MODEL, &rsp_model, sizeof(rsp_model), NULL); - if (rc != DC_STATUS_SUCCESS) { - ERROR (device->base.context, "Failed to read the model number."); - return rc; - } - *model = rsp_model; - } - break; + return 0; /* Unknown FWID — consumer falls back to ID_MODEL. */ } +} - return status; +/* Suppress unused-function warning; shearwater_fwid_to_product_version() is + * a fork-local lookup helper reserved for consumer-side use in a follow-on + * change. It is not called from the main model-resolution path. */ +static inline void shearwater_fwid_suppress_unused (void) { + (void) shearwater_fwid_to_product_version; } diff --git a/src/shearwater_common.h b/src/shearwater_common.h index 9808875b..d2ae9986 100644 --- a/src/shearwater_common.h +++ b/src/shearwater_common.h @@ -46,6 +46,9 @@ extern "C" { #define PREDATOR 2 #define PETREL 3 +/* PETREL2: Petrel 2 hardware reports ID_MODEL=PETREL (3); there is no + * distinct Product-Version value for it. FWID-based sub-model distinction + * is exposed via devinfo.devinfo_hw_id on live download. */ #define PETREL2 PETREL #define NERD 4 #define PERDIX 5 @@ -93,8 +96,6 @@ dc_status_t shearwater_common_can_wdbi (shearwater_common_device_t *device, dc_b dc_status_t shearwater_common_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime); -dc_status_t shearwater_common_get_model(shearwater_common_device_t *device, unsigned int *model); - #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index 3a9af132..94d6fcd3 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -190,16 +190,33 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call // Convert to a number. unsigned int firmware = str2num (rsp_firmware, rsp_firmware_length, 1); - unsigned int model = 0; - rc = shearwater_common_get_model (&device->base, &model); - if (rc != DC_STATUS_SUCCESS) + // Read the model number (ID_MODEL, RDBI 0x8060) — Product-Version byte, + // authoritative for the coarse product family (aligns with upstream libdc). + unsigned char rsp_model = 0; + rc = shearwater_common_rdbi (&device->base, ID_MODEL, &rsp_model, sizeof(rsp_model), NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the model number."); return rc; + } + + // Attempt to read the hardware type (ID_HARDWARE, RDBI 0x8050) for + // consumer-side sub-model differentiation (e.g. Petrel 1 vs Petrel 2). + // Best-effort: FWID can change across firmware updates and stored logs + // do not carry it. Failure is non-fatal; devinfo_hw_id remains 0. + unsigned char rsp_hardware[2] = {0}; + unsigned int fwid = 0; + dc_status_t hw_rc = shearwater_common_rdbi (&device->base, ID_HARDWARE, rsp_hardware, sizeof(rsp_hardware), NULL); + if (hw_rc == DC_STATUS_SUCCESS) { + fwid = array_uint16_be (rsp_hardware); + DEBUG (abstract->context, "Hardware type (FWID): 0x%04x", fwid); + } // Emit a device info event. - dc_event_devinfo_t devinfo; - devinfo.model = model; + dc_event_devinfo_t devinfo = {0}; + devinfo.model = rsp_model; devinfo.firmware = firmware; devinfo.serial = array_uint32_be (serial); + devinfo.devinfo_hw_id = fwid; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Read the logbook type @@ -356,15 +373,17 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call static dc_status_t shearwater_petrel_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime) { - dc_status_t status = DC_STATUS_SUCCESS; shearwater_common_device_t *device = (shearwater_common_device_t *) abstract; - unsigned int model = 0; - status = shearwater_common_get_model (device, &model); - if (status != DC_STATUS_SUCCESS) + // Read ID_MODEL (RDBI 0x8060) directly to determine time-sync variant. + unsigned char rsp_model = 0; + dc_status_t status = shearwater_common_rdbi (device, ID_MODEL, &rsp_model, sizeof(rsp_model), NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the model number."); return status; + } - if (model == TERIC) { + if (rsp_model == TERIC) { return shearwater_common_timesync_utc (device, datetime); } else { return shearwater_common_timesync_local (device, datetime); diff --git a/src/shearwater_predator.c b/src/shearwater_predator.c index 2234a5d4..67305bee 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -136,11 +136,14 @@ shearwater_predator_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) } // Emit a device info event. + // devinfo_hw_id is not available from the Predator memory dump + // (no live RDBI 0x8050 read in this path); set to 0 (unknown). unsigned char *data = dc_buffer_get_data (buffer); - dc_event_devinfo_t devinfo; + dc_event_devinfo_t devinfo = {0}; devinfo.model = data[0x2000D]; devinfo.firmware = bcd2dec (data[0x2000A]); devinfo.serial = array_uint32_be (data + 0x20002); + devinfo.devinfo_hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return status; diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 10b2f13a..5f8fb0a3 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -858,6 +858,11 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) } // Get the correct model number from the final block. + // Product-Version byte from the device's final record — authoritative for + // the coarse product family. This value is not the FWID; stored logs do not + // carry the FWID, so sub-model distinctions (e.g. Petrel 1 vs Petrel 2) are + // not recoverable on re-parse. Consumer-side refinement uses the FWID + // exposed via devinfo.devinfo_hw_id on live download. if (parser->final != UNDEFINED) { parser->model = data[parser->final + 13]; DEBUG (abstract->context, "Device: model=%u, serial=%u, firmware=%u", From 27c0477717cfd06575099d658bc5459ddaa92415 Mon Sep 17 00:00:00 2001 From: Michael Keller Date: Thu, 3 Sep 2026 12:52:04 +1200 Subject: [PATCH 2/4] descriptor: add dc_descriptor_find_by_hw_id() for hardware-id sub-model lookup Some device families share a coarse model number across multiple marketed products. The Shearwater Petrel family is one example: both Petrel 1 and Petrel 2 report ID_MODEL=3, with the hardware type (FWID) read via RDBI 0x8050 being the only runtime distinguisher. Add a generic public API to descriptor.c / descriptor.h: dc_descriptor_t * dc_descriptor_find_by_hw_id (dc_family_t family, unsigned int hw_id); The implementation keeps a separate static table g_hw_id_map[] that maps (family, hw_id) to a (family, model, product) triple, then resolves that to a direct pointer into g_descriptors[] at call time. This avoids touching g_descriptors[] and keeps the mapping table small and legible. The returned pointer is a direct reference into the static table, so dc_descriptor_free() is safe to call on it (it remains a no-op, consistent with the iterator path). hw_id==0 returns NULL immediately. The initial g_hw_id_map[] entries cover the Shearwater Petrel family: Petrel 1 (model=3): FWIDs 0x0404, 0x0909 Petrel 2 (model=3): FWIDs 0x0505, 0x0808, 0x0838, 0x08A5, 0x0B0B, 0x7828, 0x7B2C, 0x8838 Remove shearwater_fwid_to_product_version() and its suppress-unused stub from shearwater_common.c. That knowledge now lives in descriptor.c; shearwater_petrel.c continues to populate devinfo.devinfo_hw_id from the RDBI 0x8050 read, which is the source for the hw_id passed to the new API. Consumers that receive DC_EVENT_DEVINFO can call dc_descriptor_find_by_hw_id() with the reported family and devinfo_hw_id to obtain a refined descriptor without any device-specific knowledge on their side. A NULL return means the hw_id is not in the table and the caller should fall back to the coarse model-based descriptor. // AI-generated (Claude) Signed-off-by: Michael Keller --- include/libdivecomputer/descriptor.h | 20 ++++++ src/descriptor.c | 62 +++++++++++++++++++ src/shearwater_common.c | 91 ---------------------------- 3 files changed, 82 insertions(+), 91 deletions(-) diff --git a/include/libdivecomputer/descriptor.h b/include/libdivecomputer/descriptor.h index 6eaba8ed..643c5956 100644 --- a/include/libdivecomputer/descriptor.h +++ b/include/libdivecomputer/descriptor.h @@ -124,6 +124,26 @@ dc_descriptor_get_transports (const dc_descriptor_t *descriptor); int dc_descriptor_filter (const dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); +/** + * Find a descriptor by hardware identifier. + * + * Some device families share a coarse model number across multiple marketed + * products. When a device reports a hardware identifier (via + * DC_EVENT_DEVINFO.devinfo_hw_id), this function can find a more specific + * descriptor than the model number alone provides. This is best-effort: + * returns NULL if the hardware id is unknown or not in the table. + * + * The returned descriptor is a direct reference to an internal table entry + * and must be released with dc_descriptor_free(), which is safe to call on + * such a reference. + * + * @param[in] family The device family type. + * @param[in] hw_id The hardware identifier from DC_EVENT_DEVINFO. + * @returns A descriptor on success, or NULL if no match. + */ +dc_descriptor_t * +dc_descriptor_find_by_hw_id (dc_family_t family, unsigned int hw_id); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/descriptor.c b/src/descriptor.c index fd6a1509..efe96082 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -97,6 +97,38 @@ static const dc_iterator_vtable_t dc_descriptor_iterator_vtable = { * actually used to identify individual models, identical values are assigned. */ +/* Hardware-identifier to descriptor mapping. + * + * Some device families share a coarse model number (DC_EVENT_DEVINFO.model) + * across multiple marketed products; the hardware identifier (devinfo_hw_id) + * from DC_EVENT_DEVINFO can refine the selection to a specific descriptor. + * This table is best-effort: the FWID is only available on live download and + * may change across firmware updates. Consumers should treat a NULL result + * from dc_descriptor_find_by_hw_id() as "use the coarse model descriptor". */ +typedef struct { + dc_family_t family; + unsigned int model; + unsigned int hw_id; + const char *product; +} dc_hw_id_entry_t; + +static const dc_hw_id_entry_t g_hw_id_map[] = { + /* Shearwater Petrel family. + * Petrel 1 (model=3): hardware ids 0x0404, 0x0909 */ + {DC_FAMILY_SHEARWATER_PETREL, 3, 0x0404, "Petrel"}, + {DC_FAMILY_SHEARWATER_PETREL, 3, 0x0909, "Petrel"}, + /* Petrel 2 (model=3): hardware ids 0x0505, 0x0808, 0x0838, 0x08A5, + * 0x0B0B, 0x7828, 0x7B2C, 0x8838 */ + {DC_FAMILY_SHEARWATER_PETREL, 3, 0x0505, "Petrel 2"}, + {DC_FAMILY_SHEARWATER_PETREL, 3, 0x0808, "Petrel 2"}, + {DC_FAMILY_SHEARWATER_PETREL, 3, 0x0838, "Petrel 2"}, + {DC_FAMILY_SHEARWATER_PETREL, 3, 0x08A5, "Petrel 2"}, + {DC_FAMILY_SHEARWATER_PETREL, 3, 0x0B0B, "Petrel 2"}, + {DC_FAMILY_SHEARWATER_PETREL, 3, 0x7828, "Petrel 2"}, + {DC_FAMILY_SHEARWATER_PETREL, 3, 0x7B2C, "Petrel 2"}, + {DC_FAMILY_SHEARWATER_PETREL, 3, 0x8838, "Petrel 2"}, +}; + static const dc_descriptor_t g_descriptors[] = { /* Suunto Solution */ {"Suunto", "Solution", DC_FAMILY_SUUNTO_SOLUTION, 0, DC_TRANSPORT_SERIAL, NULL}, @@ -1053,6 +1085,36 @@ dc_descriptor_free (dc_descriptor_t *descriptor) return; } +dc_descriptor_t * +dc_descriptor_find_by_hw_id (dc_family_t family, unsigned int hw_id) +{ + if (hw_id == 0) + return NULL; + + for (size_t i = 0; i < C_ARRAY_SIZE(g_hw_id_map); i++) { + if (g_hw_id_map[i].family != family || g_hw_id_map[i].hw_id != hw_id) + continue; + + /* Matched — find the corresponding entry in g_descriptors[] by + * family, model, and product name. Returning a direct pointer + * into the static table is safe: dc_descriptor_free() is a + * no-op and g_descriptors[] has static storage duration. */ + for (size_t j = 0; j < C_ARRAY_SIZE(g_descriptors); j++) { + if (g_descriptors[j].type == family && + g_descriptors[j].model == g_hw_id_map[i].model && + strcmp(g_descriptors[j].product, g_hw_id_map[i].product) == 0) { + return (dc_descriptor_t *) &g_descriptors[j]; + } + } + /* hw_id matched the map but the descriptor was not found — + * product name mismatch or g_descriptors[] was edited without + * updating g_hw_id_map[]. */ + return NULL; + } + + return NULL; +} + const char * dc_descriptor_get_vendor (const dc_descriptor_t *descriptor) { diff --git a/src/shearwater_common.c b/src/shearwater_common.c index 16a46efb..0e838f73 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -762,94 +762,3 @@ shearwater_common_timesync_utc (shearwater_common_device_t *device, const dc_dat return status; } - -/* Fork-local FWID->product mapping for consumer-side sub-model refinement. - * - * ID_MODEL (RDBI 0x8060) is the authoritative model source for libdc; this - * table supplements it on live download when a finer FWID distinction is - * needed (e.g. Petrel 1 vs Petrel 2, which both report ID_MODEL=PETREL=3). - * Best-effort only: the FWID (ID_HARDWARE, RDBI 0x8050) can change across - * firmware updates and the stored log format does not carry it. - * - * Do NOT use this as the primary model source. The FWID is passed to the - * consumer via devinfo.devinfo_hw_id and this table is provided for the - * consumer to map it back to a human-readable product name. - * - * Entries with "(Petrel 2 hardware)" below are Petrel 2 hardware IDs; - * their authoritative ID_MODEL value is PETREL (3), not a distinct constant. - */ -static unsigned int -shearwater_fwid_to_product_version (unsigned int fwid) -{ - switch (fwid) { - case 0x0101: - case 0x0202: - return PREDATOR; - case 0x0404: - case 0x0909: - return PETREL; - /* Petrel 2 hardware — reports ID_MODEL=PETREL (3) */ - case 0x0505: - case 0x0808: - case 0x0838: - case 0x08A5: - case 0x0B0B: - case 0x7828: - case 0x7B2C: - case 0x8838: - return PETREL; - case 0xB407: - case 0xB429: - case 0xB469: - case 0x3C3D: - return PETREL3; - case 0x0606: - case 0x0A0A: - return NERD; - case 0x0E0D: - case 0x7E2D: - return NERD2; - case 0x0707: - return PERDIX; - case 0x0C0D: - case 0x425B: - case 0x7C2D: - case 0x8D6C: - return PERDIXAI; - case 0x704C: - case 0x924C: - case 0x9C64: - case 0xC407: - case 0xC429: - case 0xC964: - return PERDIX2; - case 0x39C2: - case 0x4AB1: - return PERDIX3; - case 0x1F0A: - case 0x1F0F: - case 0x0F0F: - case 0x1F10: - case 0x1F1A: - return TERIC; - case 0x1512: - case 0x1613: - case 0x2623: - case 0x63A5: - return PEREGRINE; - case 0x1712: - case 0x813A: - return PEREGRINE_TX; - case 0xC0E0: - return TERN; - default: - return 0; /* Unknown FWID — consumer falls back to ID_MODEL. */ - } -} - -/* Suppress unused-function warning; shearwater_fwid_to_product_version() is - * a fork-local lookup helper reserved for consumer-side use in a follow-on - * change. It is not called from the main model-resolution path. */ -static inline void shearwater_fwid_suppress_unused (void) { - (void) shearwater_fwid_to_product_version; -} From 6c8fb9b53b954fc23caa52ac63f5ff6cf48b2058 Mon Sep 17 00:00:00 2001 From: Michael Keller Date: Thu, 3 Sep 2026 15:33:52 +1200 Subject: [PATCH 3/4] device: rename devinfo_hw_id to hw_id; zero it in all non-Shearwater drivers Rename the new dc_event_devinfo_t field from devinfo_hw_id to hw_id for consistency with the existing model, firmware, and serial fields, which do not carry the struct name as a prefix. Update all references: struct definition, descriptor.h comment, shearwater_petrel.c (assignment), shearwater_predator.c (assignment and comment), shearwater_predator_parser.c (comment), shearwater_common.h (comment), and descriptor.c (comment). Add an explicit devinfo.hw_id = 0 assignment immediately before every DC_EVENT_DEVINFO emit in the 37 non-Shearwater drivers. These drivers declare dc_event_devinfo_t on the stack without an initialiser and only assign model, firmware, and serial, leaving hw_id as indeterminate stack memory. The Subsurface consumer guards the sub-model refinement path on hw_id != 0; indeterminate stack garbage could trigger a spurious dc_descriptor_find_by_hw_id() lookup. The explicit assignment is the minimal targeted fix: it adds one line per emit site and does not alter any existing line, avoiding merge conflicts if upstream adds to those blocks independently. Shearwater Petrel already sets devinfo.hw_id = fwid (RDBI 0x8050 read). Shearwater Predator already sets devinfo.hw_id = 0 explicitly. No behaviour change for any existing user: hw_id was new on this branch. Signed-off-by: AI-generated (Claude) Signed-off-by: Michael Keller --- include/libdivecomputer/descriptor.h | 2 +- include/libdivecomputer/device.h | 2 +- src/atomics_cobalt.c | 1 + src/cochran_commander.c | 2 +- src/cressi_edy.c | 2 ++ src/cressi_goa.c | 1 + src/cressi_leonardo.c | 1 + src/deepblu_cosmiq.c | 1 + src/deepsix_excursion.c | 1 + src/descriptor.c | 2 +- src/diverite_nitekq.c | 1 + src/divesoft_freedom.c | 1 + src/divesystem_idive.c | 1 + src/garmin.c | 1 + src/halcyon_symbios.c | 1 + src/hw_ostc.c | 1 + src/hw_ostc3.c | 2 ++ src/liquivision_lynx.c | 2 ++ src/mares_darwin.c | 1 + src/mares_iconhd.c | 3 +++ src/mares_nemo.c | 1 + src/mares_puck.c | 1 + src/mclean_extreme.c | 1 + src/oceanic_common.c | 1 + src/oceans_s1.c | 1 + src/pelagic_i330r.c | 1 + src/reefnet_sensus.c | 1 + src/reefnet_sensuspro.c | 1 + src/reefnet_sensusultra.c | 1 + src/seac_screen.c | 2 ++ src/shearwater_common.h | 2 +- src/shearwater_petrel.c | 4 ++-- src/shearwater_predator.c | 4 ++-- src/shearwater_predator_parser.c | 2 +- src/sporasub_sp2.c | 1 + src/suunto_common2.c | 1 + src/suunto_eon.c | 1 + src/suunto_eonsteel.c | 1 + src/suunto_solution.c | 1 + src/suunto_vyper.c | 2 ++ src/tecdiving_divecomputereu.c | 1 + src/uwatec_aladin.c | 1 + src/uwatec_memomouse.c | 1 + src/uwatec_smart.c | 1 + 44 files changed, 53 insertions(+), 10 deletions(-) diff --git a/include/libdivecomputer/descriptor.h b/include/libdivecomputer/descriptor.h index 643c5956..62b36738 100644 --- a/include/libdivecomputer/descriptor.h +++ b/include/libdivecomputer/descriptor.h @@ -129,7 +129,7 @@ dc_descriptor_filter (const dc_descriptor_t *descriptor, dc_transport_t transpor * * Some device families share a coarse model number across multiple marketed * products. When a device reports a hardware identifier (via - * DC_EVENT_DEVINFO.devinfo_hw_id), this function can find a more specific + * DC_EVENT_DEVINFO.hw_id), this function can find a more specific * descriptor than the model number alone provides. This is best-effort: * returns NULL if the hardware id is unknown or not in the table. * diff --git a/include/libdivecomputer/device.h b/include/libdivecomputer/device.h index 874a5d56..9ffce79e 100644 --- a/include/libdivecomputer/device.h +++ b/include/libdivecomputer/device.h @@ -58,7 +58,7 @@ typedef struct dc_event_devinfo_t { * from RDBI 0x8050). It supplements the coarse model field for * consumer-side sub-model differentiation. Consumers that do not use * this field are unaffected; the model field remains authoritative. */ - unsigned int devinfo_hw_id; + unsigned int hw_id; } dc_event_devinfo_t; typedef struct dc_event_clock_t { diff --git a/src/atomics_cobalt.c b/src/atomics_cobalt.c index 10de3e7c..7b86920e 100644 --- a/src/atomics_cobalt.c +++ b/src/atomics_cobalt.c @@ -333,6 +333,7 @@ atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac devinfo.serial *= 10; devinfo.serial += device->version[i] - '0'; } + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Allocate a memory buffer. diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 83f88009..eec420ea 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -937,7 +937,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call devinfo.serial = array_uint32_word_be(data.config + layout->cf_serial_number); else devinfo.serial = array_uint32_le(data.config + layout->cf_serial_number); - + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); unsigned int head_dive = 0, tail_dive = 0, dive_count = 0; diff --git a/src/cressi_edy.c b/src/cressi_edy.c index 6845a0ff..ecd9b244 100644 --- a/src/cressi_edy.c +++ b/src/cressi_edy.c @@ -414,6 +414,7 @@ cressi_edy_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = device->model; devinfo.firmware = 0; devinfo.serial = 0; + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return device_dump_read (abstract, 0, dc_buffer_get_data (buffer), @@ -438,6 +439,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v devinfo.model = device->model; devinfo.firmware = 0; devinfo.serial = 0; + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Read the logbook data. diff --git a/src/cressi_goa.c b/src/cressi_goa.c index 0fe88519..2fb6ac40 100644 --- a/src/cressi_goa.c +++ b/src/cressi_goa.c @@ -572,6 +572,7 @@ cressi_goa_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v devinfo.model = model; devinfo.firmware = firmware; devinfo.serial = serial; + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Allocate memory for the logbook data. diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c index b1ec8b4d..eccf2de1 100644 --- a/src/cressi_leonardo.c +++ b/src/cressi_leonardo.c @@ -383,6 +383,7 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = data[0]; devinfo.firmware = 0; devinfo.serial = array_uint24_le (data + 1); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return DC_STATUS_SUCCESS; diff --git a/src/deepblu_cosmiq.c b/src/deepblu_cosmiq.c index 78c91ce6..1abc2f0b 100644 --- a/src/deepblu_cosmiq.c +++ b/src/deepblu_cosmiq.c @@ -408,6 +408,7 @@ deepblu_cosmiq_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac devinfo.model = 0; devinfo.firmware = fw[0] & 0x3F; devinfo.serial = array_uint32_le (mac); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); unsigned char ndives = 0; diff --git a/src/deepsix_excursion.c b/src/deepsix_excursion.c index 1ed78677..ef0c8873 100644 --- a/src/deepsix_excursion.c +++ b/src/deepsix_excursion.c @@ -310,6 +310,7 @@ deepsix_excursion_device_foreach (dc_device_t *abstract, dc_dive_callback_t call devinfo.model = 0; devinfo.firmware = array_uint16_be (rsp_software + 4); devinfo.serial = array_convert_str2num (rsp_serial + 3, sizeof(rsp_serial) - 3); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Firmware version 6+ uses the new commands. diff --git a/src/descriptor.c b/src/descriptor.c index efe96082..9cf40e27 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -100,7 +100,7 @@ static const dc_iterator_vtable_t dc_descriptor_iterator_vtable = { /* Hardware-identifier to descriptor mapping. * * Some device families share a coarse model number (DC_EVENT_DEVINFO.model) - * across multiple marketed products; the hardware identifier (devinfo_hw_id) + * across multiple marketed products; the hardware identifier (hw_id) * from DC_EVENT_DEVINFO can refine the selection to a specific descriptor. * This table is best-effort: the FWID is only available on live download and * may change across firmware updates. Consumers should treat a NULL result diff --git a/src/diverite_nitekq.c b/src/diverite_nitekq.c index aee0784f..47dd4a6e 100644 --- a/src/diverite_nitekq.c +++ b/src/diverite_nitekq.c @@ -266,6 +266,7 @@ diverite_nitekq_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = 0; devinfo.firmware = 0; devinfo.serial = array_uint32_be (device->version + 0x0A); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Send the upload request. It's not clear whether this request is diff --git a/src/divesoft_freedom.c b/src/divesoft_freedom.c index 80117769..f60c5594 100644 --- a/src/divesoft_freedom.c +++ b/src/divesoft_freedom.c @@ -418,6 +418,7 @@ divesoft_freedom_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb devinfo.model = rsp_version[0]; devinfo.firmware = array_uint24_be (rsp_version + 3); devinfo.serial = array_convert_str2num (rsp_version + 10 + 5, 11); + devinfo.hw_id = 0; device_event_emit(abstract, DC_EVENT_DEVINFO, &devinfo); // Allocate memory for the dive list. diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index 51904b52..2799e704 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -460,6 +460,7 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb devinfo.model = array_uint16_le (packet); devinfo.firmware = array_uint32_le (packet + 2); devinfo.serial = array_uint32_le (packet + 6); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Emit a vendor event. diff --git a/src/garmin.c b/src/garmin.c index 22482685..bc78871f 100644 --- a/src/garmin.c +++ b/src/garmin.c @@ -719,6 +719,7 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void if (devinfo_p) { // first time we came through here, let's emit the // devinfo and vendor events + devinfo_p->hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, devinfo_p); devinfo_p = NULL; } diff --git a/src/halcyon_symbios.c b/src/halcyon_symbios.c index 07d6c45e..3af612be 100644 --- a/src/halcyon_symbios.c +++ b/src/halcyon_symbios.c @@ -471,6 +471,7 @@ halcyon_symbios_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba devinfo.model = info[5]; devinfo.firmware = array_uint24_be (info + 16); devinfo.serial = array_uint32_le (info); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); DEBUG (abstract->context, "Device: model=%u, serial=%u, firmware=%u.%u.%u, hw=%u, bt=%u.%u, battery=%u, pressure=%u, errorbits=%u", diff --git a/src/hw_ostc.c b/src/hw_ostc.c index 6fdc6ebf..9c525c3f 100644 --- a/src/hw_ostc.c +++ b/src/hw_ostc.c @@ -284,6 +284,7 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = 1; // OSTC Mk2 else devinfo.model = 0; // OSTC + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return DC_STATUS_SUCCESS; diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index 0e48b799..0b791a22 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -854,6 +854,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi else devinfo.model = OSTC3; } + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Allocate memory. @@ -1894,6 +1895,7 @@ hw_ostc3_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) else devinfo.model = OSTC3; } + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Allocate the required amount of memory. diff --git a/src/liquivision_lynx.c b/src/liquivision_lynx.c index 74916583..ef2ced1d 100644 --- a/src/liquivision_lynx.c +++ b/src/liquivision_lynx.c @@ -377,6 +377,7 @@ liquivision_lynx_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = array_uint16_le (device->info + 0); devinfo.firmware = 0; devinfo.serial = array_uint32_le (device->more + 0); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Allocate the required amount of memory. @@ -410,6 +411,7 @@ liquivision_lynx_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb devinfo.model = model; devinfo.firmware = 0; devinfo.serial = array_uint32_le (device->more + 0); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Read the config segment. diff --git a/src/mares_darwin.c b/src/mares_darwin.c index cac1717e..cec312e1 100644 --- a/src/mares_darwin.c +++ b/src/mares_darwin.c @@ -213,6 +213,7 @@ mares_darwin_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = device->model; devinfo.firmware = 0; devinfo.serial = array_uint16_be (data + 8); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return status; diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index 9a55769f..a851818a 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -822,6 +822,7 @@ mares_iconhd_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = device->model; devinfo.firmware = 0; devinfo.serial = array_uint32_le (data + 0x0C); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return status; @@ -848,6 +849,7 @@ mares_iconhd_device_foreach_raw (dc_device_t *abstract, dc_dive_callback_t callb devinfo.model = device->model; devinfo.firmware = 0; devinfo.serial = array_uint32_le (serial); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Enable progress notifications. @@ -1101,6 +1103,7 @@ mares_iconhd_device_foreach_object (dc_device_t *abstract, dc_dive_callback_t ca devinfo.model = device->model; devinfo.firmware = 0; devinfo.serial = serial; + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Erase the buffer. diff --git a/src/mares_nemo.c b/src/mares_nemo.c index 4b6929bb..3185b4bb 100644 --- a/src/mares_nemo.c +++ b/src/mares_nemo.c @@ -251,6 +251,7 @@ mares_nemo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = data[1]; devinfo.firmware = 0; devinfo.serial = array_uint16_be (data + 8); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return DC_STATUS_SUCCESS; diff --git a/src/mares_puck.c b/src/mares_puck.c index 14a25a20..4a3561df 100644 --- a/src/mares_puck.c +++ b/src/mares_puck.c @@ -216,6 +216,7 @@ mares_puck_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = data[1]; devinfo.firmware = 0; devinfo.serial = array_uint16_be (data + 8); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return status; diff --git a/src/mclean_extreme.c b/src/mclean_extreme.c index 8dbe7c23..f1719374 100644 --- a/src/mclean_extreme.c +++ b/src/mclean_extreme.c @@ -559,6 +559,7 @@ mclean_extreme_device_foreach(dc_device_t *abstract, dc_dive_callback_t callback devinfo.model = 0; devinfo.firmware = array_uint32_le (firmware); devinfo.serial = hashcode (serial, serial_len); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Read the computer configuration. diff --git a/src/oceanic_common.c b/src/oceanic_common.c index fc80bc11..a0f02573 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -258,6 +258,7 @@ oceanic_common_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progr (id[11] & 0x0F) * 100000 + ((id[11] & 0xF0) >> 4) * 10000 + (id[12] & 0x0F) * 1000 + ((id[12] & 0xF0) >> 4) * 100 + (id[13] & 0x0F) * 10 + ((id[13] & 0xF0) >> 4) * 1; + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return status; diff --git a/src/oceans_s1.c b/src/oceans_s1.c index 125d0908..2337c9ad 100644 --- a/src/oceans_s1.c +++ b/src/oceans_s1.c @@ -575,6 +575,7 @@ oceans_s1_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, vo devinfo.model = 0; devinfo.firmware = major << 16 | minor; devinfo.serial = 0; + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); dc_buffer_t *buffer = dc_buffer_new (4096); diff --git a/src/pelagic_i330r.c b/src/pelagic_i330r.c index 8cbbed95..a22b3b23 100644 --- a/src/pelagic_i330r.c +++ b/src/pelagic_i330r.c @@ -593,6 +593,7 @@ pelagic_i330r_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progre bcd2dec (device->hwcal[12]) + bcd2dec (device->hwcal[13]) * 100 + bcd2dec (device->hwcal[14]) * 10000; + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return DC_STATUS_SUCCESS; diff --git a/src/reefnet_sensus.c b/src/reefnet_sensus.c index 0e0345c5..feb58ced 100644 --- a/src/reefnet_sensus.c +++ b/src/reefnet_sensus.c @@ -242,6 +242,7 @@ reefnet_sensus_handshake (reefnet_sensus_device_t *device) devinfo.model = handshake[2] - '0'; devinfo.firmware = handshake[3] - '0'; devinfo.serial = array_uint16_le (handshake + 6); + devinfo.hw_id = 0; device_event_emit (&device->base, DC_EVENT_DEVINFO, &devinfo); // Emit a vendor event. diff --git a/src/reefnet_sensuspro.c b/src/reefnet_sensuspro.c index 4ba4b20c..636ad45f 100644 --- a/src/reefnet_sensuspro.c +++ b/src/reefnet_sensuspro.c @@ -203,6 +203,7 @@ reefnet_sensuspro_handshake (reefnet_sensuspro_device_t *device) devinfo.model = handshake[0]; devinfo.firmware = handshake[1]; devinfo.serial = array_uint16_le (handshake + 4); + devinfo.hw_id = 0; device_event_emit (&device->base, DC_EVENT_DEVINFO, &devinfo); // Emit a vendor event. diff --git a/src/reefnet_sensusultra.c b/src/reefnet_sensusultra.c index a29d853c..896bfd45 100644 --- a/src/reefnet_sensusultra.c +++ b/src/reefnet_sensusultra.c @@ -263,6 +263,7 @@ reefnet_sensusultra_handshake (reefnet_sensusultra_device_t *device, unsigned sh devinfo.model = handshake[1]; devinfo.firmware = handshake[0]; devinfo.serial = array_uint16_le (handshake + 2); + devinfo.hw_id = 0; device_event_emit (&device->base, DC_EVENT_DEVINFO, &devinfo); // Emit a vendor event. diff --git a/src/seac_screen.c b/src/seac_screen.c index be33a794..424c0249 100644 --- a/src/seac_screen.c +++ b/src/seac_screen.c @@ -492,6 +492,7 @@ seac_screen_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.firmware = array_uint32_le (device->info + 0x11C); } devinfo.serial = array_uint32_le (device->info + 0x10); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Emit a vendor event. @@ -531,6 +532,7 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, devinfo.firmware = array_uint32_le (device->info + 0x11C); } devinfo.serial = array_uint32_le (device->info + 0x010); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Emit a vendor event. diff --git a/src/shearwater_common.h b/src/shearwater_common.h index d2ae9986..cb870e09 100644 --- a/src/shearwater_common.h +++ b/src/shearwater_common.h @@ -48,7 +48,7 @@ extern "C" { #define PETREL 3 /* PETREL2: Petrel 2 hardware reports ID_MODEL=PETREL (3); there is no * distinct Product-Version value for it. FWID-based sub-model distinction - * is exposed via devinfo.devinfo_hw_id on live download. */ + * is exposed via devinfo.hw_id on live download. */ #define PETREL2 PETREL #define NERD 4 #define PERDIX 5 diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index 94d6fcd3..da53e9f1 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -202,7 +202,7 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call // Attempt to read the hardware type (ID_HARDWARE, RDBI 0x8050) for // consumer-side sub-model differentiation (e.g. Petrel 1 vs Petrel 2). // Best-effort: FWID can change across firmware updates and stored logs - // do not carry it. Failure is non-fatal; devinfo_hw_id remains 0. + // do not carry it. Failure is non-fatal; hw_id remains 0. unsigned char rsp_hardware[2] = {0}; unsigned int fwid = 0; dc_status_t hw_rc = shearwater_common_rdbi (&device->base, ID_HARDWARE, rsp_hardware, sizeof(rsp_hardware), NULL); @@ -216,7 +216,7 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call devinfo.model = rsp_model; devinfo.firmware = firmware; devinfo.serial = array_uint32_be (serial); - devinfo.devinfo_hw_id = fwid; + devinfo.hw_id = fwid; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Read the logbook type diff --git a/src/shearwater_predator.c b/src/shearwater_predator.c index 67305bee..159bbc78 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -136,14 +136,14 @@ shearwater_predator_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) } // Emit a device info event. - // devinfo_hw_id is not available from the Predator memory dump + // hw_id is not available from the Predator memory dump // (no live RDBI 0x8050 read in this path); set to 0 (unknown). unsigned char *data = dc_buffer_get_data (buffer); dc_event_devinfo_t devinfo = {0}; devinfo.model = data[0x2000D]; devinfo.firmware = bcd2dec (data[0x2000A]); devinfo.serial = array_uint32_be (data + 0x20002); - devinfo.devinfo_hw_id = 0; + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return status; diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 5f8fb0a3..32437eb0 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -862,7 +862,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) // the coarse product family. This value is not the FWID; stored logs do not // carry the FWID, so sub-model distinctions (e.g. Petrel 1 vs Petrel 2) are // not recoverable on re-parse. Consumer-side refinement uses the FWID - // exposed via devinfo.devinfo_hw_id on live download. + // exposed via devinfo.hw_id on live download. if (parser->final != UNDEFINED) { parser->model = data[parser->final + 13]; DEBUG (abstract->context, "Device: model=%u, serial=%u, firmware=%u", diff --git a/src/sporasub_sp2.c b/src/sporasub_sp2.c index e34966f6..4b4462d8 100644 --- a/src/sporasub_sp2.c +++ b/src/sporasub_sp2.c @@ -357,6 +357,7 @@ sporasub_sp2_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = 0; devinfo.firmware = 0; devinfo.serial = array_uint16_be (device->version + 1); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Emit a vendor event. diff --git a/src/suunto_common2.c b/src/suunto_common2.c index f80bda84..54258f24 100644 --- a/src/suunto_common2.c +++ b/src/suunto_common2.c @@ -265,6 +265,7 @@ suunto_common2_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac devinfo.model = device->version[0]; devinfo.firmware = array_uint24_be (device->version + 1); devinfo.serial = array_convert_bin2dec (serial, 4); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Read the header bytes. diff --git a/src/suunto_eon.c b/src/suunto_eon.c index a7f09dd9..0be4d4ad 100644 --- a/src/suunto_eon.c +++ b/src/suunto_eon.c @@ -186,6 +186,7 @@ suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = 0; devinfo.firmware = 0; devinfo.serial = array_convert_bcd2dec (answer + 244, 3); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return DC_STATUS_SUCCESS; diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c index a18d27c3..c765c6f9 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -717,6 +717,7 @@ suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callbac devinfo.model = eon->model; devinfo.firmware = array_uint32_be (eon->version + 0x20); devinfo.serial = array_convert_str2num(eon->version + 0x10, 16); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); rc = get_file_list(eon, &de); diff --git a/src/suunto_solution.c b/src/suunto_solution.c index e3e6b1cf..c2b4959c 100644 --- a/src/suunto_solution.c +++ b/src/suunto_solution.c @@ -226,6 +226,7 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = 0; devinfo.firmware = 0; devinfo.serial = array_convert_bcd2dec (data + 0x1D, 3); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return DC_STATUS_SUCCESS; diff --git a/src/suunto_vyper.c b/src/suunto_vyper.c index 90ef7028..185339dc 100644 --- a/src/suunto_vyper.c +++ b/src/suunto_vyper.c @@ -456,6 +456,7 @@ suunto_vyper_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.firmware = data[hoffset + 1]; devinfo.serial = 0; devinfo.serial = array_convert_bin2dec (data + hoffset + 2, 4); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); return status; @@ -502,6 +503,7 @@ suunto_vyper_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, devinfo.model = header[hoffset + 0]; devinfo.firmware = header[hoffset + 1]; devinfo.serial = array_convert_bin2dec (header + hoffset + 2, 4); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Allocate a memory buffer. diff --git a/src/tecdiving_divecomputereu.c b/src/tecdiving_divecomputereu.c index a430e0f2..a3b2077b 100644 --- a/src/tecdiving_divecomputereu.c +++ b/src/tecdiving_divecomputereu.c @@ -451,6 +451,7 @@ tecdiving_divecomputereu_device_foreach (dc_device_t *abstract, dc_dive_callback devinfo.model = 0; devinfo.firmware = 0; devinfo.serial = array_uint16_be (device->version + 0x22) << 16 | array_uint16_be (device->version + 0x26); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Emit a vendor event. diff --git a/src/uwatec_aladin.c b/src/uwatec_aladin.c index ee154331..21c0ff87 100644 --- a/src/uwatec_aladin.c +++ b/src/uwatec_aladin.c @@ -249,6 +249,7 @@ uwatec_aladin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback devinfo.model = data[HEADER + 0x7bc]; devinfo.firmware = 0; devinfo.serial = array_uint24_be (data + HEADER + 0x7ed); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); rc = uwatec_aladin_extract_dives (abstract, diff --git a/src/uwatec_memomouse.c b/src/uwatec_memomouse.c index e605578e..7c44aadb 100644 --- a/src/uwatec_memomouse.c +++ b/src/uwatec_memomouse.c @@ -503,6 +503,7 @@ uwatec_memomouse_extract_dives (dc_device_t *abstract, const unsigned char data[ devinfo.model = data[current + 3]; devinfo.firmware = 0; devinfo.serial = array_uint24_be (data + current); + devinfo.hw_id = 0; device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); } diff --git a/src/uwatec_smart.c b/src/uwatec_smart.c index 1a4734a7..2c76f7c6 100644 --- a/src/uwatec_smart.c +++ b/src/uwatec_smart.c @@ -624,6 +624,7 @@ uwatec_smart_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) devinfo.model = model[0]; devinfo.firmware = bcd2dec (software[0]); devinfo.serial = array_uint32_le (serial); + devinfo.hw_id = 0; device_event_emit (&device->base, DC_EVENT_DEVINFO, &devinfo); // Command parameters. From 68ac29c8e5573fb639f84c9e22bb28b121976696 Mon Sep 17 00:00:00 2001 From: Michael Keller Date: Fri, 4 Sep 2026 10:18:29 +1200 Subject: [PATCH 4/4] descriptor: export dc_descriptor_find_by_hw_id in symbols file The function was added to the public API (declared in include/libdivecomputer/descriptor.h, implemented in src/descriptor.c) but was omitted from src/libdivecomputer.symbols. On Autotools builds the linker export map is generated from this file, so the symbol was unexported, causing a link failure for any consumer calling it. Add dc_descriptor_find_by_hw_id in the dc_descriptor_* group, immediately after dc_descriptor_filter. Signed-off-by: Michael Keller --- src/libdivecomputer.symbols | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 48bdabef..d1b78917 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -36,6 +36,7 @@ dc_descriptor_get_type dc_descriptor_get_model dc_descriptor_get_transports dc_descriptor_filter +dc_descriptor_find_by_hw_id dc_iostream_get_transport dc_iostream_set_timeout