Skip to content

Commit a3f5837

Browse files
PhazonicRidleykammce
authored andcommitted
♻️ Separated ADC multiplexer implementations into a source file to allow for precompilation
Revert ":zap: Use libhal-soft library in tests" This reverts commit 21c88fb.
1 parent 4e3b0d2 commit a3f5837

7 files changed

Lines changed: 264 additions & 129 deletions

File tree

CMakeLists.txt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@ project(libhal-soft VERSION 0.0.1 LANGUAGES CXX)
1919
find_package(libhal REQUIRED CONFIG)
2020
find_package(libhal-util REQUIRED CONFIG)
2121

22+
if(NOT BUILD_TESTING STREQUAL OFF)
23+
add_subdirectory(tests)
24+
endif()
25+
2226
add_library(libhal-soft
2327
src/rc_servo.cpp
24-
src/i2c_minimum_speed.cpp)
28+
src/i2c_minimum_speed.cpp
29+
src/adc_mux.cpp)
2530

2631
target_include_directories(libhal-soft PUBLIC include)
2732
target_compile_features(libhal-soft PRIVATE cxx_std_20)
@@ -30,8 +35,4 @@ target_link_libraries(libhal-soft PRIVATE
3035
libhal::util
3136
)
3237

33-
if(NOT BUILD_TESTING STREQUAL OFF)
34-
add_subdirectory(tests)
35-
endif()
36-
3738
install(TARGETS libhal-soft)

include/libhal-soft/adc_mux.hpp

Lines changed: 62 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -13,111 +13,93 @@
1313
// limitations under the License.
1414

1515
#pragma once
16+
1617
#include <array>
17-
#include <libhal-util/map.hpp>
18-
#include <libhal-util/math.hpp>
18+
#include <span>
19+
1920
#include <libhal/adc.hpp>
20-
#include <libhal/error.hpp>
2121
#include <libhal/output_pin.hpp>
2222
#include <libhal/steady_clock.hpp>
23-
#include <span>
24-
25-
using namespace hal::literals;
26-
using namespace std::chrono_literals;
2723

