IR-protocol/IR_Encoder.cpp
2024-02-14 17:19:53 +03:00

326 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "IR_Encoder.h"
#include "IR_Decoder.h"
#define LoopOut 12
#define ISR_Out 10
#define TestOut 13
IR_Encoder::IR_Encoder(uint16_t addr, uint8_t pin, IR_Decoder* decPair = nullptr) {
id = addr;
this->decPair = decPair;
signal = noSignal;
isSending = false;
#if disablePairDec
if(decPair != nullptr){
blindDecoders = new IR_Decoder*[1]{decPair};
decodersCount = 1;
}
#endif
};
void IR_Encoder::setBlindDecoders(IR_Decoder* decoders[], uint8_t count){
#if disablePairDec
if(blindDecoders != nullptr) delete[] blindDecoders;
#endif
decodersCount = count;
blindDecoders = decoders;
}
IR_Encoder::~IR_Encoder() {
delete [] bitLow;
delete [] bitHigh;
};
void IR_Encoder::sendData(uint16_t addrTo, uint8_t* data, uint8_t len, bool needAccept = false) {
uint8_t packSize = msgBytes + addrBytes + addrBytes + len + crcBytes;
uint8_t msgType =
((needAccept ? IR_MSG_DATA_ACCEPT : IR_MSG_DATA_NOACCEPT) << 5) | ((packSize - crcBytes) & IR_MASK_MSG_INFO);
_sendData(addrTo, data, len, msgType);
}
void IR_Encoder::sendACK(uint16_t addrTo, uint8_t addInfo, bool forAll = false) {
memset(sendBuffer, 0x00, dataByteSizeMax);
sendBuffer[0] = IR_MSG_ACCEPT << 5;
sendBuffer[0] |= addInfo & IR_MASK_MSG_INFO;
// addr_self
if (!forAll) {
sendBuffer[1] = id >> 8 & 0xFF;
sendBuffer[2] = id & 0xFF;
}
// data crc
sendBuffer[3] = crc8(sendBuffer, 0, 3, poly1) & 0xFF;
sendBuffer[4] = crc8(sendBuffer, 0, 4, poly2) & 0xFF;
rawSend(sendBuffer, msgBytes + addrBytes + crcBytes);
}
void IR_Encoder::sendRequest(uint16_t addrTo, uint8_t addInfo) {
memset(sendBuffer, 0x00, dataByteSizeMax);
sendBuffer[0] = IR_MSG_REQUEST << 5;
sendBuffer[0] |= addInfo & IR_MASK_MSG_INFO;
// addr_self
sendBuffer[1] = id >> 8 & 0xFF;
sendBuffer[2] = id & 0xFF;
//addr_to
sendBuffer[3] = addrTo >> 8 & 0xFF;
sendBuffer[4] = addrTo & 0xFF;
// data crc
sendBuffer[5] = crc8(sendBuffer, 0, 5, poly1) & 0xFF;
sendBuffer[6] = crc8(sendBuffer, 0, 6, poly2) & 0xFF;
rawSend(sendBuffer, msgBytes + addrBytes + addrBytes + crcBytes);
}
void IR_Encoder::_sendData(uint16_t addrTo, uint8_t* data, uint8_t len, uint8_t msgType) {
memset(sendBuffer, 0x00, dataByteSizeMax);
uint8_t packSize = msgBytes + addrBytes + addrBytes + len + crcBytes;
uint8_t dataStart = msgBytes + addrBytes + addrBytes;
// формирование массива
// msg_type
sendBuffer[0] = msgType;
// addr_self
sendBuffer[1] = id >> 8 & 0xFF;
sendBuffer[2] = id & 0xFF;
// addr_to
sendBuffer[3] = addrTo >> 8 & 0xFF;
sendBuffer[4] = addrTo & 0xFF;
for (uint16_t i = dataStart; i < dataStart + len; i++) {
sendBuffer[i] = ((uint8_t*)data)[i - dataStart];
}
// data crc
sendBuffer[packSize - crcBytes] = crc8(sendBuffer, 0, packSize - crcBytes, poly1) & 0xFF;
sendBuffer[packSize - crcBytes + 1] = crc8(sendBuffer, 0, packSize - crcBytes + 1, poly2) & 0xFF;
if (decPair != nullptr) {
decPair->isWaitingAccept = ((msgType >> 5) & IR_MASK_MSG_TYPE == IR_MSG_DATA_ACCEPT);
if (decPair->isWaitingAccept) {
decPair->addrWaitingFrom = addrTo;
}
}
// отправка
rawSend(sendBuffer, packSize);
}
void IR_Encoder::setDecoder_isSending() {
if (decodersCount) {
for (uint8_t i = 0; i < decodersCount; i++) {
blindDecoders[i]->isPairSending ^= id;
}
}
}
void IR_Encoder::rawSend(uint8_t* ptr, uint8_t len) {
if (isSending) {
//TODO: Обработка повторной отправки
return;
}
sendLen = len;
setDecoder_isSending();
cli();
toggleCounter = preambToggle; // Первая генерация для первого signal
dataBitCounter = bitPerByte - 1;
dataByteCounter = 0;
preambFrontCounter = preambPulse * 2 - 1; // -1 за счёт генерации уже на этапе сразу после инициализации
dataSequenceCounter = bitPerByte * 2;
syncSequenceCounter = syncBits * 2;
signal = preamb;
isSending = true;
state = HIGH;
currentBitSequence = bitHigh;
isSending = true;
sei();
}
void IR_Encoder::isr() {
if (!isSending) return;
ir_out_virtual = !ir_out_virtual && state;
if (toggleCounter) {
toggleCounter--;
} else {
IsrStart:
switch (signal) {
case noSignal:
signal = preamb;
// сброс счетчиков
// ...
isSending = false;
setDecoder_isSending();
return;
break;
case preamb:
if (preambFrontCounter) {
preambFrontCounter--;
toggleCounter = preambToggle; // Вторая и последующие генерации для этого signal
} else {// Конец преамбулы, переход на следующий signal
signal = data;
state = !LOW; // Инверсное состояние первой генерации следующего signal
goto IsrStart; // Применение новых параметров в этй же итерации прерывания
}
break;
case data:
if (dataSequenceCounter) {
if (!(dataSequenceCounter & 1U)) { // если чётный - смена бита
currentBitSequence = ((sendBuffer[dataByteCounter] >> dataBitCounter) & 1U) ? bitHigh : bitLow; // определение текущего бита
dataBitCounter--;
}
toggleCounter = currentBitSequence[!state];
dataSequenceCounter--;
} else { // Конец data, переход на следующий signal
syncLastBit = ((sendBuffer[dataByteCounter]) & 1U);
dataByteCounter++;
dataBitCounter = bitPerByte - 1;
dataSequenceCounter = bitPerByte * 2;
signal = sync;
goto IsrStart; // Применение новых параметров в этй же итерации прерывания
}
break;
case sync:
if (syncSequenceCounter) {
if (!(syncSequenceCounter & 1U)) { // если чётный - смена бита
if (syncSequenceCounter == 2) { // Если последний бит
currentBitSequence = ((sendBuffer[dataByteCounter]) & 0b10000000) ? bitLow : bitHigh;
} else {
currentBitSequence = syncLastBit ? bitLow : bitHigh; // определение текущего бита
syncLastBit = !syncLastBit;
}
}
toggleCounter = currentBitSequence[!state];
syncSequenceCounter--;
} else { // Конец sync, переход на следующий signal
signal = data;
syncSequenceCounter = syncBits * 2;
if (dataByteCounter >= sendLen) { // определение конца данных
signal = noSignal;
}
goto IsrStart; // Применение новых параметров в этй же итерации прерывания
}
break;
default:
return;
break;
}
state = !state;
}
}
void old() {///////////////////////////////////////////////////////
// void IR_Encoder::rawSend(uint8_t* ptr, uint8_t len) {
// /*tmp*/bool LOW_FIRST = false;/*tmp*/
// if (decoders != nullptr) { decoders->isPairSending = true; }
// bool prev = 1;
// bool next;
// send_EMPTY(preambPulse); // преамбула
// for (uint16_t byteNum = 0; byteNum < len; byteNum++) {
// sendByte(ptr[byteNum], &prev, LOW_FIRST);
// if (byteNum < len - 1) {
// next = ptr[byteNum + 1] & (LOW_FIRST ? 0b00000001 : 0b10000000);
// } else {
// next = 0;
// }
// addSync(&prev, &next);
// }
// if (decoders != nullptr) { decoders->isPairSending = false; }
// }
}
void IR_Encoder::sendByte(uint8_t byte, bool* prev, bool LOW_FIRST) {
uint8_t mask = LOW_FIRST ? 0b00000001 : 0b10000000;
for (uint8_t bitShift = 8; bitShift; bitShift--) {
digitalWrite(9, HIGH);
digitalWrite(9, LOW);
byte& mask ? send_HIGH(prev) : send_LOW();
*prev = byte & mask;
LOW_FIRST ? mask <<= 1 : mask >>= 1;
digitalWrite(9, HIGH);
digitalWrite(9, LOW);
}
}
void IR_Encoder::addSync(bool* prev, bool* next) {
switch (syncBits) {
case 0: break;
case 1:
*prev ? send_LOW() : send_HIGH();
*prev = !*prev;
break;
default:
for (int16_t i = 0; i < syncBits - 1; i++) {
*prev ? send_LOW() : send_HIGH();
*prev = !*prev;
}
*next ? send_LOW() : send_HIGH(0);
*prev = !*next;
break;
}
}
void IR_Encoder::send_HIGH(bool prevBite = 1) {
// if (/* prevBite */1) {
// meanderBlock(bitPauseTakts * 2, halfPeriod, LOW);
// meanderBlock(bitActiveTakts, halfPeriod, HIGH);
// } else { // более короткий HIGH после нуля
// meanderBlock(bitTakts - (bitActiveTakts - bitPauseTakts), halfPeriod, LOW);
// meanderBlock(bitActiveTakts - bitPauseTakts, halfPeriod, HIGH);
// }
}
void IR_Encoder::send_LOW() {
// meanderBlock(bitPauseTakts, halfPeriod, LOW);
// meanderBlock(bitActiveTakts, halfPeriod, LOW);
// meanderBlock(bitPauseTakts, halfPeriod, HIGH);
}
void IR_Encoder::send_EMPTY(uint8_t count) {
// for (size_t i = 0; i < count * 2; i++) {
// meanderBlock((bitPauseTakts * 2 + bitActiveTakts), halfPeriod, prevPreambBit);
// prevPreambBit = !prevPreambBit;
// }
// meanderBlock(bitPauseTakts * 2 + bitActiveTakts, halfPeriod, 0); //TODO: Отодвинуть преамбулу
}