Skip to content

Commit

Permalink
feat(sensors): support new pipette sensor board (#797)
Browse files Browse the repository at this point in the history
* add a singlton to hold the version info and an i2c task to attempt to read the io expander and update the singleton

* EXEC-617 connect sensor hardware to the version wrapper

* EXEC_618 remove e1 firmware varient for pipettes

* get tests, simulators compiling and run format

* add test for reading presssure when board rev changes

* add a test for max pressure cause i'm supprised there wasn't one

* format the tests

* spelling

* lint

* format

* delay was too short for no reason

* R13 was intentionally not populated on the board so the expander returns 0x1 instead of 0x3

* add a getter for max sensor reading

* format

* format'
  • Loading branch information
ryanthecoder authored Jul 24, 2024
1 parent ab1b7d1 commit 7b3d7eb
Show file tree
Hide file tree
Showing 32 changed files with 443 additions and 102 deletions.
4 changes: 3 additions & 1 deletion gripper/firmware/main_proto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ auto sensor_pins = sensors::hardware::SensorHardwareConfiguration{
.pin = GPIO_PIN_6,
.active_setting = GPIO_PIN_RESET}};

auto sensor_hardware = sensors::hardware::SensorHardware(sensor_pins);
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
auto sensor_hardware =
sensors::hardware::SensorHardware(sensor_pins, version_wrapper);

auto main() -> int {
HardwareInit();
Expand Down
4 changes: 3 additions & 1 deletion gripper/firmware/main_rev1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ auto sensor_pins = sensors::hardware::SensorHardwareConfiguration{
.pin = NSYNC_OUT_PIN,
.active_setting = GPIO_PIN_RESET}};

auto sensor_hardware = sensors::hardware::SensorHardware(sensor_pins);
auto version_wrapper = sensors::hardware::SensorHardwareVersionSingleton();
auto sensor_hardware =
sensors::hardware::SensorHardware(sensor_pins, version_wrapper);