2824
namespace hal {
2925

30-
// This function does not take into account setup and hold times.
31-
hal::status set_mux_channel(uint32_t p_position,
32-
std::span<hal::output_pin*> p_signal_pins)
33-
{
34-
35-
for (int i = 0; i < static_cast<int>(p_signal_pins.size()); i++) {
36-
37-
bool value = bool(p_position & (1 << i));
38-
HAL_CHECK(p_signal_pins[i]->level(value));
39-
}
40-
return hal::success();
41-
}
42-
4326
/**
44-
* @brief A driver for Analog to Digital mulitplexers, creates adc pin objects
45-
* for each mux output
27+
* @brief A driver for an ADC multiplexer that manages and reads ADC mux pins.
28+
* This driver is intended to be used with multiplexers that use digital
29+
* signals. An ADC multiplexer can be used to expand the number of input
30+
* channels of an ADC.
4631
*/
4732
class adc_multiplexer
4833
{
4934
public:
5035
/**
51-
* @brief An internal class of a hal ADC implimentation to represent a
52-
* multiplexer pin
36+
* @brief Constructs a new adc_multiplexer object.
37+
*
38+
* @param p_signal_pins A span of the output signal pins used to determine the
39+
* channel on the mux.
40+
* @param p_source_pin The output adc pin of the multiplexer.
41+
* @param p_clock A steady clock used for delaying 500ns to give time to the
42+
* mux to have an updated signal.
43+
* @return The constructed adc_multiplexer.
5344
*/
54-
class adc_mux_pin : public hal::adc
55-
{
56-
public:
57-
/** @brief An internal constructor to build an adc mux pin.
58-
* @param p_mux_port the channel port of the pin on the mux itself.
59-
* @param p_mux A pointer to the multiplexer.
60-
* */
61-
adc_mux_pin(uint8_t p_mux_port, adc_multiplexer* p_mux)
62-
: m_mux_port{ p_mux_port }
63-
, m_mux{ p_mux } {}; // TODO add m_mux
64-
65-
/**
66-
* @brief Reads the pin.
67-
*/
68-
hal::result<read_t> driver_read() override
69-
{
70-
return m_mux->read_channel(m_mux_port);
71-
}
72-
73-
private:
74-
const uint8_t m_mux_port;
75-
adc_multiplexer* m_mux;
76-
};
45+
static adc_multiplexer create(std::span<hal::output_pin*> p_signal_pins,
46+
hal::adc& p_source_pin,
47+
hal::steady_clock& p_clock);
7748

7849
/**
79-
* @param p_signal_pins A span of output pins to represent the signal pins of
80-
* the mux, assuming the mux signals digitally.
81-
* @param p_source_pin The adc source pin that reads the output of the mux.
50+
* @brief Reads a channel on the mux.
51+
*
52+
* @param p_mux_port The port to be read. If an out of bounds port number is
53+
* passed, an error-typed result is returned.
54+
* @return The hal::adc::read_t struct of the read value or an error if an
55+
* invalid port is given.
8256
*/
83-
adc_multiplexer(std::span<hal::output_pin*> p_signal_pins,
84-
hal::adc* p_source_pin)
85-
: m_signal_pins{ p_signal_pins }
86-
, m_source_pin{ p_source_pin } {};
57+
hal::result<hal::adc::read_t> read_channel(std::uint16_t p_mux_port);
8758

8859
/**
89-
* @brief Returns a multiplexer ADC pin
90-
* @param p_channel The channel number of the pin.
60+
* @brief Gets the highest capacity channel held by the ADC mux object.
61+
* This is caluclated based off of how many source pins are available.
62+
*
63+
* @return The maximum channel number for this mux (2^n states, where n is
64+
* number of source pins).
9165
*/
92-
hal::result<adc_mux_pin> pin_factory(uint8_t p_channel)
93-
{
94-
// TODO: Ask if we should keep track of channels in use, if a port is asked
95-
// for again, disallow it.
96-
const std::uint32_t max_size = 1 << m_signal_pins.size();
97-
if (p_channel >= max_size) {
98-
return hal::new_error(
99-
"Unable to add any more pins to this multiplexer.\n");
100-
}
101-
102-
return adc_mux_pin(p_channel, this);
103-
}
66+
int get_max_channel();
10467

10568
private:
106-
/**
107-
* @brief Reads the channel
108-
*
109-
* @param p_mux_port
110-
* @return hal::result<hal::adc::read_t>
111-
*/
112-
hal::result<hal::adc::read_t> read_channel(uint8_t p_mux_port)
113-
{
114-
set_mux_channel(p_mux_port, m_signal_pins);
115-
return HAL_CHECK(m_source_pin->read());
116-
}
69+
adc_multiplexer(std::span<output_pin*> p_signal_pins,
70+
hal::adc& p_source_pin,
71+
hal::steady_clock& p_clock);
11772

11873
private:
119-
std::span<hal::output_pin*> m_signal_pins;
74+
std::span<output_pin*> m_signal_pins;
12075
hal::adc* m_source_pin;
76+
hal::steady_clock* m_clock;
77+
};
78+
79+
/**
80+
* @brief A class that represents a multiplexer pin for ADC.
81+
*/
82+
class adc_mux_pin : public hal::adc
83+
{
84+
friend result<adc_mux_pin> make_adc(adc_multiplexer& p_multiplexer,
85+
std::uint8_t p_channel);
86+
87+
private:
88+
adc_mux_pin(adc_multiplexer& p_mux, std::uint8_t p_mux_port);
89+
hal::result<read_t> driver_read() override;
90+
91+
adc_multiplexer* m_mux;
92+
std::uint8_t m_mux_port;
12193
};
12294

95+
/**
96+
* @brief Returns a multiplexer ADC pin.
97+
*
98+
* @param p_multiplexer The multiplexer object to manage each mux pin.
99+
* @param p_channel The channel number of the pin.
100+
* @return A newly constructed ADC multiplexer pin.
101+
*/
102+
result<adc_mux_pin> make_adc(adc_multiplexer& p_multiplexer,
103+
std::uint8_t p_channel);
104+
123105
} // namespace hal

