From a7d297ed574a9b1110a224eb3718fbe14b154f6d Mon Sep 17 00:00:00 2001
From: Lukas Woodtli <woodtli.lukas@gmail.com>
Date: Wed, 24 Oct 2018 22:38:38 +0200
Subject: [PATCH] Fix division by zero and cast of to big floats to int

---
 src/lib/mathlib/math/Limits.hpp             | 21 ++++++++++++++
 src/modules/simulator/accelsim/accelsim.cpp | 31 ++++++---------------
 src/modules/simulator/gyrosim/gyrosim.cpp   | 30 ++++++--------------
 3 files changed, 37 insertions(+), 45 deletions(-)

diff --git a/src/lib/mathlib/math/Limits.hpp b/src/lib/mathlib/math/Limits.hpp
index cf3e00f3f0..4610a01e40 100644
--- a/src/lib/mathlib/math/Limits.hpp
+++ b/src/lib/mathlib/math/Limits.hpp
@@ -40,6 +40,7 @@
 #pragma once
 
 #include <platforms/px4_defines.h>
+#include <float.h>
 
 //this should be defined in stdint.h, but seems to be missing in the ARM toolchain (5.2.0)
 #ifndef UINT64_C
@@ -72,6 +73,14 @@ constexpr const _Tp &constrain(const _Tp &val, const _Tp &min_val, const _Tp &ma
 	return (val < min_val) ? min_val : ((val > max_val) ? max_val : val);
 }
 
+/** Constrain float values to valid values for int16_t.
+ * Invalid values are just clipped to be in the range for int16_t. */
+inline int16_t constrainFloatToInt16(float value)
+{
+	return (int16_t)math::constrain(value, (float)INT16_MIN, (float)INT16_MAX);
+}
+
+
 template<typename _Tp>
 inline constexpr bool isInRange(const _Tp &val, const _Tp &min_val, const _Tp &max_val)
 {
@@ -90,4 +99,16 @@ constexpr T degrees(const T radians)
 	return radians * (static_cast<T>(180) / static_cast<T>(M_PI));
 }
 
+/** Save way to check if float is zero */
+inline bool isZero(const float val)
+{
+	return fabsf(val - 0.0f) < FLT_EPSILON;
+}
+
+/** Save way to check if double is zero */
+inline bool isZero(const double val)
+{
+	return fabs(val - 0.0) < DBL_EPSILON;
+}
+
 }
diff --git a/src/modules/simulator/accelsim/accelsim.cpp b/src/modules/simulator/accelsim/accelsim.cpp
index 933b03689b..5bf7d37c8a 100644
--- a/src/modules/simulator/accelsim/accelsim.cpp
+++ b/src/modules/simulator/accelsim/accelsim.cpp
@@ -82,21 +82,6 @@ extern "C" { __EXPORT int accelsim_main(int argc, char *argv[]); }
 
 using namespace DriverFramework;
 
-namespace
-{
-/** Save way to check if float is zero */
-inline bool isZero(const float &val)
-{
-	return abs(val - 0.0f) < FLT_EPSILON;
-}
-
-inline int16_t constrainToInt(float value)
-{
-	return (int16_t)math::constrain(value, (float)INT16_MIN, (float)INT16_MAX);
-}
-}
-
-
 class ACCELSIM_mag;
 
 class ACCELSIM : public VirtDevObj
@@ -864,13 +849,13 @@ ACCELSIM::_measure()
 	// whether it has had failures
 	accel_report.error_count = perf_event_count(_bad_registers) + perf_event_count(_bad_values);
 
