rf433demo/lib/inFactory/inFactoryReceive.ino

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);
}