Skip to content

Commit 241fb03

Browse files
authored
fix(sensors): Share sync line control bitmasks (#799)
* add another singletop so sensor hardware instances can share their bitmask control * update tests * format * remove prints * use inverse operator * fix pipette-simulators
1 parent 97885c9 commit 241fb03

15 files changed

+181
-89
lines changed

gripper/firmware/main_proto.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,11 @@ auto sensor_pins = sensors::hardware::SensorHardwareConfiguration{
8787
.active_setting = GPIO_PIN_RESET}};
8888

8989
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
90-
auto sensor_hardware =
91-
sensors::hardware::SensorHardware(sensor_pins, version_wrapper);
90+
static auto sync_control =
91+
sensors::hardware::SensorHardwareSyncControlSingleton();
92+
93+
auto sensor_hardware = sensors::hardware::SensorHardware(
94+
sensor_pins, version_wrapper, sync_control);
9295

9396
auto main() -> int {
9497
HardwareInit();

gripper/firmware/main_rev1.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,11 @@ auto sensor_pins = sensors::hardware::SensorHardwareConfiguration{
9898
.active_setting = GPIO_PIN_RESET}};
9999

100100
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
101-
auto sensor_hardware =
102-
sensors::hardware::SensorHardware(sensor_pins, version_wrapper);
101+
static auto sync_control =
102+
sensors::hardware::SensorHardwareSyncControlSingleton();
103+
104+
auto sensor_hardware = sensors::hardware::SensorHardware(
105+
sensor_pins, version_wrapper, sync_control);
103106

104107
auto main() -> int {
105108
HardwareInit();

gripper/simulator/main.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ static auto sensor_map =
3636
static auto i2c2 = i2c::hardware::SimI2C{sensor_map};
3737

3838
static sensors::hardware::SensorHardwareVersionSingleton version_wrapper{};
39-
static sim_mocks::MockSensorHardware fake_sensor_hw{version_wrapper};
39+
static sensors::hardware::SensorHardwareSyncControlSingleton sync_control{};
40+
static sim_mocks::MockSensorHardware fake_sensor_hw{version_wrapper,
41+
sync_control};
4042

4143
static std::shared_ptr<state_manager::StateManagerConnection<
4244
freertos_synchronization::FreeRTOSCriticalSection>>

include/pipettes/firmware/utility_configurations.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ auto led_gpio(PipetteType pipette_type) -> gpio::PinConfig;
2323

2424
auto get_sensor_hardware_container(
2525
SensorHardwareGPIO pins,
26-
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper)
26+
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper,
27+
sensors::hardware::SensorHardwareSyncControlSingleton& sync_control)
2728
-> SensorHardwareContainer;
2829

2930
template <PipetteType P>

include/sensors/core/sensor_hardware_interface.hpp

+72-32
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,67 @@ static auto get_mask_from_id(can::ids::SensorId sensor) -> uint8_t {
4343
return static_cast<uint8_t>(mask_enum);
4444
}
4545

