151 lines
3.9 KiB
C++
151 lines
3.9 KiB
C++
/*
|
|
|
|
Transmissions includes an id. Every 60 seconds the sensor transmits 6 packets:
|
|
|
|
0000 1111 | 0011 0000 | 0101 1100 | 1110 0111 | 0110 0001
|
|
iiii iiii | cccc ub?? | tttt tttt | tttt hhhh | hhhh ??nn
|
|
|
|
- i: identification // changes on battery switch
|
|
- c: CRC-4 // CCITT checksum, see below for computation specifics
|
|
- u: unknown // (sometimes set at power-on, but not always)
|
|
- b: battery low // flag to indicate low battery voltage
|
|
- h: Humidity // BCD-encoded, each nibble is one digit, 'A0' means 100%rH
|
|
- t: Temperature // in °F as binary number with one decimal place + 90 °F offset
|
|
- n: Channel // Channel number 1 - 3
|
|
*/
|
|
|
|
int old_duration = 0;
|
|
int new_duration = 0;
|
|
|
|
unsigned long old_time = 0;
|
|
unsigned long new_time = 0;
|
|
|
|
boolean old_status = LOW;
|
|
boolean new_status = LOW;
|
|
boolean started = false;
|
|
byte input = 2;
|
|
|
|
uint8_t msg[5];
|
|
byte indexBit = 0;
|
|
|
|
|
|
|
|
void setup() {
|
|
// put your setup code here, to run once:
|
|
pinMode(input, INPUT_PULLUP);
|
|
Serial.begin(500000);
|
|
}
|
|
|
|
void loop() {
|
|
// put your main code here, to run repeatedly:
|
|
receive();
|
|
|
|
}
|
|
|
|
void receive() {
|
|
new_status = digitalRead(input);
|
|
if (new_status != old_status) {
|
|
new_time = micros();
|
|
new_duration = new_time - old_time;
|
|
|
|
if (!new_status && !started) {
|
|
if (durationEquals(old_duration, 7850, 100) && (durationEquals(new_duration, 600, 100)) ) {// __________|"| //that's a start
|
|
started = true;
|
|
}
|
|
}
|
|
else if (new_status && started) {//right after rising edge
|
|
|
|
if (durationEquals(old_duration, 600, 100)) {
|
|
if (new_duration < 2700) {// it's a 0
|
|
bitWrite(msg[indexBit / 8], 7 - (indexBit % 8), 0);
|
|
}
|
|
else {// it's a 1
|
|
bitWrite(msg[indexBit / 8], 7 - (indexBit % 8), 1);
|
|
}
|
|
indexBit++;
|
|
}
|
|
else { // abort if high level duration is not correct
|
|
started = false;
|
|
indexBit = 0;
|
|
}
|
|
if (indexBit >= 40) {// stop when 40 bits are received
|
|
started = false;
|
|
indexBit = 0;
|
|
|
|
if (infactory_crc_check()) {
|
|
decode();
|
|
}
|
|
else {
|
|
Serial.println("CRC Error");
|
|
}
|
|
}
|
|
}
|
|
|
|
old_time = new_time;
|
|
old_duration = new_duration;
|
|
}
|
|
old_status = new_status;
|
|
}
|
|
|
|
void decode() {
|
|
byte iD = msg[0];
|
|
bool battery_low = (msg[1] >> 2) & 1;
|
|
int temp_raw = (msg[2] << 4) | (msg[3] >> 4);
|
|
byte humidity = (msg[3] & 0x0F) * 10 + (msg[4] >> 4); // BCD, 'A0'=100%rH
|
|
byte channel = msg[4] & 0x03;
|
|
float temp_f = ((float)temp_raw * 0.1 - 122) * 5 / 9.;
|
|
Serial.print("iD=");
|
|
Serial.print(iD, HEX);
|
|
Serial.print("; lo_bat=");
|
|
Serial.print(battery_low);
|
|
Serial.print("; hum=");
|
|
Serial.print(humidity);
|
|
Serial.print("; chn=");
|
|
Serial.print(channel);
|
|
Serial.print("; tmp=");
|
|
Serial.println(temp_f);
|
|
}
|
|
|
|
bool durationEquals(int duration1, int duration2, int tolerance) {
|
|
if (abs(duration1 - duration2) <= tolerance) return true;
|
|
else return false;
|
|
}
|
|
|
|
void printHex(byte b) {
|
|
if (b < 0x10) Serial.print("0");
|
|
Serial.print(b, HEX);
|
|
}
|
|
|
|
|
|
|
|
uint8_t crc4(uint8_t const message[], unsigned nBytes, uint8_t polynomial, uint8_t init)
|
|
{
|
|
unsigned remainder = init << 4; // LSBs are unused
|
|
unsigned poly = polynomial << 4;
|
|
unsigned bit;
|
|
|
|
while (nBytes--) {
|
|
remainder ^= *message++;
|
|
for (bit = 0; bit < 8; bit++) {
|
|
if (remainder & 0x80) {
|
|
remainder = (remainder << 1) ^ poly;
|
|
} else {
|
|
remainder = (remainder << 1);
|
|
}
|
|
}
|
|
}
|
|
return remainder >> 4 & 0x0f; // discard the LSBs
|
|
}
|
|
|
|
|
|
bool infactory_crc_check() {
|
|
uint8_t msg_crc, crc;
|
|
msg_crc = msg[1] >> 4;
|
|
// for CRC computation, channel bits are at the CRC position(!)
|
|
msg[1] = (msg[1] & 0x0F) | (msg[4] & 0x0F) << 4;
|
|
// crc4() only works with full bytes
|
|
crc = crc4(msg, 4, 0x13, 0); // Koopmann 0x9, CCITT-4; FP-4; ITU-T G.704
|
|
crc ^= msg[4] >> 4; // last nibble is only XORed
|
|
return (crc == msg_crc);
|
|
}
|