-	if (isZero(_accel_range_scale)) {
+	if (math::isZero(_accel_range_scale)) {
 		_accel_range_scale = FLT_EPSILON;
 	}
 
-	accel_report.x_raw = constrainToInt(raw_accel_report.x / _accel_range_scale);
-	accel_report.y_raw = constrainToInt(raw_accel_report.y / _accel_range_scale);
-	accel_report.z_raw = constrainToInt(raw_accel_report.z / _accel_range_scale);
+	accel_report.x_raw = math::constrainFloatToInt16(raw_accel_report.x / _accel_range_scale);
+	accel_report.y_raw = math::constrainFloatToInt16(raw_accel_report.y / _accel_range_scale);
+	accel_report.z_raw = math::constrainFloatToInt16(raw_accel_report.z / _accel_range_scale);
 
 	accel_report.x = raw_accel_report.x;
 	accel_report.y = raw_accel_report.y;
@@ -944,13 +929,13 @@ ACCELSIM::mag_measure()
 	mag_report.device_id = 196616;
 	mag_report.is_external = false;
 
-	if (isZero(_mag_range_scale)) {
+	if (math::isZero(_mag_range_scale)) {
 		_mag_range_scale = FLT_EPSILON;
 	}
 
-	float xraw_f = constrainToInt(raw_mag_report.x / _mag_range_scale);
-	float yraw_f = constrainToInt(raw_mag_report.y / _mag_range_scale);
-	float zraw_f = constrainToInt(raw_mag_report.z / _mag_range_scale);
+	float xraw_f = math::constrainFloatToInt16(raw_mag_report.x / _mag_range_scale);
+	float yraw_f = math::constrainFloatToInt16(raw_mag_report.y / _mag_range_scale);
+	float zraw_f = math::constrainFloatToInt16(raw_mag_report.z / _mag_range_scale);
 
 	mag_report.x_raw = xraw_f;
 	mag_report.y_raw = yraw_f;
diff --git a/src/modules/simulator/gyrosim/gyrosim.cpp b/src/modules/simulator/gyrosim/gyrosim.cpp
index ae94700bb4..af1f6d33a1 100644
--- a/src/modules/simulator/gyrosim/gyrosim.cpp
+++ b/src/modules/simulator/gyrosim/gyrosim.cpp
@@ -109,20 +109,6 @@ using namespace DriverFramework;
 #define EXTERNAL_BUS 0
 #endif
 
-namespace
-{
-/** Save way to check if float is zero */
-inline bool isZero(const float &val)
-{
-	return abs(val - 0.0f) < FLT_EPSILON;
-}
-
-inline int16_t constrainToInt(float value)
-{
-	return (int16_t)math::constrain(value, (float)INT16_MIN, (float)INT16_MAX);
-}
-}
-
 /*
   the GYROSIM can only handle high SPI bus speeds on the sensor and
   interrupt status registers. All other registers have a maximum 1MHz
@@ -959,13 +945,13 @@ GYROSIM::_measure()
 
 	/* NOTE: Axes have been swapped to match the board a few lines above. */
 
-	if (isZero(_accel_range_scale)) {
+	if (math::isZero(_accel_range_scale)) {
 		_accel_range_scale = FLT_EPSILON;
 	}
 
-	arb.x_raw = constrainToInt(mpu_report.accel_x / _accel_range_scale);
-	arb.y_raw = constrainToInt(mpu_report.accel_y / _accel_range_scale);
-	arb.z_raw = constrainToInt(mpu_report.accel_z / _accel_range_scale);
+	arb.x_raw = math::constrainFloatToInt16(mpu_report.accel_x / _accel_range_scale);
+	arb.y_raw = math::constrainFloatToInt16(mpu_report.accel_y / _accel_range_scale);
+	arb.z_raw = math::constrainFloatToInt16(mpu_report.accel_z / _accel_range_scale);
 
 	arb.scaling = _accel_range_scale;
 
@@ -988,13 +974,13 @@ GYROSIM::_measure()
 	/* fake device ID */
 	arb.device_id = 1376264;
 
-	if (isZero(_gyro_range_scale)) {
+	if (math::isZero(_gyro_range_scale)) {
 		_gyro_range_scale = FLT_EPSILON;
 	}
 
-	grb.x_raw = constrainToInt(mpu_report.gyro_x / _gyro_range_scale);
-	grb.y_raw = constrainToInt(mpu_report.gyro_y / _gyro_range_scale);
-	grb.z_raw = constrainToInt(mpu_report.gyro_z / _gyro_range_scale);
+	grb.x_raw = math::constrainFloatToInt16(mpu_report.gyro_x / _gyro_range_scale);
+	grb.y_raw = math::constrainFloatToInt16(mpu_report.gyro_y / _gyro_range_scale);
+	grb.z_raw = math::constrainFloatToInt16(mpu_report.gyro_z / _gyro_range_scale);
 
 	grb.scaling = _gyro_range_scale;
 
-- 
GitLab