add brightness controll

This commit is contained in:
2026-04-17 09:45:32 +03:00
parent 8daff9c46a
commit d788358ac8
8 changed files with 426 additions and 70 deletions

View File

@ -38,12 +38,120 @@ IR_Encoder::IR_Encoder(uint8_t pin, uint16_t addr, IR_DecoderRaw *decPair, bool
pinMode(pin, OUTPUT);
}
powerNumerator_ = 1;
};
HardwareTimer* IR_Encoder::IR_Timer = nullptr;
IR_Encoder::ExternalTxStartFn IR_Encoder::externalTxStartFn = nullptr;
IR_Encoder::ExternalTxBusyFn IR_Encoder::externalTxBusyFn = nullptr;
void *IR_Encoder::externalTxCtx = nullptr;
bool IR_Encoder::txIsrLegacyMode_ = false;
uint16_t IR_Encoder::s_carrierMultiply = 2;
void IR_Encoder::setCarrierMultiply(uint16_t multiply)
{
if (multiply < 2)
{
multiply = 2;
}
s_carrierMultiply = multiply;
}
uint16_t IR_Encoder::carrierMultiply()
{
return s_carrierMultiply;
}
void IR_Encoder::retuneCarrierClock()
{
if (IR_Timer == nullptr)
{
return;
}
IR_Timer->pause();
IR_Timer->setOverflow((uint32_t)carrierFrec * (uint32_t)s_carrierMultiply, HERTZ_FORMAT);
IR_Timer->pause();
}
uint16_t IR_Encoder::maxPowerNumerator()
{
return static_cast<uint16_t>(s_carrierMultiply / 2U);
}
void IR_Encoder::setPowerNumerator(uint16_t n)
{
const uint16_t cap = maxPowerNumerator();
powerNumerator_ = (n > cap) ? cap : n;
}
void IR_Encoder::setPowerPercent(uint8_t p)
{
if (p > 100U)
{
p = 100U;
}
const uint16_t cap = maxPowerNumerator();
const uint32_t n = ((uint32_t)p * (uint32_t)cap + 50U) / 100U;
powerNumerator_ = static_cast<uint16_t>(n);
}
uint16_t IR_Encoder::powerNumerator() const
{
return powerNumerator_;
}
bool IR_Encoder::scaleGateRunsToPhysical(IR_TxGateRun* runs, size_t* ioCount, size_t maxRuns, uint16_t multiply)
{
if (runs == nullptr || ioCount == nullptr || maxRuns == 0)
{
return false;
}
if (multiply < 2)
{
multiply = 2;
}
const size_t nIn = *ioCount;
if (nIn > irproto::kIsrTxMaxGateRuns)
{
return false;
}
IrTxGateRun copy[irproto::kIsrTxMaxGateRuns];
memcpy(copy, runs, nIn * sizeof(IrTxGateRun));
size_t w = 0;
for (size_t r = 0; r < nIn; r++)
{
uint32_t phys = (uint32_t)copy[r].lenTicks * (uint32_t)multiply / 2U;
if (copy[r].lenTicks > 0 && phys == 0)
{
phys = 1;
}
const bool g = copy[r].gate;
while (phys > 0)
{
if (w >= maxRuns)
{
return false;
}
const uint32_t chunk = phys > 65535U ? 65535U : phys;
runs[w].lenTicks = static_cast<uint16_t>(chunk);
runs[w].gate = g;
w++;
phys -= chunk;
}
}
*ioCount = w;
return true;
}
void IR_Encoder::setTxIsrLegacyMode(bool legacy)
{
txIsrLegacyMode_ = legacy;
}
bool IR_Encoder::txIsrLegacyMode()
{
return txIsrLegacyMode_;
}
bool IR_Encoder::txAdvanceBoundary(TxFsmState &st, const uint8_t *sendBufferLocal)
{
@ -194,7 +302,7 @@ void IR_Encoder::begin(HardwareTimer* timer, uint8_t channel, IRQn_Type IRQn, ui
IR_Timer = timer;
if(IR_Timer == nullptr) return;
IR_Timer->pause();
IR_Timer->setOverflow(carrierFrec * 2, HERTZ_FORMAT);
IR_Timer->setOverflow((uint32_t)carrierFrec * (uint32_t)s_carrierMultiply, HERTZ_FORMAT);
IR_Timer->attachInterrupt(channel, (isrCallback == nullptr ? IR_Encoder::isr : isrCallback));
NVIC_SetPriority(IRQn, priority);
IR_Timer->pause();
@ -206,7 +314,7 @@ void IR_Encoder::beginClockOnly(HardwareTimer *timer)
if (IR_Timer == nullptr)
return;
IR_Timer->pause();
IR_Timer->setOverflow(carrierFrec * 2, HERTZ_FORMAT);
IR_Timer->setOverflow((uint32_t)carrierFrec * (uint32_t)s_carrierMultiply, HERTZ_FORMAT);
IR_Timer->pause();
}
@ -607,23 +715,86 @@ void IR_Encoder::rawSend(uint8_t *ptr, uint8_t len)
}
return;
}
if (port == nullptr || mask == 0)
{
return;
}
if (ptr != sendBuffer)
{
memcpy(sendBuffer, ptr, len);
}
sendLen = len;
toggleCounter = preambToggle; // Первая генерация для первого signal
dataBitCounter = bitPerByte - 1;
dataByteCounter = 0;
if (txIsrLegacyMode_)
{
toggleCounter = preambToggle;
dataBitCounter = bitPerByte - 1;
dataByteCounter = 0;
preambFrontCounter = preambPulse * 2 - 1;
dataSequenceCounter = bitPerByte * 2;
syncSequenceCounter = syncBits * 2;
signal = preamb;
state = HIGH;
currentBitSequence = bitHigh;
txMultiplySnap_ = carrierMultiply();
{
const uint16_t cap = maxPowerNumerator();
txPowerSnap_ = (powerNumerator_ > cap) ? cap : powerNumerator_;
}
legacyPhysPerLogical_ = static_cast<uint16_t>(txMultiplySnap_ / 2U);
if (legacyPhysPerLogical_ == 0)
{
legacyPhysPerLogical_ = 1;
}
legacyPhysCounter_ = 0;
legacySlotInPeriod_ = 0;
isSending = true;
refreshBlindDecoderMuteState();
IR_Encoder::carrierResume();
return;
}
preambFrontCounter = preambPulse * 2 - 1; // -1 за счёт генерации уже на этапе сразу после инициализации
dataSequenceCounter = bitPerByte * 2;
syncSequenceCounter = syncBits * 2;
size_t nRuns = buildGateRuns(sendBuffer, len, txGateRuns_, irproto::kIsrTxMaxGateRuns);
if (nRuns == 0U)
{
return;
}
if (!scaleGateRunsToPhysical(txGateRuns_, &nRuns, irproto::kIsrTxMaxGateRuns, carrierMultiply()))
{
return;
}
uint32_t total = 0;
for (size_t i = 0; i < nRuns; i++)
{
total += txGateRuns_[i].lenTicks;
}
txBsrrTotalTicks_ = total;
const uint32_t setW = (uint32_t)mask;
const uint32_t resetW = ((uint32_t)mask) << 16U;
txMultiplySnap_ = carrierMultiply();
{
const uint16_t cap = maxPowerNumerator();
txPowerSnap_ = (powerNumerator_ > cap) ? cap : powerNumerator_;
}
txBsrrWave_.configure(setW, resetW, txGateRuns_, nRuns, txMultiplySnap_, txPowerSnap_);
txBsrrHalfLen_ = (uint16_t)(irproto::kIsrTxBsrrWordCount / 2U);
txBsrrWave_.fill(txBsrrWords_, irproto::kIsrTxBsrrWordCount);
txBsrrReadIdx_ = 0;
txBsrrTicksSent_ = 0;
signal = preamb;
isSending = true;
state = HIGH;
currentBitSequence = bitHigh;
refreshBlindDecoderMuteState();
if (port != nullptr)
{
port->BSRR = resetW;
}
IR_Encoder::carrierResume();
// interrupts();
}
void IR_Encoder::isr()
@ -641,21 +812,71 @@ void IR_Encoder::_isr()
if (!isSending)
return;
ir_out_virtual = !ir_out_virtual && state;
if (port == nullptr)
return;
port->ODR &= ~(mask);
port->ODR |= mask & (ir_out_virtual ? (uint16_t)0xFFFF : (uint16_t)0x0000);
TxFsmState st{};
loadTxFsmFromMembers(st);
const bool active = txAdvanceAfterOutput(st, sendBuffer);
storeTxFsmToMembers(st);
if (!active)
if (txIsrLegacyMode_)
{
const uint32_t setW = (uint32_t)mask;
const uint32_t resetW = ((uint32_t)mask) << 16U;
if (!state)
{
port->BSRR = resetW;
legacySlotInPeriod_ = 0;
}
else
{
port->BSRR = (legacySlotInPeriod_ < txPowerSnap_) ? setW : resetW;
legacySlotInPeriod_++;
if (legacySlotInPeriod_ >= txMultiplySnap_)
{
legacySlotInPeriod_ = 0;
}
}
legacyPhysCounter_++;
if (legacyPhysCounter_ < legacyPhysPerLogical_)
{
return;
}
legacyPhysCounter_ = 0;
TxFsmState st{};
loadTxFsmFromMembers(st);
const bool active = txAdvanceAfterOutput(st, sendBuffer);
storeTxFsmToMembers(st);
if (!active)
{
port->BSRR = resetW;
isSending = false;
refreshBlindDecoderMuteState();
carrierStopPending = true;
}
return;
}
port->BSRR = txBsrrWords_[txBsrrReadIdx_];
txBsrrReadIdx_++;
txBsrrTicksSent_++;
if (txBsrrTicksSent_ >= txBsrrTotalTicks_)
{
port->BSRR = ((uint32_t)mask) << 16U;
isSending = false;
refreshBlindDecoderMuteState();
carrierStopPending = true;
return;
}
if (txBsrrReadIdx_ == txBsrrHalfLen_)
{
txBsrrWave_.fill(&txBsrrWords_[0], txBsrrHalfLen_);
}
else if (txBsrrReadIdx_ >= irproto::kIsrTxBsrrWordCount)
{
txBsrrReadIdx_ = 0;
txBsrrWave_.fill(&txBsrrWords_[txBsrrHalfLen_], txBsrrHalfLen_);
}
}