Changeset 47dcc96 in subsurface


Ignore:
Timestamp:
May 7, 2017, 7:48:12 AM (3 months ago)
Author:
Dirk Hohndel <dirk@…>
Branches:
master
Children:
75762e5f
Parents:
618cd3f
git-author:
Salvador Cuñat <salvador.cunat@…> (05/07/17 03:46:23)
git-committer:
Dirk Hohndel <dirk@…> (05/07/17 07:48:12)
Message:

Datatrak import rework: main functions

datatrak_import() is the main function called from parse_file(), but
dt_dive_parser() is where the hard work is done, for both, drop file
seeking/reading and use memory pointers instead.

datatrak_import() now returns 0 on success or 1 on failure and abort
import if parser function fails instead of keeping on trying.

dt_dive_parser() emits a warning if libdc_model is zero (manual dives).
Do not parse profiles if libdc_model is zero, for unknown models we set
a fake 0xEE value coverted to Aladin Air X/Z libdc model number. Func
now takes a pointer to a buffer and moves along the dive, when done
returns a pointer to the actual memory position or NULL if something
went wrong.

Signed-off-by: Salvador Cuñat <salvador.cunat@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • core/datatrak.c

    rceb54e6 r47dcc96  
    142142
    143143/*
    144  * Parses the dive extracting its data and filling a subsurface's dive structure
     144 * Parses a mem buffer extracting its data and filling a subsurface's dive structure.
     145 * Returns a pointer to last position in buffer, or NULL on failure.
    145146 */
    146 bool dt_dive_parser(FILE *archivo, struct dive *dt_dive)
    147 {
    148         unsigned char n;
    149         int  profile_length;
     147unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive)
     148{
     149        int  rc, profile_length, n = 0, libdc_model;
    150150        char *tmp_notes_str = NULL;
    151151        unsigned char *tmp_string1 = NULL,
    152152                      *locality = NULL,
    153                       *dive_point = NULL;
     153                      *dive_point = NULL,
     154                      *compl_buffer,
     155                      *membuf = runner;
    154156        char buffer[1024];
    155         struct divecomputer *dc = &dt_dive->dc;
    156 
     157        device_data_t *devdata = calloc(1, sizeof(device_data_t));
     158
     159        /*
     160         * Reset global variables for new dive
     161         */
    157162        is_nitrox = is_O2 = is_SCR = 0;
    158163
     
    160165         * Parse byte to byte till next dive entry
    161166         */
    162         n = 0;
    163         CHECK(fread(&lector_bytes[n], 1, 1, archivo), 1);
    164         while (lector_bytes[n] != 0xA0)
    165                 CHECK(fread(&lector_bytes[n], 1, 1, archivo), 1);
    166 
    167         /*
    168          * Found dive header 0xA000, verify second byte
    169          */
    170         CHECK(fread(&lector_bytes[n+1], 1, 1, archivo), 1);
    171         if (two_bytes_to_int(lector_bytes[0], lector_bytes[1]) != 0xA000) {
    172                 printf("Error: byte = %4x\n", two_bytes_to_int(lector_bytes[0], lector_bytes[1]));
    173                 return false;
    174         }
     167        while (membuf[0] != 0xA0 || membuf[1] != 0x00) {
     168                JUMP(membuf, 1);
     169        }
     170        JUMP(membuf, 2);
    175171
    176172        /*
     
    180176        read_bytes(4);
    181177
    182 
    183178        /*
    184179         * Next, Time in minutes since 00:00
    185180         */
    186181        read_bytes(2);
    187 
    188182        dt_dive->dc.when = dt_dive->when = (timestamp_t)date_time_to_ssrfc(tmp_4bytes, tmp_2bytes);
    189183
     
    319313        /*
    320314         * Tank, volume size in liter*100. And initialize gasmix to air (default).
    321          * Dtrak don't record init and end pressures, but consumed bar, so let's
     315         * Dtrak doesn't record init and end pressures, but consumed bar, so let's
    322316         * init a default pressure of 200 bar.
    323317         */
     
    422416        free(byte);
    423417
    424 
    425418        /*
    426419         * Dive Activity 2 - Bit table, use tags again
     
    482475
    483476        /*
    484          * Alarms 1 - Bit table - Not in Subsurface, we use the profile
    485          */
    486         read_bytes(1);
    487 
    488         /*
    489          * Alarms 2 - Bit table - Not in Subsurface, we use the profile
    490          */
    491         read_bytes(1);
     477         * Alarms 1 and Alarms2 - Bit tables - Not in Subsurface, we use the profile
     478         */
     479        JUMP(membuf, 2);
    492480
    493481        /*
     
    500488         * Computer timestamp - Useless for Subsurface
    501489         */
    502         read_bytes(4);
    503 
    504         /*
    505          * Model - table - Not included 0x14, 0x24, 0x41, and 0x73
    506          * known to exist, but not its model name - To add in the future.
    507          * Strangely 0x00 serves for manually added dives and a dc too, at
    508          * least in EXAMPLE.LOG file, shipped with the software.
    509          */
    510         read_bytes(1);
    511         switch (tmp_1byte) {
    512                 case 0x00:
    513                         dt_dive->dc.model = strdup(QT_TRANSLATE_NOOP("gettextFromC", "Manually entered dive"));
    514                         break;
    515                 case 0x1C:
    516                         dt_dive->dc.model = strdup("Aladin Air");
    517                         break;
    518                 case 0x1D:
    519                         dt_dive->dc.model = strdup("Spiro Monitor 2 plus");
    520                         break;
    521                 case 0x1E:
    522                         dt_dive->dc.model = strdup("Aladin Sport");
    523                         break;
    524                 case 0x1F:
    525                         dt_dive->dc.model = strdup("Aladin Pro");
    526                         break;
    527                 case 0x34:
    528                         dt_dive->dc.model = strdup("Aladin Air X");
    529                         break;
    530                 case 0x3D:
    531                         dt_dive->dc.model = strdup("Spiro Monitor 2 plus");
    532                         break;
    533                 case 0x3F:
    534                         dt_dive->dc.model = strdup("Mares Genius");
    535                         break;
    536                 case 0x44:
    537                         dt_dive->dc.model = strdup("Aladin Air X");
    538                         break;
    539                 case 0x48:
    540                         dt_dive->dc.model = strdup("Spiro Monitor 3 Air");
    541                         break;
    542                 case 0xA4:
    543                         dt_dive->dc.model = strdup("Aladin Air X O2");
    544                         break;
    545                 case 0xB1:
    546                         dt_dive->dc.model = strdup("Citizen Hyper Aqualand");
    547                         break;
    548                 case 0xB2:
    549                         dt_dive->dc.model = strdup("Citizen ProMaster");
    550                         break;
    551                 case 0xB3:
    552                         dt_dive->dc.model = strdup("Mares Guardian");
    553                         break;
    554                 case 0xBC:
    555                         dt_dive->dc.model = strdup("Aladin Air X Nitrox");
    556                         break;
    557                 case 0xF4:
    558                         dt_dive->dc.model = strdup("Aladin Air X Nitrox");
    559                         break;
    560                 case 0xFF:
    561                         dt_dive->dc.model = strdup("Aladin Pro Nitrox");
     490        JUMP(membuf, 4);
     491
     492        /*
     493         * Model number to check against equivalence with libdivecomputer table.
     494         * The number also defines if the model is nitrox or O2 capable.
     495         */
     496        read_bytes(1);
     497        switch (tmp_1byte & 0xF0) {
     498                case 0xF0:
     499                        is_nitrox = 1;
     500                        break;
     501                case 0xA0:
     502                        is_O2 = 1;
    562503                        break;
    563504                default:
    564                         dt_dive->dc.model = strdup(QT_TRANSLATE_NOOP("gettextFromC", "Unknown"));
    565                         break;
    566         }
    567         if ((tmp_1byte & 0xF0) == 0xF0)
    568                 is_nitrox = 1;
    569         if ((tmp_1byte & 0xF0) == 0xA0)
    570                 is_O2 = 1;
     505                        is_nitrox = 0;
     506                        is_O2 = 0;
     507                        break;
     508        }
     509        libdc_model = dtrak_prepare_data(tmp_1byte, devdata);
     510        if (!libdc_model)
     511                report_error(translate("gettextFromC", "[Warning] Manual dive # %d\n"), dt_dive->number);
     512        dt_dive->dc.model = copy_string(devdata->model);
    571513
    572514        /*
    573515         * Air usage, unknown use. Probably allows or deny manually entering gas
    574516         * comsumption based on dc model - Useless for Subsurface
    575          */
    576         read_bytes(1);
    577         if (fseek(archivo, 6, 1) != 0)  // jump over 6 bytes whitout known use
    578                 goto bail;
     517         * And 6 bytes without known use.
     518         */
     519        JUMP(membuf, 7);
     520
    579521        /*
    580522         * Profile data length
     
    582524        read_bytes(2);
    583525        profile_length = tmp_2bytes;
    584         if (profile_length != 0) {
    585                 /*
    586                  * 8 x 2 bytes for the tissues saturation useless for subsurface
    587                  * and other 6 bytes without known use
    588                  */
    589                 if (fseek(archivo, 22, 1) != 0)
     526
     527        /*
     528         * Profile parsing, only if we have a profile and a dc model.
     529         * If just a profile, skip parsing and seek the buffer to the end of dive.
     530         */
     531        if (profile_length != 0 && libdc_model != 0) {
     532                compl_buffer = (unsigned char *) calloc(18 + profile_length, 1);
     533                rc = dt_libdc_buffer(membuf, profile_length, libdc_model, compl_buffer);
     534                if (rc == DC_STATUS_SUCCESS) {
     535                        libdc_buffer_parser(dt_dive, devdata, compl_buffer, profile_length + 18);
     536                } else {
     537                        report_error(translate("gettextFromC", "[Error] Out of memory for dive %d. Abort parsing."), dt_dive->number);
     538                        free(compl_buffer);
     539                        free(devdata);
    590540                        goto bail;
    591                 if (is_nitrox || is_O2) {
    592 
    593                         /*
    594                          * CNS  % (unsure) values table (only nitrox computers)
    595                          */
    596                         read_bytes(1);
    597 
    598                         /*
    599                          * % O2 in nitrox mix - (only nitrox and O2 computers but differents)
    600                          */
    601                         read_bytes(1);
    602                         if (is_nitrox) {
    603                                 dt_dive->cylinder[0].gasmix.o2.permille =
    604                                         lrint((tmp_1byte & 0x0F ? 20.0 + 2 * (tmp_1byte & 0x0F) : 21.0) * 10);
    605                         } else {
    606                                 dt_dive->cylinder[0].gasmix.o2.permille = tmp_1byte * 10;
    607                                 read_bytes(1)  // Jump over one byte, unknown use
    608                         }
    609541                }
    610                 /*
    611                  * profileLength = Nº bytes, need to know how many samples are there.
    612                  * 2bytes per sample plus another one each three samples. Also includes the
    613                  * bytes jumped over (22) and the nitrox (2) or O2 (3).
    614                  */
    615                 int numerator = is_O2 ? (profile_length - 25) * 3 : (profile_length - 24) * 3;
    616                 int denominator = is_O2 ? 8 : 7;
    617                 int samplenum = (numerator / denominator) + (((numerator % denominator) != 0) ? 1 : 0);
    618 
    619                 dc->events = calloc(samplenum, sizeof(struct event));
    620                 dc->alloc_samples = samplenum;
    621                 dc->samples = 0;
    622                 dc->sample = calloc(samplenum, sizeof(struct sample));
    623 
    624                 dtrak_profile(dt_dive, archivo);
    625         }
     542                if (is_nitrox)
     543                        dt_dive->cylinder[0].gasmix.o2.permille =
     544                                        lrint(membuf[23] & 0x0F ? 20.0 + 2 * (membuf[23] & 0x0F) : 21.0) * 10;
     545                if (is_O2)
     546                        dt_dive->cylinder[0].gasmix.o2.permille = membuf[23] * 10;
     547                free(compl_buffer);
     548        }
     549        JUMP(membuf, profile_length);
     550
    626551        /*
    627552         * Initialize some dive data not supported by Datatrak/WLog
    628553         */
    629         if (!strcmp(dt_dive->dc.model, "Manually entered dive"))
     554        if (!libdc_model)
    630555                dt_dive->dc.deviceid = 0;
    631556        else
     
    637562                        ((dt_dive->cylinder[0].gas_used.mliter / dt_dive->cylinder[0].type.size.mliter) * 1000);
    638563        }
    639         return true;
    640 
     564        free(devdata);
     565        return membuf;
    641566bail:
    642         return false;
    643 }
    644 
    645 void datatrak_import(const char *file, struct dive_table *table)
    646 {
    647         FILE *archivo;
    648         dtrakheader *fileheader = (dtrakheader *)malloc(sizeof(dtrakheader));
    649         int i = 0;
    650 
    651         if ((archivo = subsurface_fopen(file, "rb")) == NULL) {
    652                 report_error(translate("gettextFromC", "Error: couldn't open the file %s"), file);
    653                 free(fileheader);
    654                 return;
    655         }
    656 
    657         /*
    658          * Verify fileheader,  get number of dives in datatrak divelog
    659          */
    660         *fileheader = read_file_header(archivo);
    661         while (i < fileheader->divesNum) {
     567        return NULL;
     568}
     569/*
     570 * Main function call from file.c memblock is allocated (and freed) there.
     571 * If parsing is aborted due to errors, stores correctly parsed dives.
     572 */
     573int datatrak_import(struct memblock *mem, struct dive_table *table)
     574{
     575        unsigned char *runner;
     576        int i = 0, numdives = 0, rc = 0;
     577
     578        maxbuf = (long) mem->buffer + mem->size;
     579
     580        // Verify fileheader,  get number of dives in datatrak divelog, zero on error
     581        numdives = read_file_header((unsigned char *)mem->buffer);
     582        if (!numdives) {
     583                report_error(translate("gettextFromC", "[Error] File is not a DataTrak file. Aborted"));
     584                goto bail;
     585        }
     586        // Point to the expected begining of 1st. dive data
     587        runner = (unsigned char *)mem->buffer;
     588        JUMP(runner, 12);
     589
     590        // Secuential parsing. Abort if received NULL from dt_dive_parser.
     591        while ((i < numdives) && ((long) runner < maxbuf)) {
    662592                struct dive *ptdive = alloc_dive();
    663593
    664                 if (!dt_dive_parser(archivo, ptdive)) {
     594                runner = dt_dive_parser(runner, ptdive);
     595                if (runner == NULL) {
    665596                        report_error(translate("gettextFromC", "Error: no dive"));
    666597                        free(ptdive);
     598                        rc = 1;
     599                        goto out;
    667600                } else {
    668601                        record_dive(ptdive);
     
    670603                i++;
    671604        }
     605out:
    672606        taglist_cleanup(&g_tag_list);
    673         fclose(archivo);
    674607        sort_table(table);
    675         free(fileheader);
    676 }
     608        return rc;
     609bail:
     610        return 1;
     611}
Note: See TracChangeset for help on using the changeset viewer.