auto main() -> int {
HardwareInit();
Expand Down
3 changes: 2 additions & 1 deletion gripper/simulator/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ static auto sensor_map =
i2c::hardware::SimI2C::DeviceMap{{capsensor.get_address(), capsensor}};
static auto i2c2 = i2c::hardware::SimI2C{sensor_map};

static sim_mocks::MockSensorHardware fake_sensor_hw{};
static sensors::hardware::SensorHardwareVersionSingleton version_wrapper{};
static sim_mocks::MockSensorHardware fake_sensor_hw{version_wrapper};

static std::shared_ptr<state_manager::StateManagerConnection<
freertos_synchronization::FreeRTOSCriticalSection>>
Expand Down
2 changes: 2 additions & 0 deletions include/bootloader/core/ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ typedef enum {
can_messageid_gear_set_current_request = 0x505,
can_messageid_gear_write_motor_driver_request = 0x506,
can_messageid_gear_read_motor_driver_request = 0x507,
can_messageid_max_sensor_value_request = 0x70,
can_messageid_max_sensor_value_response = 0x71,
can_messageid_read_sensor_request = 0x82,
can_messageid_write_sensor_request = 0x83,
can_messageid_baseline_sensor_request = 0x84,
Expand Down
2 changes: 2 additions & 0 deletions include/can/core/ids.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ enum class MessageId {
gear_set_current_request = 0x505,
gear_write_motor_driver_request = 0x506,
gear_read_motor_driver_request = 0x507,
max_sensor_value_request = 0x70,
max_sensor_value_response = 0x71,
read_sensor_request = 0x82,
write_sensor_request = 0x83,
baseline_sensor_request = 0x84,
Expand Down
48 changes: 48 additions & 0 deletions include/can/core/messages.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,54 @@ struct SendAccumulatedSensorDataRequest
-> bool = default;
};

struct MaxSensorValueRequest
: BaseMessage<MessageId::max_sensor_value_request> {
uint32_t message_index = 0;
uint8_t sensor = 0;
uint8_t sensor_id = 0;
uint8_t offset_reading = 0;

template <bit_utils::ByteIterator Input, typename Limit>
static auto parse(Input body, Limit limit) -> MaxSensorValueRequest {
uint8_t sensor = 0;
uint8_t sensor_id = 0;
uint8_t offset_reading = 0;
uint32_t msg_ind = 0;

body = bit_utils::bytes_to_int(body, limit, msg_ind);
body = bit_utils::bytes_to_int(body, limit, sensor);
body = bit_utils::bytes_to_int(body, limit, sensor_id);
body = bit_utils::bytes_to_int(body, limit, offset_reading);
return MaxSensorValueRequest{.message_index = msg_ind,
.sensor = sensor,
.sensor_id = sensor_id,
.offset_reading = offset_reading};
}

auto operator==(const MaxSensorValueRequest& other) const -> bool = default;
};

struct MaxSensorValueResponse
: BaseMessage<MessageId::max_sensor_value_response> {
uint32_t message_index = 0;
can::ids::SensorType sensor{};
can::ids::SensorId sensor_id{};
int32_t sensor_data = 0;

template <bit_utils::ByteIterator Output, typename Limit>
auto serialize(Output body, Limit limit) const -> uint8_t {
auto iter = bit_utils::int_to_bytes(message_index, body, limit);
iter =
bit_utils::int_to_bytes(static_cast<uint8_t>(sensor), iter, limit);
iter = bit_utils::int_to_bytes(static_cast<uint8_t>(sensor_id), iter,
limit);
iter = bit_utils::int_to_bytes(sensor_data, iter, limit);
return iter - body;
}
auto operator==(const MaxSensorValueResponse& other) const
-> bool = default;
};

struct ReadFromSensorRequest : BaseMessage<MessageId::read_sensor_request> {
uint32_t message_index = 0;
uint8_t sensor = 0;
Expand Down
3 changes: 2 additions & 1 deletion include/gripper/core/can_task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ using SensorDispatchTarget = can::dispatch::DispatchParseTarget<
can::messages::WriteToSensorRequest, can::messages::BaselineSensorRequest,
can::messages::SetSensorThresholdRequest,
can::messages::BindSensorOutputRequest,
can::messages::PeripheralStatusRequest>;
can::messages::PeripheralStatusRequest,
can::messages::MaxSensorValueRequest>;

auto constexpr reader_message_buffer_size = 1024;

Expand Down
3 changes: 2 additions & 1 deletion include/pipettes/core/dispatch_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ using SensorDispatchTarget = can::dispatch::DispatchParseTarget<
can::messages::WriteToSensorRequest, can::messages::BaselineSensorRequest,
can::messages::SetSensorThresholdRequest,
can::messages::BindSensorOutputRequest,
can::messages::PeripheralStatusRequest>;
can::messages::PeripheralStatusRequest,
can::messages::MaxSensorValueRequest>;

using PipetteInfoDispatchTarget = can::dispatch::DispatchParseTarget<
pipette_info::PipetteInfoMessageHandler<central_tasks::QueueClient,
Expand Down
24 changes: 14 additions & 10 deletions include/pipettes/core/sensor_tasks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "sensors/core/tasks/capacitive_sensor_task.hpp"
#include "sensors/core/tasks/environmental_sensor_task.hpp"
#include "sensors/core/tasks/pressure_sensor_task.hpp"
#include "sensors/core/tasks/read_sensor_board_rev_task.hpp"
#include "sensors/core/tasks/tip_presence_notification_task.hpp"

/**
Expand All @@ -34,24 +35,24 @@ using I2CClient =
using I2CPollerClient =
i2c::poller::Poller<freertos_message_queue::FreeRTOSMessageQueue>;

void start_tasks(CanWriterTask& can_writer, I2CClient& i2c3_task_client,
I2CPollerClient& i2c3_poller_client,
I2CClient& i2c1_task_client,
I2CPollerClient& i2c1_poller_client,
sensors::hardware::SensorHardwareBase& sensor_hardware_primary,
can::ids::NodeId id,
eeprom::hardware_iface::EEPromHardwareIface& eeprom_hardware,
sensors::mmr920::SensorVersion sensor_version);
void start_tasks(
CanWriterTask& can_writer, I2CClient& i2c3_task_client,
I2CPollerClient& i2c3_poller_client, I2CClient& i2c1_task_client,
I2CPollerClient& i2c1_poller_client,
sensors::hardware::SensorHardwareBase& sensor_hardware_primary,
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper,
can::ids::NodeId id,
eeprom::hardware_iface::EEPromHardwareIface& eeprom_hardware);

void start_tasks(
CanWriterTask& can_writer, I2CClient& i2c3_task_client,
I2CPollerClient& i2c3_poller_client, I2CClient& i2c1_task_client,
I2CPollerClient& i2c1_poller_client,
sensors::hardware::SensorHardwareBase& sensor_hardware_primary,
sensors::hardware::SensorHardwareBase& sensor_hardware_secondary,
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper,
can::ids::NodeId id,
eeprom::hardware_iface::EEPromHardwareIface& eeprom_hardware,
sensors::mmr920::SensorVersion sensor_version);
eeprom::hardware_iface::EEPromHardwareIface& eeprom_hardware);

/**
* Access to all sensor/eeprom tasks. This will be a singleton.
Expand Down Expand Up @@ -80,6 +81,9 @@ struct Tasks {
sensors::tasks::TipPresenceNotificationTask<
freertos_message_queue::FreeRTOSMessageQueue>*
tip_notification_task_front{nullptr};
sensors::tasks::ReadSensorBoardTask<
freertos_message_queue::FreeRTOSMessageQueue>* read_sensor_board_task{
nullptr};
};

/**
Expand Down
4 changes: 3 additions & 1 deletion include/pipettes/firmware/utility_configurations.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ struct SensorHardwareContainer {

auto led_gpio(PipetteType pipette_type) -> gpio::PinConfig;

auto get_sensor_hardware_container(SensorHardwareGPIO pins)
auto get_sensor_hardware_container(
SensorHardwareGPIO pins,
sensors::hardware::SensorHardwareVersionSingleton& version_wrapper)
-> SensorHardwareContainer;

template <PipetteType P>
Expand Down
5 changes: 5 additions & 0 deletions include/sensors/core/message_handlers/sensors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ class SensorHandler {
can::ids::SensorId(m.sensor_id), m);
}

void visit(const can::messages::MaxSensorValueRequest &m) {
send_to_queue(can::ids::SensorType(m.sensor),
can::ids::SensorId(m.sensor_id), m);
}

void visit(const can::messages::SendAccumulatedSensorDataRequest &m) {
if (can::ids::SensorType(m.sensor_type) ==
can::ids::SensorType::pressure) {
Expand Down
37 changes: 37 additions & 0 deletions include/sensors/core/pie4ioe5.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once
namespace sensors {
namespace pie4ioe4 {
// https://www.diodes.com/assets/Datasheets/PI4IOE5V6408.pdf

constexpr uint16_t ADDRESS = 0x43 << 1;

enum class registers : uint8_t {
dev_id_and_ctl = 0x01, // default 1010 0010
// reserved 0x02
io_direction = 0x03, // default 0000 0000
// reserved 0x04
output_state = 0x05, // default 0000 0000
// reserved 0x06
output_high_impedance = 0x07, // default 1111 1111
// reserved 0x08
input_default_state = 0x09, // default 0000 0000
// reserved 0x0A
pull_up_down_enable = 0x0B, // default 1111 1111
// reserved 0x0C
pull_up_down_select = 0x0D, // default 0000 0000
// reserved 0x0E
input_status = 0x0F, // default xxxx xxxx
// reserved 0x10
interrupt_mask = 0x11, // default 0000 0000
// reserved 0x12
interrupt_status = 0x13, // default xxxx xxxx
};

enum class version_responses : uint8_t {
// right now only version D1.1 of the pipette sensor board responds
// version 0 does not respond
VERSION_1 = 0x01, // Pipette_sensor board D1.1
};

} // namespace pie4ioe4
} // namespace sensors
33 changes: 30 additions & 3 deletions include/sensors/core/sensor_hardware_interface.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "can/core/ids.hpp"
#include "common/firmware/gpio.hpp"
#include "sensors/core/utils.hpp"

namespace sensors {
namespace hardware {
Expand Down Expand Up @@ -41,15 +42,37 @@ static auto get_mask_from_id(can::ids::SensorId sensor) -> uint8_t {
}
return static_cast<uint8_t>(mask_enum);
}

class SensorHardwareVersionSingleton {
public:
SensorHardwareVersionSingleton() = default;
virtual ~SensorHardwareVersionSingleton() = default;
SensorHardwareVersionSingleton(const SensorHardwareVersionSingleton&) =
default;
auto operator=(const SensorHardwareVersionSingleton&)
-> SensorHardwareVersionSingleton& = default;
SensorHardwareVersionSingleton(SensorHardwareVersionSingleton&&) = default;
auto operator=(SensorHardwareVersionSingleton&&)
-> SensorHardwareVersionSingleton& = default;

void set_board_rev(utils::SensorBoardRev rev) { b_revision = rev; }

auto get_board_rev() -> utils::SensorBoardRev { return b_revision; }

private:
utils::SensorBoardRev b_revision = utils::SensorBoardRev::VERSION_0;
};

/** abstract sensor hardware device for a sync line */
class SensorHardwareBase {
public:
SensorHardwareBase() = default;
SensorHardwareBase(SensorHardwareVersionSingleton& version_wrapper)
: version_wrapper{version_wrapper} {}
virtual ~SensorHardwareBase() = default;
SensorHardwareBase(const SensorHardwareBase&) = default;
auto operator=(const SensorHardwareBase&) -> SensorHardwareBase& = default;
auto operator=(const SensorHardwareBase&) -> SensorHardwareBase& = delete;
SensorHardwareBase(SensorHardwareBase&&) = default;
auto operator=(SensorHardwareBase&&) -> SensorHardwareBase& = default;
auto operator=(SensorHardwareBase&&) -> SensorHardwareBase& = delete;

virtual auto set_sync() -> void = 0;
virtual auto reset_sync() -> void = 0;
Expand Down Expand Up @@ -114,11 +137,15 @@ class SensorHardwareBase {
reset_sync();
}
}
auto get_board_rev() -> utils::SensorBoardRev {
return version_wrapper.get_board_rev();
}

private:
uint8_t set_sync_required_mask = 0x00;
uint8_t set_sync_enabled_mask = 0x00;
uint8_t sync_state_mask = 0x00;
SensorHardwareVersionSingleton& version_wrapper;
};

struct SensorHardwareContainer {
Expand Down
4 changes: 4 additions & 0 deletions include/sensors/core/tasks/capacitive_sensor_task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ class CapacitiveMessageHandler {
}
}

void visit(const can::messages::MaxSensorValueRequest &m) {
std::ignore = m;
}

void visit(can::messages::WriteToSensorRequest &m) {
LOG("Received request to write data %d to %d sensor", m.data, m.sensor);
// FIXME we should send a response message after a write request
Expand Down
4 changes: 4 additions & 0 deletions include/sensors/core/tasks/environmental_sensor_task.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ class EnvironmentSensorMessageHandler {
std::ignore = m;
}

void visit(const can::messages::MaxSensorValueRequest &m) {
std::ignore = m;
}

void visit(const can::messages::BindSensorOutputRequest &m) {
LOG("Received bind sensor output request from %d sensor", m.sensor);
// sync doesn't quite mean the same thing here for us. We should
Expand Down
20 changes: 14 additions & 6 deletions include/sensors/core/tasks/pressure_driver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,13 @@ class MMR920 {
CanClient &can_client, OwnQueue &own_queue,
sensors::hardware::SensorHardwareBase &hardware,
const can::ids::SensorId &id,
const sensors::mmr920::SensorVersion version,
std::array<float, SENSOR_BUFFER_SIZE> *sensor_buffer)
: writer(writer),
poller(poller),
can_client(can_client),
own_queue(own_queue),
hardware(hardware),
sensor_id(id),
sensor_version(version),
sensor_buffer(sensor_buffer) {}

/**
Expand Down Expand Up @@ -403,12 +401,12 @@ class MMR920 {

save_pressure(shifted_data_store);
auto pressure = mmr920::PressureResult::to_pressure(
_registers.pressure_result.reading, sensor_version);
_registers.pressure_result.reading, sensor_version());

if (max_pressure_sync) {
bool this_tick_over_threshold =
std::fabs(pressure - current_pressure_baseline_pa) >=
mmr920::get_max_pressure_reading(sensor_version);
mmr920::get_max_pressure_reading(sensor_version());
bool over_threshold = false;
if (this_tick_over_threshold) {
max_pressure_consecutive_readings =
Expand Down Expand Up @@ -508,7 +506,7 @@ class MMR920 {
uint32_t shifted_data_store = temporary_data_store >> 8;

auto pressure = mmr920::PressureResult::to_pressure(shifted_data_store,
sensor_version);
sensor_version());
pressure_running_total += pressure;

if (!m.id.is_completed_poll) {
Expand Down Expand Up @@ -578,14 +576,24 @@ class MMR920 {

auto get_can_client() -> CanClient & { return can_client; }

auto sensor_version() -> sensors::mmr920::SensorVersion {
utils::SensorBoardRev rev = hardware.get_board_rev();
switch (rev) {
case utils::SensorBoardRev::VERSION_1:
return sensors::mmr920::SensorVersion::mmr920c10;
case utils::SensorBoardRev::VERSION_0:
default:
return sensors::mmr920::SensorVersion::mmr920c04;
}
}

private:
I2CQueueWriter &writer;
I2CQueuePoller &poller;
CanClient &can_client;
OwnQueue &own_queue;
hardware::SensorHardwareBase &hardware;
const can::ids::SensorId &sensor_id;
const sensors::mmr920::SensorVersion sensor_version;

mmr920::MMR920RegisterMap _registers{};
mmr920::FilterSetting filter_setting =
Expand Down
Loading

0 comments on commit 7b3d7eb

Please sign in to comment.