Program Listing for File i2c.hpp

Return to documentation for file (libspookyaction/include/pn532/esp32/i2c.hpp)

//
// Created by spak on 2/19/21.
//

#ifndef PN532_ESP32_I2C_HPP
#define PN532_ESP32_I2C_HPP

#include <driver/i2c.h>
#include <memory>
#include <mlab/result.hpp>
#include <pn532/channel.hpp>
#include <pn532/esp32/irq_assert.hpp>

namespace pn532::esp32 {

    namespace i2c {

        enum struct error : std::int16_t {
            parameter_error = ESP_ERR_INVALID_ARG,
            fail = ESP_FAIL,
            invalid_state = ESP_ERR_INVALID_STATE,
            timeout = ESP_ERR_TIMEOUT
        };

#ifndef DOXYGEN_SHOULD_SKIP_THIS
        [[nodiscard]] const char *to_string(error e);
#endif

        class command {
            i2c_cmd_handle_t _handle;
            bool _used;

            [[nodiscard]] bool assert_unused() const;

        public:
            command();

            ~command();

            command(command const &) = delete;
            command(command &&) noexcept = default;

            command &operator=(command const &) = delete;
            command &operator=(command &&) noexcept = default;

            void write(std::uint8_t b, bool enable_ack_check);

            void write(mlab::range<const uint8_t *> data, bool enable_ack_check);

            void read(mlab::range<uint8_t *> buffer, i2c_ack_type_t ack);

            void read(std::uint8_t &b, i2c_ack_type_t ack);

            void stop();

            mlab::result<error> operator()(i2c_port_t port, std::chrono::milliseconds timeout);
        };
    }// namespace i2c


    class i2c_channel final : public channel {
        i2c_port_t _port;
        std::uint8_t _slave_addr;
        irq_assert _irq_assert;

    protected:
        [[nodiscard]] i2c::command raw_prepare_command(comm_dir mode) const;

        result<> raw_send(mlab::range<bin_data::const_iterator> buffer, ms timeout) override;

        result<> raw_receive(mlab::range<bin_data::iterator> buffer, ms timeout) override;

        [[nodiscard]] inline comm_rx_mode raw_receive_mode() const override;

        bool on_receive_prepare(ms timeout) override;

    public:
        static constexpr std::uint8_t default_slave_address = 0x48;

        [[nodiscard]] inline static channel_error error_from_i2c_error(i2c::error e);

        bool wake() override;

        i2c_channel(i2c_port_t port, i2c_config_t config, std::uint8_t slave_address = default_slave_address);

        i2c_channel(i2c_port_t port, i2c_config_t config, gpio_num_t response_irq_line, bool manage_isr_service, std::uint8_t slave_address = default_slave_address);

        ~i2c_channel() override;

        [[nodiscard]] inline std::uint8_t slave_address_to_write() const;

        [[nodiscard]] inline std::uint8_t slave_address_to_read() const;
    };


}// namespace pn532::esp32

namespace pn532::esp32 {

    channel_error i2c_channel::error_from_i2c_error(i2c::error e) {
        switch (e) {
            case i2c::error::parameter_error:
                return channel_error::malformed;
            case i2c::error::timeout:
                return channel_error::timeout;
            case i2c::error::fail:
                [[fallthrough]];
            case i2c::error::invalid_state:
                return channel_error::hw_error;
        }
        return channel_error::hw_error;
    }

    std::uint8_t i2c_channel::slave_address_to_write() const {
        return _slave_addr;
    }
    std::uint8_t i2c_channel::slave_address_to_read() const {
        return _slave_addr + 1;
    }

    comm_rx_mode i2c_channel::raw_receive_mode() const {
        return comm_rx_mode::buffered;
    }

}// namespace pn532::esp32

#endif//PN532_ESP32_I2C_HPP