46+
class SensorHardwareSyncControlSingleton {
47+
public:
48+
SensorHardwareSyncControlSingleton() = default;
49+
virtual ~SensorHardwareSyncControlSingleton() = default;
50+
SensorHardwareSyncControlSingleton(
51+
const SensorHardwareSyncControlSingleton&) = default;
52+
auto operator=(const SensorHardwareSyncControlSingleton&)
53+
-> SensorHardwareSyncControlSingleton& = default;
54+
SensorHardwareSyncControlSingleton(SensorHardwareSyncControlSingleton&&) =
55+
default;
56+
auto operator=(SensorHardwareSyncControlSingleton&&)
57+
-> SensorHardwareSyncControlSingleton& = default;
58+
59+
[[nodiscard]] auto mask_satisfied() const -> bool {
60+
if (set_sync_required_mask !=
61+
static_cast<uint8_t>(SensorIdBitMask::UNUSED)) {
62+
// if anything is "required" only sync when they are all triggered
63+
return (sync_state_mask & set_sync_required_mask) ==
64+
set_sync_required_mask;
65+
}
66+
return (sync_state_mask & set_sync_enabled_mask) != 0;
67+
}
68+
69+
auto set_sync(can::ids::SensorId sensor) -> void {
70+
// force the bit for this sensor to 1
71+
sync_state_mask |= get_mask_from_id(sensor);
72+
}
73+
74+
auto reset_sync(can::ids::SensorId sensor) -> void {
75+
// force the bit for this sensor to 0
76+
sync_state_mask &= ~get_mask_from_id(sensor);
77+
}
78+
79+
auto set_sync_enabled(can::ids::SensorId sensor, bool enabled) -> void {
80+
uint8_t applied_mask = get_mask_from_id(sensor);
81+
if (!enabled) {
82+
// force enabled bit to 0
83+
set_sync_enabled_mask &= ~applied_mask;
84+
} else {
85+
// force enabled bit to 1
86+
set_sync_enabled_mask |= applied_mask;
87+
}
88+
}
89+
90+
auto set_sync_required(can::ids::SensorId sensor, bool required) -> void {
91+
uint8_t applied_mask = get_mask_from_id(sensor);
92+
if (!required) {
93+
// force required bit to 0
94+
set_sync_required_mask &= ~applied_mask;
95+
} else {
96+
// force required bit to 1
97+
set_sync_required_mask |= applied_mask;
98+
}
99+
}
100+
101+
private:
102+
uint8_t set_sync_required_mask = 0x00;
103+
uint8_t set_sync_enabled_mask = 0x00;
104+
uint8_t sync_state_mask = 0x00;
105+
};
106+
46107
class SensorHardwareVersionSingleton {
47108
public:
48109
SensorHardwareVersionSingleton() = default;
@@ -66,8 +127,9 @@ class SensorHardwareVersionSingleton {
66127
/** abstract sensor hardware device for a sync line */
67128
class SensorHardwareBase {
68129
public:
69-
SensorHardwareBase(SensorHardwareVersionSingleton& version_wrapper)
70-
: version_wrapper{version_wrapper} {}
130+
SensorHardwareBase(SensorHardwareVersionSingleton& version_wrapper,
131+
SensorHardwareSyncControlSingleton& sync_control)
132+
: version_wrapper{version_wrapper}, sync_control{sync_control} {}
71133
virtual ~SensorHardwareBase() = default;
72134
SensorHardwareBase(const SensorHardwareBase&) = default;
73135
auto operator=(const SensorHardwareBase&) -> SensorHardwareBase& = delete;
@@ -79,40 +141,27 @@ class SensorHardwareBase {
79141
virtual auto check_tip_presence() -> bool = 0;
80142

81143
[[nodiscard]] auto mask_satisfied() const -> bool {
82-
if (set_sync_required_mask !=
83-
static_cast<uint8_t>(SensorIdBitMask::UNUSED)) {
84-
// if anything is "required" only sync when they are all triggered
85-
return (sync_state_mask & set_sync_required_mask) ==
86-
set_sync_required_mask;
87-
}
88-
return (sync_state_mask & set_sync_enabled_mask) != 0;
144+
return sync_control.mask_satisfied();
89145
}
90146

91147
auto set_sync(can::ids::SensorId sensor) -> void {
92-
// force the bit for this sensor to 1
93-
sync_state_mask |= get_mask_from_id(sensor);
148+
sync_control.set_sync(sensor);
149+
// update sync state now that requirements are different
94150
if (mask_satisfied()) {
95151
set_sync();
96152
}
97153
}
98154

99155
auto reset_sync(can::ids::SensorId sensor) -> void {
100-
// force the bit for this sensor to 0
101-
sync_state_mask &= 0xFF ^ get_mask_from_id(sensor);
156+
sync_control.reset_sync(sensor);
157+
// update sync state now that requirements are different
102158
if (!mask_satisfied()) {
103159
reset_sync();
104160
}
105161
}
106162

107163
auto set_sync_enabled(can::ids::SensorId sensor, bool enabled) -> void {
108-
uint8_t applied_mask = get_mask_from_id(sensor);
109-
if (!enabled) {
110-
// force enabled bit to 0
111-
set_sync_enabled_mask &= 0xFF ^ applied_mask;
112-
} else {
113-
// force enabled bit to 1
114-
set_sync_enabled_mask |= applied_mask;
115-
}
164+
sync_control.set_sync_enabled(sensor, enabled);
116165
// update sync state now that requirements are different
117166
if (mask_satisfied()) {
118167
set_sync();
@@ -122,14 +171,7 @@ class SensorHardwareBase {
122171
}
123172

124173
auto set_sync_required(can::ids::SensorId sensor, bool required) -> void {
125-
uint8_t applied_mask = get_mask_from_id(sensor);
126-
if (!required) {
127-
// force required bit to 0
128-
set_sync_required_mask &= 0xFF ^ applied_mask;
129-
} else {
130-
// force required bit to 1
131-
set_sync_required_mask |= applied_mask;
132-
}
174+
sync_control.set_sync_required(sensor, required);
133175
// update sync state now that requirements are different
134176
if (mask_satisfied()) {
135177
set_sync();
@@ -142,10 +184,8 @@ class SensorHardwareBase {
142184
}
143185

144186
private:
145-
uint8_t set_sync_required_mask = 0x00;
146-
uint8_t set_sync_enabled_mask = 0x00;
147-
uint8_t sync_state_mask = 0x00;
148187
SensorHardwareVersionSingleton& version_wrapper;
188+
SensorHardwareSyncControlSingleton& sync_control;
149189
};
150190

151191
struct SensorHardwareContainer {

include/sensors/firmware/sensor_hardware.hpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ namespace hardware {
1010
class SensorHardware : public SensorHardwareBase {
1111
public:
1212
SensorHardware(sensors::hardware::SensorHardwareConfiguration hardware,
13-
SensorHardwareVersionSingleton& version_wrapper)
14-
: SensorHardwareBase(version_wrapper), hardware(hardware) {}
13+
SensorHardwareVersionSingleton& version_wrapper,
14+
SensorHardwareSyncControlSingleton& sync_control)
15+
: SensorHardwareBase(version_wrapper, sync_control),
16+
hardware(hardware) {}
1517
auto set_sync() -> void override { gpio::set(hardware.sync_out); }
1618
auto reset_sync() -> void override { gpio::reset(hardware.sync_out); }
1719
auto check_tip_presence() -> bool override {

include/sensors/simulation/mock_hardware.hpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ namespace sim_mocks {
1212
class MockSensorHardware : public sensors::hardware::SensorHardwareBase {
1313
public:
1414
MockSensorHardware(
15-
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper)
16-
: sensors::hardware::SensorHardwareBase{version_wrapper} {}
15+
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper,
16+
sensors::hardware::SensorHardwareSyncControlSingleton& sync_control)
17+
: sensors::hardware::SensorHardwareBase{version_wrapper, sync_control} {
18+
}
1719
auto set_sync() -> void override {
1820
if (_state_manager) {
1921
_state_manager->send_sync_msg(SyncPinState::HIGH);

include/sensors/tests/mock_hardware.hpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ namespace test_mocks {
55
class MockSensorHardware : public sensors::hardware::SensorHardwareBase {
66
public:
77
MockSensorHardware(
8-
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper)
9-
: sensors::hardware::SensorHardwareBase{version_wrapper} {}
8+
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper,
9+
sensors::hardware::SensorHardwareSyncControlSingleton& sync_control)
10+
: sensors::hardware::SensorHardwareBase{version_wrapper, sync_control} {
11+
}
1012
auto set_sync() -> void override {
1113
sync_state = true;
1214
sync_set_calls++;
@@ -17,7 +19,9 @@ class MockSensorHardware : public sensors::hardware::SensorHardwareBase {
1719
}
1820
auto check_tip_presence() -> bool override { return false; }
1921

20-
auto get_sync_state_mock() const -> bool { return sync_state; }
22+
auto get_sync_state_mock() const -> bool {
23+
return sensors::hardware::SensorHardwareBase::mask_satisfied();
24+
}
2125
auto get_sync_set_calls() const -> uint32_t { return sync_set_calls; }
2226
auto get_sync_reset_calls() const -> uint32_t { return sync_reset_calls; }
2327

pipettes/firmware/main.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,15 @@ void encoder_callback(int32_t direction) {
130130

131131
static auto version_wrapper =
132132
sensors::hardware::SensorHardwareVersionSingleton();
133+
134+
static auto sync_control =
135+
sensors::hardware::SensorHardwareSyncControlSingleton();
136+
133137
static auto pins_for_sensor =
134138
utility_configs::sensor_configurations<PIPETTE_TYPE>();
135139
static auto sensor_hardware_container =
136-
utility_configs::get_sensor_hardware_container(pins_for_sensor,
137-
version_wrapper);
140+
utility_configs::get_sensor_hardware_container(
141+
pins_for_sensor, version_wrapper, sync_control);
138142

139143
static auto tip_sense_gpio_primary = pins_for_sensor.primary.tip_sense.value();
140144

pipettes/firmware/utility_configurations.cpp

+7-6
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,19 @@ auto utility_configs::led_gpio(PipetteType pipette_type) -> gpio::PinConfig {
2828

2929
auto utility_configs::get_sensor_hardware_container(
3030
utility_configs::SensorHardwareGPIO pins,
31-
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper)
31+
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper,
32+
sensors::hardware::SensorHardwareSyncControlSingleton& sync_control)
3233
-> utility_configs::SensorHardwareContainer {
3334
if (pins.secondary.has_value()) {
3435
return utility_configs::SensorHardwareContainer{
35-
.primary = sensors::hardware::SensorHardware(pins.primary,
36-
version_wrapper),
36+
.primary = sensors::hardware::SensorHardware(
37+
pins.primary, version_wrapper, sync_control),
3738
.secondary = sensors::hardware::SensorHardware(
38-
pins.secondary.value(), version_wrapper)};
39+
pins.secondary.value(), version_wrapper, sync_control)};
3940
}
4041
return utility_configs::SensorHardwareContainer{
41-
.primary =
42-
sensors::hardware::SensorHardware(pins.primary, version_wrapper)};
42+
.primary = sensors::hardware::SensorHardware(
43+
pins.primary, version_wrapper, sync_control)};
4344
}
4445

4546
template <>

pipettes/simulator/main.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -304,11 +304,14 @@ int main(int argc, char** argv) {
304304
auto sim_eeprom = std::make_shared<eeprom::simulator::EEProm>(
305305
eeprom_model, options, TEMPORARY_PIPETTE_SERIAL);
306306
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
307+
auto sync_control = sensors::hardware::SensorHardwareSyncControlSingleton();
307308
auto fake_sensor_hw_primary =
308-
std::make_shared<sim_mocks::MockSensorHardware>(version_wrapper);
309+
std::make_shared<sim_mocks::MockSensorHardware>(version_wrapper,
310+
sync_control);
309311
fake_sensor_hw_primary->provide_state_manager(state_manager_connection);
310312
auto fake_sensor_hw_secondary =
311-
std::make_shared<sim_mocks::MockSensorHardware>(version_wrapper);
313+
std::make_shared<sim_mocks::MockSensorHardware>(version_wrapper,
314+
sync_control);
312315
fake_sensor_hw_secondary->provide_state_manager(state_manager_connection);
313316
auto pressuresensor_i2c1 = std::make_shared<mmr920_simulator::MMR920>();
314317
auto pressuresensor_i2c3 = std::make_shared<mmr920_simulator::MMR920>();

sensors/tests/test_capacitive_sensor.cpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ static std::array<float, SENSOR_BUFFER_SIZE> sensor_buffer;
3434

3535
SCENARIO("read capacitance sensor values without shared CINs") {
3636
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
37-
test_mocks::MockSensorHardware mock_hw(version_wrapper);
37+
auto sync_control = sensors::hardware::SensorHardwareSyncControlSingleton();
38+
test_mocks::MockSensorHardware mock_hw(version_wrapper, sync_control);
3839
test_mocks::MockMessageQueue<i2c::writer::TaskMessage> i2c_queue{};
3940
test_mocks::MockMessageQueue<i2c::poller::TaskMessage> poller_queue{};
4041

@@ -364,7 +365,8 @@ SCENARIO("read capacitance sensor values without shared CINs") {
364365

365366
SCENARIO("read capacitance sensor values supporting shared CINs") {
366367
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
367-
test_mocks::MockSensorHardware mock_hw{version_wrapper};
368+
auto sync_control = sensors::hardware::SensorHardwareSyncControlSingleton();
369+
test_mocks::MockSensorHardware mock_hw{version_wrapper, sync_control};
368370
test_mocks::MockMessageQueue<i2c::writer::TaskMessage> i2c_queue{};
369371
test_mocks::MockMessageQueue<i2c::poller::TaskMessage> poller_queue{};
370372

@@ -570,7 +572,8 @@ SCENARIO("read capacitance sensor values supporting shared CINs") {
570572

571573
SCENARIO("capacitance driver tests no shared CINs") {
572574
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
573-
test_mocks::MockSensorHardware mock_hw{version_wrapper};
575+
auto sync_control = sensors::hardware::SensorHardwareSyncControlSingleton();
576+
test_mocks::MockSensorHardware mock_hw{version_wrapper, sync_control};
574577
test_mocks::MockMessageQueue<i2c::writer::TaskMessage> i2c_queue{};
575578
test_mocks::MockMessageQueue<i2c::poller::TaskMessage> poller_queue{};
576579

@@ -756,7 +759,8 @@ SCENARIO("capacitance driver tests no shared CINs") {
756759

757760
SCENARIO("threshold configuration") {
758761
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
759-
test_mocks::MockSensorHardware mock_hw{version_wrapper};
762+
auto sync_control = sensors::hardware::SensorHardwareSyncControlSingleton();
763+
test_mocks::MockSensorHardware mock_hw{version_wrapper, sync_control};
760764
test_mocks::MockMessageQueue<i2c::writer::TaskMessage> i2c_queue{};
761765
test_mocks::MockMessageQueue<i2c::poller::TaskMessage> poller_queue{};
762766

sensors/tests/test_pressure_driver.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ SCENARIO("Testing the pressure sensor driver") {
4949
test_mocks::MockI2CResponseQueue response_queue{};
5050

5151
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
52+
auto sync_control = sensors::hardware::SensorHardwareSyncControlSingleton();
5253

5354
i2c::writer::TaskMessage empty_msg{};
5455
i2c::poller::TaskMessage empty_poll_msg{};
5556
auto writer = i2c::writer::Writer<test_mocks::MockMessageQueue>{};
5657
auto poller = i2c::poller::Poller<test_mocks::MockMessageQueue>{};
57-
test_mocks::MockSensorHardware hardware{version_wrapper};
58+
test_mocks::MockSensorHardware hardware{version_wrapper, sync_control};
5859
auto queue_client =
5960
mock_client::QueueClient{.pressure_sensor_queue = &pressure_queue};
6061
queue_client.set_queue(&can_queue);

sensors/tests/test_pressure_sensor.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ SCENARIO("Receiving messages through the pressure sensor message handler") {
4646
test_mocks::MockMessageQueue<sensors::utils::TaskMessage> pressure_queue{};
4747
test_mocks::MockI2CResponseQueue response_queue{};
4848
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
49-
test_mocks::MockSensorHardware mock_hw{version_wrapper};
49+
auto sync_control = sensors::hardware::SensorHardwareSyncControlSingleton();
50+
test_mocks::MockSensorHardware mock_hw{version_wrapper, sync_control};
5051

5152
i2c::writer::TaskMessage empty_msg{};
5253
i2c::poller::TaskMessage empty_poll_msg{};

0 commit comments

Comments
 (0)