Program Listing for File mcp23017.cpp

Return to documentation for file (src/mcp23017.cpp)

#include <cstdint>

#include "mcp23017/mcp23017.hh"

using iplo::MCP23017;
using iplo::MCP230XXStatus;

MCP23017::MCP23017(I2C& bus, std::uint8_t address) : MCP230XX(bus, address) {}

bool MCP23017::begin() {
    _bus.selectDevice(_address);

    if (!isConnected()) {
        return false;
    }

    if (!writeRegister(MCP23017Registers::IOCR, 0b00100000)) {
        return false;
    }
    if (!writeRegister(MCP23017Registers::PUR_A, 0xFF)) {
        return false;
    }
    if (!writeRegister(MCP23017Registers::PUR_B, 0xFF)) {
        return false;
    }

    return true;
}

bool MCP23017::isConnected() {
    auto res = _bus.readByte();
    if (res < 0) {
        _error = I2C_ERROR;
        return false;
    }

    _error = OK;
    return true;
}

bool MCP23017::pinMode(std::uint8_t pin, PinMode mode) {
    if (pin > 15) {
        _error = PIN_ERROR;
        return false;
    }
    if ((mode != PinMode::INPUT) && (mode != PinMode::INPUT_PULLUP) && (mode != PinMode::OUTPUT)) {
        _error = VALUE_ERROR;
        return false;
    }

    auto dataDirectionRegister = MCP23017Registers::DDR_A;
    if (pin > 7) {
        dataDirectionRegister = MCP23017Registers::DDR_B;
        pin -= 8;
    }

    auto registerValue = readRegister(dataDirectionRegister);
    if (_error != OK) {
        return false;
    }

    if ((mode == PinMode::INPUT) || (mode == PinMode::INPUT_PULLUP)) {
        registerValue |= 1 << pin;
    } else {
        registerValue &= ~(1 << pin);
    }

    writeRegister(dataDirectionRegister, registerValue);
    if (_error != OK) {
        return false;
    }

    return true;
}

bool MCP23017::digitalWrite(std::uint8_t pin, std::uint8_t value) {
    if (pin > 15) {
        _error = PIN_ERROR;
        return false;
    }

    auto gpioRegister = MCP23017Registers::GPIO_A;
    if (pin > 7) {
        gpioRegister = MCP23017Registers::GPIO_B;
        pin -= 8;
    }

    auto registerValue = readRegister(gpioRegister);
    if (_error != OK) {
        return false;
    }

    value ? registerValue |= 1 << pin : registerValue &= ~(1 << pin);

    writeRegister(gpioRegister, registerValue);
    if (_error != OK) {
        return false;
    }

    return true;
}

std::uint8_t MCP23017::digitalRead(std::uint8_t pin) {
    if (pin > 15) {
        _error = PIN_ERROR;
        return INVALID_READ;
    }

    auto gpioRegister = MCP23017Registers::GPIO_A;
    if (pin > 7) {
        gpioRegister = MCP23017Registers::GPIO_B;
        pin -= 8;
    }

    auto registerValue = readRegister(gpioRegister);
    if (_error != OK) {
        return INVALID_READ;
    }

    return registerValue & 1 << pin ? 1 : 0;
}

bool MCP23017::setPolarity(std::uint8_t pin, bool reversed) {
    if (pin > 15) {
        _error = PIN_ERROR;
        return false;
    }

    auto polarityRegister = MCP23017Registers::POL_A;
    if (pin > 7) {
        polarityRegister = MCP23017Registers::POL_B;
        pin -= 8;
    }

    auto registerValue = readRegister(polarityRegister);
    if (_error != OK) {
        return false;
    }

    reversed ? registerValue |= 1 << pin : registerValue &= ~(1 << pin);

    writeRegister(polarityRegister, registerValue);
    if (_error != OK) {
        return false;
    }

    return true;
}

bool MCP23017::getPolarity(std::uint8_t pin, bool& reversed) {
    if (pin > 15) {
        _error = PIN_ERROR;
        return false;
    }

    auto polarityRegister = MCP23017Registers::POL_A;
    if (pin > 7) {
        polarityRegister = MCP23017Registers::POL_B;
        pin -= 8;
    }

    const auto registerValue = readRegister(polarityRegister);
    if (_error != OK) {
        return false;
    }

    reversed = (registerValue & 1 << pin) > 0;

    return true;
}

bool MCP23017::setPullUp(std::uint8_t pin, bool pullUp) {
    if (pin > 15) {
        _error = PIN_ERROR;
        return false;
    }

    auto pullUpRegister = MCP23017Registers::PUR_A;
    if (pin > 7) {
        pullUpRegister = MCP23017Registers::PUR_B;
        pin -= 8;
    }

    auto registerValue = readRegister(pullUpRegister);
    if (_error != OK) {
        return false;
    }

    pullUp ? registerValue |= 1 << pin : registerValue &= ~(1 << pin);

    writeRegister(pullUpRegister, registerValue);
    if (_error != OK) {
        return false;
    }

    return true;
}

