diff --git a/IR_Decoder.cpp b/IR_Decoder.cpp new file mode 100644 index 0000000..2861ddf --- /dev/null +++ b/IR_Decoder.cpp @@ -0,0 +1,332 @@ +#include "IR_Decoder.h" +#include "IR_Encoder.h" + +IR_Decoder::IR_Decoder(uint16_t addr, IR_Encoder* encPair = nullptr) : addrSelf(addr), encoder(encPair) { + rawBuffer = new uint8_t[bufferRawSize] { 0 }; + prevRise = prevFall = prevPrevFall = prevPrevRise = 0; + start_RX(); +} + +IR_Decoder::~IR_Decoder() { + delete rawBuffer; +} + +void IR_Decoder::writeToBuffer(bool bit) { + if (!isBufferOverflow && !isPreamb) { + if (HIGH_FIRST) { + rawBuffer[(bufBitPos >> 3)] |= bit << (7 - (bufBitPos & ~(~0 << 3))); + }/* else { + rawBuffer[(bufBitPos >> 3)] |= bit << (bufBitPos & ~(~0 << 3)); + } */ + + #ifdef IRDEBUG + bit ? infoPulse(writeOp, 2) : infoPulse(writeOp, 1); + #endif + + if (isBufferOverflow) { //TODO: Буффер переполнен! + + } + + //const auto testval = bufferBitSizeMax; + if ((bufBitPos >= (8 * msgBytes) - syncBits) && !isMsgAvaliable) { + switch ((rawBuffer[0] >> 5) & IR_MASK_MSG_TYPE) { + + case IR_MSG_ACCEPT: + if (bufBitPos >= ((msgBytes + addrBytes + crcBytes) * (8 + 3)) - syncBits) { + const uint8_t dataSize = msgBytes + addrBytes; + isRawAvaliable = true; + isMsgAvaliable = crcCheck(dataSize); + if (isMsgAvaliable && (addrWaitingFrom == ((dataBuffer[1] << 8) | dataBuffer[2]))) { + gotAccept._set(dataBuffer, msgBytes + addrBytes + crcBytes, crcValue, errorCounter); + gotAccept._isAvaliable = true; + } + } + break; + + case IR_MSG_REQUEST: + if (bufBitPos >= ((msgBytes + addrBytes + addrBytes + crcBytes) * (8 + 3)) - syncBits) { + const uint8_t dataSize = msgBytes + addrBytes + addrBytes; + isRawAvaliable = true; + isMsgAvaliable = (crcCheck(dataSize)); + if (isMsgAvaliable && ((uint16_t)((dataBuffer[3] << 8) | dataBuffer[4]) == addrSelf)) { + gotRequest._isAvaliable = true; + gotRequest._set(dataBuffer, msgBytes + addrBytes + addrBytes + crcBytes, crcValue, errorCounter); + } + } + break; + + + case IR_MSG_DATA_ACCEPT: + case IR_MSG_DATA_NOACCEPT: + if (bufBitPos >= ((bitPerByte + syncBits) * ((rawBuffer[0] & IR_MASK_MSG_INFO) + crcBytes)) - syncBits) { + const uint8_t dataSize = (rawBuffer[0] & IR_MASK_MSG_INFO); + isRawAvaliable = true; + isMsgAvaliable = crcCheck(dataSize); + if (isMsgAvaliable && ((uint16_t)((dataBuffer[3] << 8) | dataBuffer[4]) == addrSelf) + ) { + gotData._isAvaliable = true; + gotData._set(dataBuffer, (dataSize)+crcBytes, crcValue, errorCounter); + + } + } + break; + + default: + break; + } + } + + if (bufBitPos >= bufferRawSize * 8 - 1) { isBufferOverflow = true; } + bufBitPos++; + } +} + +uint8_t* IR_Decoder::getDataBuffer(bool reset = false) { + if (!isRawAvaliable) { return nullptr; } + if (dataBuffer != nullptr) { delete dataBuffer; dataBuffer = nullptr; } // устранение утечки памяти + dataBuffer = new uint8_t[dataByteSizeMax] { 0 }; // Буффер по максимуму + + bool isData = true; + bool controlCheckFirst = true; + bool controlCheck; + + uint8_t nextControlBit = bitPerByte; + uint16_t i_dataBuffer = 0; + for (uint16_t i = 0; i < dataBitSize; i++) { + if (i == nextControlBit) { + controlCheckFirst = true; + nextControlBit += (isData ? syncBits : bitPerByte); + isData = !isData; + } + + if (isData) { + dataBuffer[i_dataBuffer / 8] |= (rawBuffer[(i / 8)] >> (7 - (i % 8)) & 1) << 7 - (i_dataBuffer % 8); + i_dataBuffer++; + } else { // Проверка контрольных sync битов + if (controlCheckFirst) { + controlCheck = (rawBuffer[(i / 8)] >> (7 - (i % 8)) & 1); + controlCheckFirst = false; + } else { + controlCheck |= (rawBuffer[(i / 8)] >> (7 - (i % 8)) & 1); + } + + } + } + + isFilterBufferAvaliable = controlCheck; + if (reset) { resetAvaliable(); } + return dataBuffer; +} + +bool IR_Decoder::crcCheck(uint8_t len) { + bool crcOK = false; + // получить буффер, если нет + if (!isFilterBufferAvaliable) getDataBuffer(); + if (dataBuffer == nullptr) { + + return false; + } + + crcValue = 0; + crcValue = (crc8(dataBuffer, 0, len, poly1) << 8) & ~((crc_t)0xFF); + crcValue |= crc8(dataBuffer, 0, len + 1, poly2) & (crc_t)0xFF; + + if ( + crcValue && + dataBuffer[len] == (crcValue >> 8) & 0xFF && + dataBuffer[len + 1] == (crcValue & 0xFF) + ) { + crcOK = true; + } else { crcOK = false; } + + + return crcOK; +} + +void IR_Decoder::start_RX() { + resetAvaliable(); + isBufferOverflow = false; + memset(rawBuffer, 0x00, bufferRawSize); + bufBitPos = 0; +} + +void IR_Decoder::resetAvaliable() { + isRawAvaliable = false; + isMsgAvaliable = false; + isFilterBufferAvaliable = false; +} + +uint16_t IR_Decoder::ceil_div(uint16_t val, uint16_t divider) { + int ret = val / divider; + if ((val << 4) / divider - (ret << 4) >= 8) + ret++; + return ret; +} + +void IR_Decoder::isr() { // в прерывании вызываем isr() + if (isPairSending) return; + + if (micros() - prevRise > timeout) { // первый + isPreamb = true; + frontCounter = preambFronts - 1U; + errorCounter = 0; + riseSyncTime = bitTime; + start_RX(); + } + + if (frontCounter > 0) { // в преамбуле + uint32_t risePeriod = micros() - prevRise; + if ((PIND >> 2) & 1 && risePeriod < timeout) { // __/``` ↑ и мы в внутри пакета + + if (freeFrec) { riseSyncTime = (riseSyncTime + risePeriod / 2) / 2; } // tuner + + if (risePeriod < riseTimeMin << 1) { // fix рваной единицы + frontCounter += 2; + errorCounter++; + } + } else { riseSyncTime = bitTime; } // сброс тюнера + frontCounter--; + } else { + if (isPreamb) {// первый фронт после + } + isPreamb = false; + } + + // определить направление фронта + if ((PIND >> 2) & 1) { // Если __/``` ↑ + + uint16_t risePeriod = micros() - prevRise; + uint16_t highTime = micros() - prevFall; + uint16_t lowTime = prevFall - prevRise; + + int8_t highCount = 0; + int8_t lowCount = 0; + int8_t allCount = 0; + + if (risePeriod < timeout && !isBufferOverflow && risePeriod > riseTimeMin) { + // Мы в пределах таймаута и буффер не переполнен и fix дроблёных единиц + + + if (aroundRise(risePeriod)) { // тактирование есть, сигнал хороший - без ошибок(?) + + if (highTime > riseTimeMin >> 1) { // 1 + #ifdef IRDEBUG + digitalWrite(wrHigh, 1); + #endif + writeToBuffer(HIGH); + } else { // 0 + #ifdef IRDEBUG + digitalWrite(wrLow, 1); + #endif + writeToBuffer(LOW); + } + + } else { // пропущены такты! сигнал средний // ошибка пропуска + + + highCount = ceil_div(highTime, riseTime); // предполагаемое колличество HIGH битов + lowCount = ceil_div(lowTime, riseTime); // предполагаемое колличество LOW битов + allCount = ceil_div(risePeriod, riseTime); // предполагаемое колличество всего битов + + if (highCount == 0 && highTime > riseTime / 3) { // fix короткой единицы (?)после пропуска нулей(?) + highCount++; + errorCounter++; + #ifdef IRDEBUG + errPulse(errOut, 2); + #endif + } + + if (lowCount + highCount > allCount) { // fix ошибочных сдвигов + if (lowCount > highCount) { // Лишние нули + lowCount = allCount - highCount; + #ifdef IRDEBUG + errPulse(errOut, 3); + #endif + } else if (lowCount < highCount) { // Лишние единицы + highCount = allCount - lowCount; + #ifdef IRDEBUG + errPulse(errOut, 4); + #endif + } else if (lowCount == highCount) {} // неизвестный случай + errorCounter += allCount; + } + + errorCounter += allCount; + #ifdef IRDEBUG + errPulse(errOut, 1); + #endif + + + for (int8_t i = 0; i < lowCount && 8 - i; i++) { // отправка LOW битов, если есть + #ifdef IRDEBUG + digitalWrite(wrLow, 1); + #endif + writeToBuffer(LOW); + } + + for (int8_t i = 0; i < highCount && 8 - i; i++) { // отправка HIGH битов, если есть + #ifdef IRDEBUG + digitalWrite(wrHigh, 1); + #endif + writeToBuffer(HIGH); + } + + } + + #ifdef IRDEBUG + digitalWrite(wrHigh, 0); + digitalWrite(wrLow, 0); + #endif + } + + if (risePeriod > riseTimeMax >> 1 || highCount || lowCount) { // комплексный фикс рваной единицы + prevPrevRise = prevRise; + prevRise = micros(); + } else { + errorCounter++; + #ifdef IRDEBUG + errPulse(errOut, 5); + #endif + } + + } else { // Если ```\__ ↓ + + if (micros() - prevFall > riseTimeMin) { + prevPrevFall = prevFall; + prevFall = micros(); + } else { + #ifdef IRDEBUG + //errPulse(errOut, 5); + #endif + } + } + + if (isPreamb && frontCounter <= 0) { + prevRise = micros() + riseTime; + } + +#ifdef IRDEBUG + digitalWrite(writeOp, isPreamb); +#endif +} + + +// IRDEBUG FUNC +#ifdef IRDEBUG +inline void IR_Decoder::errPulse(uint8_t pin, uint8_t count) { + for (size_t i = 0; i < count; i++) { + digitalWrite(pin, 1); + digitalWrite(pin, 0); + } + digitalWrite(pin, 0); +} + +inline void IR_Decoder::infoPulse(uint8_t pin, uint8_t count) { + for (size_t i = 0; i < count; i++) { + digitalWrite(pin, 1); + digitalWrite(pin, 0); + } +} +#endif + + diff --git a/IR_Decoder.h b/IR_Decoder.h new file mode 100644 index 0000000..4cd6d29 --- /dev/null +++ b/IR_Decoder.h @@ -0,0 +1,186 @@ +#pragma once +#include "IR_config.h" + +//#define IRDEBUG + +#ifdef IRDEBUG +#define wrHigh 3 // Запись HIGH инициирована // green +#define wrLow 4 // Запись LOW инициирована // blue +#define writeOp 6 // Операция записи, 1 пульс для 0 и 2 для 1 // orange +// Исправленные ошибки // purle +// 1 пульс: fix +#define errOut 5 +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////// + +#define riseTime riseSyncTime //* bitTime */ 893U // TODO: Должно высчитываться медианой +#define riseTolerance tolerance /* 250U */ // погрешность +#define riseTimeMax (riseTime + riseTolerance) +#define riseTimeMin (riseTime - riseTolerance) +#define aroundRise(t) (riseTimeMin < t && t < riseTimeMax) +#define timeout ((riseTimeMax * 8) + syncBits +1) // us // таймаут в 8 data + 3 sync + 1 + +class IR_Encoder; +class IR_Decoder : private IR_FOX { + friend IR_Encoder; +public: + uint16_t addrSelf; + + IR_Decoder(uint16_t addr, IR_Encoder* encPair = nullptr); + ~IR_Decoder(); + + // @brief Для прерывания + void isr(); + + + // @return Буффер переполнился + bool isOverflow() { return isBufferOverflow; }; + + ////////////////////////////////////////////////////////////////////////// + + class InputData { + friend IR_Decoder; + protected: + bool _isAvaliable = false; + uint8_t _msgType; + uint16_t _addrFrom = 0; + uint16_t _addrTo = 0; + uint8_t* _data = nullptr; + uint8_t _dataRawSize = 0; + uint16_t _crcPackVal; + uint16_t _crcCalcVal; + uint16_t _errCount; + + void _set(uint8_t* ptr, uint8_t len, uint16_t crc, uint16_t err) { + _crcCalcVal = crc; + _dataRawSize = len; + _errCount = err; + if (_data != nullptr) { delete _data; _data = nullptr; } + _data = new uint8_t[len]; + for (uint8_t i = 0; i < len; i++) { _data[i] = ptr[i]; } + _msgType = _data[0]; + ini(); + _isAvaliable = true; + } + private: + virtual void ini(); + + public: + bool avaliable() { return _isAvaliable; }; + uint8_t msgInfo() { return _msgType & IR_MASK_MSG_INFO; }; + uint8_t msgType() { return (_msgType >> 5) & IR_MASK_MSG_TYPE; }; + uint8_t msgRAW() { return _msgType; }; + uint16_t errorCount() { return _errCount; }; + uint16_t crcIN() { return _crcPackVal; }; + uint16_t crcCALC() { return _crcCalcVal; }; + void resetAvaliable() { _isAvaliable = false; }; + }; + + ////////////////////////////////////////////////////////////////////////// + + class Data : public InputData { + public: + uint16_t addrFrom() { return _addrFrom; }; + uint16_t addrTo() { return _addrTo; }; + uint8_t dataSize() { return _dataRawSize - (msgBytes + addrBytes + addrBytes + crcBytes); }; + uint8_t* data() { return &_data[msgBytes + addrBytes + addrBytes]; }; + uint8_t dataRawSize() { return _dataRawSize; }; + uint8_t* dataRaw() { return _data; }; + bool isNeedAccept() { return ((_msgType >> 5) & IR_MASK_MSG_TYPE) == IR_MSG_DATA_ACCEPT; }; + private: + void ini() override { + _addrFrom = (_data[1] << 8) | _data[2]; + _addrTo = (_data[3] << 8) | _data[4]; + _crcPackVal = (_data[_dataRawSize - 2] << 8) | _data[_dataRawSize - 1]; + } + + }; + + class Accept : public InputData { + public: + uint16_t addrFrom() { return _addrFrom; }; + + private: + void ini() override { + _addrFrom = (_data[1] << 8) | _data[2]; + _crcPackVal = (_data[3] << 8) | _data[4]; + } + }; + + class Request : public Accept { + public: + uint16_t addrTo() { return _addrTo; }; + private: + void ini() override { + _addrFrom = (_data[1] << 8) | _data[2]; + _addrTo = (_data[3] << 8) | _data[4]; + _crcPackVal = (_data[5] << 8) | _data[6]; + } + }; + + Data gotData; + Accept gotAccept; + Request gotRequest; + + +private: + IR_Encoder* encoder; + bool isPairSending = false; + bool IsPairSendLOW = false; + + bool isWaitingAccept = false; + uint16_t addrWaitingFrom = 0; + + + uint16_t addrFrom = 0; + + uint16_t riseSyncTime = bitTime; + + volatile bool isRawAvaliable = false; + + volatile bool isMsgAvaliable = false; + volatile bool isFilterBufferAvaliable = false; + + volatile bool isBufferOverflow = false; + + volatile bool isPreamb = false; // флаг начальной последовости + bool HIGH_FIRST = true; // порядок приходящих битов + + //Буффер + const uint8_t bufferRawSize = + ((bufferBitSizeMax % 8 > 0) ? + (bufferBitSizeMax / 8) + 1 : + (bufferBitSizeMax / 8)); + const uint8_t bufferDataSize = dataByteSizeMax; // + crc + uint8_t* rawBuffer = nullptr; + uint8_t* dataBuffer = nullptr; + + volatile uint32_t prevRise, prevFall, prevPrevFall, prevPrevRise; + volatile uint16_t errorCounter = 0; + volatile int8_t frontCounter = 0; + volatile int16_t bufBitPos = 0; + crc_t crcValue = 0; +private: + uint8_t* getDataBuffer(bool reset = false); + bool crcCheck(uint8_t len); + + inline void writeToBuffer(bool); + inline void start_RX(); + void resetAvaliable(); + + uint16_t ceil_div(uint16_t, uint16_t); + //uint16_t sma = 0; + void SMA(uint16_t); + + //TODO: Сделать функцию медианы + void medi(uint16_t); + + +#ifdef IRDEBUG + inline void errPulse(uint8_t pin, uint8_t count); + inline void infoPulse(uint8_t pin, uint8_t count); +#endif + + +}; \ No newline at end of file diff --git a/IR_Encoder.cpp b/IR_Encoder.cpp new file mode 100644 index 0000000..5dc11f6 --- /dev/null +++ b/IR_Encoder.cpp @@ -0,0 +1,186 @@ +#include "IR_Encoder.h" +#include "IR_Decoder.h" + +#define halfPeriod ((carrierPeriod / 2) - 5) //13 //8 // 14 при работе с регистрами, 14 -6 = 8 для digitalWrite() +const auto _x_ = halfPeriod; + +IR_Encoder::IR_Encoder(uint16_t addr, uint8_t pin, IR_Decoder* decPair) : ir_out(pin), addrSelf(addr), decoder(decPair) {}; +IR_Encoder::~IR_Encoder() {}; + +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) { + /*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--) { + byte& mask ? send_HIGH(prev) : send_LOW(); + *prev = byte & mask; + LOW_FIRST ? mask <<= 1 : mask >>= 1; + } +} + +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) { + 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; + } +} + +void IR_Encoder::meanderBlock(uint16_t count, uint16_t _period, bool high = true) { + for (uint16_t i = 0; i < count << 1; i++) { + + if ((i & 1)) { // Если чётное + //PORTC &= ~(1 << 3); // LOW + digitalWrite(ir_out, high ? LOW : LOW); + } else { // Если не четное + //PORTC |= 1 << 3; // HIGH + digitalWrite(ir_out, high ? HIGH : LOW); + } + + delayMicroseconds(_period); + } +} \ No newline at end of file diff --git a/IR_Encoder.h b/IR_Encoder.h new file mode 100644 index 0000000..700a655 --- /dev/null +++ b/IR_Encoder.h @@ -0,0 +1,48 @@ +#pragma once +#include "IR_config.h" + +class IR_Decoder; +class IR_Encoder : IR_FOX { + friend IR_Decoder; +public: + uint8_t ir_out; + uint16_t addrSelf; +private: + bool prevPreambBit = true; // предыдущий бит преамбулы + +public: + IR_Encoder(uint16_t addr, uint8_t pin, IR_Decoder* decPair = nullptr); + + template + void sendData(uint16_t addrTo, T& data, bool needAccept = false); + void sendACK(uint16_t addrTo, uint8_t addInfo, bool forAll = false); + void sendRequest(uint16_t addrTo, uint8_t addInfo = 0); + + + ~IR_Encoder(); +private: + IR_Decoder* decoder; + void meanderBlock(uint16_t count, uint16_t _period, bool isNoPause = true); + void sendByte(uint8_t byte, bool* prev, bool LOW_FIRST); + void addSync(bool* prev, bool* next); + void send_HIGH(bool = 1); + void send_LOW(); + void send_EMPTY(uint8_t count); + void rawSend(uint8_t* ptr, uint8_t len); + void _sendData(uint16_t addrTo, uint8_t* data, uint8_t len, uint8_t msgType); + +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////// + +template +void IR_Encoder::sendData(uint16_t addrTo, T& data, bool needAccept = false) { // TODO: переделать логику LOW_FIRST + uint8_t len = sizeof(T); + 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); +} diff --git a/IR_config.h b/IR_config.h new file mode 100644 index 0000000..808d997 --- /dev/null +++ b/IR_config.h @@ -0,0 +1,116 @@ +#pragma once +#include +/*////////////////////////////////////////////////////////////////////////////////////// + +Адресация с 1 до 65 499 +65 500 ~ 65 535 - широковещательные пакеты (всем), возможно разделить на 35 типов +Адрес 0 запрещен и зарезервирован под NULL + +IR_MSG_ACCEPT с адреса 0 воспринимается всеми устройствами + + +/```````````````````````````````````````````````` data pack `````````````````````````````````````````````\                                   +                                                                                                          +{``````````} [````````````````````````] [````````````````````] [````````````````````````] [``````````````] +{ msg type } [ addr_self uint16_t ] [ addr_to uint16_t ] [ data bytes ] [ CRC Bytes ] +{..........} [........................] [....................] [........................] [..............] +                                                                                                           +{ aka size } [addr_self_H][addr_self_L] [addr_to_H][addr_to_L] [data_H][data_n..][data_L] [ crc1 ][ crc2 ] +|     0           1            2              3         4          5                         |       |     +\____________________________________________________________________________________________/       |     +|                                                                                                    |     +\____________________________________________________________________________________________________/     + +msg type: +                                        //  __________ +                                        // | 01234567 | +                                        //  ---------- +                                        // | xxx..... | = тип сообщения +                                        // | ...xxxxx | = длина (максимум 32 бита) +                                        //  ---------- */ +#define IR_MSG_ 0U // | 000..... | = = ?? +#define IR_MSG_ACCEPT 1U // | 001..... | = */ /* = подтверждение +#define IR_MSG_REQUEST 2U // | 010..... | = */ /* = запрос +#define IR_MSG_ 3U // | 011..... | = */ /* = ?? +#define IR_MSG_ 4U // | 100..... | = */ /* = ?? +#define IR_MSG_ 5U // | 101..... | = */ /* = ?? +#define IR_MSG_DATA_NOACCEPT 6U // | 110..... | = */ /* = данные, не требующие подтверждения +//                                      // | \\\xxxxx | = = L длина данных +#define IR_MSG_DATA_ACCEPT 7U // | 111..... | = */ /* = данные требующие подтверждения +//                                      // | \\\xxxxx | = = L длина данных +/*   // ---------- + +/```````````````````` подтверждение ```````````````````\      /``````````````````````````````````````` запрос ``````````````````````````````````\ +                                                                                                                       +{``````````} [````````````````````````] [``````````````]      {``````````} [````````````````````````] [````````````````````````] [``````````````] +{ msg type } [ addr_self uint16_t ] [ CRC Bytes ]      { msg type } [ addr_self uint16_t ] [ addr_to uint16_t ] [ CRC Bytes ] +{..........} [........................] [..............]      {..........} [........................] [........................] [..............] +                                                                                                                                                  +{ 001..... } [addr_self_H][addr_self_L] [ crc1 ][ crc2 ]      { 010..... } [addr_self_H][addr_self_L] [addr_self_H][addr_self_L] [ crc1 ][ crc2 ] +|     0            1           2           3       4          |     0            1           2              3           4           5       6     +\__________________________________________/       |          \_____________________________________________________________________/       |     +|                                                  |          |                                                                             |     +\__________________________________________________/          \_____________________________________________________________________________/     + +*/ + +#define IR_MASK_MSG_TYPE 0b00000111 +#define IR_MASK_MSG_INFO 0b00011111 + +/* +/////////////////////////////////////////////////////////////////////////////////////*/ + +#define bytePerPack 3 // колличество байтов в пакете +#define freeFrec true + +///////////////////////////////////////////////////////////////////////////////////// + +#define bitPerByte 8U // Колличество бит в байте +#define addrBytes 2 +#define msgBytes 1 +#define crcBytes 2 +typedef uint16_t crc_t; +#define poly1 0x31 +#define poly2 0x8C +#define syncBits 3U // количество битов синхронизации + +#define dataByteSizeMax (msgBytes + addrBytes + addrBytes + bytePerPack + crcBytes) + // размер msg в битах // размер короткой посылки в битах +#define dataBitSize ((8 + syncBits) * dataByteSizeMax) // размер посылки с данными в битах +#define bufferBitSizeMax (dataBitSize) // Размер буффера в битах + +//const auto x = bufferBitSizeMax; +#define preambPulse 3U +#define preambFronts (preambPulse*2) // количество фронтов преамбулы + +#define carrierFrec 38000U // частота несущей +#define carrierPeriod (1000000U/carrierFrec) // период несущей в us + +// В процессе работы значения будут отклонятся в соответствии с предыдущим битом +#define bitActiveTakts 25U // длительность активной части бита в тактах +#define bitPauseTakts 5U // длительность промежутков в тактах + +#define bitTakts (bitActiveTakts+bitPauseTakts*2U) // Общая длительность бита в тактах +#define bitTime (bitTakts*carrierPeriod) // Общая длительность бита +//const auto viewValue = bitTime; +#define tolerance 300U + +class IR_FOX { +private: + bool isSending = false; +public: + uint8_t crc8(uint8_t* data, uint8_t start, uint8_t end, uint8_t poly) { //TODO: сделать возможность межбайтовой проверки + uint8_t crc = 0xff; + size_t i, j; + for (i = start; i < end; i++) { + crc ^= data[i]; + for (j = 0; j < 8; j++) { + if ((crc & 0x80) != 0) + crc = (uint8_t)((crc << 1) ^ poly); + else + crc <<= 1; + } + } + return crc; + } +};