| 
									
										
										
										
											2017-04-27 20:24:53 +02:00
										 |  |  | // SPDX-License-Identifier: GPL-2.0
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | #ifndef UNITS_H
 | 
					
						
							|  |  |  | #define UNITS_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-14 00:32:48 +02:00
										 |  |  | #include <math.h>
 | 
					
						
							| 
									
										
										
										
											2015-11-03 13:47:28 +02:00
										 |  |  | #ifndef M_PI
 | 
					
						
							|  |  |  | #define M_PI 3.14159265358979323846
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-05-14 00:32:48 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | #ifdef __cplusplus
 | 
					
						
							|  |  |  | extern "C" { | 
					
						
							| 
									
										
										
										
											2017-11-21 15:52:01 +01:00
										 |  |  | #else
 | 
					
						
							|  |  |  | #include <stdbool.h>
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define O2_IN_AIR 209 // permille
 | 
					
						
							|  |  |  | #define N2_IN_AIR 781
 | 
					
						
							| 
									
										
										
										
											2017-05-19 20:11:30 +02:00
										 |  |  | #define O2_DENSITY 1331 // mg/Liter
 | 
					
						
							| 
									
										
										
										
											2017-05-12 15:36:24 +02:00
										 |  |  | #define N2_DENSITY 1165
 | 
					
						
							| 
									
										
										
										
											2017-05-19 20:11:30 +02:00
										 |  |  | #define HE_DENSITY 166
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | #define SURFACE_PRESSURE 1013 // mbar
 | 
					
						
							|  |  |  | #define SURFACE_PRESSURE_STRING "1013"
 | 
					
						
							|  |  |  | #define ZERO_C_IN_MKELVIN 273150 // mKelvin
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-25 21:36:30 +08:00
										 |  |  | #ifdef __cplusplus
 | 
					
						
							|  |  |  | #define M_OR_FT(_m, _f) ((prefs.units.length == units::METERS) ? ((_m) * 1000) : (feet_to_mm(_f)))
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define M_OR_FT(_m, _f) ((prefs.units.length == METERS) ? ((_m) * 1000) : (feet_to_mm(_f)))
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | /* Salinity is expressed in weight in grams per 10l */ | 
					
						
							|  |  |  | #define SEAWATER_SALINITY 10300
 | 
					
						
							|  |  |  | #define FRESHWATER_SALINITY 10000
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-26 14:01:31 -03:00
										 |  |  | #include <stdint.h>
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Some silly typedefs to make our units very explicit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Also, the units are chosen so that values can be expressible as | 
					
						
							|  |  |  |  * integers, so that we never have FP rounding issues. And they | 
					
						
							|  |  |  |  * are small enough that converting to/from imperial units doesn't | 
					
						
							|  |  |  |  * really matter. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * We also strive to make '0' a meaningless number saying "not | 
					
						
							|  |  |  |  * initialized", since many values are things that may not have | 
					
						
							|  |  |  |  * been reported (eg cylinder pressure or temperature from dive | 
					
						
							| 
									
										
										
										
											2017-11-05 15:56:35 +01:00
										 |  |  |  * computers that don't support them). But for some of the values | 
					
						
							|  |  |  |  * 0 doesn't works as a flag for not initialized. Examples are | 
					
						
							|  |  |  |  * compass bearing (bearing_t) or NDL (duration_t). | 
					
						
							|  |  |  |  * Therefore some types have a default value which is -1 and has to | 
					
						
							|  |  |  |  * be set at certain points in the code. | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Thus "millibar" for pressure, for example, or "millikelvin" for | 
					
						
							|  |  |  |  * temperatures. Doing temperatures in celsius or fahrenheit would | 
					
						
							|  |  |  |  * make for loss of precision when converting from one to the other, | 
					
						
							|  |  |  |  * and using millikelvin is SI-like but also means that a temperature | 
					
						
							|  |  |  |  * of '0' is clearly just a missing temperature or cylinder pressure. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Also strive to use units that can not possibly be mistaken for a | 
					
						
							|  |  |  |  * valid value in a "normal" system without conversion. If the max | 
					
						
							|  |  |  |  * depth of a dive is '20000', you probably didn't convert from mm on | 
					
						
							| 
									
										
										
										
											2017-03-06 13:27:39 +01:00
										 |  |  |  * output, or if the max. depth gets reported as "0.2ft" it was either | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  |  * a really boring dive, or there was some missing input conversion, | 
					
						
							|  |  |  |  * and a 60-ft dive got recorded as 60mm. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Doing these as "structs containing value" means that we always | 
					
						
							|  |  |  |  * have to explicitly write out those units in order to get at the | 
					
						
							|  |  |  |  * actual value. So there is hopefully little fear of using a value | 
					
						
							|  |  |  |  * in millikelvin as Fahrenheit by mistake. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * We don't actually use these all yet, so maybe they'll change, but | 
					
						
							|  |  |  |  * I made a number of types as guidelines. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | typedef int64_t timestamp_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-05 15:56:35 +01:00
										 |  |  | 	int32_t seconds; // durations up to 34 yrs
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | } duration_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-08 12:29:06 -07:00
										 |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int32_t seconds; // offsets up to +/- 34 yrs
 | 
					
						
							|  |  |  | } offset_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-03 19:21:41 +02:00
										 |  |  | 	int32_t mm; | 
					
						
							|  |  |  | } depth_t; // depth to 2000 km
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-03 19:21:41 +02:00
										 |  |  | 	int32_t mbar; // pressure up to 2000 bar
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | } pressure_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-06-03 19:21:41 +02:00
										 |  |  | 	uint16_t mbar; | 
					
						
							|  |  |  | } o2pressure_t; // pressure up to 65 bar
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int16_t degrees; | 
					
						
							|  |  |  | } bearing_t; // compass bearing
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-03-09 18:18:58 -08:00
										 |  |  | 	uint32_t mkelvin; // up to 1750 degrees K (temperatures in K are always positive)
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | } temperature_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int mliter; | 
					
						
							|  |  |  | } volume_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int permille; | 
					
						
							|  |  |  | } fraction_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int grams; | 
					
						
							|  |  |  | } weight_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int udeg; | 
					
						
							|  |  |  | } degrees_t; | 
					
						
							| 
									
										
										
										
											2015-06-13 11:54:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static inline double udeg_to_radians(int udeg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (udeg * M_PI) / (1000000.0 * 180.0); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | static inline double grams_to_lbs(int grams) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return grams / 453.6; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int lbs_to_grams(double lbs) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-03-08 13:41:41 +07:00
										 |  |  | 	return lrint(lbs * 453.6); | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline double ml_to_cuft(int ml) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return ml / 28316.8466; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline double cuft_to_l(double cuft) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return cuft * 28.3168466; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline double mm_to_feet(int mm) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return mm * 0.00328084; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-14 11:35:04 -07:00
										 |  |  | static inline double m_to_mile(int m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return m / 1609.344; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | static inline unsigned long feet_to_mm(double feet) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-03-08 13:41:41 +07:00
										 |  |  | 	return lrint(feet * 304.8); | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int to_feet(depth_t depth) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-03-08 13:41:41 +07:00
										 |  |  | 	return lrint(mm_to_feet(depth.mm)); | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline double mkelvin_to_C(int mkelvin) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (mkelvin - ZERO_C_IN_MKELVIN) / 1000.0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline double mkelvin_to_F(int mkelvin) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return mkelvin * 9 / 5000.0 - 459.670; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline unsigned long F_to_mkelvin(double f) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-03-08 13:41:41 +07:00
										 |  |  | 	return lrint((f - 32) * 1000 / 1.8 + ZERO_C_IN_MKELVIN); | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline unsigned long C_to_mkelvin(double c) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-03-08 13:41:41 +07:00
										 |  |  | 	return lrint(c * 1000 + ZERO_C_IN_MKELVIN); | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline double psi_to_bar(double psi) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return psi / 14.5037738; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline long psi_to_mbar(double psi) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-03-08 13:41:41 +07:00
										 |  |  | 	return lrint(psi_to_bar(psi) * 1000); | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int to_PSI(pressure_t pressure) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2017-03-08 13:41:41 +07:00
										 |  |  | 	return lrint(pressure.mbar * 0.0145037738); | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline double bar_to_atm(double bar) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return bar / SURFACE_PRESSURE * 1000; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline double mbar_to_atm(int mbar) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return (double)mbar / SURFACE_PRESSURE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline int mbar_to_PSI(int mbar) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pressure_t p = { mbar }; | 
					
						
							|  |  |  | 	return to_PSI(p); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * We keep our internal data in well-specified units, but | 
					
						
							|  |  |  |  * the input and output may come in some random format. This | 
					
						
							|  |  |  |  * keeps track of those units. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /* turns out in Win32 PASCAL is defined as a calling convention */ | 
					
						
							|  |  |  | #ifdef WIN32
 | 
					
						
							|  |  |  | #undef PASCAL
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | struct units { | 
					
						
							| 
									
										
										
										
											2017-11-16 22:00:26 +01:00
										 |  |  | 	enum LENGTH { | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | 		METERS, | 
					
						
							|  |  |  | 		FEET | 
					
						
							|  |  |  | 	} length; | 
					
						
							| 
									
										
										
										
											2016-01-22 18:37:18 -02:00
										 |  |  | 	enum VOLUME { | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | 		LITER, | 
					
						
							|  |  |  | 		CUFT | 
					
						
							|  |  |  | 	} volume; | 
					
						
							| 
									
										
										
										
											2016-01-22 18:37:18 -02:00
										 |  |  | 	enum PRESSURE { | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | 		BAR, | 
					
						
							|  |  |  | 		PSI, | 
					
						
							|  |  |  | 		PASCAL | 
					
						
							|  |  |  | 	} pressure; | 
					
						
							| 
									
										
										
										
											2016-01-22 18:37:18 -02:00
										 |  |  | 	enum TEMPERATURE { | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | 		CELSIUS, | 
					
						
							|  |  |  | 		FAHRENHEIT, | 
					
						
							|  |  |  | 		KELVIN | 
					
						
							|  |  |  | 	} temperature; | 
					
						
							| 
									
										
										
										
											2016-01-22 18:37:18 -02:00
										 |  |  | 	enum WEIGHT { | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | 		KG, | 
					
						
							|  |  |  | 		LBS | 
					
						
							|  |  |  | 	} weight; | 
					
						
							| 
									
										
										
										
											2016-01-22 18:37:18 -02:00
										 |  |  | 	enum TIME { | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | 		SECONDS, | 
					
						
							|  |  |  | 		MINUTES | 
					
						
							|  |  |  | 	} vertical_speed_time; | 
					
						
							| 
									
										
										
										
											2017-05-06 13:44:22 -07:00
										 |  |  | 	enum DURATION { | 
					
						
							|  |  |  | 		MIXED, | 
					
						
							|  |  |  | 		MINUTES_ONLY, | 
					
						
							|  |  |  | 		ALWAYS_HOURS | 
					
						
							|  |  |  | 	} duration_units; | 
					
						
							| 
									
										
										
										
											2017-11-21 15:52:01 +01:00
										 |  |  | 	bool show_units_table; | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * We're going to default to SI units for input. Yes, | 
					
						
							|  |  |  |  * technically the SI unit for pressure is Pascal, but | 
					
						
							|  |  |  |  * we default to bar (10^5 pascal), which people | 
					
						
							|  |  |  |  * actually use. Similarly, C instead of Kelvin. | 
					
						
							|  |  |  |  * And kg instead of g. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2017-05-06 13:44:22 -07:00
										 |  |  | #define SI_UNITS                                                                                           \
 | 
					
						
							|  |  |  |         {                                                                                                  \ | 
					
						
							|  |  |  | 	        .length = METERS, .volume = LITER, .pressure = BAR, .temperature = CELSIUS, .weight = KG,  \ | 
					
						
							| 
									
										
										
										
											2017-10-09 08:46:18 +02:00
										 |  |  | 		.vertical_speed_time = MINUTES, .duration_units = MIXED, .show_units_table = false              \ | 
					
						
							| 
									
										
										
										
											2017-05-06 13:44:22 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define IMPERIAL_UNITS                                                                                     \
 | 
					
						
							|  |  |  |         {                                                                                                  \ | 
					
						
							|  |  |  | 	        .length = FEET, .volume = CUFT, .pressure = PSI, .temperature = FAHRENHEIT, .weight = LBS, \ | 
					
						
							| 
									
										
										
										
											2017-10-09 08:46:18 +02:00
										 |  |  | 		.vertical_speed_time = MINUTES, .duration_units = MIXED, .show_units_table = false              \ | 
					
						
							| 
									
										
										
										
											2017-05-06 13:44:22 -07:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2014-05-10 20:42:27 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef __cplusplus
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 19:21:41 +02:00
										 |  |  | #endif
 |