Skip to content

File tca9534.h

File List > dev > tca9534.h

Go to the documentation of this file

Source Code

#pragma once
#ifndef DSY_TCA9534_H
#define DSY_TCA9534_H

#include "per/gpio.h"
#include "per/i2c.h"

namespace daisy
{
enum class Tca9534Register : uint8_t
{
    INPUT    = 0x00, 
    OUTPUT   = 0x01, 
    POLARITY = 0x02, 
    CONFIG   = 0x03, 
};

enum class Tca9534Mode : uint8_t
{
    INPUT,
    OUTPUT,
};

class Tca9534
{
  public:
    struct Config
    {
        I2CHandle::Config i2c_config;
        uint8_t           i2c_address;

        void Defaults()
        {
            i2c_config.periph         = I2CHandle::Config::Peripheral::I2C_1;
            i2c_config.speed          = I2CHandle::Config::Speed::I2C_400KHZ;
            i2c_config.mode           = I2CHandle::Config::Mode::I2C_MASTER;
            i2c_config.pin_config.scl = Pin(PORTB, 8);
            i2c_config.pin_config.sda = Pin(PORTB, 9);
            // TCA9534 default (A2/A1/A0 = 000). Do not left-shift: libDaisy
            // Read/WriteDataAtAddress expect the 7-bit address.
            i2c_address = 0x20;
        }
    };

    Tca9534()
    : i2c_(nullptr),
      address_(0x20),
      output_state_(0x00),
      config_(0xFF),
      last_ok_(false),
      owns_i2c_(false)
    {
    }

    void Init()
    {
        Config cfg;
        cfg.Defaults();
        Init(cfg);
    }

    void Init(const Config& config)
    {
        address_  = config.i2c_address;
        owns_i2c_ = true;
        owned_i2c_.Init(config.i2c_config);
        i2c_ = &owned_i2c_;
        // Datasheet power-on: all pins inputs (0xFF), outputs low.
        config_       = 0xFF;
        output_state_ = 0x00;
        WriteReg(Tca9534Register::CONFIG, config_);
        WriteReg(Tca9534Register::OUTPUT, output_state_);
    }

    void Init(I2CHandle& i2c, uint8_t address = 0x20)
    {
        i2c_          = &i2c;
        address_      = address;
        owns_i2c_     = false;
        config_       = 0xFF;
        output_state_ = 0x00;
    }

    bool SetConfig(uint8_t config)
    {
        config_ = config;
        return WriteReg(Tca9534Register::CONFIG, config_);
    }

    bool SetOutputState(uint8_t output)
    {
        output_state_ = output;
        return WriteReg(Tca9534Register::OUTPUT, output_state_);
    }

    bool PinMode(uint8_t pin, Tca9534Mode mode)
    {
        if(pin > 7)
            return false;
        if(mode == Tca9534Mode::INPUT)
            config_ |= static_cast<uint8_t>(1u << pin);
        else
            config_ &= static_cast<uint8_t>(~(1u << pin));
        return WriteReg(Tca9534Register::CONFIG, config_);
    }

    bool WritePin(uint8_t pin, bool high)
    {
        if(pin > 7)
            return false;
        if(high)
            output_state_ |= static_cast<uint8_t>(1u << pin);
        else
            output_state_ &= static_cast<uint8_t>(~(1u << pin));
        return WriteReg(Tca9534Register::OUTPUT, output_state_);
    }

    bool ReadInput(uint8_t& value)
    {
        last_ok_ = ReadReg(Tca9534Register::INPUT, value);
        return last_ok_;
    }

    bool ReadPin(uint8_t pin, bool& high)
    {
        uint8_t value = 0;
        if(!ReadInput(value) || pin > 7)
            return false;
        high = (value & static_cast<uint8_t>(1u << pin)) != 0;
        return true;
    }

    bool LastTransferOk() const { return last_ok_; }
    bool LastReadOk() const { return last_ok_; }

    uint8_t OutputState() const { return output_state_; }
    uint8_t ConfigRegister() const { return config_; }
    uint8_t Address() const { return address_; }

  private:
    bool WriteReg(Tca9534Register reg, uint8_t value)
    {
        if(i2c_ == nullptr)
        {
            last_ok_ = false;
            return false;
        }
        last_ok_ = i2c_->WriteDataAtAddress(
                       address_, static_cast<uint8_t>(reg), 1, &value, 1, 10)
                   == I2CHandle::Result::OK;
        return last_ok_;
    }

    bool ReadReg(Tca9534Register reg, uint8_t& value)
    {
        if(i2c_ == nullptr)
        {
            last_ok_ = false;
            return false;
        }
        last_ok_ = i2c_->ReadDataAtAddress(
                       address_, static_cast<uint8_t>(reg), 1, &value, 1, 10)
                   == I2CHandle::Result::OK;
        return last_ok_;
    }

    I2CHandle* i2c_;
    I2CHandle  owned_i2c_;
    uint8_t    address_;
    uint8_t    output_state_;
    uint8_t    config_;
    bool       last_ok_;
    bool       owns_i2c_;
};

} // namespace daisy

#endif // DSY_TCA9534_H