Changeset 85021b9 in subsurface


Ignore:
Timestamp:
Jun 15, 2017, 2:44:18 PM (4 months ago)
Author:
Dirk Hohndel <dirk@…>
Branches:
master
Children:
27deb31
Parents:
5c1d67e
git-author:
Robert Bodily <robert@…> (06/11/17 15:11:49)
git-committer:
Dirk Hohndel <dirk@…> (06/15/17 14:44:18)
Message:

Fix buffer overrun and primary sensor id issues in Liquivision import

This changeset fixes 5 issues specific to importing from Liquivision dive logs:

Issue #1: Buffer overrun causes segmentation fault.
At the end of a dive record, untranslatable data is skipped and the file is
scanned for the start of the next dive. This scan was implemented without
regard to buffer size and so the scan ran over the buffer boundary when trying
to scan for the next record after importing the last record in the file.

Issue #2: Incorrect identification of the primary sensor.
The primary tank pressure transmitter was being identified by using the sensor
ID reported in the first pressure event record encountered. When diving with
multiple transmitters (buddy, student, or group transmitters), this is often
not the case and results in the buddy or other group transmitter's pressure
data being imported instead of the primary's.

Through empirical observation of several multi-sensor logs, I identified a
previously unhandled event code (0x10) as marking a sensor identification
event record. Parsing this record allows the primary and other sensors
to be definitively identified regardless of which one sends the first pressure
event.

Issue #3: Sensor values added to the sample collection regardless of sensor ID.
When processing events, the code previously dropped through to create a sample
for every pressure event record, regardless of which sensor ID that event is
associated with. Pressure events for sensors other than the primary are now
ignored and omitted from the sample collection.

Issue #4: Duplicate samples when pressure event time syncs with sample time.
The sample index (d) was not incremented in this specific case resulting in
a duplicate sample (for the same sample time) being created when processing
the next pressure event record.

Issue #5: Unsigned time difference results in erroneous interpolated samples.
When interpolating/extrapolating depth and temperature values for a between-
samples pressure event, a signed time value is subtracted from an unsigned time
value, resulting in an unsigned term. This term is used as a scaling factor
and should be signed to allow for a negative value. Currently, negative values
are instead treated as large unsigned values which result in erroneous scaled
depth and temperature values.

