This repository has been archived by the owner on Jan 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resolves #201
1 parent
800c57f
commit c7f4b75
Showing
3 changed files
with
313 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#pragma once | ||
|
||
#include <units/isq/si/length.h> | ||
|
||
#include "../adc/interface.hpp" | ||
#include "../math.hpp" | ||
|
||
namespace embed { | ||
/** | ||
* @brief Linear potentiometer driver that takes an embed::adc and a | ||
* settings struct, and reads the distance the linear potentiometer has traveled | ||
* in nanometres. | ||
* | ||
*/ | ||
class linear_potentiometer | ||
{ | ||
public: | ||
/// Universal unit for length | ||
using length = | ||
units::isq::si::length<units::isq::si::nanometre, std::int64_t>; | ||
/** | ||
* @brief Settings for a linear potentiometer object. Contains | ||
* variables for minimum and maximum travel distance, as well as variables for | ||
* minimum and maximum percentages for the ADC. | ||
* | ||
*/ | ||
struct settings | ||
{ | ||
/// Minimum travel distance in nanometres | ||
length p_min_distance = units::aliases::isq::si::nm<std::int64_t>(0); | ||
/// Maximum travel distance in nanometres | ||
length p_max_distance = units::aliases::isq::si::nm<std::int64_t>(0); | ||
/// Minimum percent that can be read from ADC | ||
embed::percent p_min_adc_output = embed::percent::from_ratio(0, 1); | ||
/// Maximum percent that can be read from ADC | ||
embed::percent p_max_adc_output = embed::percent::from_ratio(1, 1); | ||
}; | ||
|
||
/** | ||
* @brief Construct a new linear potentiometer object. | ||
* | ||
* @param p_adc ADC of linear potentiometer. | ||
* @param p_settings Settings for linear potentiometer. | ||
*/ | ||
linear_potentiometer(embed::adc& p_adc, settings p_settings) | ||
: m_adc(&p_adc) | ||
, m_settings(p_settings) | ||
{ | ||
} | ||
|
||
/** | ||
* @brief Read the distance the linear potentiometer has traveled. | ||
* | ||
* @return boost::leaf::result<length> - the distance traveled of the | ||
* potentiometer in nanometres. | ||
*/ | ||
boost::leaf::result<length> read() | ||
{ | ||
auto adc_percent = BOOST_LEAF_CHECK(m_adc->read()); | ||
auto scaled_percent = adc_percent.scale(m_settings.p_min_adc_output, | ||
m_settings.p_max_adc_output); | ||
auto scaled_distance = scaled_percent.scale( | ||
m_settings.p_min_distance.number(), m_settings.p_max_distance.number()); | ||
return units::aliases::isq::si::nm<std::int64_t>(scaled_distance); | ||
} | ||
|
||
private: | ||
embed::adc* m_adc = nullptr; | ||
settings m_settings{}; | ||
}; | ||
} // namespace embed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
#include <boost/ut.hpp> | ||
#include <libembeddedhal/adc/mock.hpp> | ||
#include <libembeddedhal/linear_potentiometer/interface.hpp> | ||
#include <units/isq/si/international/length.h> | ||
|
||
namespace embed { | ||
boost::ut::suite linear_pot_test = []() { | ||
using namespace boost::ut; | ||
|
||
"embed::linear_potentiometer::read() default settings"_test = []() { | ||
// Setup | ||
embed::mock::adc mock(embed::percent::from_ratio(1, 2)); | ||
embed::linear_potentiometer::settings settings; | ||
embed::linear_potentiometer test(mock, settings); | ||
|
||
// Exercise + Verify | ||
expect(that % 0 == test.read().value().number()); | ||
}; | ||
|
||
"embed::linear_potentiometer::read() positive percent range"_test = []() { | ||
// Setup | ||
embed::mock::adc mock(embed::percent::from_ratio(0, 1)); | ||
embed::linear_potentiometer::settings settings; | ||
settings.p_min_distance = units::aliases::isq::si::nm<std::int64_t>(1); | ||
settings.p_max_distance = units::aliases::isq::si::nm<std::int64_t>(100); | ||
settings.p_min_adc_output = embed::percent::from_ratio(0, 1); | ||
settings.p_max_adc_output = embed::percent::from_ratio(1, 1); | ||
embed::linear_potentiometer test(mock, settings); | ||
|
||
// Exercise + Verify | ||
expect(that % 1 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 4)); | ||
expect(that % 25 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 2)); | ||
expect(that % 50 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(3, 4)); | ||
expect(that % 75 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 1)); | ||
expect(that % 100 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(2, 1)); | ||
expect(that % 100 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-1, 2)); | ||
expect(that % 1 == test.read().value().number()); | ||
}; | ||
|
||
"embed::linear_potentiometer::read() negative percent range"_test = []() { | ||
// Setup | ||
embed::mock::adc mock(embed::percent::from_ratio(-1, 1)); | ||
embed::linear_potentiometer::settings settings; | ||
settings.p_min_distance = units::aliases::isq::si::nm<std::int64_t>(0); | ||
settings.p_max_distance = units::aliases::isq::si::nm<std::int64_t>(100); | ||
settings.p_min_adc_output = embed::percent::from_ratio(-1, 1); | ||
settings.p_max_adc_output = embed::percent::from_ratio(0, 1); | ||
embed::linear_potentiometer test(mock, settings); | ||
|
||
// Exercise + Verify | ||
expect(that % 0 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-1, 4)); | ||
expect(that % 75 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-1, 2)); | ||
expect(that % 50 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-3, 4)); | ||
expect(that % 25 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(0, 1)); | ||
expect(that % 100 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 2)); | ||
expect(that % 100 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-2, 1)); | ||
expect(that % 0 == test.read().value().number()); | ||
}; | ||
|
||
"embed::linear_potentiometer::read() negative distances"_test = []() { | ||
// Setup | ||
embed::mock::adc mock(embed::percent::from_ratio(0, 1)); | ||
embed::linear_potentiometer::settings settings; | ||
settings.p_min_distance = units::aliases::isq::si::nm<std::int64_t>(-200); | ||
settings.p_max_distance = units::aliases::isq::si::nm<std::int64_t>(-100); | ||
settings.p_min_adc_output = embed::percent::from_ratio(0, 1); | ||
settings.p_max_adc_output = embed::percent::from_ratio(1, 1); | ||
embed::linear_potentiometer test(mock, settings); | ||
|
||
// Exercise + Verify | ||
expect(that % -200 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 4)); | ||
expect(that % -175 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 2)); | ||
expect(that % -150 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(3, 4)); | ||
expect(that % -125 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 1)); | ||
expect(that % -100 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-1, 2)); | ||
expect(that % -200 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(2, 1)); | ||
expect(that % -100 == test.read().value().number()); | ||
}; | ||
|
||
"embed::linear_potentiometer::read() large positive range"_test = []() { | ||
// Setup | ||
embed::mock::adc mock(embed::percent::from_ratio(0, 1)); | ||
embed::linear_potentiometer::settings settings; | ||
settings.p_min_distance = units::aliases::isq::si::nm<std::int64_t>(0); | ||
settings.p_max_distance = | ||
units::aliases::isq::si::nm<std::int64_t>(4000000000000000000); | ||
settings.p_min_adc_output = embed::percent::from_ratio(0, 1); | ||
settings.p_max_adc_output = embed::percent::from_ratio(1, 1); | ||
embed::linear_potentiometer test(mock, settings); | ||
|
||
// Exercise + Verify | ||
expect(that % 0 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 4)); | ||
// TODO: Fix with issue #273, expected value adjusted to work with current | ||
// division arithmetic | ||
expect(that % 999999998603016137 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 2)); | ||
expect(that % 1999999999068677424 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(3, 4)); | ||
expect(that % 2999999999534338712 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 1)); | ||
expect(that % 4000000000000000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(2, 1)); | ||
expect(that % 4000000000000000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-1, 2)); | ||
expect(that % 0 == test.read().value().number()); | ||
}; | ||
|
||
"embed::linear_potentiometer::read() large negative range"_test = []() { | ||
// Setup | ||
embed::mock::adc mock(embed::percent::from_ratio(0, 1)); | ||
embed::linear_potentiometer::settings settings; | ||
settings.p_min_distance = | ||
units::aliases::isq::si::nm<std::int64_t>(-4000000000000000000); | ||
settings.p_max_distance = units::aliases::isq::si::nm<std::int64_t>(0); | ||
settings.p_min_adc_output = embed::percent::from_ratio(0, 1); | ||
settings.p_max_adc_output = embed::percent::from_ratio(1, 1); | ||
embed::linear_potentiometer test(mock, settings); | ||
|
||
// Exercise + Verify | ||
expect(that % -4000000000000000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 4)); | ||
// TODO: Fix with issue #273, expected value adjusted to work with current | ||
// division arithmetic | ||
expect(that % -3000000001396983863 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 2)); | ||
expect(that % -2000000000931322576 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(3, 4)); | ||
expect(that % -1000000000465661288 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 1)); | ||
expect(that % 0 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(2, 1)); | ||
expect(that % 0 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-1, 2)); | ||
expect(that % -4000000000000000000 == test.read().value().number()); | ||
}; | ||
|
||
"embed::linear_potentiometer::read() range exceeds max integer value"_test = | ||
[]() { | ||
// Setup | ||
embed::mock::adc mock(embed::percent::from_ratio(0, 1)); | ||
embed::linear_potentiometer::settings settings; | ||
settings.p_min_distance = | ||
units::aliases::isq::si::nm<std::int64_t>(-4000000000000000000); | ||
settings.p_max_distance = | ||
units::aliases::isq::si::nm<std::int64_t>(4000000000000000000); | ||
settings.p_min_adc_output = embed::percent::from_ratio(0, 1); | ||
settings.p_max_adc_output = embed::percent::from_ratio(1, 1); | ||
embed::linear_potentiometer test(mock, settings); | ||
|
||
// Exercise + Verify | ||
expect(that % -4000000000000000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 4)); | ||
// TODO: Fix with issue #273, expected value adjusted to work with current | ||
// division arithmetic | ||
expect(that % -2000000002793967726 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 2)); | ||
expect(that % -1862645152 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(3, 4)); | ||
expect(that % 1999999999068677424 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 1)); | ||
expect(that % 4000000000000000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(2, 1)); | ||
expect(that % 4000000000000000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-1, 2)); | ||
expect(that % -4000000000000000000 == test.read().value().number()); | ||
}; | ||
|
||
"embed::linear_potentiometer::read() range in meters"_test = []() { | ||
// Setup | ||
embed::mock::adc mock(embed::percent::from_ratio(0, 1)); | ||
embed::linear_potentiometer::settings settings; | ||
settings.p_min_distance = units::aliases::isq::si::m<std::int64_t>(1); | ||
settings.p_max_distance = units::aliases::isq::si::m<std::int64_t>(2); | ||
settings.p_min_adc_output = embed::percent::from_ratio(0, 1); | ||
settings.p_max_adc_output = embed::percent::from_ratio(1, 1); | ||
embed::linear_potentiometer test(mock, settings); | ||
|
||
// Exercise + Verify | ||
expect(that % 1000000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 4)); | ||
expect(that % 1250000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 2)); | ||
expect(that % 1500000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(3, 4)); | ||
expect(that % 1750000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 1)); | ||
expect(that % 2000000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(2, 1)); | ||
expect(that % 2000000000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-1, 2)); | ||
expect(that % 1000000000 == test.read().value().number()); | ||
}; | ||
|
||
"embed::linear_potentiometer::read() range in inches"_test = []() { | ||
// Setup | ||
embed::mock::adc mock(embed::percent::from_ratio(0, 1)); | ||
embed::linear_potentiometer::settings settings; | ||
settings.p_min_distance = | ||
units::aliases::isq::si::international::in<std::int64_t>(1); | ||
settings.p_max_distance = | ||
units::aliases::isq::si::international::in<std::int64_t>(4); | ||
settings.p_min_adc_output = embed::percent::from_ratio(0, 1); | ||
settings.p_max_adc_output = embed::percent::from_ratio(1, 1); | ||
embed::linear_potentiometer test(mock, settings); | ||
|
||
// Exercise + Verify | ||
expect(that % 25400000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 4)); | ||
expect(that % 44450000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 2)); | ||
expect(that % 63500000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(3, 4)); | ||
expect(that % 82550000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(1, 1)); | ||
expect(that % 101600000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(2, 1)); | ||
expect(that % 101600000 == test.read().value().number()); | ||
mock.set(embed::percent::from_ratio(-1, 2)); | ||
expect(that % 25400000 == test.read().value().number()); | ||
}; | ||
}; | ||
} // namespace embed |