diff options
author | Salvador Cuñat <salvador.cunat@gmail.com> | 2020-08-26 12:37:33 +0200 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2020-09-03 11:38:13 -0700 |
commit | c888a1727e250c27a8d494dac7d340c8b7475867 (patch) | |
tree | e975145aa9a672a6bf071944888602bb07ed2058 | |
parent | 37ae5a7d83bac4a002597bfc3df977b61d50d5ce (diff) | |
download | subsurface-c888a1727e250c27a8d494dac7d340c8b7475867.tar.gz |
DataTrak import: Add support for WLog extensions.
WLog is a Win32 based ancient shareware program whose target was:
1) fully support divelogs coming from DataTrak (DOS or Win)
2) fill some meaningful data which wasn't supported by Uwatec software
3) have a more user-friendly GUI than Datatrak had
The problem achieving goals 1) and 2) at the same time was solved by
adding a complementary file with .add extension and - mandatory - same
base name than .log file (including directory tree).
This .add file has a fixed structure composed of a 12 bytes header,
including file type check and Nº of dives following; then a fixed 850
bytes size for each dive in the log file. Data fields size and position
are fixed inside these blocks and heavily zero padded, so they are easy
to parse.
A serious restriction imposed to the WLog user was *Do not edit the logs
with other software than Wlog*; this was due the order of dives in .log
file being the same than the order of dives in .add file. Thought you
could show a WLog divelog in Datatrak, editing it resulted in mixing all
extended data for dives following the edited one.
Thus, we have to trust files are correct and is to the user ensure this
is so. If extended data are mangled, they are mangled in WLog too and we
are not trying to fix the mess, just importing.
On the technical side, we try to be smart about tank names as neither
DataTrak nor WLog record them. So we just take the first tank in users
list matching the volume recorded in WLog.
For weights we add a translatable "unknown" string as an empty string
results in weight not being shown in subsurface-mobile (which could be a
reportable issue, BTW).
Signed-off-by: Salvador Cuñat <salvador.cunat@gmail.com>
-rw-r--r-- | core/datatrak.c | 127 | ||||
-rw-r--r-- | core/file.c | 14 | ||||
-rw-r--r-- | core/file.h | 2 |
3 files changed, 139 insertions, 4 deletions
diff --git a/core/datatrak.c b/core/datatrak.c index 2c7abefba..60454ccf4 100644 --- a/core/datatrak.c +++ b/core/datatrak.c @@ -124,6 +124,23 @@ static int dtrak_prepare_data(int model, device_data_t *dev_data) } /* + * Return a default name for a tank based on it's size. + * Just get the first in the user's list for given size. + * Reaching the end of the list means there is no tank of this size. + */ +static char *cyl_type_by_size(int size) +{ + struct tank_info_t *ti = tank_info; + + while (ti->ml != size && ti < tank_info + MAX_TANK_INFO) + ti++; + if (ti == tank_info + MAX_TANK_INFO) + return ""; + else + return copy_string(ti->name); +} + +/* * Reads the size of a datatrak profile from actual position in buffer *ptr, * zero padds it with a faked header and inserts the model number for * libdivecomputer parsing. Puts the completed buffer in a pre-allocated @@ -320,7 +337,7 @@ static unsigned char *dt_dive_parser(unsigned char *runner, struct dive *dt_dive if (tmp_2bytes != 0x7FFF) { cylinder_t cyl = empty_cylinder; cyl.type.size.mliter = tmp_2bytes * 10; - cyl.type.description = ""; + cyl.type.description = cyl_type_by_size(tmp_2bytes * 10); cyl.start.mbar = 200000; cyl.gasmix.he.permille = 0; cyl.gasmix.o2.permille = 210; @@ -562,10 +579,104 @@ bail: return NULL; } /* + * Parses the header of the .add file, returns the number of dives in + * the archive (must be the same than number of dives in .log file). + */ +static unsigned int wlog_header_parser (struct memblock *mem) +{ + int tmp; + unsigned char *runner = (unsigned char *) mem->buffer; + if (!runner) + return -1; + tmp = (runner[1] << 8) + runner[0]; + if (tmp == 0x0252) { + runner += 8; + tmp = (runner[1] << 8) + runner[0]; + return tmp; + } else { + fprintf(stderr, "Error, not a Wlog .add file\n"); + return -1; + } +} + +static void wlog_compl_parser(struct memblock *wl_mem, struct dive *dt_dive, int dcount) +{ + int strlong = 256, tmp = 0, offset = 12 + (dcount * 850), + pos_weight = offset + 256, + pos_viz = offset + 258, + pos_tank_init = offset + 266, + pos_suit = offset + 268; + char *wlog_notes = NULL, *wlog_suit = NULL, *buffer = NULL; + unsigned char *runner = (unsigned char *) wl_mem->buffer; + + /* + * Extended notes string. Fixed length 256 bytes. 0 padded if not complete + */ + if (*(runner + offset)) { + wlog_notes = calloc(strlong + 1, 1); + wlog_notes = memcpy(wlog_notes, runner + offset, 256); + wlog_notes = to_utf8((unsigned char *) wlog_notes); + } + if (dt_dive->notes && wlog_notes) { + buffer = calloc (strlen(dt_dive->notes) + strlen(wlog_notes) + 1, 1); + sprintf(buffer, "%s%s", dt_dive->notes, wlog_notes); + free(dt_dive->notes); + dt_dive->notes = copy_string(buffer); + } else if (wlog_notes) { + dt_dive->notes = copy_string(wlog_notes); + } + free(buffer); + free(wlog_notes); + + /* + * Weight in Kg * 100 + */ + tmp = (runner[pos_weight + 1] << 8) + runner[pos_weight]; + if (tmp != 0x7fff) { + weightsystem_t ws = { {lrint(tmp * 10)}, QT_TRANSLATE_NOOP("gettextFromC", "unknown") }; + add_cloned_weightsystem(&dt_dive->weightsystems, ws); + } + + /* + * Visibility in m * 100. Arbitrarily choosed to be 5 stars if >= 25m and + * then assign a star for each 5 meters, resulting 0 stars if < 5 m + */ + tmp = (runner[pos_viz + 1] << 8) + runner[pos_viz]; + if (tmp != 0x7fff) { + tmp = tmp > 2500 ? 2500 / 100 : tmp / 100; + dt_dive->visibility = (int) floor(tmp / 5); + } + + /* + * Tank initial pressure in bar * 100 + * If we know initial pressure, rework end pressure. + */ + tmp = (runner[pos_tank_init + 1] << 8) + runner[pos_tank_init]; + if (tmp != 0x7fff) { + get_cylinder(dt_dive, 0)->start.mbar = tmp * 10; + get_cylinder(dt_dive, 0)->end.mbar = get_cylinder(dt_dive, 0)->start.mbar - lrint(get_cylinder(dt_dive, 0)->gas_used.mliter / get_cylinder(dt_dive, 0)->type.size.mliter) * 1000; + } + + /* + * Dive suit, fixed length of 26 bytes, zero padded if shorter. + * Expected to be preferred by the user if he did the work of setting it. + */ + strlong = 26; + if (*(runner + pos_suit)) { + wlog_suit = calloc(strlong, 1); + wlog_suit = memcpy(wlog_suit, runner + pos_suit, strlong); + wlog_suit = to_utf8((unsigned char *) wlog_suit); + } + if (wlog_suit) + dt_dive->suit = copy_string(wlog_suit); + free(wlog_suit); +} + +/* * Main function call from file.c memblock is allocated (and freed) there. * If parsing is aborted due to errors, stores correctly parsed dives. */ -int datatrak_import(struct memblock *mem, struct dive_table *table, struct trip_table *trips, struct dive_site_table *sites) +int datatrak_import(struct memblock *mem, struct memblock *wl_mem, struct dive_table *table, struct trip_table *trips, struct dive_site_table *sites) { UNUSED(trips); unsigned char *runner; @@ -579,6 +690,16 @@ int datatrak_import(struct memblock *mem, struct dive_table *table, struct trip_ report_error(translate("gettextFromC", "[Error] File is not a DataTrak file. Aborted")); goto bail; } + // Verify WLog .add file, Beginning sequence and Nº dives + if(wl_mem) { + int compl_dives_n = wlog_header_parser(wl_mem); + if (compl_dives_n != numdives) { + report_error("ERROR: Not the same number of dives in .log %d and .add file %d.\nWill not parse .add file", numdives , compl_dives_n); + free(wl_mem->buffer); + wl_mem->buffer = NULL; + wl_mem = NULL; + } + } // Point to the expected begining of 1st. dive data runner = (unsigned char *)mem->buffer; JUMP(runner, 12); @@ -588,6 +709,8 @@ int datatrak_import(struct memblock *mem, struct dive_table *table, struct trip_ struct dive *ptdive = alloc_dive(); runner = dt_dive_parser(runner, ptdive, sites, maxbuf); + if (wl_mem) + wlog_compl_parser(wl_mem, ptdive, i); if (runner == NULL) { report_error(translate("gettextFromC", "Error: no dive")); free(ptdive); diff --git a/core/file.c b/core/file.c index 0fece03a9..ed00b7948 100644 --- a/core/file.c +++ b/core/file.c @@ -338,8 +338,20 @@ int parse_file(const char *filename, struct dive_table *table, struct trip_table /* DataTrak/Wlog */ if (fmt && !strcasecmp(fmt + 1, "LOG")) { - ret = datatrak_import(&mem, table, trips, sites); + struct memblock wl_mem; + const char *t = strrchr(filename, '.'); + char *wl_name = memcpy(calloc(t - filename + 1, 1), filename, t - filename); + wl_name = realloc(wl_name, strlen(wl_name) + 5); + wl_name = strcat(wl_name, ".add"); + if((ret = readfile(wl_name, &wl_mem)) < 0) { + fprintf(stderr, "No file %s found. No WLog extensions.\n", wl_name); + ret = datatrak_import(&mem, NULL, table, trips, sites); + } else { + ret = datatrak_import(&mem, &wl_mem, table, trips, sites); + free(wl_mem.buffer); + } free(mem.buffer); + free(wl_name); return ret; } diff --git a/core/file.h b/core/file.h index d184d169a..d282eb38b 100644 --- a/core/file.h +++ b/core/file.h @@ -20,7 +20,7 @@ extern "C" { #endif extern int try_to_open_cochran(const char *filename, struct memblock *mem, struct dive_table *table, struct trip_table *trips, struct dive_site_table *sites); extern int try_to_open_liquivision(const char *filename, struct memblock *mem, struct dive_table *table, struct trip_table *trips, struct dive_site_table *sites); -extern int datatrak_import(struct memblock *mem, struct dive_table *table, struct trip_table *trips, struct dive_site_table *sites); +extern int datatrak_import(struct memblock *mem, struct memblock *wl_mem, struct dive_table *table, struct trip_table *trips, struct dive_site_table *sites); extern void ostctools_import(const char *file, struct dive_table *table, struct trip_table *trips, struct dive_site_table *sites); extern int readfile(const char *filename, struct memblock *mem); |