summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--uemis-downloader.c314
1 files changed, 232 insertions, 82 deletions
diff --git a/uemis-downloader.c b/uemis-downloader.c
index 6f7140640..0cb0f9fe4 100644
--- a/uemis-downloader.c
+++ b/uemis-downloader.c
@@ -59,9 +59,13 @@ static int filenr;
static int number_of_files;
static char *mbuf = NULL;
static int mbuf_size = 0;
-
static int nr_divespots = -1;
+static int buddies_start = 0;
+static int buddies = -1;
+static int max_mem_used = -1;
+static int next_table_index = 0;
+
/* helper function to parse the Uemis data structures */
static void uemis_ts(char *buffer, void *_when)
{
@@ -784,7 +788,7 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, char *
bool done = false;
int inbuflen = strlen(inbuf);
char *endptr = buf + inbuflen;
- bool log = false;
+ bool is_log, is_dive = false;
char *sections[10];
int s, nr_sections = 0;
struct dive *dive = NULL;
@@ -798,7 +802,7 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, char *
tp = next_token(&bp);
if (strcmp(tp, "divelog") == 0) {
/* this is a divelog */
- log = true;
+ is_log = true;
tp = next_token(&bp);
/* is it a valid entry or nothing ? */
if (strcmp(tp, "1.0") != 0 || strstr(inbuf, "divelog{1.0{{{{")) {
@@ -807,6 +811,7 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, char *
}
} else if (strcmp(tp, "dive") == 0) {
/* this is dive detail */
+ is_dive = true;
tp = next_token(&bp);
if (strcmp(tp, "1.0") != 0) {
free(buf);
@@ -817,7 +822,7 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, char *
free(buf);
return false;
}
- if (log) {
+ if (is_log) {
dive = uemis_start_dive(deviceid);
} else {
/* remember, we don't know if this is the right entry,
@@ -857,26 +862,30 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, char *
continue;
}
val = next_token(&bp);
- if (log && !strcmp(tag, "object_id")) {
#if UEMIS_DEBUG & 8
if (strlen(val) < 20)
fprintf(debugfile, "Parsed %s, %s, %s\n*************************\n", tag, type, val);
#endif
+ if (is_log && strcmp(tag, "object_id") == 0) {
free(*max_divenr);
*max_divenr = strdup(val);
dive->dc.diveid = atoi(val);
#if UEMIS_DEBUG % 2
fprintf(debugfile, "Adding new dive from log with object_id %d.\n", atoi(val));
#endif
+ /* glerch Sep. 2015
+ * maybe I am missing something here but this seems wrong
if (keep_number)
dive->number = atoi(val);
- } else if (!log && !strcmp(tag, "logfilenr")) {
+ */
+ } else if (is_dive && strcmp(tag, "logfilenr") == 0) {
/* this one tells us which dive we are adding data to */
dive = get_dive_by_uemis_diveid(devdata, atoi(val));
if (for_dive)
*for_dive = atoi(val);
- } else if (!log && dive && !strcmp(tag, "divespot_id")) {
- dive->dive_site_uuid = create_dive_site("from Uemis", dive->when);
+ } else if (!is_log && dive && !strcmp(tag, "divespot_id")) {
+ timestamp_t t;
+ dive->dive_site_uuid = create_dive_site("from Uemis", (int)time(NULL));
track_divespot(val, dive->dc.diveid, dive->dive_site_uuid);
#if UEMIS_DEBUG & 2
fprintf(debugfile, "Created divesite %d for diveid : %d\n", dive->dive_site_uuid, dive->dc.diveid);
@@ -884,7 +893,7 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, char *
} else if (dive) {
parse_tag(dive, tag, val);
}
- if (log && !strcmp(tag, "file_content"))
+ if (is_log && !strcmp(tag, "file_content"))
done = true;
/* done with one dive (got the file_content tag), but there could be more:
* a '{' indicates the end of the record - but we need to see another "{{"
@@ -897,7 +906,7 @@ static bool process_raw_buffer(device_data_t *devdata, uint32_t deviceid, char *
dive = uemis_start_dive(deviceid);
}
}
- if (log) {
+ if (is_log) {
if (dive->dc.diveid) {
record_uemis_dive(devdata, dive);
mark_divelist_changed(true);
@@ -928,7 +937,7 @@ static char *uemis_get_divenr(char *deviceidstr)
struct dive *d;
for_each_dive (i, d) {
struct divecomputer *dc;
- for_each_dc(d, dc) {
+ for_each_dc (d, dc) {
if (dc->model && !strcmp(dc->model, "Uemis Zurich") &&
(dc->deviceid == 0 || dc->deviceid == 0x7fffffff || dc->deviceid == deviceid) &&
dc->diveid > maxdiveid)
@@ -1008,43 +1017,65 @@ static int get_memory(struct dive_table *td)
return UEMIS_MEM_OK;
}
+/* mark a dive as deleted by setting download to false
+ * this will be picked up by some cleaning statement later */
+static void do_delete_dives(struct dive_table *td, int idx)
+{
+ for (int x = idx; x < td->nr; x++)
+ td->dives[x]->downloaded = false;
+}
+
const char *do_uemis_import(device_data_t *data)
{
const char *mountpath = data->devname;
short force_download = data->force_download;
char *newmax = NULL;
int first, start, end = -2;
- int i, offset = 0;
+ int i = 0;
uint32_t deviceidnr;
- char objectid[10];
+ //char objectid[10];
char *deviceid = NULL;
const char *result = NULL;
char *endptr;
bool success, keep_number = false, once = true;
+ char dive_to_read_buf[10];
+ char log_file_no_to_find[20];
+ int deleted_files = 0;
+ int last_found_log_file_nr = 0;
+ int match_dive_and_log = 0;
+ int start_cleanup = 0;
+ struct dive_table *td = NULL;
+ struct dive *dive = NULL;
+ int uemis_mem_status = UEMIS_MEM_OK;
+
+ const char *dTime;
if (dive_table.nr == 0)
keep_number = true;
+
uemis_info(translate("gettextFromC", "Initialise communication"));
if (!uemis_init(mountpath)) {
free(reqtxt_path);
return translate("gettextFromC", "Uemis init failed");
}
+
if (!uemis_get_answer(mountpath, "getDeviceId", 0, 1, &result))
goto bail;
deviceid = strdup(param_buff[0]);
deviceidnr = atoi(deviceid);
- /* the answer from the DeviceId call becomes the input parameter for getDeviceData */
- if (!uemis_get_answer(mountpath, "getDeviceData", 1, 0, &result))
- goto bail;
+
/* param_buff[0] is still valid */
if (!uemis_get_answer(mountpath, "initSession", 1, 6, &result))
goto bail;
+
uemis_info(translate("gettextFromC", "Start download"));
if (!uemis_get_answer(mountpath, "processSync", 0, 2, &result))
goto bail;
+
/* before starting the long download, check if user pressed cancel */
if (import_thread_cancelled)
goto bail;
+
param_buff[1] = "notempty";
/* if we force it we start downloading from the first dive on the Uemis;
* otherwise check which was the last dive downloaded */
@@ -1052,108 +1083,227 @@ const char *do_uemis_import(device_data_t *data)
newmax = uemis_get_divenr(deviceid);
else
newmax = strdup("0");
+
+ // newmax = strdup("240");
first = start = atoi(newmax);
+
+#if UEMIS_DEBUG & 2
+ int rounds = -1;
+ int round = 0;
+#endif
for (;;) {
+#if UEMIS_DEBUG & 2
+ round++;
+#endif
#if UEMIS_DEBUG & 4
fprintf(debugfile, "d_u_i inner loop start %d end %d newmax %s\n", start, end, newmax);
#endif
+ /* start at the last filled download table index */
+ start_cleanup = match_dive_and_log = data->download_table->nr;
+ sprintf(newmax, "%d", start);
param_buff[2] = newmax;
param_buff[3] = 0;
success = uemis_get_answer(mountpath, "getDivelogs", 3, 0, &result);
- /* process the buffer we have assembled */
- if (mbuf)
+ uemis_mem_status = get_memory(data->download_table);
+ if (success && mbuf && uemis_mem_status != UEMIS_MEM_FULL) {
+#if UEMIS_DEBUG % 2
+ do_dump_buffer_to_file(mbuf, strdup("Divelogs"), round);
+#endif
+ /* process the buffer we have assembled */
+
if (!process_raw_buffer(data, deviceidnr, mbuf, &newmax, keep_number, NULL)) {
/* if no dives were downloaded, mark end appropriately */
if (end == -2)
end = start - 1;
success = false;
}
- if (once) {
- char *t = first_object_id_val(mbuf);
- if (t && atoi(t) > start)
- start = atoi(t);
- free(t);
- once = false;
- }
- /* clean up mbuf */
- endptr = strstr(mbuf, "{{{");
- if (endptr)
- *(endptr + 2) = '\0';
- /* last object_id we parsed */
- sscanf(newmax, "%d", &end);
+ if (once) {
+ char *t = first_object_id_val(mbuf);
+ if (t && atoi(t) > start)
+ start = atoi(t);
+ free(t);
+ once = false;
+ }
+ /* clean up mbuf */
+ endptr = strstr(mbuf, "{{{");
+ if (endptr)
+ *(endptr + 2) = '\0';
+ /* last object_id we parsed */
+ sscanf(newmax, "%d", &end);
#if UEMIS_DEBUG & 4
- fprintf(debugfile, "d_u_i after download and parse start %d end %d newmax %s progress %4.2f\n", start, end, newmax, progress_bar_fraction);
+ fprintf(debugfile, "d_u_i after download and parse start %d end %d newmax %s progress %4.2f\n", start, end, newmax, progress_bar_fraction);
+#endif
+ /* The way this works is that I am reading the current dive from what has been loaded during the getDiveLogs call to the UEMIS.
+ * As the object_id of the divelog entry and the object_id of the dive details are not necessarily the same, the match needs
+ * to happen based on the logfilenr.
+ * What the following part does is to optimize the mapping by using
+ * dive_to_read = the dive deatils entry that need to be read using the object_id
+ * logFileNoToFind = map the logfilenr of the dive details with the object_id = diveid from the get dive logs */
+ int dive_to_read = (last_found_log_file_nr > 0 ? last_found_log_file_nr + 1 : start);
+ td = data->download_table;
+
+ for (int i = match_dive_and_log; i < td->nr; i++) {
+ dive = td->dives[i];
+ dTime = get_dive_date_c_string(dive->when);
+ snprintf(log_file_no_to_find, sizeof(log_file_no_to_find), "logfilenr{int{%d", dive->dc.diveid);
+
+ bool found = false;
+ while (!found) {
+ snprintf(dive_to_read_buf, sizeof(dive_to_read_buf), "%d", dive_to_read);
+ param_buff[2] = dive_to_read_buf;
+ success = uemis_get_answer(mountpath, "getDive", 3, 0, &result);
+#if UEMIS_DEBUG % 2
+ do_dump_buffer_to_file(mbuf, strdup("Dive"), round);
#endif
- /* now download the additional dive data with "getDive" for the dives
- * we just downloaded - yes, this is completely insane - why isn't all of
- * this downloaded in the first place??? */
- for (i = start; i <= end; i++) {
- snprintf(objectid, sizeof(objectid), "%d", i + offset);
- param_buff[2] = objectid;
+ uemis_mem_status = get_memory(data->download_table);
+ if (uemis_mem_status == UEMIS_MEM_OK || uemis_mem_status == UEMIS_MEM_CRITICAL) {
+ /* if the memory isn's completely full we can try to read more divelog vs. dive details
+ * UEMIS_MEM_CRITICAL means not enough space for a full round but the dive details
+ * and the divespots should fit into the UEMIS memory
+ * The match we do here is to map the object_id to the logfilenr, we do this
+ * by iterating through the last set of loaded divelogs and then find the corresponding
+ * dive with the matching logfilenr */
+ if (mbuf) {
+ if (strstr(mbuf, log_file_no_to_find)) {
+ /* we found the logfilenr that matches our object_id from the divelog we were looking for
+ * we mark the search sucessfull even if the dive has been deleted. */
+ found = true;
+ process_raw_buffer(data, deviceidnr, mbuf, &newmax, false, NULL);
+ if (strstr(mbuf, strdup("deleted{bool{true")) == NULL) {
+ /* remember the last log file number as it is very likely that subsequent dives
+ * have the same or higher logfile number.
+ * UEMIS unfortunately deletes dives by deleting the dive details and not the logs. */
#if UEMIS_DEBUG & 2
- fprintf(debugfile, "getDive %d, object_id %s\n", i, objectid);
+ fprintf(debugfile, "Matching divelog id %d from %s with dive details %d\n", dive->dc.diveid, dTime, iDiveToRead);
#endif
- /* there is no way I have found to directly get the dive information
- * for dive #i as the object_id and logfilenr can be different in the
- * getDive call; so we get the first one, compare the actual divenr
- * with the one that we wanted, calculate the offset and try again.
- * What an insane design... */
- success = uemis_get_answer(mountpath, "getDive", 3, 0, &result);
- if (mbuf) {
- int divenr;
- (void)process_raw_buffer(data, deviceidnr, mbuf, &newmax, false, &divenr);
+ last_found_log_file_nr = dive_to_read;
+ } else {
+ /* in this case we found a deleted file, so let's increment */
#if UEMIS_DEBUG & 2
- fprintf(debugfile, "got dive %d, looking for dive %d\n", divenr, i);
+ fprintf(debugfile, "TRY matching divelog id %d from %s with dive details %d but details are deleted\n", dive->dc.diveid, dTime, iDiveToRead);
#endif
- if (divenr != i) {
- if (divenr == -1) {
- offset--;
- } else {
- offset += i - divenr;
- }
+ deleted_files++;
+ /* mark this log entry as deleted and cleanup later, otherwise we mess up our array */
+ dive->downloaded = false;
#if UEMIS_DEBUG & 2
- fprintf(debugfile, " -> trying again with offset %d\n", offset);
+ fprintf(debugfile, "Deleted dive from %s, with id %d from table\n", dTime, dive->dc.diveid);
#endif
- i = start - 1;
- if (i + offset < 0)
+ }
+ } else {
+ /* Ugly, need something better than this
+ * essentially, if we start reading divelogs not from the start
+ * we have no idea on how many log entries are there that have no
+ * valid dive details */
+ if (dive_to_read >= dive->dc.diveid)
+ dive_to_read = (dive_to_read - 2 >= 0 ? dive_to_read - 2 : 0);
+ }
+ }
+ dive_to_read++;
+ } else {
+ /* At this point the memory of the UEMIS is full, let's cleanup all divelog files were
+ * we could not match the details to. */
+ do_delete_dives(td, i);
break;
- continue;
+ }
}
+ /* decrement iDiveToRead by the amount of deleted entries found to assure
+ * we are not missing any valid matches when processing subsequent logs */
+ dive_to_read = (dive_to_read - deleted_files > 0 ? dive_to_read - deleted_files : 0);
+ deleted_files = 0;
+ if (uemis_mem_status == UEMIS_MEM_FULL)
+ /* game over, not enough memory left */
+ break;
}
- if (!success || import_thread_cancelled)
+
+ /*
+ for (int i = iStartCleanup; i < data->download_table->nr; i++)
+ if (!data->download_table->dives[i]->downloaded) {
+ uemis_delete_dive(data, data->download_table->dives[i]->dc.diveid);
+ i = (i > iStartCleanup ? i-- : i = iStartCleanup);
+ }
+ */
+ start = end;
+
+ /* Do some memory checking here */
+ uemis_mem_status = get_memory(data->download_table);
+ if (uemis_mem_status != UEMIS_MEM_OK)
break;
- }
- start = end + 1;
- /* if the user clicked cancel, exit gracefully */
- if (import_thread_cancelled)
- goto bail;
- /* if we got an error or got nothing back, stop trying */
- if (!success || !param_buff[3])
- break;
- /* finally, if the memory is getting too full, maybe we better stop, too */
- if (progress_bar_fraction > 0.80) {
- result = translate("gettextFromC", ERR_FS_ALMOST_FULL);
+
+ /* if the user clicked cancel, exit gracefully */
+ if (import_thread_cancelled)
+ break;
+
+ /* if we got an error or got nothing back, stop trying */
+ if (!success || !param_buff[3])
+ break;
+
+ /* finally, if the memory is getting too full, maybe we better stop, too */
+ if (progress_bar_fraction > 0.80) {
+ result = translate("gettextFromC", ERR_FS_ALMOST_FULL);
+ break;
+ }
+
+
+#if UEMIS_DEBUG & 2
+ if (rounds != -1)
+ if (rounds-- == 0)
+ goto bail;
+#endif
+ } else {
+ /* some of the loading from the UEMIS failed at the divelog level
+ * if the memory status = full, we cant even load the divespots and/or buddys.
+ * The loaded block of divelogs is useless and all new loaded divelogs need to
+ * be deleted from the download_table.
+ */
+ if (uemis_mem_status == UEMIS_MEM_FULL)
+ do_delete_dives(data->download_table, match_dive_and_log);
break;
}
}
+
if (end == -2 && sscanf(newmax, "%d", &end) != 1)
end = start;
+
#if UEMIS_DEBUG & 2
- fprintf(debugfile, "done: read from object_id %d to %d\n", first, end);
+ fprintf(debugfile, "Done: read from object_id %d to %d\n", first, end);
#endif
- free(newmax);
- success = true;
- for (i = 0; i <= nr_divespots; i++) {
- char divespotnr[10];
- snprintf(divespotnr, sizeof(divespotnr), "%d", i);
- param_buff[2] = divespotnr;
+
+ /* Regardless on where we are with the memory situation, it's time now
+ * to see if we have to clean some dead bodies from our download table */
+ next_table_index = 0;
+ while (data->download_table->dives[next_table_index]) {
+ if (!data->download_table->dives[next_table_index]->downloaded)
+ uemis_delete_dive(data, data->download_table->dives[next_table_index]->dc.diveid);
+ else
+ next_table_index++;
+ }
+
+ switch (uemis_mem_status) {
+ case UEMIS_MEM_CRITICAL:
+ case UEMIS_MEM_OK:
+ for (i = 0; i <= nr_divespots; i++) {
+ char divespotnr[10];
+ snprintf(divespotnr, sizeof(divespotnr), "%d", i);
+ param_buff[2] = divespotnr;
+#if UEMIS_DEBUG & 2
+ fprintf(debugfile, "getDivespot %d of %d, started at %d\n", i, nr_divespots, 0);
+#endif
+ success = uemis_get_answer(mountpath, "getDivespot", 3, 0, &result);
+ if (mbuf && success) {
#if UEMIS_DEBUG & 2
- fprintf(debugfile, "getDivespot %d\n", i);
+ do_dump_buffer_to_file(mbuf, strdup("Spot"), round);
#endif
- success = uemis_get_answer(mountpath, "getDivespot", 3, 0, &result);
- if (mbuf)
- parse_divespot(mbuf);
+ parse_divespot(mbuf);
+ }
+ }
+ if (uemis_mem_status == UEMIS_MEM_CRITICAL)
+ result = translate("gettextFromC", ERR_FS_ALMOST_FULL);
+ break;
+ case UEMIS_MEM_FULL:
+ result = translate("gettextFromC", ERR_FS_FULL);
+ break;
}
+
bail:
(void)uemis_get_answer(mountpath, "terminateSync", 0, 3, &result);
if (!strcmp(param_buff[0], "error")) {