#include <R4DCB08_Driver.h>

namespace drivers
{
    R4DCB08::R4DCB08(drivers::MODBUS &bus, const uint8_t address) : m_address(address), m_bus(bus), m_sensors(0)
    {
        m_sensors = getNum();
    }

    R4DCB08::~R4DCB08()
    {
    }

    const float R4DCB08::getTemp(const uint8_t ch)
    {
        uint8_t retries(0);
        std::vector<uint16_t> rawT;
        if (ch < 0 || ch > getNum())
        {
            LOG_ERROR("Invalid Temperature Channel number", ch);
            return MAXFLOAT;
        }
        while (retries++ < maxRetries)
        {
            if (m_bus.readHoldingRegisters(m_address, REG_TEMP + ch, 1, rawT) && !rawT.empty())
            {
                return rawT.front() / 10.0f;
            }
            LOG_ERROR("Failed to Read Temperature, device", m_address, "channel", ch);
            rawT.clear();
            delay(50);
        }
        return MAXFLOAT;
    }

    const std::vector<float> R4DCB08::getTempAll()
    {
        uint8_t retries(0);
        std::vector<uint16_t> rawT;
        std::vector<float> out;
        while (retries++ < maxRetries)
        {
            if (m_bus.readHoldingRegisters(m_address, REG_TEMP, getNum(), rawT) && !rawT.empty())
            {
                out.reserve(rawT.size());
                for (auto v : rawT)
                {
                    out.push_back(v / 10.0f);
                }
                return out;
            }
            LOG_ERROR("Failed to Read All Temperature, device", m_address);
            rawT.clear();
            delay(50);
        }
        out.clear();
        return out;
    }

    void R4DCB08::setCorrection(std::vector<float> corr)
    {
        uint8_t retries(0);
        uint8_t channel(0);
        corr.resize(getNum()); // max number of temperature correction values is equal to number of sensors

        for (auto v : corr)
        { // convert to decimal degreees to register value
            while (retries++ < maxRetries)
            {
                if (m_bus.writeRegister(m_address, REG_TEMPCORR + channel, v*10))
                {
                    channel++;
                    delay(50);
                    break;
                }
                LOG_ERROR("Failed to Set Temperature Correction, device", m_address);
                delay(50);
            }
        }
    }

    std::vector<float> R4DCB08::getCorrection()
    {
        uint8_t retries(0);
        std::vector<uint16_t> rawV;
        std::vector<float> out;
        rawV.reserve(getNum());

        while (retries++ < maxRetries)
        {
            if (m_bus.readHoldingRegisters(m_address, REG_TEMPCORR, getNum(), rawV))
            {
                out.reserve(rawV.size());
                for (auto v : rawV)
                {
                    out.push_back(v/10.0f);
                }
                return out;
            }
            LOG_ERROR("Failed to Get Temperature Correction, device", m_address);
            rawV.clear();
            delay(50);
        }
        out.clear();
        return out;
    }

    const uint8_t R4DCB08::getNum()
    {
        if (m_sensors)
            return m_sensors;
        uint8_t retries(0);
        uint8_t sensors(0);
        std::vector<uint16_t> rawT;
        while (retries++ < maxRetries)
        {
            if (m_bus.readHoldingRegisters(m_address, REG_TEMP, T_MAX, rawT))
            {
                for (auto v : rawT)
                {
                    if (v <= INT16_MAX)
                        sensors++; // 32768 is returned if sensor is disconnected
                }
                m_sensors = sensors;
                return m_sensors;
            }
            LOG_ERROR("Failed to Get Sensor Number, device", m_address);
            delay(50);
        }
        LOG_ERROR("No Temperature Sensors Detected, device", m_address);
        return 0;
    }
}
