diff --git a/README.md b/README.md
index 6cdfeda..6388f9e 100644
--- a/README.md
+++ b/README.md
@@ -2,9 +2,12 @@

# Gyver433
Библиотека для радиомодулей 433 МГц и Arduino
-- Не использует прерывания и таймеры (кроме нулевого, читает micros())
-- Встроенный CRC контроль целостности
+- Супер лёгкая либа, заведётся даже на тини13 (отправка)
+- Поддержка кривых китайских модулей
+- Интерфейс Manchester Coding (v1.1)
+- Встроенный CRC контроль целостности (CRC8 или XOR)
- Ускоренный алгоритм IO для AVR Arduino
+- Опционально работа в прерывании (приём данных)
### Совместимость
Совместима со всеми Arduino платформами (используются Arduino-функции)
@@ -33,22 +36,40 @@
## Инициализация
```cpp
-// указать пин
-Gyver433_RX rx(2);
-Gyver433_TX tx(2);
+//Классы:
+Gyver433_RX // приёмник
+Gyver433_TX // передатчик
+
+Gyver433_xx<пин, буфер, CRC> xx;
+// пин: цифровой пин
+// буфер: размер буфера в байтах. На "ручную" отправку буфер не нужен (пример raw_tx). По умолч. 64 байта
+// CRC: проверка целостности данных: G433_CRC8 (надёжный), G433_XOR (лёгкий), G433_NOCRC (отключено). По умолч. G433_CRC8
+
+// Дефайны-настройки перед подключением библиотеки
+#define G433_SLOW_MODE // "медленный режим" для синих модулей SYN480R
+#define G433_SPEED 1000 // скорость 100-8000 бит/с, по умолч. 2000 бит/с
```
## Использование
```cpp
// ========= Gyver433_TX =========
-void sendData(T &data); // отправить данные любого типа
+void sendData(T &data); // отправить данные любого типа (CRC добавится автоматически)
+void write(uint8_t* buf, uint8_t size); // отправить массив байт указанного размера (CRC не добавляется)
+uint8_t buffer[]; // доступ к буферу для отладки
// ========= Gyver433_RX =========
uint8_t tick(); // неблокирующий приём, вернёт кол-во успешно принятых байт
uint8_t tickWait(); // блокирующий приём, вернёт кол-во успешно принятых байт
bool readData(T &data); // прочитает буфер в любой тип данных (в указанную переменную)
int getSize(); // получить размер принятых данных
+bool gotData(); // вернёт true при получении корректных данных (если tick опрашивается в другом месте)
+uint8_t buffer[]; // доступ к буферу для отладки
+
+// ============= CRC =============
+// можно использовать встроенные функции для генерации байта CRC для ручной упаковки пакетов
+uint8_t G433_crc8(uint8_t *buffer, uint8_t size); // ручной CRC8
+uint8_t G433_crc_xor(uint8_t *buffer, uint8_t size); // ручной CRC XOR
```
@@ -56,26 +77,41 @@ int getSize(); // получить размер принятых д
Остальные примеры смотри в **examples**!
### Отправка
```cpp
-// мелкий передатчик 3.6V SYN115
-
-#define G433_BUFSIZE 50 // размер буфера
-#define G433_SPEED 2000 // скорость бит/сек (минимальная)
-
+// ======== ПЕРЕДАТЧИК =========
+#define G433_SLOW_MODE
#include
-Gyver433_TX tx(2); // указали пин
+Gyver433_TX<2, 20> tx; // указали пин и размер буфера
void setup() {
}
-char data[] = "Hello from #xx";
-byte count = 0;
+char data[] = "Hello from #xx"; // строка для отправки
+byte count = 0; // счётчик для отправки
+
void loop() {
+ // добавляем счётчик в строку
data[12] = (count / 10) + '0';
data[13] = (count % 10) + '0';
if (++count >= 100) count = 0;
- tx.sendData(data);
+ tx.sendData(data);
delay(100);
}
+
+// ======== ПРИЁМНИК =========
+#define G433_SLOW_MODE
+#include
+Gyver433_RX<2, 20> rx; // указали пин и размер буфера
+
+void setup() {
+ Serial.begin(9600);
+}
+
+void loop() {
+ if (rx.tickWait()) {
+ Serial.write(rx.buffer, rx.size);
+ Serial.println();
+ }
+}
```
### Приём
@@ -107,6 +143,7 @@ void loop() {
## Версии
- v1.0
+- v1.1 - оптимизация, новый интерфейс, поддержка дешёвых синих модулей, работа в прерывании
## Баги и обратная связь
diff --git a/examples/demo_rx/demo_rx.ino b/examples/demo_rx/demo_rx.ino
new file mode 100644
index 0000000..f676f0c
--- /dev/null
+++ b/examples/demo_rx/demo_rx.ino
@@ -0,0 +1,36 @@
+// крупный приёмник SYN480R [VCC: 3.3-5.5V, logic: VCC]
+// или MX-RM-5V (RF-5V) [VCC: 5V, logic: 5V]
+
+// "медленный режим" для синих модулей SYN480R
+// Объявляется перед подключением библиотеки
+// Зелёным модулям не нужен!
+#define G433_SLOW_MODE
+
+// можно указать скорость, по умолч. стоит 2000 бит/с
+// рабочий диапазон: 100-8000 бит/с
+//#define G433_SPEED 1000
+
+#include
+// Gyver433_TX<пин, буфер, CRC>
+// пин: цифровой пин
+// буфер: размер приёмного буфера в байтах
+// CRC: проверка целостности данных: G433_CRC8 (надёжный), G433_XOR (лёгкий), G433_NOCRC (отключено). По умолч. G433_CRC8
+Gyver433_RX<2, 20> rx; // указали пин и размер буфера
+
+void setup() {
+ Serial.begin(9600);
+}
+
+void loop() {
+ // "тик" опрашивает радио и вернёт количество успешно принятых байт
+ // tick принимает асинхронно, но может ловить ошибки при загруженном коде
+ // tickWait блокирует выполнение, но принимает данные чётко
+
+ //if (rx.tick()) {
+ if (rx.tickWait()) {
+ // принятые данные доступны в .buffer
+ // и имеют размер .size
+ Serial.write(rx.buffer, rx.size);
+ Serial.println();
+ }
+}
\ No newline at end of file
diff --git a/examples/demo_tx/demo_tx.ino b/examples/demo_tx/demo_tx.ino
new file mode 100644
index 0000000..848fd2f
--- /dev/null
+++ b/examples/demo_tx/demo_tx.ino
@@ -0,0 +1,37 @@
+// мелкий передатчик SYN115 [VCC: 1.8-3.6V, logic: VCC]
+// или FS1000A [VCC: 3-12V, logic: 5V]
+
+// "медленный режим" для синих модулей SYN115
+// Объявляется перед подключением библиотеки
+// зелёным модулям не нужен!
+#define G433_SLOW_MODE
+
+// можно указать скорость, по умолч. стоит 2000 бит/с
+// рабочий диапазон: 100-8000 бит/с
+//#define G433_SPEED 1000
+
+#include
+// Gyver433_TX<пин, буфер, CRC>
+// пин: цифровой пин
+// буфер: размер буфера в байтах. На "ручную" отправку буфер не нужен. По умолч. 64
+// CRC: проверка целостности данных: G433_CRC8 (надёжный), G433_XOR (лёгкий), G433_NOCRC (отключено). По умолч. G433_CRC8
+Gyver433_TX<2, 20> tx; // указали пин и размер буфера
+
+void setup() {
+}
+
+char data[] = "Hello from #xx"; // строка для отправки
+byte count = 0; // счётчик для отправки
+
+void loop() {
+ // добавляем счётчик в строку
+ data[12] = (count / 10) + '0';
+ data[13] = (count % 10) + '0';
+ if (++count >= 100) count = 0;
+
+ // отправка данных любого типа. Блокирующая на период отправки
+ tx.sendData(data);
+
+ // отправка 10 раз в сек
+ delay(100);
+}
\ No newline at end of file
diff --git a/examples/isr_rx/isr_rx.ino b/examples/isr_rx/isr_rx.ino
new file mode 100644
index 0000000..b59039b
--- /dev/null
+++ b/examples/isr_rx/isr_rx.ino
@@ -0,0 +1,28 @@
+// приём в прерывании. Отправляет пример demo_tx
+#define G433_SLOW_MODE
+
+#include
+Gyver433_RX<2, 20> rx; // указали пин и размер буфера
+
+void setup() {
+ Serial.begin(9600);
+ // взводим прерывания по CHANGE
+ attachInterrupt(0, isr, CHANGE);
+}
+
+void isr() {
+ rx.tick(); // тикер вызывается в прерывании
+}
+
+void loop() {
+ // .gotData() вернёт true при получении корректных данных
+ // и сам сбросится до следующего приёма
+ // внутри gotData() встроен тик!
+ if (rx.gotData()) {
+ Serial.write(rx.buffer, rx.size);
+ Serial.println();
+ }
+
+ // имитация загруженного кода
+ delay(200);
+}
diff --git a/examples/raw_rx/raw_rx.ino b/examples/raw_rx/raw_rx.ino
new file mode 100644
index 0000000..cdc4317
--- /dev/null
+++ b/examples/raw_rx/raw_rx.ino
@@ -0,0 +1,16 @@
+// обмен сырыми данными без CRC и буфера на отправку
+
+#define G433_SLOW_MODE
+#include
+Gyver433_RX<2, 20, G433_NOCRC> rx; // буфер на приём нужен!
+
+void setup() {
+ Serial.begin(9600);
+}
+
+void loop() {
+ if (rx.tickWait()) {
+ Serial.write(rx.buffer, rx.size);
+ Serial.println();
+ }
+}
\ No newline at end of file
diff --git a/examples/raw_tx/raw_tx.ino b/examples/raw_tx/raw_tx.ino
new file mode 100644
index 0000000..043327f
--- /dev/null
+++ b/examples/raw_tx/raw_tx.ino
@@ -0,0 +1,24 @@
+// обмен сырыми данными без CRC и буфера на отправку
+
+#define G433_SLOW_MODE
+#include
+Gyver433_TX<2, 0, G433_NOCRC> tx;
+
+void setup() {
+}
+
+char data[] = "Hello from #xx"; // строка для отправки
+byte count = 0; // счётчик для отправки
+
+void loop() {
+ // добавляем счётчик в строку
+ data[12] = (count / 10) + '0';
+ data[13] = (count % 10) + '0';
+ if (++count >= 100) count = 0;
+
+ // отправка данных типа byte*
+ tx.write(data, sizeof(data));
+
+ // отправка 10 раз в сек
+ delay(100);
+}
diff --git a/examples/rx433/rx433.ino b/examples/rx433/rx433.ino
deleted file mode 100644
index eb3c918..0000000
--- a/examples/rx433/rx433.ino
+++ /dev/null
@@ -1,22 +0,0 @@
-// крупный приёмник 5.0 SYN480R
-
-#define G433_BUFSIZE 50 // размер буфера
-#define G433_SPEED 2000 // скорость бит/сек (минимальная)
-
-#include
-Gyver433_RX rx(2);
-
-void setup() {
- Serial.begin(9600);
-}
-
-
-void loop() {
- // tick принимает асинхронно, но может ловить ошибки при загруженном коде
- // tickWait блокирует выполнение, но принимает данные чётко
- if (rx.tickWait()) {
- byte buf[64];
- rx.readData(buf);
- for (byte i = 0; i < rx.size; i++) Serial.write(buf[i]);
- }
-}
diff --git a/examples/rx433_lcd/rx433_lcd.ino b/examples/rx433_lcd/rx433_lcd.ino
index 5ceb5be..3262288 100644
--- a/examples/rx433_lcd/rx433_lcd.ino
+++ b/examples/rx433_lcd/rx433_lcd.ino
@@ -1,28 +1,20 @@
-// крупный приёмник 5.0V SYN480R
-#define G433_BUFSIZE 50 // размер буфера
-#define G433_SPEED 2000 // скорость бит/сек (минимальная)
+// выводим данные на дисплей. Отправляет пример demo_tx
#include
-Gyver433_RX rx(2); // указали пин
+Gyver433_RX<2> rx; // указали пин
-#include
#include
LiquidCrystal_I2C lcd(0x3f, 16, 2); // или 0x27
void setup() {
- Serial.begin(9600);
lcd.init();
lcd.backlight();
}
void loop() {
- // tick принимает асинхронно, но может ловить ошибки при загруженном коде
- // tickWait блокирует выполнение, но принимает данные чётко
if (rx.tick()) {
- byte buf[64];
- rx.readData(buf); // прочитать в buf
lcd.clear();
- lcd.home();
- for (byte i = 0; i < rx.size; i++) lcd.write(buf[i]);
+ lcd.home();
+ for (byte i = 0; i < rx.size; i++) lcd.write(rx.buffer[i]);
}
}
diff --git a/examples/rx433_struct/rx433_struct.ino b/examples/rx433_struct/rx433_struct.ino
index 8b6cf00..316cfef 100644
--- a/examples/rx433_struct/rx433_struct.ino
+++ b/examples/rx433_struct/rx433_struct.ino
@@ -1,10 +1,8 @@
-// передача структуры данных
-// крупный приёмник 5.0V SYN480R
-#define G433_BUFSIZE 50 // размер буфера
-#define G433_SPEED 2000 // скорость бит/сек (минимальная)
+// приём структуры данных
+#define G433_SLOW_MODE
#include
-Gyver433_RX rx(2); // указали пин
+Gyver433_RX<2, 10> rx; // указали пин и размер буфера
// формат пакета для приёма (такой же как отправляется)
struct dataPack {
@@ -19,11 +17,9 @@ void setup() {
}
void loop() {
- // tick принимает асинхронно, но может ловить ошибки при загруженном коде
- // tickWait блокирует выполнение, но принимает данные чётко
if (rx.tick()) {
- dataPack data;
- rx.readData(data); // прочитать в buf
+ dataPack data; // "буферная" структура
+ rx.readData(data); // переписываем данные в неё
Serial.println("Received:");
Serial.println(data.counter);
diff --git a/examples/tx433/tx433.ino b/examples/tx433/tx433.ino
deleted file mode 100644
index a5f8a69..0000000
--- a/examples/tx433/tx433.ino
+++ /dev/null
@@ -1,18 +0,0 @@
-// мелкий передатчик 3.6V SYN115
-#define G433_BUFSIZE 50 // размер буфера
-#define G433_SPEED 2000 // скорость бит/сек (минимальная)
-#include
-Gyver433_TX tx(2); // указали пин
-
-void setup() {
-}
-
-char data[] = "Hello from #xx";
-byte count = 0;
-void loop() {
- data[12] = (count / 10) + '0';
- data[13] = (count % 10) + '0';
- if (++count >= 100) count = 0;
- tx.sendData(data);
- delay(100);
-}
diff --git a/examples/tx433_struct/tx433_struct.ino b/examples/tx433_struct/tx433_struct.ino
index 91dae0e..5c33d28 100644
--- a/examples/tx433_struct/tx433_struct.ino
+++ b/examples/tx433_struct/tx433_struct.ino
@@ -1,10 +1,8 @@
// передача структуры данных
-// мелкий передатчик 3.6V SYN115
-#define G433_BUFSIZE 50 // размер буфера
-#define G433_SPEED 2000 // скорость бит/сек (минимальная)
+#define G433_SLOW_MODE
#include
-Gyver433_TX tx(2); // указали пин
+Gyver433_TX<2, 10> tx; // указали пин и размер буфера
// формат пакета для отправки
struct dataPack {
@@ -25,6 +23,8 @@ void loop() {
data.analog = analogRead(0); // тут ацп
data.time = millis(); // тут миллис
+ tx.sendData(data);
+
Serial.println("Transmit:");
Serial.println(data.counter);
Serial.println(data.randomNum);
@@ -32,6 +32,5 @@ void loop() {
Serial.println(data.time);
Serial.println();
- tx.sendData(data);
delay(1000);
}
diff --git a/keywords.txt b/keywords.txt
index ee6890d..0e7eb9a 100644
--- a/keywords.txt
+++ b/keywords.txt
@@ -13,14 +13,22 @@ Gyver433_RX KEYWORD1
# Methods and Functions (KEYWORD2)
#######################################
sendData KEYWORD2
+write KEYWORD2
tick KEYWORD2
tickWait KEYWORD2
readData KEYWORD2
size KEYWORD2
+buffer KEYWORD2
getSize KEYWORD2
+gotData KEYWORD2
+G433_crc8 KEYWORD2
+G433_crc_xor KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+G433_CRC8 LITERAL1
+G433_XOR LITERAL1
+G433_NOCRC LITERAL1
G433_SPEED LITERAL1
-G433_BUFSIZE LITERAL1
\ No newline at end of file
+G433_SLOW_MODE LITERAL1
\ No newline at end of file
diff --git a/library.properties b/library.properties
index 073a5af..a48f5d0 100644
--- a/library.properties
+++ b/library.properties
@@ -1,5 +1,5 @@
name=Gyver433
-version=1.0
+version=1.1
author=AlexGyver
maintainer=AlexGyver
sentence=Simple library for 433 MHz radio
diff --git a/src/FastIO.h b/src/FastIO.h
new file mode 100644
index 0000000..7bba4a5
--- /dev/null
+++ b/src/FastIO.h
@@ -0,0 +1,109 @@
+// Быстрый IO для AVR (для остальных будет digitalxxxxx)
+// v1.0
+
+#ifndef FastIO_h
+#define FastIO_h
+#include
+
+bool fastRead(const uint8_t pin); // быстрое чтение пина
+void fastWrite(const uint8_t pin, bool val); // быстрая запись
+uint8_t fastShiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder); // быстрый shiftIn
+void fastShiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t data); // быстрый shiftOut
+
+// ================================================================
+bool fastRead(const uint8_t pin) {
+#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
+ if (pin < 8) return bitRead(PIND, pin);
+ else if (pin < 14) return bitRead(PINB, pin - 8);
+ else if (pin < 20) return bitRead(PINC, pin - 14);
+
+#elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny13__)
+ return bitRead(PINB, pin);
+
+#elif defined(AVR)
+ uint8_t *_pin_reg = portInputRegister(digitalPinToPort(pin));
+ uint8_t _bit_mask = digitalPinToBitMask(pin);
+ return bool(*_pin_reg & _bit_mask);
+
+#else
+ return digitalRead(pin);
+
+#endif
+ return 0;
+}
+
+
+void fastWrite(const uint8_t pin, bool val) {
+#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
+ if (pin < 8) bitWrite(PORTD, pin, val);
+ else if (pin < 14) bitWrite(PORTB, (pin - 8), val);
+ else if (pin < 20) bitWrite(PORTC, (pin - 14), val);
+
+#elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny13__)
+ bitWrite(PORTB, pin, val);
+
+#elif defined(AVR)
+ uint8_t *_port_reg = portInputRegister(digitalPinToPort(pin));
+ uint8_t _bit_mask = digitalPinToBitMask(pin);
+ _port_reg = portOutputRegister(digitalPinToPort(pin));
+ _bit_mask = digitalPinToBitMask(pin);
+ if (val) *_port_reg |= _bit_mask; // HIGH
+ else *_port_reg &= ~_bit_mask; // LOW
+
+#else
+ digitalWrite(pin, val);
+
+#endif
+}
+
+
+uint8_t fastShiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
+#if defined(AVR)
+ volatile uint8_t *_clk_port = portOutputRegister(digitalPinToPort(clockPin));
+ volatile uint8_t *_dat_port = portInputRegister(digitalPinToPort(dataPin));
+ uint8_t _clk_mask = digitalPinToBitMask(clockPin);
+ uint8_t _dat_mask = digitalPinToBitMask(dataPin);
+ uint8_t data = 0;
+ for (uint8_t i = 0; i < 8; i++) {
+ *_clk_port |= _clk_mask;
+ if (bitOrder == MSBFIRST) {
+ data <<= 1;
+ if (bool(*_dat_port & _dat_mask)) data |= 1;
+ } else {
+ data >>= 1;
+ if (bool(*_dat_port & _dat_mask)) data |= 1 << 7;
+ }
+ *_clk_port &= ~_clk_mask;
+ }
+ return data;
+#else
+ return shiftIn(dataPin, clockPin, bitOrder);
+#endif
+}
+
+
+void fastShiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t data) {
+#if defined(AVR)
+ volatile uint8_t *_clk_port = portOutputRegister(digitalPinToPort(clockPin));
+ volatile uint8_t *_dat_port = portOutputRegister(digitalPinToPort(dataPin));
+ uint8_t _clk_mask = digitalPinToBitMask(clockPin);
+ uint8_t _dat_mask = digitalPinToBitMask(dataPin);
+ for (uint8_t i = 0; i < 8; i++) {
+ if (bitOrder == MSBFIRST) {
+ if (data & (1 << 7)) *_dat_port |= _dat_mask;
+ else *_dat_port &= ~_dat_mask;
+ data <<= 1;
+ } else {
+ if (data & 1) *_dat_port |= _dat_mask;
+ else *_dat_port &= ~_dat_mask;
+ data >>= 1;
+ }
+ *_clk_port |= _clk_mask;
+ *_clk_port &= ~_clk_mask;
+ }
+#else
+ shiftOut(dataPin, clockPin, bitOrder, data);
+#endif
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Gyver433.h b/src/Gyver433.h
index 1449a73..69d63e0 100644
--- a/src/Gyver433.h
+++ b/src/Gyver433.h
@@ -6,6 +6,7 @@
- Не использует прерывания и таймеры (кроме нулевого, читает micros())
- Встроенный CRC контроль целостности
- Ускоренный алгоритм IO для AVR Arduino
+ - Работает с хорошими и плохими 433 МГц модулями
AlexGyver, alex@alexgyver.ru
https://alexgyver.ru/
@@ -13,59 +14,67 @@
Версии:
v1.0 - релиз
+ v1.1 - оптимизация, новый интерфейс, поддержка дешёвых синих модулей, работа в прерывании
*/
#ifndef Gyver433_h
#define Gyver433_h
#include
+#include "FastIO.h"
-/*
- Передатчик:
- Gyver433_TX tx(пин) - создать объект
- sendData(data) - отправить, любой тип данных
-
- Приёмник:
- Gyver433_RX rx(пин) - создать объект
- tick() - вызывать постоянно для чтения. Асинхронный. Вернёт количество принятых байт
- tickWait() - тож самое, но блокирует выполнение, принимает более четко
- readData(data) - прочитать, любой тип данных
- size - количество принятых байтов
-*/
+// настройки из скетча:
+// #define G433_SLOW_MODE - включить "медленный режим" для плохих модулей
+// #define G433_SPEED n - скорость, бит/сек. Рекомендуется 2000. Работает вплоть до 6000
+uint8_t G433_crc8(uint8_t *buffer, uint8_t size); // ручной CRC8
+uint8_t G433_crc_xor(uint8_t *buffer, uint8_t size); // ручной CRC XOR
+#define TRAINING_TIME_SLOW (500000ul) // время синхронизации для SLOW_MODE
+
+// =========================================================================
#ifndef G433_SPEED
-#define G433_SPEED 2000 // скорость бит/сек (минимальная)
-#endif
-#ifndef G433_BUFSIZE
-#define G433_BUFSIZE 64 // размер буфера приёма и отправки
+#define G433_SPEED 3000 // скорость по умолчанию
#endif
-// тайминги интерфейса (компилятор посчитает)
-#define HIGH_PULSE (1000000ul/G433_SPEED)
-#define LOW_PULSE (HIGH_PULSE/2)
-#define START_PULSE (HIGH_PULSE*2)
-#define PULSE_HYST (LOW_PULSE/2)
-#define START_MIN (START_PULSE-PULSE_HYST)
-#define START_MAX (START_PULSE+PULSE_HYST)
-#define LOW_MIN (LOW_PULSE-PULSE_HYST)
-#define LOW_MAX (LOW_PULSE+PULSE_HYST)
-#define HIGH_MIN (HIGH_PULSE-PULSE_HYST)
-#define HIGH_MAX (HIGH_PULSE+PULSE_HYST)
+// тайминги интерфейса
+#define FRAME_TIME (1000000ul / G433_SPEED) // время фрейма
+#define HALF_FRAME (FRAME_TIME / 2) // полфрейма
+#define START_PULSE (FRAME_TIME * 2) // стартовый импульс
+#define TRAINING_AMOUNT_SLOW (TRAINING_TIME_SLOW / FRAME_TIME / 2) // количество импульсов для SLOW_MODE
-// crc
-uint8_t G433_crc(uint8_t *buffer, uint8_t size);
-void G433_crc_byte(uint8_t &crc, uint8_t data);
+// количество импульсов в зависимости от SLOW_MODE
+#ifdef G433_SLOW_MODE
+#define TRAINING_AMOUNT 40
+#else
+#define TRAINING_AMOUNT 10
+#endif
+
+// окно времени для обработки старта и фрейма
+#define START_MIN (START_PULSE * 3 / 4)
+#define START_MAX (START_PULSE * 5 / 4)
+#define FRAME_MIN (FRAME_TIME * 3 / 4)
+#define FRAME_MAX (FRAME_TIME * 5 / 4)
+
+// жоский delay для avr
+#ifdef AVR
+#define G433_DELAY(x) _delay_us(x)
+#else
+#define G433_DELAY(x) delayMicroseconds(x)
+#endif
+
+// режимы CRC
+#define G433_CRC8 0
+#define G433_XOR 1
+#define G433_NOCRC 2
+
+// crc8 один байт
+void G433_crc8_byte(uint8_t &crc, uint8_t data);
// ============ ПЕРЕДАТЧИК ============
+template
class Gyver433_TX {
public:
- Gyver433_TX(uint8_t pin) {
-#if defined(__AVR__)
- _port_reg = portOutputRegister(digitalPinToPort(pin));
- _bit_mask = digitalPinToBitMask(pin);
-#else
- _pin = pin;
-#endif
- pinMode(pin, OUTPUT);
+ Gyver433_TX() {
+ pinMode(TX_PIN, OUTPUT);
}
// отправка, блокирующая. Кушает любой тип данных
@@ -73,195 +82,203 @@ public:
void sendData(T &data) {
const uint8_t *ptr = (const uint8_t*) &data;
for (uint16_t i = 0; i < sizeof(T); i++) buffer[i] = *ptr++;
- buffer[sizeof(T)] = G433_crc(buffer, sizeof(T)); // CRC последним байтом
- bool flag = 0; // флаг дрыга
- for (uint8_t i = 0; i < 30; i++) { // 30 импульсов для синхронизации
- flag = !flag;
- fastDW(flag);
- delayMicroseconds(HIGH_PULSE);
+ if (CRC_MODE == G433_CRC8) {
+ buffer[sizeof(T)] = G433_crc8(buffer, sizeof(T));
+ write(buffer, sizeof(T) + 1);
+ } else if (CRC_MODE == G433_XOR) {
+ buffer[sizeof(T)] = G433_crc_xor(buffer, sizeof(T));
+ write(buffer, sizeof(T) + 1);
+ } else {
+ write(buffer, sizeof(T));
}
- fastDW(1); // старт бит
- delayMicroseconds(START_PULSE); // старт бит
- for (int n = 0; n < sizeof(T) + 1; n++) { // буфер + CRC
+ }
+
+ // отправка сырого набора байтов
+ void write(uint8_t* buf, uint16_t size) {
+ #ifdef G433_SLOW_MODE
+ for (uint16_t i = 0; i < ((millis() - tmr > 400) ? TRAINING_AMOUNT_SLOW : TRAINING_AMOUNT); i++) {
+ #else
+ for (uint16_t i = 0; i < TRAINING_AMOUNT; i++) {
+ #endif
+ fastWrite(TX_PIN, 1);
+ G433_DELAY(FRAME_TIME);
+ fastWrite(TX_PIN, 0);
+ G433_DELAY(FRAME_TIME);
+ }
+ fastWrite(TX_PIN, 1); // старт
+ G433_DELAY(START_PULSE); // ждём
+ fastWrite(TX_PIN, 0); // старт бит
+ G433_DELAY(HALF_FRAME); // ждём
+ for (uint16_t n = 0; n < size; n++) {
+ uint8_t data = buf[n];
for (uint8_t b = 0; b < 8; b++) {
- fastDW(flag);
- flag = !flag;
- if (bitRead(buffer[n], b)) delayMicroseconds(HIGH_PULSE);
- else delayMicroseconds(LOW_PULSE);
+ fastWrite(TX_PIN, !(data & 1));
+ G433_DELAY(HALF_FRAME);
+ fastWrite(TX_PIN, (data & 1));
+ G433_DELAY(HALF_FRAME);
+ data >>= 1;
}
}
- fastDW(0); // передача окончена
- }
-
-private:
- void fastDW(bool state) {
-#if defined(__AVR__)
- if (state) *_port_reg |= _bit_mask; // HIGH
- else *_port_reg &= ~_bit_mask; // LOW
-#else
- digitalWrite(_pin, state);
-#endif
- }
- uint8_t buffer[G433_BUFSIZE];
-
-#if defined(__AVR__)
- volatile uint8_t *_port_reg;
- volatile uint8_t _bit_mask;
-#else
- uint8_t _pin;
-#endif
-};
-
-
-// ============ ПРИЁМНИК ============
-class Gyver433_RX {
-public:
- Gyver433_RX(uint8_t pin) {
-#if defined(__AVR__)
- _pin_reg = portInputRegister(digitalPinToPort(pin));
- _bit_mask = digitalPinToBitMask(pin);
-#else
- _pin = pin;
-#endif
- }
-
- // неблокирующий приём, вернёт кол-во успешно принятых байт
- uint8_t tick() {
- bool newState = fastDR(); // читаем пин
- if (newState != prevState) { // ловим изменение сигнала
- uint32_t thisUs = micros();
- uint32_t thisPulse = thisUs - tmr;
- if (parse == 1) { // в прошлый раз поймали фронт
- if (thisPulse > START_MIN && thisPulse < START_MAX) { // старт бит?
- parse = 2; // ключ на старт
- tmr = thisUs;
- byteCount = 0;
- bitCount = 0;
- size = 0;
- for (uint8_t i = 0; i < G433_BUFSIZE; i++) buffer[i] = 0;
- } else { // не старт бит
- parse = 0;
- }
- } else if (parse == 2) { // идёт парсинг
- if (thisPulse > LOW_MIN && thisPulse < LOW_MAX) { // low бит
- // просто пропускаем (в буфере уже нули)
- tmr = thisUs;
- bitCount++;
- if (bitCount == 8) {
- bitCount = 0;
- byteCount++;
- if (byteCount > G433_BUFSIZE) parse = 0; // оверфлоу
- }
- } else if (thisPulse > HIGH_MIN && thisPulse < HIGH_MAX) { // high бит
- bitSet(buffer[byteCount], bitCount); // ставим бит единичку
- tmr = thisUs;
- bitCount++;
- if (bitCount == 8) {
- bitCount = 0;
- byteCount++;
- if (byteCount > G433_BUFSIZE) parse = 0; // оверфлоу
- }
- } else { // ошибка или конец передачи
- tmr = thisUs;
- parse = 0;
- // проверяем, есть ли данные и целые ли они
- if (byteCount > 0 && G433_crc(buffer, byteCount) == 0) {
- size = byteCount - 2; // длина даты (минус crc)
- return size;
- }
- else return 0;
- }
- }
-
- if (newState && !prevState && parse == 0) { // ловим фронт
- parse = 1; // в следующий раз ждём флаг
- tmr = thisUs;
- }
- prevState = newState;
+ fastWrite(TX_PIN, 0); // конец передачи
+ #ifdef G433_SLOW_MODE
+ tmr = millis();
+ #endif
}
- return 0;
- }
-
- // блокирующий приём, вернёт кол-во успешно принятых байт
- uint8_t tickWait() {
- do {
- tick();
- } while (parse == 2);
- if (byteCount > 0) {
- byteCount = 0;
+
+ // доступ к буферу
+ uint8_t buffer[TX_BUF];
+
+ private:
+ #ifdef G433_SLOW_MODE
+ uint32_t tmr = 0;
+ #endif
+ };
+
+ // ============ ПРИЁМНИК ============
+ template
+ class Gyver433_RX {
+ public:
+ Gyver433_RX() {
+ pinMode(RX_PIN, INPUT);
+ }
+
+ // неблокирующий приём, вернёт кол-во успешно принятых байт
+ uint8_t tick() {
+ uint32_t thisPulse = micros() - tmr; // время импульса
+ if (parse == 2 && thisPulse >= FRAME_TIME * 2) { // фрейм не закрыт
+ parse = size = 0; // приём окончен
+ if (byteCount > 1) { // если что то приняли
+ if (CRC_MODE == G433_CRC8) { // CRC8
+ if (!G433_crc8(buffer, byteCount)) {
+ size = byteCount - 2;
+ dataReady = 1;
+ }
+ } else if (CRC_MODE == G433_XOR) { // CRC XOR
+ if (!G433_crc_xor(buffer, byteCount)) {
+ size = byteCount - 2;
+ dataReady = 1;
+ }
+ } else { // без CRC
+ size = byteCount - 1;
+ dataReady = 1;
+ }
+ }
+ return size;
+ }
+ bool bit = fastRead(RX_PIN); // читаем пин
+ if (bit != prevBit) { // ловим изменение сигнала
+ if (parse == 1) { // в прошлый раз поймали фронт
+ tmr += thisPulse; // сброс таймера
+ if (thisPulse > START_MIN && thisPulse < START_MAX) { // старт бит?
+ parse = 2; // ключ на старт
+ byteCount = bitCount = size = 0; // сброс
+ dataReady = 0;
+ for (uint8_t i = 0; i < RX_BUF; i++) buffer[i] = 0; // чистим буфер
+ } else parse = 0; // не старт бит
+ } else if (parse == 2) { // идёт парсинг
+ if (thisPulse > FRAME_MIN && thisPulse < FRAME_MAX) { // фронт внутри таймфрейма
+ tmr += thisPulse; // синхронизируем тайминги
+ buffer[byteCount] >>= 1; // двигаем байт
+ if (bit && !prevBit) buffer[byteCount] |= _BV(7); // пишем единичку
+ bitCount++; // счётчик битов
+ }
+ if (bitCount == 8) { // собрали байт
+ bitCount = 0; // сброс
+ if (++byteCount >= RX_BUF) parse = 0; // буфер переполнен
+ }
+ }
+
+ if (bit && !prevBit && parse == 0) { // ловим фронт
+ parse = 1; // флаг на старт
+ tmr += thisPulse; // сброс таймера
+ }
+ prevBit = bit;
+ }
+ return 0;
+ }
+
+ // блокирующий приём, вернёт кол-во успешно принятых байт
+ uint8_t tickWait() {
+ do {
+ if (tick()) return size;
+ } while (parse == 2);
+ return 0;
+ }
+
+ // прочитает буфер в любой тип данных
+ template
+ bool readData(T &data) {
+ if (sizeof(T) > RX_BUF) return false;
+ uint8_t *ptr = (uint8_t*) &data;
+ for (uint16_t i = 0; i < sizeof(T); i++) *ptr++ = buffer[i];
+ return true;
+ }
+
+ // вернёт true при получении корректных данных
+ bool gotData() {
+ tick();
+ if (dataReady) {
+ dataReady = 0;
+ return 1;
+ } return 0;
+ }
+
+ // получить размер принятых данных
+ int getSize() {
return size;
- } else return 0;
- }
-
- // прочитает буфер в любой тип данных
- template
- bool readData(T &data) {
- if (sizeof(T) > G433_BUFSIZE) return false;
- uint8_t *ptr = (uint8_t*) &data;
- for (uint16_t i = 0; i < sizeof(T); i++) *ptr++ = buffer[i];
- return true;
- }
-
- // получить размер принятых данных
- int getSize() {
- return size;
- }
-
- int size = 0;
-
-private:
- bool fastDR() {
-#if defined(__AVR__)
- return bool(*_pin_reg & _bit_mask);
-#else
- return digitalRead(_pin);
-#endif
- }
- uint8_t buffer[G433_BUFSIZE];
- bool prevState;
- uint8_t parse = 0;
- uint32_t tmr = 0;
- uint8_t bitCount = 0, byteCount = 0;
-#if defined(__AVR__)
- volatile uint8_t *_pin_reg;
- volatile uint8_t _bit_mask;
-#else
- uint8_t _pin;
-#endif
-};
+ }
+
+ // размер принятых данных
+ int size = 0;
+
+ // доступ к буферу
+ uint8_t buffer[RX_BUF];
+
+ private:
+ bool prevBit, dataReady = 0;
+ uint8_t parse = 0;
+ uint32_t tmr = 0;
+ uint8_t bitCount = 0, byteCount = 0;
+ };
-void G433_crc_byte(uint8_t &crc, uint8_t data) {
+ // ===== CRC =====
+ void G433_crc8_byte(uint8_t &crc, uint8_t data) {
#if defined (__AVR__)
- // резкий алгоритм для AVR
- uint8_t counter;
- uint8_t buffer;
- asm volatile (
- "EOR %[crc_out], %[data_in] \n\t"
- "LDI %[counter], 8 \n\t"
- "LDI %[buffer], 0x8C \n\t"
- "_loop_start_%=: \n\t"
- "LSR %[crc_out] \n\t"
- "BRCC _loop_end_%= \n\t"
- "EOR %[crc_out], %[buffer] \n\t"
- "_loop_end_%=: \n\t"
- "DEC %[counter] \n\t"
- "BRNE _loop_start_%="
- : [crc_out]"=r" (crc), [counter]"=d" (counter), [buffer]"=d" (buffer)
- : [crc_in]"0" (crc), [data_in]"r" (data)
- );
+ // резкий алгоритм для AVR
+ uint8_t counter;
+ uint8_t buffer;
+ asm volatile (
+ "EOR %[crc_out], %[data_in] \n\t"
+ "LDI %[counter], 8 \n\t"
+ "LDI %[buffer], 0x8C \n\t"
+ "_loop_start_%=: \n\t"
+ "LSR %[crc_out] \n\t"
+ "BRCC _loop_end_%= \n\t"
+ "EOR %[crc_out], %[buffer] \n\t"
+ "_loop_end_%=: \n\t"
+ "DEC %[counter] \n\t"
+ "BRNE _loop_start_%="
+ : [crc_out]"=r" (crc), [counter]"=d" (counter), [buffer]"=d" (buffer)
+ : [crc_in]"0" (crc), [data_in]"r" (data)
+ );
#else
- // обычный для всех остальных
- uint8_t i = 8;
- while (i--) {
- crc = ((crc ^ data) & 1) ? (crc >> 1) ^ 0x8C : (crc >> 1);
- data >>= 1;
- }
+ // обычный для всех остальных
+ uint8_t i = 8;
+ while (i--) {
+ crc = ((crc ^ data) & 1) ? (crc >> 1) ^ 0x8C : (crc >> 1);
+ data >>= 1;
+ }
#endif
-}
+ }
-uint8_t G433_crc(uint8_t *buffer, uint8_t size) {
- uint8_t crc = 0;
- for (uint8_t i = 0; i < size; i++) G433_crc_byte(crc, buffer[i]);
- return crc;
-}
+ uint8_t G433_crc8(uint8_t *buffer, uint8_t size) {
+ uint8_t crc = 0;
+ for (uint8_t i = 0; i < size; i++) G433_crc8_byte(crc, buffer[i]);
+ return crc;
+ }
+ uint8_t G433_crc_xor(uint8_t *buffer, uint8_t size) {
+ uint8_t crc = 0;
+ for (uint8_t i = 0; i < size; i++) crc ^= buffer[i];
+ return crc;
+ }
#endif
\ No newline at end of file