Signed-off-by: Robert Bodily <robert@…>
Signed-off-by: Dirk Hohndel <dirk@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • core/liquivision.c

    r6399eaf r85021b9  
    2222};
    2323
    24 uint16_t primary_sensor;
     24// Liquivision supports the following sensor configurations:
     25// Primary sensor only
     26// Primary + Buddy sensor
     27// Primary + Up to 4 additional sensors
     28// Primary + Up to 9 addiitonal sensors
     29struct lv_sensor_ids {
     30        uint16_t primary;
     31        uint16_t buddy;
     32        uint16_t group[9];
     33};
     34
     35struct lv_sensor_ids sensor_ids;
    2536
    2637static int handle_event_ver2(int code, const unsigned char *ps, unsigned int ps_ptr, struct lv_event *event)
     
    6273                // Tank pressure
    6374                event->time = array_uint32_le(ps + ps_ptr);
    64 
    65                 /* As far as I know, Liquivision supports 2 sensors, own and buddie's. This is my
    66                  * best guess how it is represented. */
    67 
    6875                current_sensor = array_uint16_le(ps + ps_ptr + 4);
    69                 if (primary_sensor == 0) {
    70                         primary_sensor = current_sensor;
    71                 }
    72                 if (current_sensor == primary_sensor) {
     76
     77                event->pressure.sensor = -1;
     78                event->pressure.mbar = array_uint16_le(ps + ps_ptr + 6) * 10; // cb->mb
     79
     80                if (current_sensor == sensor_ids.primary) {
    7381                        event->pressure.sensor = 0;
    74                         event->pressure.mbar = array_uint16_le(ps + ps_ptr + 6) * 10; // cb->mb
     82                } else if (current_sensor == sensor_ids.buddy) {
     83                        event->pressure.sensor = 1;
    7584                } else {
    76                         /* Ignoring the buddy sensor for no as we cannot draw it on the profile.
    77                         event->pressure.sensor = 1;
    78                         event->pressure.mbar = array_uint16_le(ps + ps_ptr + 6) * 10; // cb->mb
    79                         */
    80                 }
     85                        int i;
     86                        for (i = 0; i < 9; ++i) {
     87                                if (current_sensor == sensor_ids.group[i]) {
     88                                        event->pressure.sensor = i + 2;
     89                                        break;
     90                                }
     91                        }
     92                }
     93
    8194                // 1 byte PSR
    8295                // 1 byte ST
     
    8497                break;
    8598        case 0x0010:
     99                // 4 byte time
     100                // 2 byte primary transmitter S/N
     101                // 2 byte buddy transmitter S/N
     102                // 2 byte group transmitter S/N (9x)
     103
     104                // I don't think it's possible to change sensor IDs once a dive has started but disallow it here just in case
     105                if (sensor_ids.primary == 0) {
     106                        sensor_ids.primary = array_uint16_le(ps + ps_ptr + 4);
     107                }
     108
     109                if (sensor_ids.buddy == 0) {
     110                        sensor_ids.buddy = array_uint16_le(ps + ps_ptr + 6);
     111                }
     112
     113                int i;
     114                const unsigned char *group_ptr = ps + ps_ptr + 8;
     115                for (i = 0; i < 9; ++i, group_ptr += 2) {
     116                        if (sensor_ids.group[i] == 0) {
     117                                sensor_ids.group[i] = array_uint16_le(group_ptr);
     118                        }
     119                }
     120
    86121                skip = 26;
    87122                break;
     
    110145                bool found_divesite = false;
    111146                dive = alloc_dive();
    112                 primary_sensor = 0;
     147                memset(&sensor_ids, 0, sizeof(sensor_ids));
    113148                dc = &dive->dc;
    114149
     
    240275                        dive->otu = lrintf(*(float *) (buf + ptr));
    241276                        ptr += 4;
    242                         dive_mode = *(buf + ptr++);     // 0=Deco, 1=Gauge, 2=None
     277                        dive_mode = *(buf + ptr++);     // 0=Deco, 1=Gauge, 2=None, 35=Rec
    243278                        algorithm = *(buf + ptr++);     // 0=ZH-L16C+GF
    244279                        sample_count = array_uint32_le(buf + ptr);
     
    276311                        if (log_version == 3) {
    277312                                ps_ptr += handle_event_ver3(event_code, ps, ps_ptr, &event);
    278                                 if (event_code != 0xf)
    279                                         continue;       // ignore all by pressure sensor event
     313                                // Ignoring the buddy sensor for now as we cannot draw it on the profile.
     314                                if ((event_code != 0xf) || (event.pressure.sensor != 0))
     315                                        continue;       // ignore all but pressure sensor event
    280316                        } else {        // version 2
    281317                                ps_ptr += handle_event_ver2(event_code, ps, ps_ptr, &event);
     
    320356                                        sample->cylinderpressure.mbar = event.pressure.mbar;
    321357                                        finish_sample(dc);
     358                                        d++;
    322359
    323360                                        break;
     
    334371                                                last_temp = C_to_mkelvin((float) array_uint16_le(ts + (d - 1) * 2) / 10); // dC->mK
    335372                                                sample->depth.mm = last_depth + (depth_mm - last_depth)
    336                                                         * (event.time - last_time) / sample_interval;
     373                                                        * ((int)event.time - last_time) / sample_interval;
    337374                                                sample->temperature.mkelvin = last_temp + (temp_mk - last_temp)
    338                                                         * (event.time - last_time) / sample_interval;
     375                                                        * ((int)event.time - last_time) / sample_interval;
    339376                                        }
    340377                                        finish_sample(dc);
     
    376413                        }
    377414
    378                         while (*(ps + ps_ptr) != 0x04)
     415                        while (((ptr + ps_ptr + 4) < buf_size) && (*(ps + ps_ptr) != 0x04))
    379416                                ps_ptr++;
    380417                }
Note: See TracChangeset for help on using the changeset viewer.