One more thing. If I first import "stig dykker logg.lvd" that I sent you, then click on a dive or three, and then import "griffon.lvd", Subsurface crashes:
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 org.hohndel.subsurface 0x00000001000157a7 try_to_open_liquivision + 3895 1 org.hohndel.subsurface 0x0000000100010fde parse_file + 1358 2 org.hohndel.subsurface 0x000000010007be3c MainWindow::importFiles(QStringList) + 300 3 org.hohndel.subsurface 0x000000010007c4e3 MainWindow::on_actionImportDiveLog_triggered() + 931 4 org.hohndel.subsurface 0x0000000100131310 MainWindow::qt_metacall(QMetaObject::Call, int, void**) + 80 5 QtCore 0x00000001034faf86 QMetaObject::activate(QObject*, int, int, void**) + 2374 6 QtWidgets 0x0000000103e6faef QAction::activate(QAction::ActionEvent) + 271 7 QtWidgets 0x0000000103e6ff54 QAction::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) + 404 8 QtCore 0x00000001034fb015 QMetaObject::activate(QObject*, int, int, void**) + 2517 9 libqcocoa.dylib 0x00000001069ec310 -[QCocoaMenuDelegate itemFired:] + 112 10 libsystem_trace.dylib 0x00007fff8b09ccd7 _os_activity_initiate + 75 11 com.apple.AppKit 0x00007fff91c6b5e7 -[NSApplication sendAction:to:from:] + 410 12 com.apple.AppKit 0x00007fff91c8572a -[NSMenuItem _corePerformAction] + 382 13 com.apple.AppKit 0x00007fff91c85447 -[NSCarbonMenuImpl performActionWithHighlightingForItemAtIndex:] + 114 14 libsystem_trace.dylib 0x00007fff8b09ccd7 _os_activity_initiate + 75 15 com.apple.AppKit 0x00007fff91cd2ce6 -[NSMenu performActionForItemAtIndex:] + 131 16 com.apple.AppKit 0x00007fff91cd2c56 -[NSMenu _internalPerformActionForItemAtIndex:] + 35 17 com.apple.AppKit 0x00007fff91cd2aa2 -[NSCarbonMenuImpl _carbonCommandProcessEvent:handlerCallRef:] + 107 18 com.apple.AppKit 0x00007fff91c7b03b NSSLMMenuEventHandler + 724 19 com.apple.HIToolbox 0x00007fff925c232c DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 1260 20 com.apple.HIToolbox 0x00007fff925c176e SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 386 21 com.apple.HIToolbox 0x00007fff925d6286 SendEventToEventTarget + 40 22 com.apple.HIToolbox 0x00007fff9260b795 SendHICommandEvent(unsigned int, HICommand const*, unsigned int, unsigned int, unsigned char, void const*, OpaqueEventTargetRef*, OpaqueEventTargetRef*, OpaqueEventRef**) + 428 23 com.apple.HIToolbox 0x00007fff9263ee8d SendMenuCommandWithContextAndModifiers + 59 24 com.apple.HIToolbox 0x00007fff9263ee34 SendMenuItemSelectedEvent + 188 25 com.apple.HIToolbox 0x00007fff9263ed06 FinishMenuSelection(SelectionData*, MenuResult*, MenuResult*) + 96 26 com.apple.HIToolbox 0x00007fff926468b1 MenuSelectCore(MenuData*, Point, double, unsigned int, OpaqueMenuRef**, unsigned short*) + 702 27 com.apple.HIToolbox 0x00007fff9264649e _HandleMenuSelection2 + 446 28 com.apple.AppKit 0x00007fff91c00e6e _NSHandleCarbonMenuEvent + 277 29 com.apple.AppKit 0x00007fff91a9cb90 _DPSNextEvent + 1843 30 com.apple.AppKit 0x00007fff91a9bfd0 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 194 31 com.apple.AppKit 0x00007fff91a8ff73 -[NSApplication run] + 594 32 libqcocoa.dylib 0x00000001069e891d QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 2189 33 QtCore 0x00000001034c565d QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 381 34 QtCore 0x00000001034c863c QCoreApplication::exec() + 364 35 org.hohndel.subsurface 0x0000000100018d42 main + 1698 36 org.hohndel.subsurface 0x0000000100006894 start + 52 Henrik On Fri, Nov 7, 2014 at 6:18 PM, Henrik Brautaset Aronsen < [email protected]> wrote: > It works fine with the files I tried. Just a couple of things: > > I think you need to add ... > > extern int try_to_open_liquivision(const char *filename, struct memblock > *mem); > > ... in file.h, my compiler complains: > > file.c:361:10: warning: implicit declaration of function > 'try_to_open_liquivision' is invalid in C99. > > Also, there seems to be a = vs == problem in: > > liquivision.c:225:23: note: use '=' to turn this equality comparison > into an assignment > sample->depth.mm == array_uint16_le(ds + (d - 1) * 2) * 10; // cm->mm > > > Henrik > > > > On Fri, Nov 7, 2014 at 6:10 PM, Henrik Brautaset Aronsen < > [email protected]> wrote: > > > > Great work! > > > > H > > > > On Fri, Nov 7, 2014 at 5:30 PM, John Van Ostrand <[email protected]> > wrote: > >> > >> Support includes cylinder pressures and works for v3.0 log files. > >> --- > >> CMakeLists.txt | 1 + > >> file.c | 2 + > >> liquivision.c | 352 > +++++++++++++++++++++++++++++++++++++++++++++++++++ > >> qt-ui/mainwindow.cpp | 8 +- > >> subsurface.pro | 1 + > >> 5 files changed, 361 insertions(+), 3 deletions(-) > >> create mode 100644 liquivision.c > >> > >> diff --git a/CMakeLists.txt b/CMakeLists.txt > >> index c04e968..868ad4f 100644 > >> --- a/CMakeLists.txt > >> +++ b/CMakeLists.txt > >> @@ -85,6 +85,7 @@ SET(SUBSURFACE_CORE_LIB_SRCS > >> equipment.c > >> file.c > >> libdivecomputer.c > >> + liquivision.c > >> load-git.c > >> membuffer.c > >> parse-xml.c > >> diff --git a/file.c b/file.c > >> index bab7909..dadc11f 100644 > >> --- a/file.c > >> +++ b/file.c > >> @@ -357,6 +357,8 @@ static int open_by_filename(const char *filename, > const char *fmt, struct memblo > >> /* Cochran export comma-separated-value files */ > >> if (!strcasecmp(fmt, "DPT")) > >> return try_to_open_csv(filename, mem, CSV_DEPTH); > >> + if (!strcasecmp(fmt, "LVD")) > >> + return try_to_open_liquivision(filename, mem); > >> if (!strcasecmp(fmt, "TMP")) > >> return try_to_open_csv(filename, mem, CSV_TEMP); > >> if (!strcasecmp(fmt, "HP1")) > >> diff --git a/liquivision.c b/liquivision.c > >> new file mode 100644 > >> index 0000000..bb71bfd > >> --- /dev/null > >> +++ b/liquivision.c > >> @@ -0,0 +1,352 @@ > >> +#include <string.h> > >> + > >> +#include "dive.h" > >> +#include "divelist.h" > >> +#include "file.h" > >> + > >> + > >> +// Convert bytes into an INT > >> +#define array_uint16_le(p) ((unsigned int) (p)[0] \ > >> + + ((p)[1]<<8) ) > >> +#define array_uint32_le(p) ((unsigned int) (p)[0] \ > >> + + ((p)[1]<<8) + > ((p)[2]<<16) \ > >> + + ((p)[3]<<24)) > >> + > >> + > >> +static void > >> +parse_dives (int log_version, const unsigned char *buf, unsigned int > buf_size) { > >> + unsigned int ptr = 0; > >> + unsigned char model; > >> + > >> + struct dive *dive; > >> + struct divecomputer *dc; > >> + struct sample *sample; > >> + > >> + while (ptr < buf_size) { > >> + dive = alloc_dive(); > >> + dc = &dive->dc; > >> + > >> + // Model 0=Xen, 1,2=Xeo, 4=Lynx, other=Liquivision > >> + model = *(buf + ptr); > >> + switch (model) { > >> + case 0: > >> + dc->model = "Xen"; > >> + break; > >> + case 1: > >> + case 2: > >> + dc->model = "Xeo"; > >> + break; > >> + case 4: > >> + dc->model = "Lynx"; > >> + break; > >> + default: > >> + dc->model = "LiquiVision"; > >> + break; > >> + } > >> + ptr++; > >> + > >> + // Dive location, assemble Location and Place > >> + unsigned int len, place_len; > >> + len = array_uint32_le(buf + ptr); > >> + ptr += 4; > >> + place_len = array_uint32_le(buf + ptr + len); > >> + > >> + if (len && place_len) { > >> + dive->location = malloc(len + place_len + 4); > >> + memset(dive->location, 0, len + place_len + 4); > >> + memcpy(dive->location, buf + ptr, len); > >> + memcpy(dive->location + len, ", ", 2); > >> + memcpy(dive->location + len + 2, buf + ptr + > len + 4, place_len); > >> + } else if (len) { > >> + dive->location = strndup(buf + ptr, len); > >> + } else if (place_len) { > >> + dive->location = strndup(buf + ptr + len + 4, > place_len); > >> + } > >> + > >> + ptr += len + 4 + place_len; > >> + > >> + // Dive comment > >> + len = array_uint32_le(buf + ptr); > >> + ptr += 4; > >> + > >> + // Blank notes are better than the default text > >> + if (len && strncmp(buf + ptr, "Comment ...", 11)) { > >> + dive->notes = strndup(buf + ptr, len); > >> + } > >> + ptr += len; > >> + > >> + dive->id = array_uint32_le(buf + ptr); > >> + ptr += 4; > >> + > >> + dive->number = array_uint16_le(buf + ptr) + 1; > >> + ptr += 2; > >> + > >> + dive->duration.seconds = array_uint32_le(buf + ptr); > // seconds > >> + ptr += 4; > >> + > >> + dive->maxdepth.mm = array_uint16_le(buf + ptr) * 10; > // cm->mm > >> + ptr += 2; > >> + > >> + dive->meandepth.mm = array_uint16_le(buf + ptr) * 10; > // cm->mm > >> + ptr += 2; > >> + > >> + dive->when = array_uint32_le(buf + ptr); > >> + ptr += 4; > >> + > >> + //unsigned int end_time = array_uint32_le(buf + ptr); > >> + ptr += 4; > >> + > >> + //unsigned int sit = array_uint32_le(buf + ptr); > >> + ptr += 4; > >> + //if (sit == 0xffffffff) { > >> + //} > >> + > >> + dive->surface_pressure.mbar = array_uint16_le(buf + > ptr); // ??? > >> + ptr += 2; > >> + > >> + //unsigned int rep_dive = array_uint16_le(buf + ptr); > >> + ptr += 2; > >> + > >> + dive->mintemp.mkelvin = > C_to_mkelvin((float)array_uint16_le(buf + ptr)/10);// C->mK > >> + ptr += 2; > >> + > >> + dive->maxtemp.mkelvin = > C_to_mkelvin((float)array_uint16_le(buf + ptr)/10);// C->mK > >> + ptr += 2; > >> + > >> + dive->salinity = *(buf + ptr); // ??? > >> + ptr += 1; > >> + > >> + unsigned int sample_count = array_uint32_le(buf + ptr); > >> + ptr += 4; > >> + > >> + // Sample interval > >> + unsigned char sample_interval; > >> + sample_interval = 1; > >> + > >> + unsigned char intervals[6] = {1,2,5,10,30,60}; > >> + if (*(buf + ptr) < 6) > >> + sample_interval = intervals[*(buf + ptr)]; > >> + ptr += 1; > >> + > >> + float start_cns = 0; > >> + unsigned char dive_mode = 0, algorithm = 0; > >> + if (array_uint32_le(buf + ptr) != sample_count) { > >> + // Xeo, with CNS and OTU > >> + start_cns = *(float *) (buf + ptr); > >> + ptr += 4; > >> + dive->cns = *(float *) (buf + ptr); // end > cns > >> + ptr += 4; > >> + dive->otu = *(float *) (buf + ptr); > >> + ptr += 4; > >> + dive_mode = *(buf + ptr++); // 0=Deco, > 1=Gauge, 2=None > >> + algorithm = *(buf + ptr++); // 0=ZH-L16C+GF > >> + sample_count = array_uint32_le(buf + ptr); > >> + } > >> + ptr += 4; > >> + > >> + // Parse dive samples > >> + const unsigned char *ds = buf + ptr; > >> + const unsigned char *ts = buf + ptr + sample_count * 2 > + 4; > >> + const unsigned char *ps = buf + ptr + sample_count * 4 > + 4; > >> + unsigned int ps_count = array_uint32_le(ps); > >> + ps += 4; > >> + > >> + // Bump ptr > >> + ptr += sample_count * 4 + 4; > >> + > >> + // Handle events > >> + unsigned int event; > >> + unsigned int ps_ptr; > >> + ps_ptr = 0; > >> + > >> + unsigned int d = 0, e; > >> + int event_time, mbar, sensor; > >> + > >> + // Loop through events > >> + for (e = 0; e < ps_count; e++) { > >> + // Get event > >> + event = array_uint16_le(ps + ps_ptr); > >> + ps_ptr += 2; > >> + > >> + switch (event) { > >> + case 0x0002: // Unknown > >> + case 0x0004: // Unknown > >> + ps_ptr += 4; > >> + continue; > >> + case 0x0005: // Unknown > >> + ps_ptr += 6; > >> + continue; > >> + case 0x0007: // Gas > >> + // 4 byte time > >> + // 1 byte O2, 1 bye He > >> + ps_ptr += 6; > >> + continue; > >> + case 0x0008: > >> + // 4 byte time > >> + // 2 byte gas set point 2 > >> + ps_ptr += 6; > >> + continue; > >> + case 0x000f: > >> + // Tank pressure > >> + event_time = array_uint32_le(ps + > ps_ptr); > >> + sensor = 0; //array_uint16_le(ps + > ps_ptr + 4); > >> + mbar = array_uint16_le(ps + ps_ptr + 6) > * 10; // cb->mb > >> + // 1 byte PSR > >> + // 1 byte ST > >> + ps_ptr += 10; > >> + break; > >> + case 0x0010: > >> + ps_ptr += 26; > >> + continue; > >> + case 0x0015: // Unknown > >> + ps_ptr += 2; > >> + continue; > >> + default: > >> + ps_ptr += 4; > >> + continue; > >> + } > >> + > >> + int sample_time, next_time, last_time; > >> + int depth_mm, last_depth, temp_mk, last_temp; > >> + > >> + while (true) { > >> + sample = prepare_sample(dc); > >> + > >> + // Get sample times > >> + sample_time = d * sample_interval; > >> + depth_mm = array_uint16_le(ds + d * 2) > * 10; // cm->mm > >> + temp_mk = > C_to_mkelvin(array_uint16_le(ts + d * 2) / 10); // dC->mK > >> + next_time = (d < sample_count - 1 ? (d > + 1) * sample_interval : sample_time); > >> + last_time = (d ? (d - 1) * > sample_interval : 0); > >> + > >> + if (d == sample_count) { > >> + // We still have events to > record > >> + sample->time.seconds = > event_time; > >> + sample->depth.mm == > array_uint16_le(ds + (d - 1) * 2) * 10; // cm->mm > >> + sample->temperature.mkelvin = > C_to_mkelvin(array_uint16_le(ts + (d - 1) * 2) / 10); // dC->mK > >> + sample->sensor = sensor; > >> + sample->cylinderpressure.mbar = > mbar; > >> + finish_sample(dc); > >> + > >> + break; > >> + } else if (event_time > sample_time) { > >> + // Record sample and loop > >> + sample->time.seconds = > sample_time; > >> + sample->depth.mm = depth_mm; > >> + sample->temperature.mkelvin = > temp_mk; > >> + finish_sample(dc); > >> + d++; > >> + > >> + continue; > >> + } else if (event_time == sample_time) { > >> + sample->time.seconds = > sample_time; > >> + sample->depth.mm = depth_mm; > >> + sample->temperature.mkelvin = > temp_mk; > >> + sample->sensor = sensor; > >> + sample->cylinderpressure.mbar = > mbar; > >> + finish_sample(dc); > >> + > >> + break; > >> + } else { // Event is prior to > sample > >> + sample->time.seconds = > event_time; > >> + sample->sensor = sensor; > >> + sample->cylinderpressure.mbar = > mbar; > >> + if (last_time == sample_time) { > >> + sample->depth.mm = > depth_mm; > >> + > sample->temperature.mkelvin = temp_mk; > >> + } else { > >> + // Extrapolate > >> + last_depth = > array_uint16_le(ds + (d - 1) * 2) * 10; // cm->mm > >> + last_temp = > C_to_mkelvin(array_uint16_le(ts + (d - 1) * 2) / 10); // dC->mK > >> + sample->depth.mm = > last_depth + (depth_mm - last_depth) > >> + * (event_time - > last_time) / sample_interval; > >> + > sample->temperature.mkelvin = last_temp + (temp_mk - last_temp) > >> + * (event_time - > last_time) / sample_interval; > >> + } > >> + finish_sample(dc); > >> + > >> + break; > >> + } > >> + } // while (true); > >> + } // for each event sample > >> + > >> + // record trailing depth samples > >> + for ( ;d < sample_count; d++) { > >> + sample = prepare_sample(dc); > >> + sample->time.seconds = d * sample_interval; > >> + > >> + sample->depth.mm = array_uint16_le(ds + d * 2) > * 10; // cm->mm > >> + sample->temperature.mkelvin = > >> + C_to_mkelvin((float)array_uint16_le(ts > + d * 2) / 10); > >> + finish_sample(dc); > >> + } > >> + > >> + if (log_version == 3 && model == 4) { > >> + // Advance to begin of next dive > >> + switch (array_uint16_le(ps + ps_ptr)) { > >> + case 0x0000: > >> + ps_ptr += 5; > >> + break; > >> + case 0x0100: > >> + ps_ptr += 7; > >> + break; > >> + case 0x0200: > >> + ps_ptr += 9; > >> + break; > >> + case 0x0300: > >> + ps_ptr += 11; > >> + break; > >> + case 0x0b0b: > >> + ps_ptr += 27; > >> + break; > >> + } > >> + > >> + while (*(ps + ps_ptr) != 0x04) > >> + ps_ptr++; > >> + } > >> + > >> + // End dive > >> + dive->downloaded = true; > >> + record_dive(dive); > >> + mark_divelist_changed(true); > >> + > >> + // Advance ptr for next dive > >> + ptr += ps_ptr + 4; > >> + } // while > >> + > >> + save_dives("/tmp/test.xml"); > >> +} > >> + > >> + > >> +int > >> +try_to_open_liquivision(const char *filename, struct memblock *mem) > >> +{ > >> + void *name; > >> + const unsigned char *buf = mem->buffer; > >> + unsigned int buf_size = mem->size; > >> + unsigned int ptr; > >> + int log_version; > >> + > >> + // Get name > >> + unsigned int len = array_uint32_le(buf); > >> + if (len) { > >> + name = malloc(len); > >> + strncpy(name, buf + 4, len); > >> + } > >> + ptr = 4 + len; > >> + > >> + unsigned int dive_count = array_uint32_le(buf + ptr); > >> + if (dive_count == 0xffffffff) { > >> + // File version 3.0 > >> + log_version = 3; > >> + ptr += 6; > >> + dive_count = array_uint32_le(buf + ptr); > >> + } else { > >> + log_version = 2; > >> + } > >> + ptr += 4; > >> + > >> + parse_dives(log_version, buf + ptr, buf_size - ptr); > >> + > >> + return 1; > >> +} > >> diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp > >> index cc2d970..5811d4e 100644 > >> --- a/qt-ui/mainwindow.cpp > >> +++ b/qt-ui/mainwindow.cpp > >> @@ -725,7 +725,8 @@ QString MainWindow::filter() > >> QString f; > >> f += "ALL ( *.ssrf *.xml *.XML *.uddf *.udcf *.UDFC *.jlb *.JLB > "; > >> f += "*.sde *.SDE *.dld *.DLD "; > >> - f += "*.db *.can"; > >> + f += "*.db *.can "; > >> + f += "*.lvd "; > >> f += ");;"; > >> > >> f += "Subsurface (*.ssrf);;"; > >> @@ -737,7 +738,8 @@ QString MainWindow::filter() > >> f += "SDE (*.sde *.SDE);;"; > >> f += "DLD (*.dld *.DLD);;"; > >> f += "DB (*.db);;"; > >> - f += "CAN (*.can)"; > >> + f += "CAN (*.can);;"; > >> + f += "LVD (*.lvd)"; > >> > >> return f; > >> } > >> @@ -1247,7 +1249,7 @@ void MainWindow::loadFiles(const QStringList > fileNames) > >> void MainWindow::on_actionImportDiveLog_triggered() > >> { > >> QStringList fileNames = QFileDialog::getOpenFileNames(this, > tr("Open dive log file"), lastUsedDir(), > >> - tr("Dive log files (*.xml *.uddf *.udcf *.csv *.jlb > *.dld *.sde *.db *.can);;" > >> + tr("Dive log files (*.xml *.uddf *.udcf *.csv *.jlb > *.dld *.sde *.db *.can *.lvd);;" > >> "XML files (*.xml);;UDDF/UDCF files(*.uddf > *.udcf);;JDiveLog files(*.jlb);;" > >> "Suunto files(*.sde *.db);;CSV > files(*.csv);;MkVI files(*.txt);;All files(*)")); > >> > >> diff --git a/subsurface.pro b/subsurface.pro > >> index 7b38fd6..07e7b29 100644 > >> --- a/subsurface.pro > >> +++ b/subsurface.pro > >> @@ -120,6 +120,7 @@ SOURCES = \ > >> file.c \ > >> gettextfromc.cpp \ > >> libdivecomputer.c \ > >> + liquivision.c \ > >> load-git.c \ > >> main.cpp \ > >> membuffer.c \ > >> -- > >> 1.8.3.1 > >> > >> _______________________________________________ > >> subsurface mailing list > >> [email protected] > >> http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface > > > > >
_______________________________________________ subsurface mailing list [email protected] http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface
