184 lines
4.7 KiB
C++
184 lines
4.7 KiB
C++
/*
|
|
* 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 2011-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 <SensorTransmitter.h>
|
|
|
|
|
|
|
|
/*******************
|
|
* Sensor base class
|
|
******************/
|
|
|
|
SensorTransmitter::SensorTransmitter(byte transmitterPin, byte randomId) {
|
|
_transmitterPin = transmitterPin;
|
|
_randomId = randomId;
|
|
|
|
pinMode(_transmitterPin, OUTPUT);
|
|
}
|
|
|
|
/* Encrypt data byte to send to station */
|
|
byte SensorTransmitter::encryptByte(byte b) {
|
|
byte a;
|
|
for(a=0; b; b<<=1) {
|
|
a^=b;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
/* The second checksum. Input is OldChecksum^NewByte */
|
|
byte SensorTransmitter::secondCheck(byte b) {
|
|
byte c;
|
|
if (b&0x80) {
|
|
b^=0x95;
|
|
}
|
|
c = b^(b>>1);
|
|
if (b&1) {
|
|
c^=0x5f;
|
|
}
|
|
if (c&1) {
|
|
b^=0x5f;
|
|
}
|
|
return b^(c>>1);
|
|
}
|
|
|
|
/* Example to encrypt a package for sending,
|
|
Input: Buffer holds the unencrypted data.
|
|
Returns the number of bytes to send,
|
|
Buffer now holds data ready for sending.
|
|
*/
|
|
byte SensorTransmitter::encryptAndAddCheck(byte *buffer) {
|
|
byte cs1,cs2,count,i;
|
|
|
|
count=(buffer[2]>>1) & 0x1f;
|
|
cs1=0;
|
|
cs2=0;
|
|
for(i=1; i<count+1; i++) {
|
|
buffer[i]=encryptByte(buffer[i]);
|
|
cs1^=buffer[i];
|
|
cs2 =secondCheck(buffer[i]^cs2);
|
|
}
|
|
buffer[count+1]=cs1;
|
|
buffer[count+2]=secondCheck(cs1^cs2);
|
|
return count+3;
|
|
}
|
|
|
|
/* Send one byte and keep the transmitter ready to send the next */
|
|
void SensorTransmitter::sendManchesterByte(byte transmitterPin, byte b) {
|
|
byte i;
|
|
|
|
// Send start-bit 0.
|
|
digitalWrite(transmitterPin, LOW);
|
|
delayMicroseconds(500);
|
|
digitalWrite(transmitterPin, HIGH);
|
|
delayMicroseconds(500);
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
if (b&1) {
|
|
digitalWrite(transmitterPin, HIGH);
|
|
} else {
|
|
digitalWrite(transmitterPin, LOW);
|
|
}
|
|
|
|
delayMicroseconds(500); /* 500uS delay */
|
|
|
|
b=~b;
|
|
if (i&1) {
|
|
b>>=1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Send bytes (prepared by “encryptAndAddCheck”) and pause at the end. */
|
|
void SensorTransmitter::sendManchesterPackage(byte transmitterPin, byte *data, byte cnt) {
|
|
byte i;
|
|
|
|
for (i=0; i<cnt; i++) {
|
|
sendManchesterByte(transmitterPin, data[i]);
|
|
}
|
|
|
|
digitalWrite(transmitterPin, LOW); /* Drop the transmitter line */
|
|
}
|
|
|
|
/**
|
|
* Encrypts, adds checksums and transmits the data. The value of byte 3 in the data is ignored.
|
|
*/
|
|
void SensorTransmitter::sendPackage(byte transmitterPin, byte *data) {
|
|
byte buffer[14], temp, count;
|
|
for (temp=0x40; temp>=0x40; temp+=0x40) { /* Sends 3 packages */
|
|
memcpy(buffer, data, ((data[2] >> 1) & 0x1f) + 1);
|
|
|
|
buffer[3] = (buffer[3] & 0x1f) + temp;
|
|
|
|
count = encryptAndAddCheck(buffer); /* Encrypt, add checksum bytes */
|
|
sendManchesterPackage(transmitterPin, buffer,count); /* Send the package */
|
|
|
|
delay(30);
|
|
}
|
|
}
|
|
|
|
|
|
/************************************
|
|
* Thermo / Hygro sensor transmitter
|
|
***********************************/
|
|
|
|
ThermoHygroTransmitter::ThermoHygroTransmitter(byte transmitterPin, byte randomId, byte channel) : SensorTransmitter(transmitterPin, randomId) {
|
|
_channel = channel;
|
|
}
|
|
|
|
void ThermoHygroTransmitter::sendTempHumi(int temperature, byte humidity) {
|
|
byte buffer[10];
|
|
|
|
// Note: temperature is 10x the actual temperature! So, 23.5 degrees is passed as 235.
|
|
|
|
buffer[0] = 0x75; /* Header byte */
|
|
buffer[1] = (_channel << 5) | _randomId ; /* Thermo-hygro at channel 1 (see table1)*/
|
|
buffer[2] = 0xce; /* Package size byte for th-sensor */
|
|
buffer[3] = 0x1e; /* Themo/Hygro */
|
|
|
|
if ( temperature < 0 ) {
|
|
buffer[5] = 0x4 << 4; // High nibble is 0x4 for sub zero temperatures...
|
|
temperature = -temperature; // Make temperature positive
|
|
} else {
|
|
buffer[5] = 0xc << 4; // ...0xc for positive
|
|
}
|
|
|
|
// Note: temperature is now always positive!
|
|
buffer[4] = (((temperature % 100) / 10 ) << 4) | // the "3" from 23.5
|
|
(temperature % 10); // the "5" from 23.5
|
|
buffer[5] |= (temperature / 100); // the "2" from 23.5
|
|
|
|
buffer[6] = ((humidity / 10) << 4) | (humidity % 10); // BCD encoded
|
|
|
|
buffer[7]=0xff; /* Comfort flag */
|
|
|
|
sendPackage(_transmitterPin, buffer);
|
|
}
|
|
|
|
void ThermoHygroTransmitter::sendRainlevel(unsigned int level){ // in 0.7mm
|
|
byte buffer[10];
|
|
|
|
// Note: temperature is 10x the actual temperature! So, 23.5 degrees is passed as 235.
|
|
|
|
buffer[0] = 0x75; /* Header byte */
|
|
buffer[1] = (_channel << 5) | _randomId ; /* Thermo-hygro at channel 1 (see table1)*/
|
|
buffer[2] = 0xcc; /* Package size byte for rain-sensor */
|
|
buffer[3] = 0x0e; /* Rain level */
|
|
|
|
// Note: temperature is now always positive!
|
|
buffer[4] = level & 0xff; // Low byte
|
|
buffer[5] = (level >>8) & 0xff; // High byte
|
|
|
|
sendPackage(_transmitterPin, buffer);
|
|
}
|