/* * RemoteSensor library v1.0.2 (20130601) for Arduino 1.0 * * This library encodes, encrypts en transmits data to * remote weather stations made by Hideki Electronics.. * * Copyright 20112-2013 by Randy Simons http://randysimons.nl/ * * Parts of this code based on Oopsje's CrestaProtocol.pdf, for which * I thank him very much! * * License: GPLv3. See license.txt */ #include byte SensorReceiver::halfBit = 0; word SensorReceiver::clockTime; boolean SensorReceiver::isOne; unsigned long SensorReceiver::lastChange=0; SensorReceiverCallback SensorReceiver::callback; byte SensorReceiver::data[14]; byte SensorReceiver::packageLength; word SensorReceiver::duration; boolean SensorReceiver::enabled; void SensorReceiver::init(int8_t interrupt, SensorReceiverCallback callbackIn) { callback = callbackIn; enable(); if (interrupt >= 0) { attachInterrupt(interrupt, interruptHandler, CHANGE); } } void SensorReceiver::interruptHandler() { if (!enabled) { return; } /* I'll follow CrestaProtocol documentation here. However, I suspect it is inaccurate at some points: * - there is no stop-bit after every byte. Instead, there's a start-bit (0) before every byte. * - Conversely, there is no start-bit "1" before every byte. * - An up-flank is 0, down-flank is 1, at least with both my receivers. * * However, since the first start-bit 0 is hard to distinguish given the current clock-detecting * algorithm, I pretend there *is* a stop-bit 0 instead of start-bit. However, this means the * last stop-bit of a package must be ignored, as it simply isn't there. * * This manchester decoder is based on the principle that short edges indicate the current bit is the * same as previous bit, and that long edge indicate that the current bit is the complement of the * previous bit. */ static byte halfBitCounter = 255; unsigned long currentTime=micros(); duration=currentTime-lastChange; // Duration = Time between edges lastChange=currentTime; if (halfBit==0) { // Automatic clock detection. One clock-period is half the duration of the first edge. clockTime = duration >> 1; // Some sanity checking, very short (<200us) or very long (>1000us) signals are ignored. if (clockTime < 200 || clockTime > 1000) { return; } isOne = true; } else { // Edge is not too long, nor too short? if (duration < (clockTime >> 1) || duration > (clockTime << 1) + clockTime) { // read as: duration < 0.5 * clockTime || duration > 3 * clockTime // Fail. Abort. reset(); return; } // Only process every second half bit, i.e. every whole bit. if (halfBit & 1) { byte currentByte = halfBit / 18; byte currentBit = (halfBit >> 1) % 9; // nine bits in a byte. if (currentBit < 8) { if (isOne) { // Set current bit of current byte data[currentByte] |= 1 << currentBit; } else { // Reset current bit of current byte data[currentByte] &= ~(1 << currentBit); } } else { // Ninth bit must be 0 if (isOne) { // Bit is 1. Fail. Abort. reset(); return; } } if (halfBit == 17) { // First byte has been received // First data byte must be x75. if (data[0] != 0x75) { reset(); return; } } else if (halfBit == 53) { // Third byte has been received // Obtain the length of the data byte decodedByte = data[2]^(data[2]<<1); packageLength = (decodedByte >> 1) & 0x1f; // Do some checking to see if we should proceed if (packageLength < 6 || packageLength > 11) { reset(); return; } halfBitCounter = (packageLength + 3) * 9 * 2 - 2 - 1; // 9 bits per byte, 2 edges per bit, minus last stop-bit (see comment above) } // Done? if (halfBit >= halfBitCounter) { if (halfBit == halfBitCounter) { // Yes! Decrypt and call the callback if (decryptAndCheck()) { (callback)(data); } } // reset halfBit = 0; return; } } // Edge is long? if (duration > clockTime + (clockTime >> 1)) { // read as: duration > 1.5 * clockTime // Long edge. isOne = !isOne; // Long edge takes 2 halfbits halfBit++; } } halfBit++; return; } void SensorReceiver::reset() { halfBit = 1; clockTime = duration >> 1; isOne = true; } boolean SensorReceiver::decryptAndCheck() { byte cs1,cs2,i; cs1=0; cs2=0; for (i=1; i>1); if (b&1) c^=0x5f; if (c&1) b^=0x5f; return b^(c>>1); } void SensorReceiver::enable() { halfBit = 0; enabled = true; } void SensorReceiver::disable() { enabled = false; } void SensorReceiver::decodeThermoHygro(byte *data, byte &channel, byte &randomId, int &temp, byte &humidity) { channel = data[1] >> 5; // Internally channel 4 is used for the other sensor types (rain, uv, anemo). // Therefore, if channel is decoded 5 or 6, the real value set on the device itself is 4 resp 5. if (channel >= 5) { channel--; } randomId = data[1] & 0x1f; temp = 100 * (data[5] & 0x0f) + 10 * (data[4] >> 4) + (data[4] & 0x0f); // temp is negative? if (!(data[5] & 0x80)) { temp = -temp; } humidity = 10 * (data[6] >> 4) + (data[6] & 0x0f); }