Merge pull request #333 from ygator/master

Oregon Scientific V1 Decoding
This commit is contained in:
Benjamin Larsson
2016-03-20 12:06:01 +01:00
9 changed files with 183 additions and 4 deletions

View File

@@ -115,6 +115,10 @@ Supported devices:
[43] CurrentCost Current Sensor
[44] OpenEnergyMonitor emonTx v3
[45] HT680 Remote control
[46] S3318P Temperature & Humidity Sensor
[47] Akhan 100F14 remote keyless entry
[48] Quhwa
[49] Oregon Scientific v1 Temperature Sensor
```

3
include/pulse_demod.h Normal file → Executable file
View File

@@ -135,4 +135,7 @@ int pulse_demod_manchester_zerobit(const pulse_data_t *pulses, struct protocol_s
/// @return number of events processed
int pulse_demod_clock_bits(const pulse_data_t *pulses, struct protocol_state *device);
int pulse_demod_osv1(const pulse_data_t *pulses, struct protocol_state *device);
#endif /* INCLUDE_PULSE_DEMOD_H_ */

View File

@@ -35,7 +35,7 @@
#define DEFAULT_LEVEL_LIMIT 8000 // Theoretical high level at I/Q saturation is 128x128 = 16384 (above is ripple)
#define MINIMAL_BUF_LENGTH 512
#define MAXIMAL_BUF_LENGTH (256 * 16384)
#define MAX_PROTOCOLS 48
#define MAX_PROTOCOLS 49
#define SIGNAL_GRABBER_BUFFER (12 * DEFAULT_BUF_LENGTH)
/* Supported modulation types */
@@ -45,7 +45,8 @@
#define OOK_PULSE_PWM_PRECISE 6 // Pulse Width Modulation with precise timing parameters
#define OOK_PULSE_PWM_RAW 7 // Pulse Width Modulation. Short pulses = 1, Long = 0
#define OOK_PULSE_PWM_TERNARY 8 // Pulse Width Modulation with three widths: Sync, 0, 1. Sync determined by argument
#define OOK_PULSE_CLOCK_BITS 9 // Level shift within the clock cycle.
#define OOK_PULSE_CLOCK_BITS 9 // Level shift within the clock cycle.
#define OOK_PULSE_PWM_OSV1 10 // Pulse Width Modulation. Oregon Scientific v1
#define FSK_DEMOD_MIN_VAL 16 // Dummy. FSK demodulation must start at this value
#define FSK_PULSE_PCM 16 // FSK, Pulse Code Modulation

View File

@@ -49,9 +49,10 @@
DECL(current_cost) \
DECL(emontx) \
DECL(ht680) \
DECL(s3318p) \
DECL(s3318p) \
DECL(akhan_100F14) \
DECL(quhwa)
DECL(quhwa) \
DECL(oregon_scientific_v1)
typedef struct {
char name[256];

View File

@@ -55,6 +55,7 @@ add_executable(rtl_433
devices/nexus.c
devices/oil_watchman.c
devices/oregon_scientific.c
devices/oregon_scientific_v1.c
devices/prologue.c
devices/rubicson.c
devices/silvercrest.c

View File

@@ -41,6 +41,7 @@ rtl_433_SOURCES = baseband.c \
devices/nexus.c \
devices/oil_watchman.c \
devices/oregon_scientific.c \
devices/oregon_scientific_v1.c \
devices/prologue.c \
devices/quhwa.c \
devices/rubicson.c \

View File

@@ -0,0 +1,92 @@
#include "rtl_433.h"
#include "data.h"
#include "util.h"
#define OSV1_BITS 32
static int rev_nibble(int nib)
{
int revnib = 0;
revnib += (nib >> 3) & 0x1;
revnib += (nib >> 1) & 0x2;
revnib += (nib << 1) & 0x4;
revnib += (nib << 3) & 0x8;
return(revnib);
}
static int oregon_scientific_callback_v1(bitbuffer_t *bitbuffer) {
int ret = 0;
char time_str[LOCAL_TIME_BUFLEN];
int row;
int cs;
int i;
int nibble[OSV1_BITS/4];
int sid, channel, uk1;
float tempC;
int battery, uk2, sign, uk3, checksum;
data_t *data;
local_time_str(0, time_str);
for(row = 0; row < bitbuffer->num_rows; row++) {
if(bitbuffer->bits_per_row[row] == OSV1_BITS) {
cs = 0;
for(i = 0; i < OSV1_BITS / 8; i++) {
nibble[i * 2 ] = rev_nibble((bitbuffer->bb[row][i] >> 4));
nibble[i * 2 + 1] = rev_nibble((bitbuffer->bb[row][i] & 0x0f));
if(i < ((OSV1_BITS / 8) - 1))
cs += nibble[i * 2] + 16 * nibble[i * 2 + 1];
}
cs = (cs & 0xFF) + (cs >> 8);
checksum = nibble[6] + (nibble[7] << 4);
if(checksum == cs) {
sid = nibble[0];
channel = ((nibble[1] >> 2) & 0x03) + 1;
uk1 = (nibble[1] >> 0) & 0x03; /* unknown. Seen change every 60 minutes */
tempC = nibble[2] / 10. + nibble[3] + nibble[4] * 10.;
battery = (nibble[5] >> 3) & 0x01;
uk2 = (nibble[5] >> 2) & 0x01; /* unknown. Always zero? */
sign = (nibble[5] >> 1) & 0x01;
uk3 = (nibble[5] >> 0) & 0x01; /* unknown. Always zero? */
if(sign) tempC = -tempC;
data = data_make(
"time", "", DATA_STRING, time_str,
"model", "", DATA_STRING, "OSv1 Temperature Sensor",
"sid", "SID", DATA_INT, sid,
"channel", "Channel", DATA_INT, channel,
"battery", "Battery", DATA_STRING, battery ? "LOW" : "OK",
"temperature_C","Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, tempC,
NULL);
data_acquired_handler(data);
ret++;
}
}
}
return ret;
}
static char *output_fields[] = {
"time",
"model",
"id",
"channel",
"battery",
"temperature_C",
NULL
};
r_device oregon_scientific_v1 = {
.name = "OSv1 Temperature Sensor",
.modulation = OOK_PULSE_PWM_OSV1,
.short_limit = 300,
.long_limit = 430,
.reset_limit = 14000,
.json_callback = &oregon_scientific_callback_v1,
.disabled = 0,
.demod_arg = 0,
.fields = output_fields
};

72
src/pulse_demod.c Normal file → Executable file
View File

@@ -319,3 +319,75 @@ int pulse_demod_clock_bits(const pulse_data_t *pulses, struct protocol_state *de
return events;
}
/*
* Oregon Scientific V1 Protocol
* Starts with a clean preamble of 12 pulses with
* consistent timing followed by an out of time Sync pulse.
* Data then follows with manchester encoding, but
* care must be taken with the gap after the sync pulse since it
* is outside of the normal clocking. Because of this a data stream
* beginning with a 0 will have data in this gap.
* This code looks at pulse and gap width and clocks bits
* in from this. Since this is manchester encoded every other
* bit is discarded.
*/
int pulse_demod_osv1(const pulse_data_t *pulses, struct protocol_state *device) {
unsigned int n;
int preamble = 0;
int events = 0;
int manbit = 0;
bitbuffer_t bits = {0};
/* preamble */
for(n = 0; n < pulses->num_pulses; ++n) {
if(pulses->pulse[n] >= 350 && pulses->gap[n] >= 200) {
preamble++;
if(pulses->gap[n] >= 400)
break;
} else
return(events);
}
if(preamble != 12) {
printf("preamble %d %d %d\n", preamble, pulses->pulse[0], pulses->gap[0]);
return(events);
}
/* sync */
++n;
if(pulses->pulse[n] < 1000 || pulses->gap[n] < 1000) {
return(events);
}
/* data bits - manchester encoding */
/* sync gap could be part of data when the first bit is 0 */
if(pulses->gap[n] > pulses->pulse[n]) {
manbit ^= 1;
if(manbit) bitbuffer_add_bit(&bits, 0);
}
/* remaining data bits */
for(n++; n < pulses->num_pulses; ++n) {
manbit ^= 1;
if(manbit) bitbuffer_add_bit(&bits, 1);
if(pulses->pulse[n] > 615) {
manbit ^= 1;
if(manbit) bitbuffer_add_bit(&bits, 1);
}
if (n == pulses->num_pulses - 1 || pulses->gap[n] > device->reset_limit) {
if((bits.bits_per_row[bits.num_rows-1] == 32) && device->callback) {
events += device->callback(&bits);
}
return(events);
}
manbit ^= 1;
if(manbit) bitbuffer_add_bit(&bits, 0);
if(pulses->gap[n] > 450) {
manbit ^= 1;
if(manbit) bitbuffer_add_bit(&bits, 0);
}
}
return events;
}

View File

@@ -647,6 +647,9 @@ static void rtlsdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) {
case OOK_PULSE_CLOCK_BITS:
pulse_demod_clock_bits(&demod->pulse_data, demod->r_devs[i]);
break;
case OOK_PULSE_PWM_OSV1:
pulse_demod_osv1(&demod->pulse_data, demod->r_devs[i]);
break;
// FSK decoders
case FSK_PULSE_PCM:
case FSK_PULSE_PWM_RAW:
@@ -669,6 +672,7 @@ static void rtlsdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) {
case OOK_PULSE_PWM_TERNARY:
case OOK_PULSE_MANCHESTER_ZEROBIT:
case OOK_PULSE_CLOCK_BITS:
case OOK_PULSE_PWM_OSV1:
break;
case FSK_PULSE_PCM:
pulse_demod_pcm(&demod->fsk_pulse_data, demod->r_devs[i]);