From b4260e73f3c4c64e11bb0b7783b35d259a1b54a8 Mon Sep 17 00:00:00 2001 From: Sergey Polyakov Date: Sun, 5 Feb 2017 16:19:48 +0200 Subject: [PATCH 1/2] Avoid division by zero when map() is called with incorrect parameters; provide map() overload for double type --- user/tests/wiring/api/wiring.cpp | 7 ++++++- user/tests/wiring/no_fixture/misc.cpp | 30 +++++++++++++++++++++++++++ wiring/inc/spark_wiring.h | 6 +++--- wiring/src/spark_wiring.cpp | 17 ++++++++++++--- 4 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 user/tests/wiring/no_fixture/misc.cpp diff --git a/user/tests/wiring/api/wiring.cpp b/user/tests/wiring/api/wiring.cpp index 335825641d..fa1ccea82d 100644 --- a/user/tests/wiring/api/wiring.cpp +++ b/user/tests/wiring/api/wiring.cpp @@ -186,7 +186,12 @@ test(api_wire) test(api_map) { - map(0x01,0x00,0xFF,0,255); + int i = 0; + API_COMPILE(i = map(0x01, 0x00, 0xFF, 0, 255)); + double d = 0; + API_COMPILE(d = map(5.0, 0.0, 10.0, 0.0, 20.0)); + (void)i; // avoid unused variable warning + (void)d; } /** diff --git a/user/tests/wiring/no_fixture/misc.cpp b/user/tests/wiring/no_fixture/misc.cpp new file mode 100644 index 0000000000..f35346bf66 --- /dev/null +++ b/user/tests/wiring/no_fixture/misc.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017 Particle Industries, Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "application.h" +#include "unit-test/unit-test.h" + +test(MISC_01_map) { + // int map(int, int, int, int, int) + assertEqual(map(5, 0, 10, 0, 10), 5); + assertEqual(map(5, 0, 10, 0, 20), 10); + assertEqual(map(5, 10, 10, 10, 10), 5); // Shouldn't cause division by zero + // double map(double, double, double, double, double) + assertEqual(map(5.0, 0.0, 10.0, 0.0, 10.0), 5); + assertEqual(map(5.0, 0.0, 10.0, 0.0, 15.0), 7.5); + assertEqual(map(5.5, 10.0, 10.0, 10.0, 10.0), 5.5); // Shouldn't cause division by zero +} diff --git a/wiring/inc/spark_wiring.h b/wiring/inc/spark_wiring.h index a2d266daba..90522acc4b 100644 --- a/wiring/inc/spark_wiring.h +++ b/wiring/inc/spark_wiring.h @@ -71,9 +71,6 @@ bool pinAvailable(uint16_t pin); void digitalWrite(uint16_t pin, uint8_t value); int32_t digitalRead(uint16_t pin); - -long map(long value, long fromStart, long fromEnd, long toStart, long toEnd); - void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); @@ -92,4 +89,7 @@ uint8_t analogWriteResolution(pin_t pin); uint32_t analogWriteMaxFrequency(pin_t pin); void setDACBufferred(pin_t pin, uint8_t state); +int map(int value, int fromStart, int fromEnd, int toStart, int toEnd); +double map(double value, double fromStart, double fromEnd, double toStart, double toEnd); + #endif /* SPARK_WIRING_H_ */ diff --git a/wiring/src/spark_wiring.cpp b/wiring/src/spark_wiring.cpp index af5c6854d9..c549bc7096 100644 --- a/wiring/src/spark_wiring.cpp +++ b/wiring/src/spark_wiring.cpp @@ -32,12 +32,23 @@ */ void setADCSampleTime(uint8_t ADC_SampleTime) { - HAL_ADC_Set_Sample_Time(ADC_SampleTime); + HAL_ADC_Set_Sample_Time(ADC_SampleTime); } -long map(long value, long fromStart, long fromEnd, long toStart, long toEnd) +int map(int value, int fromStart, int fromEnd, int toStart, int toEnd) { - return (value - fromStart) * (toEnd - toStart) / (fromEnd - fromStart) + toStart; + if (fromEnd == fromStart) { + return value; + } + return (value - fromStart) * (toEnd - toStart) / (fromEnd - fromStart) + toStart; +} + +double map(double value, double fromStart, double fromEnd, double toStart, double toEnd) +{ + if (fromEnd == fromStart) { + return value; + } + return (value - fromStart) * (toEnd - toStart) / (fromEnd - fromStart) + toStart; } void delay(unsigned long ms) From 9e8e46ca985aaaf347e946b07aa5fbe130a61e3a Mon Sep 17 00:00:00 2001 From: Julien Vanier Date: Thu, 9 Feb 2017 15:05:58 -0500 Subject: [PATCH 2/2] Update docs for map() --- docs/reference/firmware.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/reference/firmware.md b/docs/reference/firmware.md index 359c4248d2..21fea5ca3b 100644 --- a/docs/reference/firmware.md +++ b/docs/reference/firmware.md @@ -7569,9 +7569,9 @@ The function also handles negative numbers well, so that this example is also valid and works well. -The `map()` function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, and are not rounded or averaged. +When called with integers, the `map()` function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, not rounded. -*Parameters:* +*Parameters can either be integers or floating point numbers:* - `value`: the number to map - `fromLow`: the lower bound of the value's current range @@ -7579,15 +7579,18 @@ The `map()` function uses integer math so will not generate fractions, when the - `toLow`: the lower bound of the value's target range - `toHigh`: the upper bound of the value's target range -The function returns the mapped value +The function returns the mapped value, as integer or floating point depending on the arguments. *Appendix:* For the mathematically inclined, here's the whole function ```C++ -long map(long x, long in_min, long in_max, long out_min, long out_max) +int map(int value, int fromStart, int fromEnd, int toStart, int toEnd) { - return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; + if (fromEnd == fromStart) { + return value; + } + return (value - fromStart) * (toEnd - toStart) / (fromEnd - fromStart) + toStart; } ```