#include <S50140_Driver.h>

namespace drivers
{

    S50140::S50140(drivers::MODBUS &bus, const uint8_t address) : m_bus(bus), m_address(address), m_lastRequest(millis())
    {
    }
    S50140::~S50140()
    {
    }

    const S50140::powerinfo_t S50140::getAll()
    {
        powerinfo_t info{MAXFLOAT};
        info.v = getV();
        info.a = getA();
        info.pAct = getPact();
        info.pApp = getPapp();
        info.pRea = getPrea();
        info.pf = getPf();
        info.f = getF();
        info.whTot = getWhTot();
        info.whPar = getWhPar();
        return info;
    }

    const float_t S50140::getV()
    {
        return readFloatReg(REG_V);
    }
    const float_t S50140::getA()
    {
        return readFloatReg(REG_A);
    }
    const float_t S50140::getPact()
    {
        return readFloatReg(REG_Pact);
    }
    const float_t S50140::getPapp()
    {
        return readFloatReg(REG_Papp);
    }
    const float_t S50140::getPrea()
    {
        return readFloatReg(REG_Prea);
    }
    const float_t S50140::getPf()
    {
        return readFloatReg(REG_Pf);
    }
    const float_t S50140::getF()
    {
        return readFloatReg(REG_Freq);
    }
    const float_t S50140::getWhTot()
    {
        return readFloatReg(REG_WhTot);
    }
    const float_t S50140::getWhPar()
    {
        return readFloatReg(REG_WhPart);
    }

    void S50140::delayRequest()
    {
        auto now = millis();
        if ((now - m_lastRequest) < minDelay)
        { // minimum m_lastRequest between requests
            vTaskDelay(pdMS_TO_TICKS(now - m_lastRequest));
        }
        m_lastRequest = now;
    }

    const uint8_t S50140::getRegset()
    {
        std::vector<uint16_t> value;
        delayRequest();
        m_bus.readHoldingRegisters(m_address, REG_Regset, 2, value);
        if (value.empty())
            return UINT8_MAX;
        return value.front() + value.back();
    }

    const uint16_t S50140::getCounterStatus()
    {
        std::vector<uint16_t> value;
        delayRequest();
        m_bus.readHoldingRegisters(m_address, REG_PartCount, 2, value);
        if (value.empty())
            return UINT16_MAX;
        return value.front() + value.back();
    }

    void S50140::resetPartialCounters()
    {
        uint8_t retries(0);
        constexpr uint16_t nullVal = 0x0000;
        constexpr uint16_t resetAll = 0x0A03;
        constexpr uint16_t stopAll = 0x0A02;
        constexpr uint16_t startAll = 0x0A01;
        while (retries++ < maxRetries)
        {
            bool ok(true);
            delayRequest();
            LOG_WARN("Powermeter Counter STOP");
            ok &= m_bus.writeRegisters(m_address, REG_PartCount, {nullVal, stopAll});
            delayRequest();
            LOG_WARN("Powermeter Counter RESET");
            ok &= m_bus.writeRegisters(m_address, REG_PartCount, {nullVal, resetAll});
            delayRequest();
            LOG_WARN("Powermeter Counter START");
            ok &= m_bus.writeRegisters(m_address, REG_PartCount, {nullVal, startAll});
            if (ok)
                return;
            LOG_ERROR("Unable to Reset Powermeter Partial Counters, device", m_address);
        }
        return;
    }

    float_t S50140::readFloatReg(const uint16_t reg)
    {
        uint8_t retries(0);
        std::vector<uint16_t> values;

        while (retries++ < maxRetries)
        {
            delayRequest();
            if (m_bus.readHoldingRegisters(m_address, reg, dataWords, values) && values.size() == dataWords)
            {
                floatval_t fv;           // potrebbe essere il contrario, vedremo
                fv.words.lo = values[0]; // magari va invertita ancora l'endianness
                fv.words.hi = values[1];
                return fv.f;
            }
            LOG_ERROR("Unable to Read Powermeter values, device", m_address);
        }
        return MAXFLOAT;
    }

}