mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2025-05-03 23:00:16 +00:00
322 lines
11 KiB
C++
322 lines
11 KiB
C++
#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, uint8_t tune = 0, IR_Decoder* decPair) {
|
||
sendBuffer = new uint8_t[dataByteSizeMax] { 0 };
|
||
ir_out = pin;
|
||
pinMode(ir_out, OUTPUT);
|
||
addrSelf = addr;
|
||
decoder = decPair;
|
||
carrierTune = tune;
|
||
halfPeriod = (carrierPeriod / 2) - carrierTune;
|
||
dataBitCounter = 0 - preambFronts;
|
||
|
||
signal = noSignal;
|
||
};
|
||
|
||
IR_Encoder::~IR_Encoder() {
|
||
delete [] bitHigh;
|
||
delete [] bitLow;
|
||
delete [] sendBuffer;
|
||
};
|
||
|
||
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) {
|
||
uint8_t* ptr = new uint8_t[msgBytes + addrBytes + crcBytes] { 0 };
|
||
|
||
ptr[0] = IR_MSG_ACCEPT << 5;
|
||
ptr[0] |= addInfo & IR_MASK_MSG_INFO;
|
||
|
||
// addr_self
|
||
if (!forAll) {
|
||
ptr[1] = addrSelf >> 8 & 0xFF;
|
||
ptr[2] = addrSelf & 0xFF;
|
||
}
|
||
|
||
// data crc
|
||
ptr[3] = crc8(ptr, 0, 3, poly1) & 0xFF;
|
||
ptr[4] = crc8(ptr, 0, 4, poly2) & 0xFF;
|
||
|
||
rawSend(ptr, msgBytes + addrBytes + crcBytes);
|
||
|
||
// освобождение ресурсов
|
||
delete ptr;
|
||
ptr = nullptr;
|
||
}
|
||
|
||
void IR_Encoder::sendRequest(uint16_t addrTo, uint8_t addInfo) {
|
||
uint8_t* ptr = new uint8_t[msgBytes + addrBytes + crcBytes] { 0 };
|
||
|
||
ptr[0] = IR_MSG_REQUEST << 5;
|
||
ptr[0] |= addInfo & IR_MASK_MSG_INFO;
|
||
|
||
// addr_self
|
||
ptr[1] = addrSelf >> 8 & 0xFF;
|
||
ptr[2] = addrSelf & 0xFF;
|
||
|
||
//addr_to
|
||
ptr[3] = addrTo >> 8 & 0xFF;
|
||
ptr[4] = addrTo & 0xFF;
|
||
|
||
// data crc
|
||
ptr[5] = crc8(ptr, 0, 5, poly1) & 0xFF;
|
||
ptr[6] = crc8(ptr, 0, 6, poly2) & 0xFF;
|
||
|
||
rawSend(ptr, msgBytes + addrBytes + addrBytes + crcBytes);
|
||
|
||
// освобождение ресурсов
|
||
delete ptr;
|
||
ptr = nullptr;
|
||
}
|
||
|
||
void IR_Encoder::_sendData(uint16_t addrTo, uint8_t* data, uint8_t len, uint8_t msgType) {
|
||
|
||
uint8_t packSize = msgBytes + addrBytes + addrBytes + len + crcBytes;
|
||
uint8_t dataStart = msgBytes + addrBytes + addrBytes;
|
||
|
||
// создание массива для отправки
|
||
uint8_t* ptr = new uint8_t[packSize] { 0 };
|
||
//memset(ptr, 0, sizeof(ptr));
|
||
|
||
// формирование массива
|
||
// msg_type
|
||
ptr[0] = msgType;
|
||
|
||
// addr_self
|
||
ptr[1] = addrSelf >> 8 & 0xFF;
|
||
ptr[2] = addrSelf & 0xFF;
|
||
|
||
// addr_to
|
||
ptr[3] = addrTo >> 8 & 0xFF;
|
||
ptr[4] = addrTo & 0xFF;
|
||
|
||
for (uint16_t i = dataStart; i < dataStart + len; i++) {
|
||
ptr[i] = ((uint8_t*)data)[i - dataStart];
|
||
}
|
||
|
||
// data crc
|
||
ptr[packSize - crcBytes] = crc8(ptr, 0, packSize - crcBytes, poly1) & 0xFF;
|
||
ptr[packSize - crcBytes + 1] = crc8(ptr, 0, packSize - crcBytes + 1, poly2) & 0xFF;
|
||
|
||
if (decoder != nullptr) {
|
||
decoder->isWaitingAccept = ((msgType >> 5) & IR_MASK_MSG_TYPE == IR_MSG_DATA_ACCEPT);
|
||
decoder->addrWaitingFrom = addrTo;
|
||
}
|
||
// отправка
|
||
rawSend(ptr, packSize);
|
||
|
||
// освобождение ресурсов
|
||
delete ptr;
|
||
ptr = nullptr;
|
||
|
||
}
|
||
|
||
void IR_Encoder::rawSend(uint8_t* ptr, uint8_t len) {
|
||
digitalToggle(9); digitalToggle(9);
|
||
memset(sendBuffer, 0x00, dataByteSizeMax);
|
||
memcpy(sendBuffer, ptr, len);
|
||
sendLen = len;
|
||
// *sendBuffer = 0b10010011;
|
||
isSending = true;
|
||
|
||
cli();
|
||
if (decoder != nullptr) { decoder->isPairSending = isSending; }
|
||
// #define preambToggle 2*2-1 //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||
#define preambToggle ((bitPauseTakts * 2 + bitActiveTakts) * 2 - 1) //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||
|
||
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;
|
||
sei();
|
||
}
|
||
|
||
|
||
|
||
void IR_Encoder::isr() {
|
||
if (!isSending) return;
|
||
|
||
ir_out_virtual = !ir_out_virtual && state;
|
||
|
||
if (toggleCounter) {
|
||
toggleCounter--;
|
||
} else {
|
||
IsrStart:
|
||
switch (signal) {
|
||
case noSignal:
|
||
// сброс счетчиков
|
||
// ...
|
||
isSending = false;
|
||
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 (decoder != nullptr) { decoder->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 (decoder != nullptr) { decoder->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: Отодвинуть преамбулу
|
||
}
|
||
|
||
|