mirror of
https://github.com/Show-maket/IR-protocol.git
synced 2025-05-03 23:00:16 +00:00
v1.00
This commit is contained in:
parent
a48a4b2393
commit
a11553c46f
332
IR_Decoder.cpp
Normal file
332
IR_Decoder.cpp
Normal file
@ -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
|
||||
|
||||
|
186
IR_Decoder.h
Normal file
186
IR_Decoder.h
Normal file
@ -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
|
||||
|
||||
|
||||
};
|
186
IR_Encoder.cpp
Normal file
186
IR_Encoder.cpp
Normal file
@ -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);
|
||||
}
|
||||
}
|
48
IR_Encoder.h
Normal file
48
IR_Encoder.h
Normal file
@ -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<typename T>
|
||||
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<typename T>
|
||||
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);
|
||||
}
|
116
IR_config.h
Normal file
116
IR_config.h
Normal file
@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
/*//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Адресация с 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;
|
||||
}
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user