2017-04-27 18:24:53 +00:00
|
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2017-03-11 20:08:31 +00:00
|
|
|
|
#ifdef __clang__
|
2016-03-09 18:17:17 +00:00
|
|
|
|
// Clang has a bug on zero-initialization of C structs.
|
|
|
|
|
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
|
2017-03-11 20:08:31 +00:00
|
|
|
|
#endif
|
2016-03-09 18:17:17 +00:00
|
|
|
|
|
2011-09-20 19:40:34 +00:00
|
|
|
|
/* equipment.c */
|
2011-09-09 15:38:48 +00:00
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <time.h>
|
2019-06-04 11:52:48 +00:00
|
|
|
|
#include <limits.h>
|
2019-05-30 18:51:30 +00:00
|
|
|
|
#include "equipment.h"
|
2013-10-06 15:55:58 +00:00
|
|
|
|
#include "gettext.h"
|
2011-09-09 15:38:48 +00:00
|
|
|
|
#include "dive.h"
|
|
|
|
|
#include "display.h"
|
|
|
|
|
#include "divelist.h"
|
2019-07-15 20:16:56 +00:00
|
|
|
|
#include "subsurface-string.h"
|
2019-06-26 15:21:03 +00:00
|
|
|
|
#include "table.h"
|
|
|
|
|
|
2019-11-03 22:14:35 +00:00
|
|
|
|
/* Warning: this has strange semantics for C-code! Not the weightsystem object
|
|
|
|
|
* is freed, but the data it references. The object itself is passed in by value.
|
|
|
|
|
* This is due to the fact how the table macros work.
|
|
|
|
|
*/
|
|
|
|
|
void free_weightsystem(weightsystem_t ws)
|
2019-06-26 15:21:03 +00:00
|
|
|
|
{
|
2019-11-03 22:14:35 +00:00
|
|
|
|
free((void *)ws.description);
|
2019-06-26 15:21:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
|
static void free_cylinder(cylinder_t c)
|
|
|
|
|
{
|
|
|
|
|
free((void *)c.type.description);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-26 15:21:03 +00:00
|
|
|
|
void copy_weights(const struct weightsystem_table *s, struct weightsystem_table *d)
|
|
|
|
|
{
|
|
|
|
|
clear_weightsystem_table(d);
|
|
|
|
|
for (int i = 0; i < s->nr; i++)
|
|
|
|
|
add_cloned_weightsystem(d, s->weightsystems[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* weightsystem table functions */
|
|
|
|
|
//static MAKE_GET_IDX(weightsystem_table, weightsystem_t, weightsystems)
|
|
|
|
|
static MAKE_GROW_TABLE(weightsystem_table, weightsystem_t, weightsystems)
|
|
|
|
|
//static MAKE_GET_INSERTION_INDEX(weightsystem_table, weightsystem_t, weightsystems, weightsystem_less_than)
|
|
|
|
|
MAKE_ADD_TO(weightsystem_table, weightsystem_t, weightsystems)
|
|
|
|
|
MAKE_REMOVE_FROM(weightsystem_table, weightsystems)
|
|
|
|
|
//MAKE_SORT(weightsystem_table, weightsystem_t, weightsystems, comp_weightsystems)
|
|
|
|
|
//MAKE_REMOVE(weightsystem_table, weightsystem_t, weightsystem)
|
|
|
|
|
MAKE_CLEAR_TABLE(weightsystem_table, weightsystems, weightsystem)
|
2019-07-15 20:16:56 +00:00
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
|
/* cylinder table functions */
|
|
|
|
|
//static MAKE_GET_IDX(cylinder_table, cylinder_t, cylinders)
|
|
|
|
|
static MAKE_GROW_TABLE(cylinder_table, cylinder_t, cylinders)
|
|
|
|
|
//static MAKE_GET_INSERTION_INDEX(cylinder_table, cylinder_t, cylinders, cylinder_less_than)
|
|
|
|
|
MAKE_ADD_TO(cylinder_table, cylinder_t, cylinders)
|
|
|
|
|
MAKE_REMOVE_FROM(cylinder_table, cylinders)
|
|
|
|
|
//MAKE_SORT(cylinder_table, cylinder_t, cylinders, comp_cylinders)
|
|
|
|
|
//MAKE_REMOVE(cylinder_table, cylinder_t, cylinder)
|
|
|
|
|
MAKE_CLEAR_TABLE(cylinder_table, cylinders, cylinder)
|
|
|
|
|
|
2019-07-15 20:16:56 +00:00
|
|
|
|
const char *cylinderuse_text[NUM_GAS_USE] = {
|
|
|
|
|
QT_TRANSLATE_NOOP("gettextFromC", "OC-gas"), QT_TRANSLATE_NOOP("gettextFromC", "diluent"), QT_TRANSLATE_NOOP("gettextFromC", "oxygen"), QT_TRANSLATE_NOOP("gettextFromC", "not used")
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int cylinderuse_from_text(const char *text)
|
|
|
|
|
{
|
|
|
|
|
for (enum cylinderuse i = 0; i < NUM_GAS_USE; i++) {
|
|
|
|
|
if (same_string(text, cylinderuse_text[i]) || same_string(text, translate("gettextFromC", cylinderuse_text[i])))
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-09-09 15:38:48 +00:00
|
|
|
|
|
2013-05-03 18:04:51 +00:00
|
|
|
|
/* placeholders for a few functions that we need to redesign for the Qt UI */
|
2019-06-05 18:26:51 +00:00
|
|
|
|
void add_cylinder_description(const cylinder_type_t *type)
|
2013-05-03 18:04:51 +00:00
|
|
|
|
{
|
|
|
|
|
const char *desc;
|
2013-12-28 22:56:01 +00:00
|
|
|
|
int i;
|
2013-05-03 18:04:51 +00:00
|
|
|
|
|
|
|
|
|
desc = type->description;
|
|
|
|
|
if (!desc)
|
|
|
|
|
return;
|
2018-06-19 01:02:02 +00:00
|
|
|
|
for (i = 0; i < MAX_TANK_INFO && tank_info[i].name != NULL; i++) {
|
2013-12-28 22:56:01 +00:00
|
|
|
|
if (strcmp(tank_info[i].name, desc) == 0)
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-06-19 01:02:02 +00:00
|
|
|
|
if (i < MAX_TANK_INFO) {
|
2014-12-18 07:47:58 +00:00
|
|
|
|
// FIXME: leaked on exit
|
2014-11-14 21:33:12 +00:00
|
|
|
|
tank_info[i].name = strdup(desc);
|
2013-12-28 22:56:01 +00:00
|
|
|
|
tank_info[i].ml = type->size.mliter;
|
|
|
|
|
tank_info[i].bar = type->workingpressure.mbar / 1000;
|
|
|
|
|
}
|
2013-05-03 18:04:51 +00:00
|
|
|
|
}
|
2019-06-26 15:21:03 +00:00
|
|
|
|
|
2019-06-05 18:26:51 +00:00
|
|
|
|
void add_weightsystem_description(const weightsystem_t *weightsystem)
|
2013-05-03 18:04:51 +00:00
|
|
|
|
{
|
|
|
|
|
const char *desc;
|
2013-09-10 18:42:26 +00:00
|
|
|
|
int i;
|
2013-05-03 18:04:51 +00:00
|
|
|
|
|
|
|
|
|
desc = weightsystem->description;
|
|
|
|
|
if (!desc)
|
|
|
|
|
return;
|
2018-06-19 00:59:33 +00:00
|
|
|
|
for (i = 0; i < MAX_WS_INFO && ws_info[i].name != NULL; i++) {
|
2013-09-10 18:42:26 +00:00
|
|
|
|
if (strcmp(ws_info[i].name, desc) == 0) {
|
|
|
|
|
ws_info[i].grams = weightsystem->weight.grams;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-19 00:59:33 +00:00
|
|
|
|
if (i < MAX_WS_INFO) {
|
2014-12-18 07:47:58 +00:00
|
|
|
|
// FIXME: leaked on exit
|
2014-11-14 21:33:12 +00:00
|
|
|
|
ws_info[i].name = strdup(desc);
|
2013-09-10 18:42:26 +00:00
|
|
|
|
ws_info[i].grams = weightsystem->weight.grams;
|
|
|
|
|
}
|
2013-05-03 18:04:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-11-03 14:04:48 +00:00
|
|
|
|
weightsystem_t clone_weightsystem(weightsystem_t ws)
|
|
|
|
|
{
|
|
|
|
|
weightsystem_t res = { ws.weight, copy_string(ws.description) };
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-26 15:21:03 +00:00
|
|
|
|
/* Add a clone of a weightsystem to the end of a weightsystem table.
|
|
|
|
|
* Cloned in means that the description-string is copied. */
|
|
|
|
|
void add_cloned_weightsystem(struct weightsystem_table *t, weightsystem_t ws)
|
|
|
|
|
{
|
2019-11-03 14:04:48 +00:00
|
|
|
|
add_to_weightsystem_table(t, t->nr, clone_weightsystem(ws));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add a clone of a weightsystem to the end of a weightsystem table.
|
|
|
|
|
* Cloned in means that the description-string is copied. */
|
|
|
|
|
void add_cloned_weightsystem_at(struct weightsystem_table *t, weightsystem_t ws)
|
|
|
|
|
{
|
|
|
|
|
add_to_weightsystem_table(t, t->nr, clone_weightsystem(ws));
|
2019-06-26 15:21:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
|
/* Add a clone of a cylinder to the end of a cylinder table.
|
|
|
|
|
* Cloned in means that the description-string is copied. */
|
|
|
|
|
void add_cloned_cylinder(struct cylinder_table *t, cylinder_t cyl)
|
2011-12-24 03:41:16 +00:00
|
|
|
|
{
|
2019-08-04 16:44:57 +00:00
|
|
|
|
cyl.type.description = copy_string(cyl.type.description);
|
|
|
|
|
add_to_cylinder_table(t, t->nr, cyl);
|
2011-10-02 20:13:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
|
bool same_weightsystem(weightsystem_t w1, weightsystem_t w2)
|
Fix missing save of (almost empty) cylinder information
If we have no explicit cylinder info at all (it's normal air, no size or
working pressure information, and no beginning/end pressure information),
we don't save the cylinders in question because that would be redundant.
Such non-saved cylinders may still show up in the equipment list because
there may be implicit mention of them elsewhere, notably due to sample
data, so not saving them is the right thing to do - there is nothing to
save.
However, we missed one case: if there were other cylinders that *did* have
explicit information in it following such an uninteresting cylinder, we do
need to save the cylinder information for the useless case - if only in
order to be able to save the non-useless information for subsequent
cylinders.
This patch does that. Now, if you had an air-filled cylinder with no
information as your first cylinder, and a 51% nitrox as your second one,
it will save that information as
<cylinder />
<cylinder o2='51.0%' />
rather than dropping the cylinder information entirely.
This bug has been there for a long time, and was hidden by the fact that
normally you'd fill in cylinder descriptions etc after importing new
dives. It also used to be that we saved the cylinder beginning/end
pressure even if that was generated from the sample data, so if you
imported from a air-integrated computer and had samples for that cylinder,
we used to save it even though it was technically redundant.
We stopped saving redundant air sample information in commit 0089dd8819b7
("Don't save cylinder start/end pressures unless set by hand").
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Removed start and end in save_cylinder_info(). These two variables are no
longer used.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-21 21:06:57 +00:00
|
|
|
|
{
|
2019-08-04 16:44:57 +00:00
|
|
|
|
return w1.weight.grams == w2.weight.grams &&
|
|
|
|
|
same_string(w1.description, w2.description);
|
Fix missing save of (almost empty) cylinder information
If we have no explicit cylinder info at all (it's normal air, no size or
working pressure information, and no beginning/end pressure information),
we don't save the cylinders in question because that would be redundant.
Such non-saved cylinders may still show up in the equipment list because
there may be implicit mention of them elsewhere, notably due to sample
data, so not saving them is the right thing to do - there is nothing to
save.
However, we missed one case: if there were other cylinders that *did* have
explicit information in it following such an uninteresting cylinder, we do
need to save the cylinder information for the useless case - if only in
order to be able to save the non-useless information for subsequent
cylinders.
This patch does that. Now, if you had an air-filled cylinder with no
information as your first cylinder, and a 51% nitrox as your second one,
it will save that information as
<cylinder />
<cylinder o2='51.0%' />
rather than dropping the cylinder information entirely.
This bug has been there for a long time, and was hidden by the fact that
normally you'd fill in cylinder descriptions etc after importing new
dives. It also used to be that we saved the cylinder beginning/end
pressure even if that was generated from the sample data, so if you
imported from a air-integrated computer and had samples for that cylinder,
we used to save it even though it was technically redundant.
We stopped saving redundant air sample information in commit 0089dd8819b7
("Don't save cylinder start/end pressures unless set by hand").
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Removed start and end in save_cylinder_info(). These two variables are no
longer used.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-21 21:06:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
|
bool same_cylinder(cylinder_t cyl1, cylinder_t cyl2)
|
Fix missing save of (almost empty) cylinder information
If we have no explicit cylinder info at all (it's normal air, no size or
working pressure information, and no beginning/end pressure information),
we don't save the cylinders in question because that would be redundant.
Such non-saved cylinders may still show up in the equipment list because
there may be implicit mention of them elsewhere, notably due to sample
data, so not saving them is the right thing to do - there is nothing to
save.
However, we missed one case: if there were other cylinders that *did* have
explicit information in it following such an uninteresting cylinder, we do
need to save the cylinder information for the useless case - if only in
order to be able to save the non-useless information for subsequent
cylinders.
This patch does that. Now, if you had an air-filled cylinder with no
information as your first cylinder, and a 51% nitrox as your second one,
it will save that information as
<cylinder />
<cylinder o2='51.0%' />
rather than dropping the cylinder information entirely.
This bug has been there for a long time, and was hidden by the fact that
normally you'd fill in cylinder descriptions etc after importing new
dives. It also used to be that we saved the cylinder beginning/end
pressure even if that was generated from the sample data, so if you
imported from a air-integrated computer and had samples for that cylinder,
we used to save it even though it was technically redundant.
We stopped saving redundant air sample information in commit 0089dd8819b7
("Don't save cylinder start/end pressures unless set by hand").
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Removed start and end in save_cylinder_info(). These two variables are no
longer used.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-21 21:06:57 +00:00
|
|
|
|
{
|
2019-08-04 16:44:57 +00:00
|
|
|
|
return same_string(cyl1.type.description, cyl2.type.description) &&
|
|
|
|
|
same_gasmix(cyl1.gasmix, cyl2.gasmix) &&
|
|
|
|
|
cyl1.start.mbar == cyl2.start.mbar &&
|
|
|
|
|
cyl1.end.mbar == cyl2.end.mbar &&
|
|
|
|
|
cyl1.cylinder_use == cyl2.cylinder_use;
|
Fix missing save of (almost empty) cylinder information
If we have no explicit cylinder info at all (it's normal air, no size or
working pressure information, and no beginning/end pressure information),
we don't save the cylinders in question because that would be redundant.
Such non-saved cylinders may still show up in the equipment list because
there may be implicit mention of them elsewhere, notably due to sample
data, so not saving them is the right thing to do - there is nothing to
save.
However, we missed one case: if there were other cylinders that *did* have
explicit information in it following such an uninteresting cylinder, we do
need to save the cylinder information for the useless case - if only in
order to be able to save the non-useless information for subsequent
cylinders.
This patch does that. Now, if you had an air-filled cylinder with no
information as your first cylinder, and a 51% nitrox as your second one,
it will save that information as
<cylinder />
<cylinder o2='51.0%' />
rather than dropping the cylinder information entirely.
This bug has been there for a long time, and was hidden by the fact that
normally you'd fill in cylinder descriptions etc after importing new
dives. It also used to be that we saved the cylinder beginning/end
pressure even if that was generated from the sample data, so if you
imported from a air-integrated computer and had samples for that cylinder,
we used to save it even though it was technically redundant.
We stopped saving redundant air sample information in commit 0089dd8819b7
("Don't save cylinder start/end pressures unless set by hand").
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Removed start and end in save_cylinder_info(). These two variables are no
longer used.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-21 21:06:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-16 17:10:10 +00:00
|
|
|
|
void get_gas_string(struct gasmix gasmix, char *text, int len)
|
2014-06-02 03:56:29 +00:00
|
|
|
|
{
|
|
|
|
|
if (gasmix_is_air(gasmix))
|
|
|
|
|
snprintf(text, len, "%s", translate("gettextFromC", "air"));
|
2015-01-05 19:09:30 +00:00
|
|
|
|
else if (get_he(gasmix) == 0 && get_o2(gasmix) < 1000)
|
2014-06-02 03:56:29 +00:00
|
|
|
|
snprintf(text, len, translate("gettextFromC", "EAN%d"), (get_o2(gasmix) + 5) / 10);
|
2015-01-05 19:09:30 +00:00
|
|
|
|
else if (get_he(gasmix) == 0 && get_o2(gasmix) == 1000)
|
|
|
|
|
snprintf(text, len, "%s", translate("gettextFromC", "oxygen"));
|
2014-06-02 03:56:29 +00:00
|
|
|
|
else
|
|
|
|
|
snprintf(text, len, "(%d/%d)", (get_o2(gasmix) + 5) / 10, (get_he(gasmix) + 5) / 10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Returns a static char buffer - only good for immediate use by printf etc */
|
2018-08-16 17:10:10 +00:00
|
|
|
|
const char *gasname(struct gasmix gasmix)
|
2014-06-02 03:56:29 +00:00
|
|
|
|
{
|
|
|
|
|
static char gas[64];
|
|
|
|
|
get_gas_string(gasmix, gas, sizeof(gas));
|
|
|
|
|
return gas;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-04 11:52:48 +00:00
|
|
|
|
int gas_volume(const cylinder_t *cyl, pressure_t p)
|
|
|
|
|
{
|
|
|
|
|
double bar = p.mbar / 1000.0;
|
|
|
|
|
double z_factor = gas_compressibility_factor(cyl->gasmix, bar);
|
|
|
|
|
return lrint(cyl->type.size.mliter * bar_to_atm(bar) / z_factor);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
|
int find_best_gasmix_match(struct gasmix mix, const struct cylinder_table *cylinders)
|
2019-06-04 11:52:48 +00:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int best = -1, score = INT_MAX;
|
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
|
for (i = 0; i < cylinders->nr; i++) {
|
2019-06-04 11:52:48 +00:00
|
|
|
|
const cylinder_t *match;
|
|
|
|
|
int distance;
|
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
|
match = cylinders->cylinders + i;
|
2019-06-04 11:52:48 +00:00
|
|
|
|
distance = gasmix_distance(mix, match->gasmix);
|
|
|
|
|
if (distance >= score)
|
|
|
|
|
continue;
|
|
|
|
|
best = i;
|
|
|
|
|
score = distance;
|
|
|
|
|
}
|
|
|
|
|
return best;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-11 00:14:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* We hardcode the most common standard cylinders,
|
|
|
|
|
* we should pick up any other names from the dive
|
|
|
|
|
* logs directly.
|
|
|
|
|
*/
|
2018-06-19 01:02:02 +00:00
|
|
|
|
struct tank_info_t tank_info[MAX_TANK_INFO] = {
|
2011-09-11 00:14:07 +00:00
|
|
|
|
/* Need an empty entry for the no-cylinder case */
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
|
{ "", },
|
2011-09-11 00:14:07 +00:00
|
|
|
|
|
|
|
|
|
/* Size-only metric cylinders */
|
2014-06-22 13:47:25 +00:00
|
|
|
|
{ "10.0ℓ", .ml = 10000 },
|
|
|
|
|
{ "11.1ℓ", .ml = 11100 },
|
2011-09-11 00:14:07 +00:00
|
|
|
|
|
|
|
|
|
/* Most common AL cylinders */
|
2014-02-28 04:09:57 +00:00
|
|
|
|
{ "AL40", .cuft = 40, .psi = 3000 },
|
|
|
|
|
{ "AL50", .cuft = 50, .psi = 3000 },
|
|
|
|
|
{ "AL63", .cuft = 63, .psi = 3000 },
|
|
|
|
|
{ "AL72", .cuft = 72, .psi = 3000 },
|
|
|
|
|
{ "AL80", .cuft = 80, .psi = 3000 },
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
|
{ "AL100", .cuft = 100, .psi = 3300 },
|
2011-09-11 00:14:07 +00:00
|
|
|
|
|
2014-06-25 08:43:03 +00:00
|
|
|
|
/* Metric AL cylinders */
|
|
|
|
|
{ "ALU7", .ml = 7000, .bar = 200 },
|
|
|
|
|
|
2011-09-11 00:14:07 +00:00
|
|
|
|
/* Somewhat common LP steel cylinders */
|
2014-02-28 04:09:57 +00:00
|
|
|
|
{ "LP85", .cuft = 85, .psi = 2640 },
|
|
|
|
|
{ "LP95", .cuft = 95, .psi = 2640 },
|
2012-04-01 22:38:52 +00:00
|
|
|
|
{ "LP108", .cuft = 108, .psi = 2640 },
|
|
|
|
|
{ "LP121", .cuft = 121, .psi = 2640 },
|
2011-09-11 00:14:07 +00:00
|
|
|
|
|
|
|
|
|
/* Somewhat common HP steel cylinders */
|
2014-02-28 04:09:57 +00:00
|
|
|
|
{ "HP65", .cuft = 65, .psi = 3442 },
|
|
|
|
|
{ "HP80", .cuft = 80, .psi = 3442 },
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
|
{ "HP100", .cuft = 100, .psi = 3442 },
|
2016-08-10 03:32:44 +00:00
|
|
|
|
{ "HP117", .cuft = 117, .psi = 3442 },
|
Clean up reference tank information table
This makes the reference tanks ("struct tank_info") use a saner format
which specifies explicitly whether the size is in ml or cubic feet, and
whether the pressure is in psi or bar.
So instead of having magic rules ("size is in cuft if < 1000, otherwise
mliter"), just set the size explicitly:
{ "11.1 l", .ml = 11100 },
{ "AL80", .cuft = 80, .psi = 3000 },
and then the code can just convert to standard measurements without any
odd rules, and the initialization table becomes self-explanatory too.
This is in preparation for doing the metric tanks with pressure: Henrik
Aronsen sent a really ugly patch using the previous setup, I just
couldn't stand the additional hackery.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-12-11 19:54:17 +00:00
|
|
|
|
{ "HP119", .cuft = 119, .psi = 3442 },
|
|
|
|
|
{ "HP130", .cuft = 130, .psi = 3442 },
|
2011-09-11 00:14:07 +00:00
|
|
|
|
|
2011-12-11 20:03:55 +00:00
|
|
|
|
/* Common European steel cylinders */
|
2014-06-22 13:47:25 +00:00
|
|
|
|
{ "3ℓ 232 bar", .ml = 3000, .bar = 232 },
|
|
|
|
|
{ "3ℓ 300 bar", .ml = 3000, .bar = 300 },
|
2017-03-20 16:17:05 +00:00
|
|
|
|
{ "10ℓ 200 bar", .ml = 10000, .bar = 200 },
|
|
|
|
|
{ "10ℓ 232 bar", .ml = 10000, .bar = 232 },
|
2014-06-22 13:47:25 +00:00
|
|
|
|
{ "10ℓ 300 bar", .ml = 10000, .bar = 300 },
|
|
|
|
|
{ "12ℓ 200 bar", .ml = 12000, .bar = 200 },
|
|
|
|
|
{ "12ℓ 232 bar", .ml = 12000, .bar = 232 },
|
|
|
|
|
{ "12ℓ 300 bar", .ml = 12000, .bar = 300 },
|
|
|
|
|
{ "15ℓ 200 bar", .ml = 15000, .bar = 200 },
|
|
|
|
|
{ "15ℓ 232 bar", .ml = 15000, .bar = 232 },
|
2014-02-28 04:09:57 +00:00
|
|
|
|
{ "D7 300 bar", .ml = 14000, .bar = 300 },
|
2011-12-11 20:03:55 +00:00
|
|
|
|
{ "D8.5 232 bar", .ml = 17000, .bar = 232 },
|
2014-02-28 04:09:57 +00:00
|
|
|
|
{ "D12 232 bar", .ml = 24000, .bar = 232 },
|
2014-08-05 15:05:07 +00:00
|
|
|
|
{ "D13 232 bar", .ml = 26000, .bar = 232 },
|
|
|
|
|
{ "D15 232 bar", .ml = 30000, .bar = 232 },
|
|
|
|
|
{ "D16 232 bar", .ml = 32000, .bar = 232 },
|
|
|
|
|
{ "D18 232 bar", .ml = 36000, .bar = 232 },
|
|
|
|
|
{ "D20 232 bar", .ml = 40000, .bar = 232 },
|
2011-12-11 20:03:55 +00:00
|
|
|
|
|
2011-09-11 00:14:07 +00:00
|
|
|
|
/* We'll fill in more from the dive log dynamically */
|
2011-09-09 15:38:48 +00:00
|
|
|
|
{ NULL, }
|
|
|
|
|
};
|
|
|
|
|
|
2011-12-24 03:41:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* We hardcode the most common weight system types
|
|
|
|
|
* This is a bit odd as the weight system types don't usually encode weight
|
|
|
|
|
*/
|
2018-06-19 00:59:33 +00:00
|
|
|
|
struct ws_info_t ws_info[MAX_WS_INFO] = {
|
2014-02-28 04:09:57 +00:00
|
|
|
|
{ QT_TRANSLATE_NOOP("gettextFromC", "integrated"), 0 },
|
|
|
|
|
{ QT_TRANSLATE_NOOP("gettextFromC", "belt"), 0 },
|
|
|
|
|
{ QT_TRANSLATE_NOOP("gettextFromC", "ankle"), 0 },
|
2017-03-07 07:15:07 +00:00
|
|
|
|
{ QT_TRANSLATE_NOOP("gettextFromC", "backplate"), 0 },
|
2014-02-28 04:09:57 +00:00
|
|
|
|
{ QT_TRANSLATE_NOOP("gettextFromC", "clip-on"), 0 },
|
2011-12-24 03:41:16 +00:00
|
|
|
|
};
|
|
|
|
|
|
2013-05-22 17:02:28 +00:00
|
|
|
|
void remove_cylinder(struct dive *dive, int idx)
|
|
|
|
|
{
|
2019-08-04 16:44:57 +00:00
|
|
|
|
remove_from_cylinder_table(&dive->cylinders, idx);
|
2013-05-22 17:02:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void remove_weightsystem(struct dive *dive, int idx)
|
|
|
|
|
{
|
2019-06-26 15:21:03 +00:00
|
|
|
|
remove_from_weightsystem_table(&dive->weightsystems, idx);
|
2013-05-22 17:02:28 +00:00
|
|
|
|
}
|
2014-05-29 21:36:14 +00:00
|
|
|
|
|
2014-05-30 16:10:35 +00:00
|
|
|
|
/* when planning a dive we need to make sure that all cylinders have a sane depth assigned
|
2014-07-04 18:40:02 +00:00
|
|
|
|
* and if we are tracking gas consumption the pressures need to be reset to start = end = workingpressure */
|
|
|
|
|
void reset_cylinders(struct dive *dive, bool track_gas)
|
2014-05-29 21:36:14 +00:00
|
|
|
|
{
|
2014-12-04 19:56:17 +00:00
|
|
|
|
pressure_t decopo2 = {.mbar = prefs.decopo2};
|
2014-05-30 16:10:35 +00:00
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
|
for (int i = 0; i < dive->cylinders.nr; i++) {
|
2019-08-04 20:13:49 +00:00
|
|
|
|
cylinder_t *cyl = get_cylinder(dive, i);
|
2014-12-04 19:56:17 +00:00
|
|
|
|
if (cyl->depth.mm == 0) /* if the gas doesn't give a mod, calculate based on prefs */
|
2018-08-16 17:10:10 +00:00
|
|
|
|
cyl->depth = gas_mod(cyl->gasmix, decopo2, dive, M_OR_FT(3,10));
|
2014-07-17 06:04:30 +00:00
|
|
|
|
if (track_gas)
|
2014-05-30 16:10:35 +00:00
|
|
|
|
cyl->start.mbar = cyl->end.mbar = cyl->type.workingpressure.mbar;
|
2014-06-01 16:59:38 +00:00
|
|
|
|
cyl->gas_used.mliter = 0;
|
2014-07-05 14:49:06 +00:00
|
|
|
|
cyl->deco_gas_used.mliter = 0;
|
2014-05-29 21:36:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-27 11:36:20 +00:00
|
|
|
|
|
2019-08-04 12:42:21 +00:00
|
|
|
|
static void copy_cylinder_type(const cylinder_t *s, cylinder_t *d)
|
|
|
|
|
{
|
2019-08-04 16:44:57 +00:00
|
|
|
|
free_cylinder(*d);
|
2019-08-04 12:42:21 +00:00
|
|
|
|
d->type = s->type;
|
|
|
|
|
d->type.description = s->type.description ? strdup(s->type.description) : NULL;
|
|
|
|
|
d->gasmix = s->gasmix;
|
|
|
|
|
d->depth = s->depth;
|
|
|
|
|
d->cylinder_use = s->cylinder_use;
|
|
|
|
|
d->manually_added = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* copy the equipment data part of the cylinders but keep pressures */
|
|
|
|
|
void copy_cylinder_types(const struct dive *s, struct dive *d)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
if (!s || !d)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-08-04 16:44:57 +00:00
|
|
|
|
for (i = 0; i < s->cylinders.nr && i < d->cylinders.nr; i++)
|
2019-08-04 20:13:49 +00:00
|
|
|
|
copy_cylinder_type(get_cylinder(s, i), get_cylinder(d, i));
|
2019-08-04 16:44:57 +00:00
|
|
|
|
|
|
|
|
|
for ( ; i < s->cylinders.nr; i++)
|
2019-08-04 20:13:49 +00:00
|
|
|
|
add_cloned_cylinder(&d->cylinders, *get_cylinder(s, i));
|
2019-08-04 16:44:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-04 17:17:11 +00:00
|
|
|
|
cylinder_t *add_empty_cylinder(struct cylinder_table *t)
|
2019-08-04 16:44:57 +00:00
|
|
|
|
{
|
|
|
|
|
cylinder_t cyl = { 0 };
|
|
|
|
|
cyl.type.description = strdup("");
|
|
|
|
|
add_to_cylinder_table(t, t->nr, cyl);
|
2019-08-04 17:17:11 +00:00
|
|
|
|
return &t->cylinders[t->nr - 1];
|
2019-08-04 16:44:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* access to cylinders is controlled by two functions:
|
|
|
|
|
* - get_cylinder() returns the cylinder of a dive and supposes that
|
|
|
|
|
* the cylinder with the given index exists. If it doesn't, an error
|
|
|
|
|
* message is printed and NULL returned.
|
|
|
|
|
* - get_or_create_cylinder() creates an empty cylinder if it doesn't exist.
|
|
|
|
|
* Multiple cylinders might be created if the index is bigger than the
|
|
|
|
|
* number of existing cylinders
|
|
|
|
|
*/
|
|
|
|
|
cylinder_t *get_cylinder(const struct dive *d, int idx)
|
|
|
|
|
{
|
|
|
|
|
if (idx < 0 || idx >= d->cylinders.nr) {
|
|
|
|
|
fprintf(stderr, "Warning: accessing invalid cylinder %d (%d existing)\n", idx, d->cylinders.nr);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return &d->cylinders.cylinders[idx];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cylinder_t *get_or_create_cylinder(struct dive *d, int idx)
|
|
|
|
|
{
|
|
|
|
|
if (idx < 0) {
|
|
|
|
|
fprintf(stderr, "Warning: accessing invalid cylinder %d\n", idx);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
while (idx >= d->cylinders.nr)
|
|
|
|
|
add_empty_cylinder(&d->cylinders);
|
|
|
|
|
return &d->cylinders.cylinders[idx];
|
2019-08-04 12:42:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 11:36:20 +00:00
|
|
|
|
#ifdef DEBUG_CYL
|
|
|
|
|
void dump_cylinders(struct dive *dive, bool verbose)
|
|
|
|
|
{
|
|
|
|
|
printf("Cylinder list:\n");
|
2019-08-04 16:44:57 +00:00
|
|
|
|
for (int i = 0; i < dive->cylinders; i++) {
|
2019-08-04 20:13:49 +00:00
|
|
|
|
cylinder_t *cyl = get_cylinder(dive, i);
|
2017-11-27 11:36:20 +00:00
|
|
|
|
|
|
|
|
|
printf("%02d: Type %s, %3.1fl, %3.0fbar\n", i, cyl->type.description, cyl->type.size.mliter / 1000.0, cyl->type.workingpressure.mbar / 1000.0);
|
|
|
|
|
printf(" Gasmix O2 %2.0f%% He %2.0f%%\n", cyl->gasmix.o2.permille / 10.0, cyl->gasmix.he.permille / 10.0);
|
|
|
|
|
printf(" Pressure Start %3.0fbar End %3.0fbar Sample start %3.0fbar Sample end %3.0fbar\n", cyl->start.mbar / 1000.0, cyl->end.mbar / 1000.0, cyl->sample_start.mbar / 1000.0, cyl->sample_end.mbar / 1000.0);
|
|
|
|
|
if (verbose) {
|
|
|
|
|
printf(" Depth %3.0fm\n", cyl->depth.mm / 1000.0);
|
|
|
|
|
printf(" Added %s\n", (cyl->manually_added ? "manually" : ""));
|
|
|
|
|
printf(" Gas used Bottom %5.0fl Deco %5.0fl\n", cyl->gas_used.mliter / 1000.0, cyl->deco_gas_used.mliter / 1000.0);
|
|
|
|
|
printf(" Use %d\n", cyl->cylinder_use);
|
|
|
|
|
printf(" Bestmix %s %s\n", (cyl->bestmix_o2 ? "O2" : " "), (cyl->bestmix_he ? "He" : " "));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|