void finish_sample(sep_sample_t &sample, const vec_mutation_t &fixations, const unsigned nsam, const bool removeFixed, const sugar::treat_neutral) { finish_sample(sample.first, fixations, nsam, removeFixed, sugar::treat_neutral::NEUTRAL); finish_sample(sample.second, fixations, nsam, removeFixed, sugar::treat_neutral::SELECTED); }
static void sample_parser(char *line, struct divecomputer *dc) { int m, s = 0; struct sample *sample = new_sample(dc); m = strtol(line, &line, 10); if (*line == ':') s = strtol(line+1, &line, 10); sample->time.seconds = m*60+s; for (;;) { char c; while (isspace(c = *line)) line++; if (!c) break; /* Less common sample entries have a name */ if (c >= 'a' && c <= 'z') { line = parse_keyvalue_entry(parse_sample_keyvalue, sample, line); } else { const char *end; double val = ascii_strtod(line, &end); if (end == line) { report_error("Odd sample data: %s", line); break; } line = (char *)end; line = parse_sample_unit(sample, val, line); } } finish_sample(dc); }
std::vector<sample_t> sample_details( const poptype &p, const std::vector<integer_type> &individuals, const bool removeFixed, const std::vector<std::pair<double, double>> &locus_boundaries) { auto temp = fwdpp_internal::ms_sample_separate_mlocus( p.mutations, p.gametes, p.diploids, individuals, 2 * individuals.size(), removeFixed); if (!removeFixed && temp.size() != locus_boundaries.size()) { throw std::runtime_error( "incorrect number of elements in locus_boundaries"); } std::vector<sample_t> rv; std::size_t j = 0; for (auto &i : temp) { rv.emplace_back(std::move(i.first)); std::move(i.second.begin(), i.second.end(), std::back_inserter(rv[j])); } for (std::size_t i = 0; i < locus_boundaries.size(); ++i) { finish_sample(rv.at(i), p.fixations, 2 * individuals.size(), removeFixed, sugar::treat_neutral::ALL, locus_boundaries.at(i)); } return rv; }
void finish_sample( std::vector<sep_sample_t> &sample, const vec_mutation_t &fixations, const unsigned nsam, const bool removeFixed, const sugar::treat_neutral, const std::vector<std::pair<double, double>> &locus_boundaries) { for (std::size_t i = 0; i < sample.size(); ++i) { finish_sample(sample[i].first, fixations, nsam, removeFixed, sugar::treat_neutral::NEUTRAL, locus_boundaries.at(i)); finish_sample(sample[i].second, fixations, nsam, removeFixed, sugar::treat_neutral::SELECTED, locus_boundaries.at(i)); } }
int try_to_open_csv(struct memblock *mem, enum csv_format type) { char *p = mem->buffer; char *header[8]; int i, time; timestamp_t date; struct dive *dive; struct divecomputer *dc; for (i = 0; i < 8; i++) { header[i] = p; p = strchr(p, ','); if (!p) return 0; p++; } date = parse_date(header[2]); if (!date) return 0; dive = alloc_dive(); dive->when = date; dive->number = atoi(header[1]); dc = &dive->dc; time = 0; for (;;) { char *end; double val; struct sample *sample; errno = 0; val = strtod(p, &end); // FIXME == localization issue if (end == p) break; if (errno) break; sample = prepare_sample(dc); sample->time.seconds = time; add_sample_data(sample, type, val); finish_sample(dc); time++; dc->duration.seconds = time; if (*end != ',') break; p = end + 1; } record_dive(dive); return 1; }
void sample_cb(parser_sample_type_t type, parser_sample_value_t value, void *userdata) { int i; struct dive **divep = userdata; struct dive *dive = *divep; struct sample *sample; /* * We fill in the "previous" sample - except for SAMPLE_TYPE_TIME, * which creates a new one. */ sample = dive->samples ? dive->sample+dive->samples-1 : NULL; switch (type) { case SAMPLE_TYPE_TIME: sample = prepare_sample(divep); sample->time.seconds = value.time; finish_sample(*divep, sample); break; case SAMPLE_TYPE_DEPTH: sample->depth.mm = value.depth * 1000 + 0.5; break; case SAMPLE_TYPE_PRESSURE: sample->cylinderindex = value.pressure.tank; sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5; break; case SAMPLE_TYPE_TEMPERATURE: sample->temperature.mkelvin = (value.temperature + 273.15) * 1000 + 0.5; break; case SAMPLE_TYPE_EVENT: handle_event(dive, sample, value); break; case SAMPLE_TYPE_RBT: printf(" <rbt>%u</rbt>\n", value.rbt); break; case SAMPLE_TYPE_HEARTBEAT: printf(" <heartbeat>%u</heartbeat>\n", value.heartbeat); break; case SAMPLE_TYPE_BEARING: printf(" <bearing>%u</bearing>\n", value.bearing); break; case SAMPLE_TYPE_VENDOR: printf(" <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size); for (i = 0; i < value.vendor.size; ++i) printf("%02X", ((unsigned char *) value.vendor.data)[i]); printf("</vendor>\n"); break; default: break; } }
static void sample_end(void) { if (!cur_dive) return; finish_sample(get_dc()); lastndl = cur_sample->ndl.seconds; lastindeco = cur_sample->in_deco; laststoptime = cur_sample->stoptime.seconds; laststopdepth = cur_sample->stopdepth.mm; lastcns = cur_sample->cns; lastpo2 = cur_sample->po2; cur_sample = NULL; }
sample_t sample_details(const poptype &p, const std::vector<integer_type> &individuals, const bool removeFixed) { sep_sample_t temp = fwdpp_internal::ms_sample_separate_single_deme( p.mutations, p.gametes, p.diploids, individuals, 2 * individuals.size(), removeFixed); auto rv = std::move(temp.first); std::move(temp.second.begin(), temp.second.end(), std::back_inserter(rv)); finish_sample(rv, p.fixations, 2 * individuals.size(), removeFixed, sugar::treat_neutral::ALL); return rv; }
/* simply overwrite the data in the displayed_dive * return false if something goes wrong */ static void create_dive_from_plan(struct diveplan *diveplan, bool track_gas) { struct divedatapoint *dp; struct divecomputer *dc; struct sample *sample; struct gasmix oldgasmix; struct event *ev; cylinder_t *cyl; int oldpo2 = 0; int lasttime = 0; int lastdepth = 0; if (!diveplan || !diveplan->dp) return; #if DEBUG_PLAN & 4 printf("in create_dive_from_plan\n"); dump_plan(diveplan); #endif // reset the cylinders and clear out the samples and events of the // displayed dive so we can restart reset_cylinders(&displayed_dive, track_gas); dc = &displayed_dive.dc; free(dc->sample); dc->sample = NULL; dc->samples = 0; dc->alloc_samples = 0; while ((ev = dc->events)) { dc->events = dc->events->next; free(ev); } dp = diveplan->dp; cyl = &displayed_dive.cylinder[0]; oldgasmix = cyl->gasmix; sample = prepare_sample(dc); sample->po2.mbar = dp->po2; if (track_gas && cyl->type.workingpressure.mbar) sample->cylinderpressure.mbar = cyl->end.mbar; finish_sample(dc); while (dp) { struct gasmix gasmix = dp->gasmix; int po2 = dp->po2; int time = dp->time; int depth = dp->depth; if (time == 0) { /* special entries that just inform the algorithm about * additional gases that are available */ if (verify_gas_exists(gasmix) < 0) goto gas_error_exit; dp = dp->next; continue; } /* Check for SetPoint change */ if (oldpo2 != po2) { if (lasttime) /* this is a bad idea - we should get a different SAMPLE_EVENT type * reserved for this in libdivecomputer... overloading SMAPLE_EVENT_PO2 * with a different meaning will only cause confusion elsewhere in the code */ add_event(dc, lasttime, SAMPLE_EVENT_PO2, 0, po2, "SP change"); oldpo2 = po2; } /* Make sure we have the new gas, and create a gas change event */ if (gasmix_distance(&gasmix, &oldgasmix) > 0) { int idx; if ((idx = verify_gas_exists(gasmix)) < 0) goto gas_error_exit; /* need to insert a first sample for the new gas */ add_gas_switch_event(&displayed_dive, dc, lasttime + 1, idx); cyl = &displayed_dive.cylinder[idx]; sample = prepare_sample(dc); sample[-1].po2.mbar = po2; sample->time.seconds = lasttime + 1; sample->depth.mm = lastdepth; if (track_gas && cyl->type.workingpressure.mbar) sample->cylinderpressure.mbar = cyl->sample_end.mbar; finish_sample(dc); oldgasmix = gasmix; } /* Create sample */ sample = prepare_sample(dc); /* set po2 at beginning of this segment */ /* and keep it valid for last sample - where it likely doesn't matter */ sample[-1].po2.mbar = po2; sample->po2.mbar = po2; sample->time.seconds = lasttime = time; sample->depth.mm = lastdepth = depth; if (track_gas) { update_cylinder_pressure(&displayed_dive, sample[-1].depth.mm, depth, time - sample[-1].time.seconds, dp->entered ? diveplan->bottomsac : diveplan->decosac, cyl, !dp->entered); if (cyl->type.workingpressure.mbar) sample->cylinderpressure.mbar = cyl->end.mbar; } finish_sample(dc); dp = dp->next; } #if DEBUG_PLAN & 32 save_dive(stdout, &displayed_dive); #endif return; gas_error_exit: report_error(translate("gettextFromC", "Too many gas mixes")); return; }
int parse_txt_file(const char *filename, const char *csv) { struct memblock memtxt, memcsv; if (readfile(filename, &memtxt) < 0) { return report_error(translate("gettextFromC", "Failed to read '%s'"), filename); } /* * MkVI stores some information in .txt file but the whole profile and events are stored in .csv file. First * make sure the input .txt looks like proper MkVI file, then start parsing the .csv. */ if (MATCH(memtxt.buffer, "MkVI_Config") == 0) { int d, m, y, he; int hh = 0, mm = 0, ss = 0; int prev_depth = 0, cur_sampletime = 0, prev_setpoint = -1, prev_ndl = -1; bool has_depth = false, has_setpoint = false, has_ndl = false; char *lineptr, *key, *value; int cur_cylinder_index = 0; unsigned int prev_time = 0; struct dive *dive; struct divecomputer *dc; struct tm cur_tm; value = parse_mkvi_value(memtxt.buffer, "Dive started at"); if (sscanf(value, "%d-%d-%d %d:%d:%d", &y, &m, &d, &hh, &mm, &ss) != 6) { free(value); return -1; } free(value); cur_tm.tm_year = y; cur_tm.tm_mon = m - 1; cur_tm.tm_mday = d; cur_tm.tm_hour = hh; cur_tm.tm_min = mm; cur_tm.tm_sec = ss; dive = alloc_dive(); dive->when = utc_mktime(&cur_tm);; dive->dc.model = strdup("Poseidon MkVI Discovery"); value = parse_mkvi_value(memtxt.buffer, "Rig Serial number"); dive->dc.deviceid = atoi(value); free(value); dive->dc.divemode = CCR; dive->dc.no_o2sensors = 2; dive->cylinder[cur_cylinder_index].cylinder_use = OXYGEN; dive->cylinder[cur_cylinder_index].type.size.mliter = 3000; dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = 200000; dive->cylinder[cur_cylinder_index].type.description = strdup("3l Mk6"); dive->cylinder[cur_cylinder_index].gasmix.o2.permille = 1000; cur_cylinder_index++; dive->cylinder[cur_cylinder_index].cylinder_use = DILUENT; dive->cylinder[cur_cylinder_index].type.size.mliter = 3000; dive->cylinder[cur_cylinder_index].type.workingpressure.mbar = 200000; dive->cylinder[cur_cylinder_index].type.description = strdup("3l Mk6"); value = parse_mkvi_value(memtxt.buffer, "Helium percentage"); he = atoi(value); free(value); value = parse_mkvi_value(memtxt.buffer, "Nitrogen percentage"); dive->cylinder[cur_cylinder_index].gasmix.o2.permille = (100 - atoi(value) - he) * 10; free(value); dive->cylinder[cur_cylinder_index].gasmix.he.permille = he * 10; cur_cylinder_index++; lineptr = strstr(memtxt.buffer, "Dive started at"); while (!empty_string(lineptr) && (lineptr = strchr(lineptr, '\n'))) { ++lineptr; // Skip over '\n' key = next_mkvi_key(lineptr); if (!key) break; value = parse_mkvi_value(lineptr, key); if (!value) { free(key); break; } add_extra_data(&dive->dc, key, value); free(key); free(value); } dc = &dive->dc; /* * Read samples from the CSV file. A sample contains all the lines with same timestamp. The CSV file has * the following format: * * timestamp, type, value * * And following fields are of interest to us: * * 6 sensor1 * 7 sensor2 * 8 depth * 13 o2 tank pressure * 14 diluent tank pressure * 20 o2 setpoint * 39 water temp */ if (readfile(csv, &memcsv) < 0) { free(dive); return report_error(translate("gettextFromC", "Poseidon import failed: unable to read '%s'"), csv); } lineptr = memcsv.buffer; for (;;) { struct sample *sample; int type; int value; int sampletime; int gaschange = 0; /* Collect all the information for one sample */ sscanf(lineptr, "%d,%d,%d", &cur_sampletime, &type, &value); has_depth = false; has_setpoint = false; has_ndl = false; sample = prepare_sample(dc); /* * There was a bug in MKVI download tool that resulted in erroneous sample * times. This fix should work similarly as the vendor's own. */ sample->time.seconds = cur_sampletime < 0xFFFF * 3 / 4 ? cur_sampletime : prev_time; prev_time = sample->time.seconds; do { int i = sscanf(lineptr, "%d,%d,%d", &sampletime, &type, &value); switch (i) { case 3: switch (type) { case 0: //Mouth piece position event: 0=OC, 1=CC, 2=UN, 3=NC switch (value) { case 0: add_event(dc, cur_sampletime, 0, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position OC")); break; case 1: add_event(dc, cur_sampletime, 0, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position CC")); break; case 2: add_event(dc, cur_sampletime, 0, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position unknown")); break; case 3: add_event(dc, cur_sampletime, 0, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "Mouth piece position not connected")); break; } break; case 3: //Power Off event add_event(dc, cur_sampletime, 0, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "Power off")); break; case 4: //Battery State of Charge in % #ifdef SAMPLE_EVENT_BATTERY add_event(dc, cur_sampletime, SAMPLE_EVENT_BATTERY, 0, value, QT_TRANSLATE_NOOP("gettextFromC", "battery")); #endif break; case 6: //PO2 Cell 1 Average add_sample_data(sample, POSEIDON_SENSOR1, value); break; case 7: //PO2 Cell 2 Average add_sample_data(sample, POSEIDON_SENSOR2, value); break; case 8: //Depth * 2 has_depth = true; prev_depth = value; add_sample_data(sample, POSEIDON_DEPTH, value); break; //9 Max Depth * 2 //10 Ascent/Descent Rate * 2 case 11: //Ascent Rate Alert >10 m/s add_event(dc, cur_sampletime, SAMPLE_EVENT_ASCENT, 0, 0, QT_TRANSLATE_NOOP("gettextFromC", "ascent")); break; case 13: //O2 Tank Pressure add_sample_pressure(sample, 0, lrint(value * 1000)); break; case 14: //Diluent Tank Pressure add_sample_pressure(sample, 1, lrint(value * 1000)); break; //16 Remaining dive time #1? //17 related to O2 injection case 20: //PO2 Setpoint has_setpoint = true; prev_setpoint = value; add_sample_data(sample, POSEIDON_SETPOINT, value); break; case 22: //End of O2 calibration Event: 0 = OK, 2 = Failed, rest of dive setpoint 1.0 if (value == 2) add_event(dc, cur_sampletime, 0, SAMPLE_FLAGS_END, 0, QT_TRANSLATE_NOOP("gettextFromC", "O₂ calibration failed")); add_event(dc, cur_sampletime, 0, SAMPLE_FLAGS_END, 0, QT_TRANSLATE_NOOP("gettextFromC", "O₂ calibration")); break; case 25: //25 Max Ascent depth add_sample_data(sample, POSEIDON_CEILING, value); break; case 31: //Start of O2 calibration Event add_event(dc, cur_sampletime, 0, SAMPLE_FLAGS_BEGIN, 0, QT_TRANSLATE_NOOP("gettextFromC", "O₂ calibration")); break; case 37: //Remaining dive time #2? has_ndl = true; prev_ndl = value; add_sample_data(sample, POSEIDON_NDL, value); break; case 39: // Water Temperature in Celcius add_sample_data(sample, POSEIDON_TEMP, value); break; case 85: //He diluent part in % gaschange += value << 16; break; case 86: //O2 diluent part in % gaschange += value; break; //239 Unknown, maybe PO2 at sensor validation? //240 Unknown, maybe PO2 at sensor validation? //247 Unknown, maybe PO2 Cell 1 during pressure test //248 Unknown, maybe PO2 Cell 2 during pressure test //250 PO2 Cell 1 //251 PO2 Cell 2 default: break; } /* sample types */ break; case EOF: break; default: printf("Unable to parse input: %s\n", lineptr); break; } lineptr = strchr(lineptr, '\n'); if (!lineptr || !*lineptr) break; lineptr++; /* Grabbing next sample time */ sscanf(lineptr, "%d,%d,%d", &cur_sampletime, &type, &value); } while (sampletime == cur_sampletime); if (gaschange) add_event(dc, cur_sampletime, SAMPLE_EVENT_GASCHANGE2, 0, gaschange, QT_TRANSLATE_NOOP("gettextFromC", "gaschange")); if (!has_depth) add_sample_data(sample, POSEIDON_DEPTH, prev_depth); if (!has_setpoint && prev_setpoint >= 0) add_sample_data(sample, POSEIDON_SETPOINT, prev_setpoint); if (!has_ndl && prev_ndl >= 0) add_sample_data(sample, POSEIDON_NDL, prev_ndl); finish_sample(dc); if (!lineptr || !*lineptr) break; } record_dive(dive); return 1; } else { return 0; } return 0; }
/* * Parse sample data, extract events and build a dive */ static void cochran_parse_samples(struct dive *dive, const unsigned char *log, const unsigned char *samples, unsigned int size, unsigned int *duration, double *max_depth, double *avg_depth, double *min_temp) { const unsigned char *s; unsigned int offset = 0, profile_period = 1, sample_cnt = 0; double depth = 0, temp = 0, depth_sample = 0, psi = 0, sgc_rate = 0; int ascent_rate = 0; unsigned int ndl = 0; unsigned int in_deco = 0, deco_ceiling = 0, deco_time = 0; struct divecomputer *dc = &dive->dc; struct sample *sample; // Initialize stat variables *max_depth = 0, *avg_depth = 0, *min_temp = 0xFF; // Get starting depth and temp (tank PSI???) switch (config.type) { case TYPE_GEMINI: depth = (float) (log[CMD_START_DEPTH] + log[CMD_START_DEPTH + 1] * 256) / 4; temp = log[CMD_START_TEMP]; psi = log[CMD_START_PSI] + log[CMD_START_PSI + 1] * 256; sgc_rate = (float)(log[CMD_START_SGC] + log[CMD_START_SGC + 1] * 256) / 2; profile_period = log[CMD_PROFILE_PERIOD]; break; case TYPE_COMMANDER: depth = (float) (log[CMD_START_DEPTH] + log[CMD_START_DEPTH + 1] * 256) / 4; temp = log[CMD_START_TEMP]; profile_period = log[CMD_PROFILE_PERIOD]; break; case TYPE_EMC: depth = (float) log [EMC_START_DEPTH] / 256 + log[EMC_START_DEPTH + 1]; temp = log[EMC_START_TEMP]; profile_period = log[EMC_PROFILE_PERIOD]; break; } // Skip past pre-dive events unsigned int x = 0; unsigned int c; while (x < size && (samples[x] & 0x80) == 0 && samples[x] != 0x40) { c = cochran_predive_event_bytes(samples[x]) + 1; #ifdef COCHRAN_DEBUG printf("Predive event: "); for (unsigned int y = 0; y < c && x + y < size; y++) printf("%02x ", samples[x + y]); putchar('\n'); #endif x += c; } // Now process samples offset = x; while (offset + config.sample_size < size) { s = samples + offset; // Start with an empty sample sample = prepare_sample(dc); sample->time.seconds = sample_cnt * profile_period; // Check for event if (s[0] & 0x80) { cochran_dive_event(dc, s, sample_cnt * profile_period, &in_deco, &deco_ceiling, &deco_time); offset += cochran_dive_event_bytes(s[0]) + 1; continue; } // Depth is in every sample depth_sample = (float)(s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1); depth += depth_sample; #ifdef COCHRAN_DEBUG cochran_debug_sample(s, sample_cnt); #endif switch (config.type) { case TYPE_COMMANDER: switch (sample_cnt % 2) { case 0: // Ascent rate ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1); break; case 1: // Temperature temp = s[1] / 2 + 20; break; } break; case TYPE_GEMINI: // Gemini with tank pressure and SAC rate. switch (sample_cnt % 4) { case 0: // Ascent rate ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1); break; case 2: // PSI change psi -= (float)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 4; break; case 1: // SGC rate sgc_rate -= (float)(s[1] & 0x7f) * (s[1] & 0x80 ? 1 : -1) / 2; break; case 3: // Temperature temp = (float)s[1] / 2 + 20; break; } break; case TYPE_EMC: switch (sample_cnt % 2) { case 0: // Ascent rate ascent_rate = (s[1] & 0x7f) * (s[1] & 0x80 ? 1: -1); break; case 1: // Temperature temp = (float)s[1] / 2 + 20; break; } // Get NDL and deco information switch (sample_cnt % 24) { case 20: if (offset + 5 < size) { if (in_deco) { // Fist stop time //first_deco_time = (s[2] + s[5] * 256 + 1) * 60; // seconds ndl = 0; } else { // NDL ndl = (s[2] + s[5] * 256 + 1) * 60; // seconds deco_time = 0; } } break; case 22: if (offset + 5 < size) { if (in_deco) { // Total stop time deco_time = (s[2] + s[5] * 256 + 1) * 60; // seconds ndl = 0; } } break; } } // Track dive stats if (depth > *max_depth) *max_depth = depth; if (temp < *min_temp) *min_temp = temp; *avg_depth = (*avg_depth * sample_cnt + depth) / (sample_cnt + 1); sample->depth.mm = lrint(depth * FEET * 1000); sample->ndl.seconds = ndl; sample->in_deco = in_deco; sample->stoptime.seconds = deco_time; sample->stopdepth.mm = lrint(deco_ceiling * FEET * 1000); sample->temperature.mkelvin = C_to_mkelvin((temp - 32) / 1.8); sample->sensor[0] = 0; sample->pressure[0].mbar = lrint(psi * PSI / 100); finish_sample(dc); offset += config.sample_size; sample_cnt++; } UNUSED(ascent_rate); // mark the variable as unused if (sample_cnt > 0) *duration = sample_cnt * profile_period - 1; }