From aca1569a65acfa2b5f0a44a06a69415fa4339f80 Mon Sep 17 00:00:00 2001 From: YGator Date: Thu, 17 Mar 2016 14:24:01 -0400 Subject: [PATCH] Oregon Scientific V1 Decoding Oregon Scientific V1 Decoding Oregon Scientific V1 Decoding --- README.md | 4 ++ include/pulse_demod.h | 3 + include/rtl_433.h | 5 +- include/rtl_433_devices.h | 5 +- src/CMakeLists.txt | 1 + src/Makefile.am | 1 + src/devices/oregon_scientific_v1.c | 92 ++++++++++++++++++++++++++++++ src/pulse_demod.c | 72 +++++++++++++++++++++++ src/rtl_433.c | 4 ++ 9 files changed, 183 insertions(+), 4 deletions(-) mode change 100644 => 100755 include/pulse_demod.h create mode 100755 src/devices/oregon_scientific_v1.c mode change 100644 => 100755 src/pulse_demod.c diff --git a/README.md b/README.md index 5806f96d..e2c82c79 100755 --- a/README.md +++ b/README.md @@ -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 ``` diff --git a/include/pulse_demod.h b/include/pulse_demod.h old mode 100644 new mode 100755 index a68271cb..15e489ae --- a/include/pulse_demod.h +++ b/include/pulse_demod.h @@ -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_ */ diff --git a/include/rtl_433.h b/include/rtl_433.h index 42666fb4..1aa552ca 100755 --- a/include/rtl_433.h +++ b/include/rtl_433.h @@ -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 diff --git a/include/rtl_433_devices.h b/include/rtl_433_devices.h index 1e6d22e5..7cd9e35c 100755 --- a/include/rtl_433_devices.h +++ b/include/rtl_433_devices.h @@ -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]; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 630c750b..0ab08a72 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index 9e758c6a..140c8beb 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/devices/oregon_scientific_v1.c b/src/devices/oregon_scientific_v1.c new file mode 100755 index 00000000..0b9e8e55 --- /dev/null +++ b/src/devices/oregon_scientific_v1.c @@ -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 +}; diff --git a/src/pulse_demod.c b/src/pulse_demod.c old mode 100644 new mode 100755 index 309e540a..2fd8d67e --- a/src/pulse_demod.c +++ b/src/pulse_demod.c @@ -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; +} diff --git a/src/rtl_433.c b/src/rtl_433.c index 3ec2f1ab..4a4d31c3 100755 --- a/src/rtl_433.c +++ b/src/rtl_433.c @@ -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]);