src/adc_mux.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include <libhal-soft/adc_mux.hpp>
2+
#include <libhal-util/steady_clock.hpp>
3+
4+
namespace hal {
5+
using namespace hal::literals;
6+
using namespace std::chrono_literals;
7+
8+
namespace {
9+
/**
10+
* @brief Set the ADC mux to a specific channel.
11+
*
12+
* @param p_position The desired channel.
13+
* @param p_signal_pins A span of the source pins.
14+
* @param p_clock A steady clock used for delaying 500ns to give time to the mux
15+
* to have an updated signal
16+
* @return The status of the operation.
17+
*/
18+
hal::status set_mux_channel(std::uint16_t p_position,
19+
std::span<output_pin*> p_signal_pins,
20+
hal::steady_clock& p_clock)
21+
{
22+
for (std::size_t i = 0; i < p_signal_pins.size(); i++) {
23+
bool value = bool(p_position & (1 << i));
24+
hal::delay(p_clock, 500ns);
25+
HAL_CHECK(p_signal_pins[i]->level(value));
26+
}
27+
return success();
28+
}
29+
} // namespace
30+
31+
result<adc_mux_pin> make_adc(adc_multiplexer& p_multiplexer,
32+
std::uint8_t p_channel)
33+
{
34+
if (p_channel > p_multiplexer.get_max_channel()) {
35+
return hal::new_error(1);
36+
}
37+
return adc_mux_pin(p_multiplexer, p_channel);
38+
}
39+
40+
// Implementations for adc_multiplexer
41+
42+
adc_multiplexer::adc_multiplexer(std::span<output_pin*> p_signal_pins,
43+
hal::adc& p_source_pin,
44+
hal::steady_clock& p_clock)
45+
: m_signal_pins{ p_signal_pins }
46+
, m_source_pin{ &p_source_pin }
47+
, m_clock{ &p_clock } {};
48+
49+
adc_multiplexer adc_multiplexer::create(
50+
std::span<hal::output_pin*> p_signal_pins,
51+
hal::adc& p_source_pin,
52+
hal::steady_clock& p_clock)
53+
{
54+
return adc_multiplexer(p_signal_pins, p_source_pin, p_clock);
55+
}
56+
57+
int adc_multiplexer::get_max_channel()
58+
{
59+
return 1 << this->m_signal_pins.size();
60+
}
61+
62+
hal::result<hal::adc::read_t> adc_multiplexer::read_channel(
63+
std::uint16_t p_mux_port)
64+
{
65+
set_mux_channel(p_mux_port, m_signal_pins, *m_clock);
66+
hal::delay(*m_clock, 500ns);
67+
return HAL_CHECK(m_source_pin->read());
68+
}
69+
70+
// Implementations for adc_mux_pin
71+
72+
adc_mux_pin::adc_mux_pin(adc_multiplexer& p_mux, std::uint8_t p_mux_port)
73+
: m_mux{ &p_mux }
74+
, m_mux_port{ p_mux_port } {};
75+
76+
hal::result<hal::adc::read_t> adc_mux_pin::driver_read()
77+
{
78+
return m_mux->read_channel(m_mux_port);
79+
}
80+
} // namespace hal

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ find_package(libhal-util REQUIRED CONFIG)
4545
find_package(libhal-mock REQUIRED CONFIG)
4646

4747
add_executable(${PROJECT_NAME}
48+
adc_mux.test.cpp
4849
i2c_minimum_speed.test.cpp
4950
rc_servo.test.cpp
5051

0 commit comments

Comments
 (0)