bool MCP23017::getPullUp(std::uint8_t pin, bool& pullUp) {
    if (pin > 15) {
        _error = PIN_ERROR;
        return false;
    }

    auto pullUpRegister = MCP23017Registers::PUR_A;
    if (pin > 7) {
        pullUpRegister = MCP23017Registers::PUR_B;
        pin -= 8;
    }

    const auto val = readRegister(pullUpRegister);
    if (_error != OK) {
        return false;
    }

    pullUp = (val & 1 << pin) > 0;

    return true;
}

bool MCP23017::pinMode8(MCP23017Port port, std::uint8_t value) {
    if (port == MCP23017Port::DDRA) {
        return writeRegister(MCP23017Registers::DDR_A, value);
    }

    return writeRegister(MCP23017Registers::DDR_B, value);
}

bool MCP23017::digitalWrite8(MCP23017Port port, std::uint8_t value) {
    if (port == MCP23017Port::DDRA) {
        return writeRegister(MCP23017Registers::GPIO_A, value);
    }

    return writeRegister(MCP23017Registers::GPIO_B, value);
}

std::uint8_t MCP23017::digitalRead8(MCP23017Port port) {
    if (port == MCP23017Port::DDRA) {
        return readRegister(MCP23017Registers::GPIO_A);
    }

    return readRegister(MCP23017Registers::GPIO_B);
}

bool MCP23017::setPolarity8(MCP23017Port port, std::uint8_t mask) {
    if (port == MCP23017Port::DDRA) {
        return writeRegister(MCP23017Registers::POL_A, mask);
    }

    return writeRegister(MCP23017Registers::POL_B, mask);
}

bool MCP23017::getPolarity8(MCP23017Port port, std::uint8_t& mask) {
    if (port == MCP23017Port::DDRA) {
        mask = readRegister(MCP23017Registers::POL_A);
    } else {
        mask = readRegister(MCP23017Registers::POL_B);
    }

    return _error == OK;
}

bool MCP23017::setPullUp8(MCP23017Port port, std::uint8_t mask) {
    if (port == MCP23017Port::DDRA) {
        return writeRegister(MCP23017Registers::PUR_A, mask);
    }

    return writeRegister(MCP23017Registers::PUR_B, mask);
}

bool MCP23017::getPullUp8(MCP23017Port port, std::uint8_t& mask) {
    if (port == MCP23017Port::DDRA) {
        mask = readRegister(MCP23017Registers::PUR_A);
    } else {
        mask = readRegister(MCP23017Registers::PUR_B);
    }

    return _error == OK;
}

bool MCP23017::pinMode16(std::uint16_t value) {
    if (!writeRegister(MCP23017Registers::DDR_A, value >> 8)) {
        return false;
    }
    return writeRegister(MCP23017Registers::DDR_B, value & 0xFF);
}

bool MCP23017::digitalWrite16(std::uint16_t value) {
    if (!writeRegister(MCP23017Registers::GPIO_A, value >> 8)) {
        return false;
    }
    return writeRegister(MCP23017Registers::GPIO_B, value & 0xFF);
}

std::uint16_t MCP23017::digitalRead16() {
    std::uint16_t value = readRegister(MCP23017Registers::GPIO_A);
    value <<= 8;
    value += readRegister(MCP23017Registers::GPIO_B);
    return value;
}

bool MCP23017::setPolarity16(std::uint16_t mask) {
    if (!writeRegister(MCP23017Registers::POL_A, mask >> 8)) {
        return false;
    }
    return writeRegister(MCP23017Registers::POL_B, mask & 0xFF);
}

bool MCP23017::getPolarity16(std::uint16_t& mask) {
    mask = readRegister(MCP23017Registers::POL_A);
    mask <<= 8;
    mask += readRegister(MCP23017Registers::POL_B);
    return _error == OK;
}

bool MCP23017::setPullUp16(std::uint16_t mask) {
    if (!writeRegister(MCP23017Registers::PUR_A, mask >> 8)) {
        return false;
    }
    return writeRegister(MCP23017Registers::PUR_B, mask & 0xFF);
}

bool MCP23017::getPullUp16(std::uint16_t& mask) {
    mask = readRegister(MCP23017Registers::PUR_A);
    mask <<= 8;
    mask += readRegister(MCP23017Registers::PUR_B);
    return _error == OK;
}

std::uint16_t MCP23017::readAll() {
    return digitalRead16();
}


std::uint8_t MCP23017::extractPinValue(std::uint16_t registerValue, std::uint8_t pin) {
    return registerValue & 1 << pin ? 1 : 0;
}