diff options
Diffstat (limited to 'core/dive.c')
-rw-r--r-- | core/dive.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/core/dive.c b/core/dive.c index c977183a3..da4b19346 100644 --- a/core/dive.c +++ b/core/dive.c @@ -4062,3 +4062,245 @@ fraction_t best_he(depth_t depth, struct dive *dive) fhe.permille = 0; return fhe; } + +bool gasmix_is_air(const struct gasmix *gasmix) +{ + int o2 = gasmix->o2.permille; + int he = gasmix->he.permille; + return (he == 0) && (o2 == 0 || ((o2 >= O2_IN_AIR - 1) && (o2 <= O2_IN_AIR + 1))); +} + +void invalidate_dive_cache(struct dive *dive) +{ + memset(dive->git_id, 0, 20); +} + +bool dive_cache_is_valid(const struct dive *dive) +{ + static const unsigned char null_id[20] = { 0, }; + return !!memcmp(dive->git_id, null_id, 20); +} + +int get_surface_pressure_in_mbar(const struct dive *dive, bool non_null) +{ + int mbar = dive->surface_pressure.mbar; + if (!mbar && non_null) + mbar = SURFACE_PRESSURE; + return mbar; +} + +/* Pa = N/m^2 - so we determine the weight (in N) of the mass of 10m + * of water (and use standard salt water at 1.03kg per liter if we don't know salinity) + * and add that to the surface pressure (or to 1013 if that's unknown) */ +int calculate_depth_to_mbar(int depth, pressure_t surface_pressure, int salinity) +{ + double specific_weight; + int mbar = surface_pressure.mbar; + + if (!mbar) + mbar = SURFACE_PRESSURE; + if (!salinity) + salinity = SEAWATER_SALINITY; + if (salinity < 500) + salinity += FRESHWATER_SALINITY; + specific_weight = salinity / 10000.0 * 0.981; + mbar += lrint(depth / 10.0 * specific_weight); + return mbar; +} + +int depth_to_mbar(int depth, struct dive *dive) +{ + return calculate_depth_to_mbar(depth, dive->surface_pressure, dive->salinity); +} + +double depth_to_bar(int depth, struct dive *dive) +{ + return depth_to_mbar(depth, dive) / 1000.0; +} + +double depth_to_atm(int depth, struct dive *dive) +{ + return mbar_to_atm(depth_to_mbar(depth, dive)); +} + +/* for the inverse calculation we use just the relative pressure + * (that's the one that some dive computers like the Uemis Zurich + * provide - for the other models that do this libdivecomputer has to + * take care of this, but the Uemis we support natively */ +int rel_mbar_to_depth(int mbar, struct dive *dive) +{ + int cm; + double specific_weight = 1.03 * 0.981; + if (dive->dc.salinity) + specific_weight = dive->dc.salinity / 10000.0 * 0.981; + /* whole mbar gives us cm precision */ + cm = (int)lrint(mbar / specific_weight); + return cm * 10; +} + +int mbar_to_depth(int mbar, struct dive *dive) +{ + pressure_t surface_pressure; + if (dive->surface_pressure.mbar) + surface_pressure = dive->surface_pressure; + else + surface_pressure.mbar = SURFACE_PRESSURE; + return rel_mbar_to_depth(mbar - surface_pressure.mbar, dive); +} + +/* MOD rounded to multiples of roundto mm */ +depth_t gas_mod(struct gasmix *mix, pressure_t po2_limit, struct dive *dive, int roundto) +{ + depth_t rounded_depth; + + double depth = (double) mbar_to_depth(po2_limit.mbar * 1000 / get_o2(mix), dive); + rounded_depth.mm = (int)lrint(depth / roundto) * roundto; + return rounded_depth; +} + +/* Maximum narcotic depth rounded to multiples of roundto mm */ +depth_t gas_mnd(struct gasmix *mix, depth_t end, struct dive *dive, int roundto) +{ + depth_t rounded_depth; + pressure_t ppo2n2; + ppo2n2.mbar = depth_to_mbar(end.mm, dive); + + int maxambient = (int)lrint(ppo2n2.mbar / (1 - get_he(mix) / 1000.0)); + rounded_depth.mm = (int)lrint(((double)mbar_to_depth(maxambient, dive)) / roundto) * roundto; + return rounded_depth; +} + +struct dive *get_dive(int nr) +{ + if (nr >= dive_table.nr || nr < 0) + return NULL; + return dive_table.dives[nr]; +} + +struct dive *get_dive_from_table(int nr, struct dive_table *dt) +{ + if (nr >= dt->nr || nr < 0) + return NULL; + return dt->dives[nr]; +} + +struct dive_site *get_dive_site_for_dive(struct dive *dive) +{ + if (dive) + return get_dive_site_by_uuid(dive->dive_site_uuid); + return NULL; +} + +const char *get_dive_country(struct dive *dive) +{ + struct dive_site *ds = get_dive_site_by_uuid(dive->dive_site_uuid); + if (ds) { + int idx = taxonomy_index_for_category(&ds->taxonomy, TC_COUNTRY); + if (idx >= 0) + return ds->taxonomy.category[idx].value; + } + return NULL; +} + +char *get_dive_location(struct dive *dive) +{ + struct dive_site *ds = get_dive_site_by_uuid(dive->dive_site_uuid); + if (ds && ds->name) + return ds->name; + return NULL; +} + +unsigned int number_of_computers(struct dive *dive) +{ + unsigned int total_number = 0; + struct divecomputer *dc = &dive->dc; + + if (!dive) + return 1; + + do { + total_number++; + dc = dc->next; + } while (dc); + return total_number; +} + +struct divecomputer *get_dive_dc(struct dive *dive, int nr) +{ + struct divecomputer *dc; + if (!dive) + return NULL; + dc = &dive->dc; + + while (nr-- > 0) { + dc = dc->next; + if (!dc) + return &dive->dc; + } + return dc; +} + +struct dive *get_dive_by_uniq_id(int id) +{ + int i; + struct dive *dive = NULL; + + for_each_dive (i, dive) { + if (dive->id == id) + break; + } +#ifdef DEBUG + if (dive == NULL) { + fprintf(stderr, "Invalid id %x passed to get_dive_by_diveid, try to fix the code\n", id); + exit(1); + } +#endif + return dive; +} + +int get_idx_by_uniq_id(int id) +{ + int i; + struct dive *dive = NULL; + + for_each_dive (i, dive) { + if (dive->id == id) + break; + } +#ifdef DEBUG + if (dive == NULL) { + fprintf(stderr, "Invalid id %x passed to get_dive_by_diveid, try to fix the code\n", id); + exit(1); + } +#endif + return i; +} + +bool dive_site_has_gps_location(struct dive_site *ds) +{ + return ds && (ds->latitude.udeg || ds->longitude.udeg); +} + +int dive_has_gps_location(struct dive *dive) +{ + if (!dive) + return false; + return dive_site_has_gps_location(get_dive_site_by_uuid(dive->dive_site_uuid)); +} + +struct gasmix *get_gasmix(struct dive *dive, struct divecomputer *dc, int time, struct event **evp, struct gasmix *gasmix) +{ + struct event *ev = *evp; + + if (!gasmix) { + int cyl = explicit_first_cylinder(dive, dc); + gasmix = &dive->cylinder[cyl].gasmix; + ev = dc ? get_next_event(dc->events, "gaschange") : NULL; + } + while (ev && ev->time.seconds < time) { + gasmix = get_gasmix_from_event(dive, ev); + ev = get_next_event(ev->next, "gaschange"); + } + *evp = ev; + return gasmix; +} |