Added oregon v2.1 support to ArduinoTellstick along with some code cleanup
Former-commit-id: d05ee71fa4f2f91afd6452e894385bbcd7020917
This commit is contained in:
parent
c2d03347ca
commit
1c23a7c360
11 changed files with 391 additions and 116 deletions
|
|
@ -3,27 +3,30 @@
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timer2 interrupt in 16kHz. Samples the RF Rx data pin
|
||||||
|
*/
|
||||||
|
ISR(TIMER2_COMPA_vect) {
|
||||||
|
|
||||||
ISR(TIMER2_COMPA_vect) { //timer2 interrupt 16kHz. Samples the RF Rx data pin
|
if ( !IS_RADIO_RECIEVER_ON() ) { //if no Radio Rx should be performed
|
||||||
|
|
||||||
if (!RFRX) { //if no Radio Rx should be performed
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t bit = digitalRead(RX_PIN); // optimized "digital_read(7)" = "PIND & 0x1"
|
uint8_t bit = RX_PIN_READ();
|
||||||
|
|
||||||
//will store "lows" on even buffer addresses and "highs" on odd buffer addresses
|
//will store "lows" on even buffer addresses and "highs" on odd buffer addresses
|
||||||
if ( ( ((int)bufferWriteP) & 0x1 ) != bit ) { //compare the bit and the buffer pointer address. true if one is odd and one is even.
|
if ( ( ((uintptr_t)bufferWriteP) & 0x1 ) != bit ) { //compare the bit and the buffer pointer address. true if one is odd and one is even.
|
||||||
//step the buffer pointer
|
//step the buffer pointer
|
||||||
if ( bufferWriteP + 1 > RF_rxBufferEndP) {
|
if ( bufferWriteP+1 > RF_rxBufferEndP ) {
|
||||||
|
*RF_rxBufferStartP = 1; //reset the next data point before going there
|
||||||
bufferWriteP = RF_rxBufferStartP;
|
bufferWriteP = RF_rxBufferStartP;
|
||||||
} else {
|
} else {
|
||||||
|
*(bufferWriteP+1) = 1; //reset the next data point before going there
|
||||||
++bufferWriteP;
|
++bufferWriteP;
|
||||||
}
|
}
|
||||||
*bufferWriteP = 1; //reset and step once on this addess
|
|
||||||
} else {
|
} else {
|
||||||
if (*bufferWriteP < 255) { //only values up to 255
|
if ( *bufferWriteP < 255 ) { //Do not step the value if it already is 255 (max value)
|
||||||
++(*bufferWriteP); //step the buffer
|
++(*bufferWriteP); //step the buffer value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -34,26 +37,27 @@ void setup() {
|
||||||
|
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
|
|
||||||
pinMode(RX_PIN, INPUT); //set RX pin to input
|
setupPins();
|
||||||
pinMode(TX_PIN, OUTPUT); //ser TX pin as output
|
|
||||||
|
|
||||||
//setup timer2 interrupt at 16kHz for RF sampling
|
//setup timer2 interrupt at 16kHz for RF sampling
|
||||||
cli();//stop interrupts
|
cli(); //stop interrupts
|
||||||
TCCR2A = 0;// set entire TCCR2A register to 0
|
TCCR2A = 0; // set entire TCCR2A register to 0
|
||||||
TCCR2B = 0;// same for TCCR2B
|
TCCR2B = 0; // same for TCCR2B
|
||||||
TCNT2 = 0;//initialize counter value to 0
|
TCNT2 = 0; //initialize counter value to 0
|
||||||
OCR2A = 124;// = ( (16*10^6) / (16000Hz*8pc) ) - 1 (must be <256)
|
OCR2A = 124; // = ( (16000000Hz) / (16000Hz*8prescaler) ) - 1 (must be <256)
|
||||||
TCCR2A |= (1 << WGM21); // turn on CTC mode
|
TCCR2A |= (1 << WGM21); // turn on CTC mode
|
||||||
TCCR2B |= (1 << CS21); // Set CS21 bit for 8 prescaler
|
TCCR2B |= (1 << CS21); // Set CS21 bit for 8 prescaler
|
||||||
TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt
|
TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt
|
||||||
sei();//allow interrupts
|
sei(); //allow interrupts
|
||||||
|
|
||||||
//reset buffer just to be sure
|
//reset buffer just to be sure
|
||||||
for (uint8_t* p = RF_rxBufferStartP; p <= RF_rxBufferEndP; ++p) {
|
for (uint8_t* p = RF_rxBufferStartP; p <= RF_rxBufferEndP; ++p) {
|
||||||
*p = 0;
|
*p = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Serial.println(F("+V2"));
|
||||||
|
|
||||||
RFRX = true; //start receiving radio data
|
ACTIVATE_RADIO_RECEIVER();
|
||||||
|
|
||||||
};//end setup
|
};//end setup
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,70 @@
|
||||||
#include "archtech.h"
|
#include "archtech.h"
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
bool parseArctechSelfLearning(uint8_t* bufStartP, uint8_t* bufEndP) { //start points to a "one" buffer byte, end points to a "zero" buffer byte
|
/*******************************************************************************
|
||||||
|
--ARCHTECH PROTOCOL SPECIFICATION--
|
||||||
|
|
||||||
|
----SIGNAL----
|
||||||
|
A signal consists of a PREAMBLE, DATA and an POSTAMBLE.
|
||||||
|
Each signal is sent 4 times in a row to increase the delivery success rate.
|
||||||
|
|
||||||
|
----PREAMBLE----
|
||||||
|
send high for 250 microseconds
|
||||||
|
send low for 2,500 microseconds
|
||||||
|
|
||||||
|
----DATA----
|
||||||
|
26 bits of transmitter id
|
||||||
|
1 bit indicating if the on/off bit is targeting a group
|
||||||
|
1 bit indicating "on" or "off"
|
||||||
|
4 bits indicating the targeted unit/channel/device
|
||||||
|
4 bits indicating a absolute dim level (optional)
|
||||||
|
|
||||||
|
Total: 32 or 36 bits depending if absolute dimming is used
|
||||||
|
|
||||||
|
Each real bit in the data field is sent over air as a pair of two inverted bits.
|
||||||
|
real bit bits over air
|
||||||
|
1 = "01"
|
||||||
|
0 = "10"
|
||||||
|
|
||||||
|
Over air a "1"(one) is sent as:
|
||||||
|
send high for 250 microseconds
|
||||||
|
send low for 1,250 microseconds
|
||||||
|
|
||||||
|
Over air a "0"(zero) is sent as:
|
||||||
|
send high for 250 microseconds
|
||||||
|
send low for 250 microseconds
|
||||||
|
|
||||||
|
----POSTAMBLE----
|
||||||
|
send high for 250 microseconds
|
||||||
|
send low for 10,000 microseconds
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#define ARCHTECH_SHORT_MIN 2
|
||||||
|
#define ARCHTECH_SHORT_MAX 7
|
||||||
|
#define ARCHTECH_LONG_MIN 17
|
||||||
|
#define ARCHTECH_LONG_MAX 23
|
||||||
|
|
||||||
|
#define IS_SHORT(b) ( ARCHTECH_SHORT_MIN <= b && b <= ARCHTECH_SHORT_MAX )
|
||||||
|
#define IS_LONG(b) ( ARCHTECH_LONG_MIN <= b && b <= ARCHTECH_LONG_MAX )
|
||||||
|
|
||||||
|
#define IS_ZERO(b1,b2,b3,b4) ( IS_SHORT(b1) && IS_LONG(b2) && IS_SHORT(b3) && IS_SHORT(b4) )
|
||||||
|
#define IS_ONE(b1,b2,b3,b4) ( IS_SHORT(b1) && IS_SHORT(b2) && IS_SHORT(b3) && IS_LONG(b4) )
|
||||||
|
|
||||||
|
bool parseArctechSelfLearning(uint8_t* bufStartP, uint8_t* bufEndP) { //start points to a "high" buffer byte, end points to a "low" buffer byte
|
||||||
uint64_t data = 0;
|
uint64_t data = 0;
|
||||||
bool dimValuePresent = false;
|
bool dimValuePresent;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 31; ++i) {
|
uint16_t bitsInBuffer = calculateBufferPointerDistance(bufStartP, bufEndP) / 4; //each bit is representd by 4 high/low
|
||||||
|
if (bitsInBuffer == 32) {
|
||||||
if (calculateBufferPointerDistance(bufStartP, bufEndP) < 4) { //less than 4 more high/low rto read in buffer
|
dimValuePresent = false;
|
||||||
return false;
|
}else if(bitsInBuffer == 36){
|
||||||
}
|
dimValuePresent = true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < bitsInBuffer-1; ++i) {
|
||||||
|
|
||||||
uint8_t b1 = *bufStartP; //no of high
|
uint8_t b1 = *bufStartP; //no of high
|
||||||
stepBufferPointer(&bufStartP);
|
stepBufferPointer(&bufStartP);
|
||||||
|
|
@ -20,18 +75,10 @@ bool parseArctechSelfLearning(uint8_t* bufStartP, uint8_t* bufEndP) { //start
|
||||||
uint8_t b4 = *bufStartP; //no of low
|
uint8_t b4 = *bufStartP; //no of low
|
||||||
stepBufferPointer(&bufStartP);
|
stepBufferPointer(&bufStartP);
|
||||||
|
|
||||||
//TODO: add support for absolute dim values
|
if (IS_ONE(b1,b2,b3,b4)) { //"one" is sent over air
|
||||||
|
|
||||||
if (ARCHTECH_LOW_LOW <= b1 && b1 <= ARCHTECH_LOW_HIGH &&
|
|
||||||
ARCHTECH_LOW_LOW <= b2 && b2 <= ARCHTECH_LOW_HIGH &&
|
|
||||||
ARCHTECH_LOW_LOW <= b3 && b3 <= ARCHTECH_LOW_HIGH &&
|
|
||||||
ARCHTECH_HIGH_LOW <= b4 && b4 <= ARCHTECH_HIGH_HIGH) { //"one" is sent over air
|
|
||||||
data <<= 1; //shift in a zero
|
data <<= 1; //shift in a zero
|
||||||
data |= 0x1; //add one
|
data |= 0x1; //add one
|
||||||
} else if (ARCHTECH_LOW_LOW <= b1 && b1 <= ARCHTECH_LOW_HIGH &&
|
} else if (IS_ZERO(b1,b2,b3,b4)) { //"zero" is sent over air
|
||||||
ARCHTECH_HIGH_LOW <= b2 && b2 <= ARCHTECH_HIGH_HIGH &&
|
|
||||||
ARCHTECH_LOW_LOW <= b3 && b3 <= ARCHTECH_LOW_HIGH &&
|
|
||||||
ARCHTECH_LOW_LOW <= b4 && b4 <= ARCHTECH_LOW_HIGH) { //"zero" is sent over air
|
|
||||||
data <<= 1; //shift in a zero
|
data <<= 1; //shift in a zero
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,6 @@
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
#define ARCHTECH_LOW_LOW 2 //a "low" is defined as at least this many "low" samples in a row
|
|
||||||
#define ARCHTECH_LOW_HIGH 7 //a "low" is defined as at most this many "low" samples in a row
|
|
||||||
#define ARCHTECH_HIGH_LOW 17 //a "high" is defined as at least this many "high" samples in a row
|
|
||||||
#define ARCHTECH_HIGH_HIGH 23 //a "high" is defined as at most this many "high" samples in a row
|
|
||||||
|
|
||||||
bool parseArctechSelfLearning(uint8_t* bufStartP, uint8_t* bufEndP);
|
bool parseArctechSelfLearning(uint8_t* bufStartP, uint8_t* bufEndP);
|
||||||
|
|
||||||
#endif //ARCHTECH_H
|
#endif //ARCHTECH_H
|
||||||
|
|
@ -4,23 +4,3 @@ uint8_t RF_rxBuffer[512]; //must have and even number of elements
|
||||||
uint8_t* RF_rxBufferStartP = &RF_rxBuffer[0];
|
uint8_t* RF_rxBufferStartP = &RF_rxBuffer[0];
|
||||||
uint8_t* RF_rxBufferEndP = &RF_rxBuffer[511];
|
uint8_t* RF_rxBufferEndP = &RF_rxBuffer[511];
|
||||||
volatile uint8_t* bufferWriteP = RF_rxBufferStartP;
|
volatile uint8_t* bufferWriteP = RF_rxBufferStartP;
|
||||||
|
|
||||||
uint16_t calculateBufferPointerDistance(uint8_t* bufStartP, uint8_t* bufEndP) {
|
|
||||||
if (bufStartP <= bufEndP) {
|
|
||||||
return bufEndP - bufStartP + 1;
|
|
||||||
} else {
|
|
||||||
return (RF_rxBufferEndP - bufStartP) + (bufEndP - RF_rxBufferStartP) + 2;
|
|
||||||
}
|
|
||||||
}; //end calculateBufferPointerDistance
|
|
||||||
|
|
||||||
uint8_t* getNextBufferPointer(uint8_t* p) {
|
|
||||||
if ( p + 1 > RF_rxBufferEndP) {
|
|
||||||
return RF_rxBufferStartP;
|
|
||||||
} else {
|
|
||||||
return p + 1;
|
|
||||||
}
|
|
||||||
}; //end getNextBufferPointer
|
|
||||||
|
|
||||||
void stepBufferPointer(uint8_t** p) {
|
|
||||||
*p = getNextBufferPointer(*p);
|
|
||||||
}; //end stepBufferPointer
|
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,29 @@
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
uint16_t calculateBufferPointerDistance(uint8_t* bufStartP, uint8_t* bufEndP);
|
|
||||||
uint8_t* getNextBufferPointer(uint8_t* p);
|
|
||||||
void stepBufferPointer(uint8_t** p);
|
|
||||||
|
|
||||||
extern uint8_t RF_rxBuffer[512]; //must have and even number of elements
|
extern uint8_t RF_rxBuffer[512]; //must have and even number of elements
|
||||||
extern uint8_t* RF_rxBufferStartP;
|
extern uint8_t* RF_rxBufferStartP;
|
||||||
extern uint8_t* RF_rxBufferEndP;
|
extern uint8_t* RF_rxBufferEndP;
|
||||||
extern volatile uint8_t* bufferWriteP;
|
extern volatile uint8_t* bufferWriteP;
|
||||||
|
|
||||||
|
inline uint16_t calculateBufferPointerDistance(uint8_t* bufStartP, uint8_t* bufEndP) {
|
||||||
|
if (bufStartP <= bufEndP) {
|
||||||
|
return bufEndP - bufStartP + 1;
|
||||||
|
} else {
|
||||||
|
return (RF_rxBufferEndP - bufStartP) + (bufEndP - RF_rxBufferStartP) + 2;
|
||||||
|
}
|
||||||
|
}; //end calculateBufferPointerDistance
|
||||||
|
|
||||||
|
inline uint8_t* getNextBufferPointer(uint8_t* p) {
|
||||||
|
if ( p + 1 > RF_rxBufferEndP) {
|
||||||
|
return RF_rxBufferStartP;
|
||||||
|
} else {
|
||||||
|
return p + 1;
|
||||||
|
}
|
||||||
|
}; //end getNextBufferPointer
|
||||||
|
|
||||||
|
inline void stepBufferPointer(uint8_t** p) {
|
||||||
|
*p = getNextBufferPointer(*p);
|
||||||
|
}; //end stepBufferPointer
|
||||||
|
|
||||||
#endif //BUFFER_H
|
#endif //BUFFER_H
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,25 @@
|
||||||
#ifndef CONFIG_H
|
#ifndef CONFIG_H
|
||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
|
|
||||||
#define RX_PIN 7
|
#include "Arduino.h"
|
||||||
#define TX_PIN 8
|
|
||||||
|
/*
|
||||||
|
* RX PIN = 7
|
||||||
|
* TX PIN = 8
|
||||||
|
*/
|
||||||
|
inline void setupPins(){
|
||||||
|
pinMode(7, INPUT);
|
||||||
|
pinMode(8, OUTPUT);
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__)
|
||||||
|
//pin7 = PD7 = port D, bit 8
|
||||||
|
#define RX_PIN_READ() ( PIND & 0b00000001 ) // optimized "digitalRead(7)"
|
||||||
|
//pin8 = PB0 = port B, bit 1
|
||||||
|
#define TX_PIN_LOW() ( PORTB &= 0b01111111 ) // optimized "digitalWrite(8, LOW)"
|
||||||
|
#define TX_PIN_HIGH() ( PORTB |= 0b10000000 ) // optimized "digitalWrite(8, HIGH)"
|
||||||
|
#else
|
||||||
|
#unsupported architecture
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif //CONFIG_H
|
#endif //CONFIG_H
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
SIGNAL
|
|
||||||
signal i s two times in a row with a "low" pause of 8192us between them
|
|
||||||
|
|
||||||
The message buffer is 9 bytes long
|
|
||||||
|
|
||||||
Each signal starts with a preampble, the data and a postamble
|
|
||||||
|
|
||||||
PREAMBLE
|
|
||||||
consists of two "one"-bytes
|
|
||||||
|
|
||||||
DATA
|
|
||||||
9 bytes
|
|
||||||
|
|
||||||
POSTAMBLE
|
|
||||||
consists of one "zero"-byte
|
|
||||||
|
|
||||||
A "one" bit is sent over the air as:
|
|
||||||
high for 512us
|
|
||||||
low for 1024us
|
|
||||||
high for 512us
|
|
||||||
|
|
||||||
A "zero" bit is sent over the air as:
|
|
||||||
low for 512us
|
|
||||||
high for 1024us
|
|
||||||
low for 512us
|
|
||||||
|
|
||||||
1 byte = 8*(512+512+1024)us = 16384us
|
|
||||||
one signal = 2+9+1 bytes = 12 bytes = 196608us
|
|
||||||
signal + 8192 + signal = 401408us = 401.408ms
|
|
||||||
210
arduino/ArduinoTellstickDuo/oregonV2.1.cpp
Normal file
210
arduino/ArduinoTellstickDuo/oregonV2.1.cpp
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
#include "oregonV2.1.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
--OREGON v2.1 PROTOCOL SPECIFICATION--
|
||||||
|
|
||||||
|
----SIGNAL----
|
||||||
|
A signal consists of a PREAMBLE, DATA and an POSTAMBLE.
|
||||||
|
Each signal is sent 2 times in a row to increase the delivery success rate.
|
||||||
|
Between the two times there is a "low" pause of 8192us.
|
||||||
|
|
||||||
|
----PREAMBLE----
|
||||||
|
send 16 "1"(ones) over the air
|
||||||
|
|
||||||
|
----DATA----
|
||||||
|
16 bits of sensor type
|
||||||
|
XX bits of data (where XX <= 64)
|
||||||
|
|
||||||
|
The length XX depends on the sensor type. I.e. 0x1A2D => XX=56
|
||||||
|
|
||||||
|
Over air a "1"(one) is sent as:
|
||||||
|
send high for 512 microseconds
|
||||||
|
send low for 1024 microseconds
|
||||||
|
send high for 512 microseconds
|
||||||
|
|
||||||
|
Over air a "0"(zero) is sent as:
|
||||||
|
send low for 512 microseconds
|
||||||
|
send high for 1024 microseconds
|
||||||
|
send low for 512 microseconds
|
||||||
|
|
||||||
|
----POSTAMBLE----
|
||||||
|
send 8 "0"(zeros) over the air
|
||||||
|
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#define SMALL_PULSE(x) ( 4<=x && x<=13 )
|
||||||
|
#define BIG_PULSE(x) ( 12<=x && x<=22 )
|
||||||
|
#define MORE_DATA_NEEDED -1
|
||||||
|
#define INVALID_DATA -2
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PARSE_PREAMP = 0,
|
||||||
|
PARSE_ID,
|
||||||
|
PARSE_DATA
|
||||||
|
} static state = PARSE_PREAMP;
|
||||||
|
|
||||||
|
static uint8_t byteCnt = 0;
|
||||||
|
static uint8_t bitCnt = 0;
|
||||||
|
static uint8_t totByteCnt = 0;
|
||||||
|
int8_t byteLength = -1;
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
byteCnt = 0;
|
||||||
|
bitCnt = 0;
|
||||||
|
totByteCnt = 0;
|
||||||
|
state = PARSE_PREAMP;
|
||||||
|
byteLength = -1;
|
||||||
|
}; //end reset
|
||||||
|
|
||||||
|
void parseOregonStream(bool level, uint8_t count) {
|
||||||
|
static uint8_t cnt = 0; //used for counting stuff independent in every state
|
||||||
|
static uint16_t sensorType = 0;
|
||||||
|
static int8_t byte;
|
||||||
|
static uint8_t bytesToParse = 0; //the number of bytes left in the data part to parse
|
||||||
|
static uint8_t buffer[8];
|
||||||
|
|
||||||
|
if (level) {
|
||||||
|
count+=3;
|
||||||
|
} else {
|
||||||
|
count-=3;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(state) {
|
||||||
|
case PARSE_PREAMP: //look for 25 big pulses followed by one short in a row
|
||||||
|
if (BIG_PULSE(count)) {
|
||||||
|
++cnt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (SMALL_PULSE(count)) {
|
||||||
|
if (cnt > 25) {
|
||||||
|
state=PARSE_ID;
|
||||||
|
sensorType = 0;
|
||||||
|
}
|
||||||
|
cnt = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARSE_ID: //get the two first Bytes
|
||||||
|
byte = getByte(level, count);
|
||||||
|
if (byte == INVALID_DATA) {
|
||||||
|
reset();
|
||||||
|
cnt = 0;
|
||||||
|
break;
|
||||||
|
} else if (byte == MORE_DATA_NEEDED) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (sensorType == 0) {
|
||||||
|
sensorType = byte << 8;
|
||||||
|
} else {
|
||||||
|
sensorType |= byte;
|
||||||
|
switch (sensorType) {
|
||||||
|
case 0xEA4C:
|
||||||
|
bytesToParse = 5;
|
||||||
|
byteLength = 63;
|
||||||
|
break;
|
||||||
|
case 0x0A4D:
|
||||||
|
case 0x1A2D: //sensor THGR2228N (channel + sensor_id + battery_level + temp + humidity + checksum)
|
||||||
|
bytesToParse = 7;
|
||||||
|
byteLength = 79;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
reset();
|
||||||
|
cnt = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state = PARSE_DATA;
|
||||||
|
cnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PARSE_DATA: //get the remaining data
|
||||||
|
byte = getByte(level, count);
|
||||||
|
if (byte == INVALID_DATA) {
|
||||||
|
reset();
|
||||||
|
cnt = 0;
|
||||||
|
break;
|
||||||
|
} else if (byte == MORE_DATA_NEEDED) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer[cnt] = byte;
|
||||||
|
++cnt;
|
||||||
|
if (bytesToParse == 0) {
|
||||||
|
Serial.print(F("+Wclass:sensor;protocol:oregon;model:0x"));
|
||||||
|
Serial.print(sensorType, HEX);
|
||||||
|
Serial.print(F(";data:0x"));
|
||||||
|
for (int8_t i = 0; i < cnt; ++i) {
|
||||||
|
Serial.print(buffer[i], HEX);
|
||||||
|
}
|
||||||
|
Serial.println(F(";"));
|
||||||
|
reset();
|
||||||
|
cnt = 0;
|
||||||
|
}
|
||||||
|
--bytesToParse;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; //end parseOregonStream
|
||||||
|
|
||||||
|
int8_t getByte(bool level, uint8_t count) {
|
||||||
|
int8_t bit = getBit(level, count);
|
||||||
|
static uint8_t byte = 0;
|
||||||
|
|
||||||
|
if (bit == INVALID_DATA) {
|
||||||
|
return INVALID_DATA;
|
||||||
|
} else if (bit == MORE_DATA_NEEDED) {
|
||||||
|
return MORE_DATA_NEEDED;
|
||||||
|
}
|
||||||
|
byte >>= 1;
|
||||||
|
if (bit) {
|
||||||
|
byte |= (1<<7);
|
||||||
|
}
|
||||||
|
++totByteCnt;
|
||||||
|
++byteCnt;
|
||||||
|
if (byteCnt < 8) {
|
||||||
|
return MORE_DATA_NEEDED;
|
||||||
|
}
|
||||||
|
byteCnt=0;
|
||||||
|
return byte;
|
||||||
|
}; //end getByte
|
||||||
|
|
||||||
|
int8_t getBit(bool level, uint8_t count) {
|
||||||
|
static bool bit = 0;
|
||||||
|
|
||||||
|
if (bitCnt == 0) {
|
||||||
|
//First pulse must be small
|
||||||
|
if (!SMALL_PULSE(count)) {
|
||||||
|
return INVALID_DATA;
|
||||||
|
}
|
||||||
|
bitCnt = 1;
|
||||||
|
|
||||||
|
} else if (bitCnt == 1) {
|
||||||
|
//Second pulse must be long
|
||||||
|
if (!BIG_PULSE(count) && totByteCnt!=byteLength){ //special check - last byte might have strange values
|
||||||
|
bitCnt = 0;
|
||||||
|
return INVALID_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
bit = level;
|
||||||
|
bitCnt = 2;
|
||||||
|
return bit;
|
||||||
|
|
||||||
|
} else if (bitCnt == 2) {
|
||||||
|
//Prepare for next bit
|
||||||
|
if (level && SMALL_PULSE(count)) {
|
||||||
|
//Clean start
|
||||||
|
bitCnt = 0;
|
||||||
|
} else if (BIG_PULSE(count)) {
|
||||||
|
//Combined bit
|
||||||
|
bitCnt = 1;
|
||||||
|
} else if (SMALL_PULSE(count)) {
|
||||||
|
//Clean start
|
||||||
|
bitCnt = 0;
|
||||||
|
}
|
||||||
|
return MORE_DATA_NEEDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MORE_DATA_NEEDED;
|
||||||
|
}; //end getBit
|
||||||
11
arduino/ArduinoTellstickDuo/oregonV2.1.h
Normal file
11
arduino/ArduinoTellstickDuo/oregonV2.1.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef OREGONV21_H
|
||||||
|
#define OREGONV21_H
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void parseOregonStream(bool level, uint8_t sampleCount);
|
||||||
|
int8_t getByte(bool level, uint8_t count);
|
||||||
|
int8_t getBit(bool level, uint8_t count);
|
||||||
|
|
||||||
|
#endif //OREGONV21_H
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
#include "archtech.h"
|
#include "archtech.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "oregonV2.1.h"
|
||||||
|
|
||||||
|
#define SILENCE_LENGTH 100 //the number of samples with "low" that represents a silent period between two signals
|
||||||
|
|
||||||
volatile bool RFRX = false;
|
volatile bool RFRX = false;
|
||||||
|
|
||||||
|
|
@ -13,19 +16,29 @@ void parseRadioRXBuffer() {
|
||||||
|
|
||||||
bool parse = false;
|
bool parse = false;
|
||||||
while (bufferReadP != bufferWriteP) { //stop if the read pointer is pointing to where the writing is currently performed
|
while (bufferReadP != bufferWriteP) { //stop if the read pointer is pointing to where the writing is currently performed
|
||||||
|
uint8_t sampleCount = *bufferReadP;
|
||||||
if ( (((int)bufferReadP) & 0x1) == 1 ) { //buffer pointer is odd (stores highs)
|
|
||||||
|
if ( (((uintptr_t)bufferReadP) & 0x1) == 1 ) { //buffer pointer is odd (stores highs)
|
||||||
if (prevValue >= SILENCE_LENGTH) {
|
if (prevValue >= SILENCE_LENGTH) {
|
||||||
startDataP = bufferReadP; //some new data must starrt here since this is the first "high" after a silent period
|
startDataP = bufferReadP; //some new data must start here since this is the first "high" after a silent period
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//stream data to stream parsers
|
||||||
|
parseOregonStream(HIGH, sampleCount);
|
||||||
|
|
||||||
} else { //buffer pointer is even (stores lows)
|
} else { //buffer pointer is even (stores lows)
|
||||||
if (*bufferReadP >= SILENCE_LENGTH) { //evaluate if it is time to parse the curernt data
|
if (sampleCount >= SILENCE_LENGTH) { //evaluate if it is time to parse the curernt data
|
||||||
endDataP = bufferReadP; //this is a silient period and must be the end of a data
|
endDataP = bufferReadP; //this is a silient period and must be the end of a data
|
||||||
parse = true;
|
parse = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//stream data to stream parsers
|
||||||
|
parseOregonStream(LOW, sampleCount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//step the read pointer one step
|
||||||
uint8_t* nextBufferReadP = getNextBufferPointer(bufferReadP);
|
uint8_t* nextBufferReadP = getNextBufferPointer(bufferReadP);
|
||||||
if (nextBufferReadP == startDataP) { //next pointer will point to startDataP. Data will overflow. Reset the data pointers.
|
if (nextBufferReadP == startDataP) { //next pointer will point to startDataP. Data will overflow. Reset the data pointers.
|
||||||
startDataP = 0;
|
startDataP = 0;
|
||||||
|
|
@ -35,7 +48,7 @@ void parseRadioRXBuffer() {
|
||||||
//advance buffer pointer one step
|
//advance buffer pointer one step
|
||||||
bufferReadP = nextBufferReadP;
|
bufferReadP = nextBufferReadP;
|
||||||
|
|
||||||
prevValue = *bufferReadP; //update previous value
|
prevValue = sampleCount; //update previous value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parse) {
|
if (!parse) {
|
||||||
|
|
@ -51,50 +64,57 @@ void parseRadioRXBuffer() {
|
||||||
* and the endDataP will point at the first (low) silent period after the data data start.
|
* and the endDataP will point at the first (low) silent period after the data data start.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//make sure that the data set size is big enought to parse.
|
|
||||||
uint16_t dataSetSize = calculateBufferPointerDistance(startDataP, endDataP);
|
|
||||||
if (dataSetSize < 32) { //at least 32 low/high
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Let all available parsers parse the data set now.
|
//Let all available parsers parse the data set now.
|
||||||
parseArctechSelfLearning(startDataP, endDataP);
|
parseArctechSelfLearning(startDataP, endDataP);
|
||||||
//TODO: add more parsers here
|
//TODO: add more parsers here
|
||||||
|
|
||||||
|
//reset the data pointers since the data have been parsed at this point
|
||||||
|
startDataP = 0;
|
||||||
|
endDataP = 0;
|
||||||
|
|
||||||
}; //end radioTask
|
}; //end radioTask
|
||||||
|
|
||||||
void sendTCodedData(uint8_t* data, uint8_t T_long, uint8_t* timings, uint8_t repeat, uint8_t pause) {
|
void sendTCodedData(uint8_t* data, uint8_t T_long, uint8_t* timings, uint8_t repeat, uint8_t pause) {
|
||||||
RFRX = false; //turn off the RF reciever
|
ACTIVATE_RADIO_TRANSMITTER();
|
||||||
for (uint8_t rep = 0; rep < repeat; ++rep) {
|
for (uint8_t rep = 0; rep < repeat; ++rep) {
|
||||||
bool nextPinState = HIGH;
|
bool nextPinState = HIGH;
|
||||||
for (int i = 0; i < T_long; ++i) {
|
for (int i = 0; i < T_long; ++i) {
|
||||||
uint8_t timeIndex = (data[i / 4] >> (6 - (2 * (i % 4)))) & 0x03;
|
uint8_t timeIndex = (data[i / 4] >> (6 - (2 * (i % 4)))) & 0x03;
|
||||||
if (timings[timeIndex] > 0 || i == T_long - 1) {
|
if (timings[timeIndex] > 0 || i == T_long - 1) {
|
||||||
digitalWrite(TX_PIN, nextPinState);
|
if(nextPinState){
|
||||||
|
TX_PIN_HIGH();
|
||||||
|
}else{
|
||||||
|
TX_PIN_LOW();
|
||||||
|
}
|
||||||
delayMicroseconds(10 * timings[timeIndex]);
|
delayMicroseconds(10 * timings[timeIndex]);
|
||||||
}
|
}
|
||||||
nextPinState = !nextPinState;
|
nextPinState = !nextPinState;
|
||||||
}
|
}
|
||||||
digitalWrite(TX_PIN, LOW);
|
TX_PIN_LOW();
|
||||||
if (rep < repeat - 1) {
|
if (rep < repeat - 1) {
|
||||||
delay(pause);
|
delay(pause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RFRX = true; //turn on the RF reciever
|
ACTIVATE_RADIO_RECEIVER();
|
||||||
};
|
};
|
||||||
|
|
||||||
void sendSCodedData(uint8_t* data, uint8_t pulseCount, uint8_t repeat, uint8_t pause) {
|
void sendSCodedData(uint8_t* data, uint8_t pulseCount, uint8_t repeat, uint8_t pause) {
|
||||||
RFRX = false; //turn off the RF reciever
|
ACTIVATE_RADIO_TRANSMITTER();
|
||||||
for (uint8_t rep = 0; rep < repeat; ++rep) {
|
for (uint8_t rep = 0; rep < repeat; ++rep) {
|
||||||
bool nextPinState = HIGH;
|
bool nextPinState = HIGH;
|
||||||
for (int i = 0; i < pulseCount; ++i) {
|
for (int i = 0; i < pulseCount; ++i) {
|
||||||
if (data[i] > 0 || i == pulseCount - 1) {
|
if (data[i] > 0 || i == pulseCount - 1) {
|
||||||
digitalWrite(TX_PIN, nextPinState);
|
if(nextPinState){
|
||||||
|
TX_PIN_HIGH();
|
||||||
|
}else{
|
||||||
|
TX_PIN_LOW();
|
||||||
|
}
|
||||||
delayMicroseconds(data[i] * 10);
|
delayMicroseconds(data[i] * 10);
|
||||||
}
|
}
|
||||||
nextPinState = !nextPinState;
|
nextPinState = !nextPinState;
|
||||||
}
|
}
|
||||||
delay(pause);
|
delay(pause);
|
||||||
}
|
}
|
||||||
RFRX = false; //turn on the RF reciever
|
TX_PIN_LOW();
|
||||||
|
ACTIVATE_RADIO_RECEIVER();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,15 @@
|
||||||
|
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
|
|
||||||
#define SILENCE_LENGTH 100 //the number of samples with "low" that represents a silent period between two signals
|
#define ACTIVATE_RADIO_RECEIVER() (RFRX = true)
|
||||||
|
#define ACTIVATE_RADIO_TRANSMITTER() (RFRX = false)
|
||||||
|
#define IS_RADIO_RECIEVER_ON() (RFRX)
|
||||||
|
#define IS_RADIO_TRANSMITTER_ON() (!RFRX)
|
||||||
|
|
||||||
|
extern volatile bool RFRX;
|
||||||
|
|
||||||
void parseRadioRXBuffer();
|
void parseRadioRXBuffer();
|
||||||
void sendTCodedData(uint8_t* data, uint8_t T_long, uint8_t* timings, uint8_t repeat, uint8_t pause);
|
void sendTCodedData(uint8_t* data, uint8_t T_long, uint8_t* timings, uint8_t repeat, uint8_t pause);
|
||||||
void sendSCodedData(uint8_t* data, uint8_t pulseCount, uint8_t repeat, uint8_t pause);
|
void sendSCodedData(uint8_t* data, uint8_t pulseCount, uint8_t repeat, uint8_t pause);
|
||||||
|
|
||||||
extern volatile bool RFRX;
|
|
||||||
|
|
||||||
#endif //RF_H
|
#endif //RF_H
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue