-
Notifications
You must be signed in to change notification settings - Fork 5
/
TempSensorDecode.cpp
163 lines (135 loc) · 4.51 KB
/
TempSensorDecode.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
TempSensorDecode.cpp - Library for decoding
prologue temperature sensor data from inexpensive
433 MHz based weather sensors.
Created by Martin Marinov, 2020
Released into the public domain.
*/
#include "Arduino.h"
#include "TempSensorDecode.h"
#define PULSE ((long) 500)
#define ZERO ((long) 2000)
#define ONE ((long) 4000)
#define SYNC ((long) 8500)
#define ERROR_PERCENTAGE (10)
#define NUMBER_OF_BITS_IN_PACKET (36)
#define NO_SYNC (-999)
#define CHECK(duration, expected_duration) ( (duration * 100 > expected_duration * (100 - ERROR_PERCENTAGE)) && (duration * 100 < expected_duration * (100 + ERROR_PERCENTAGE)) )
#if defined(ESP8266) || defined(ESP32)
#define ISR_PREFIX ICACHE_RAM_ATTR
#else
#define ISR_PREFIX
#endif
volatile int16_t TempSensorDecode::_temperature_raw;
volatile uint8_t TempSensorDecode::_humidity;
volatile bool TempSensorDecode::_isButtonPressed;
volatile uint8_t TempSensorDecode::_batteryState;
volatile uint8_t TempSensorDecode::_channel;
volatile bool TempSensorDecode::_hasNewData = false;
volatile bool TempSensorDecode::_hasAnyData = false;
volatile uint64_t TempSensorDecode::_packet_raw;
// API
bool TempSensorDecode::hasNewData() {
bool hasNewData = TempSensorDecode::_hasNewData;
TempSensorDecode::_hasNewData = false;
return hasNewData;
}
bool TempSensorDecode::hasAnyData() {
return TempSensorDecode::_hasAnyData;
}
float TempSensorDecode::getTemperature() {
return float(TempSensorDecode::_temperature_raw) / 10;
}
uint8_t TempSensorDecode::getHumidity() {
return TempSensorDecode::_humidity;
}
bool TempSensorDecode::getIsButtonPressed() {
return TempSensorDecode::_isButtonPressed;
}
uint8_t TempSensorDecode::getBatteryState() {
return TempSensorDecode::_batteryState;
}
uint8_t TempSensorDecode::getChannel() {
return TempSensorDecode::_channel;
}
uint64_t TempSensorDecode::getRawPacket() {
return TempSensorDecode::_packet_raw;
}
// Driver & Signal processing
void TempSensorDecode::setup(int pin)
{
pinMode(pin, INPUT);
digitalWrite(pin, LOW);
attachInterrupt(digitalPinToInterrupt(pin), TempSensorDecode::_handleInterrupt, CHANGE);
}
ISR_PREFIX void TempSensorDecode::_handleInterrupt() {
static unsigned long lastTime;
long timeNow = micros();
unsigned long duration = timeNow - lastTime;
lastTime = timeNow;
TempSensorDecode::_handleDuration(duration);
}
void TempSensorDecode::_handleDuration(unsigned long duration) {
static bool lastWasPulse = false;
static int validBits = NO_SYNC;
static uint64_t packet = 0;
bool isPulse = CHECK(duration, PULSE);
if (lastWasPulse) {
if (CHECK(duration, SYNC)) {
// Start of data transmission
validBits = 0;
} else if (duration > PULSE && (duration * 100) < (ONE * (100 + ERROR_PERCENTAGE))) {
// We have a valid zero or one, let's try to distinguish
packet = packet << 1;
if (2 * duration > ZERO + ONE) {
// It's a 1
bitSet(packet, 0);
} else {
// It's a 0
bitClear(packet, 0);
}
validBits++;
if (validBits == NUMBER_OF_BITS_IN_PACKET) {
TempSensorDecode::_handlePacket(packet);
} else if (validBits > NUMBER_OF_BITS_IN_PACKET) {
// Too many bits, something is wrong
validBits = NO_SYNC;
}
} else {
// We were expecting a 0 or 1
validBits = NO_SYNC;
}
} else if (!isPulse) {
// Last was not pulse, this was not pulse
// Reset as this is invalid packet
validBits = NO_SYNC;
}
lastWasPulse = isPulse;
}
void TempSensorDecode::_handlePacket(uint64_t packet) {
uint8_t battery = (packet >> 20) & 0x8;
uint8_t channel = 1 + ((packet >> 20) & 0x3); // Channels start at 0
// ESP32 do not support floating point operations in interrupts. Arrange
// to shift the left-aligned 12-bit value as an int16_t so that we get
// sign extension for the final value to support negative numbers.
int16_t temperature_raw = (packet >> 4) & 0xFFFF;
temperature_raw >>= 4;
uint8_t humidity = packet & 0xFF;
bool button = (packet >> 20) & 0x4;
TempSensorDecode::_packet_raw = packet;
if (temperature_raw > 550 || temperature_raw < -250) {
// invalid temperature
return;
}
if (humidity > 100) {
// invalid humidity
return;
}
TempSensorDecode::_temperature_raw = temperature_raw;
TempSensorDecode::_humidity = humidity;
TempSensorDecode::_channel = channel;
TempSensorDecode::_batteryState = battery;
TempSensorDecode::_isButtonPressed = button;
TempSensorDecode::_hasNewData = true;
TempSensorDecode::_hasAnyData = true;
}