diff --git a/.gitignore b/.gitignore index 5ef05322..55821f1f 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ install-sh stamp-h1 libtool Doxyfile +build .tarball-version .version @@ -39,3 +40,10 @@ CMakeCache.txt */CMakeFiles CMakeFiles *.cmake + +build/ +.cproject +.settings +.project + +*.orig diff --git a/README b/README index acc298bc..4f3eb5b3 100644 --- a/README +++ b/README @@ -29,3 +29,20 @@ Usage: [-d device_index (default: 0)] ./rtl_433 will run the software in receive mode. Some sensor data can be receviced. This software is mostly useable for developers right now. + +## Supported Devices +Rubicson Temperature Sensor +Silvercrest Remote Control +ELV EM 1000 +ELV WS 2000 +Waveman Switch Transmitter +Steffen Switch Transmitter +Acurite 5n1 Weather Station +Acurite Temperature and Humidity Sensor +Acurite 896 Rain Gauge +LaCrosse TX Temperature / Humidity Sensor +Oregon Scientific Weather Sensor +KlikAanKlikUit Wireless Switch +AlectoV1 Weather Sensor +Intertechno 433 +Mebus 433 diff --git a/include/rtl_433.h b/include/rtl_433.h new file mode 100644 index 00000000..49f9159d --- /dev/null +++ b/include/rtl_433.h @@ -0,0 +1,54 @@ +#ifndef INCLUDE_RTL_433_H_ +#define INCLUDE_RTL_433_H_ + +#include +#include +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#else +#include +#include +#include +#include "getopt/getopt.h" +#endif + +#define DEFAULT_SAMPLE_RATE 250000 +#define DEFAULT_FREQUENCY 433920000 +#define DEFAULT_HOP_TIME (60*10) +#define DEFAULT_HOP_EVENTS 2 +#define DEFAULT_ASYNC_BUF_NUMBER 32 +#define DEFAULT_BUF_LENGTH (16 * 16384) +#define DEFAULT_LEVEL_LIMIT 10000 +#define DEFAULT_DECIMATION_LEVEL 0 +#define MINIMAL_BUF_LENGTH 512 +#define MAXIMAL_BUF_LENGTH (256 * 16384) +#define FILTER_ORDER 1 +#define MAX_PROTOCOLS 15 +#define SIGNAL_GRABBER_BUFFER (12 * DEFAULT_BUF_LENGTH) +#define BITBUF_COLS 34 +#define BITBUF_ROWS 50 + +/* Supported modulation types */ +#define OOK_PWM_D 1 /* Pulses are of the same length, the distance varies */ +#define OOK_PWM_P 2 /* The length of the pulses varies */ +#define OOK_MANCHESTER 3 /* Manchester code */ + +typedef struct { + unsigned int id; + char name[256]; + unsigned int modulation; + unsigned int short_limit; + unsigned int long_limit; + unsigned int reset_limit; + int (*json_callback)(uint8_t bits_buffer[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) ; +} r_device; + +extern int debug_output; +int debug_callback(uint8_t buffer[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]); + +#endif /* INCLUDE_RTL_433_H_ */ diff --git a/include/rtl_433_devices.h b/include/rtl_433_devices.h new file mode 100644 index 00000000..53cf9170 --- /dev/null +++ b/include/rtl_433_devices.h @@ -0,0 +1,21 @@ +#ifndef INCLUDE_RTL_433_DEVICES_H_ +#define INCLUDE_RTL_433_DEVICES_H_ + +extern r_device silvercrest; +extern r_device rubicson; +extern r_device prologue; +extern r_device waveman; +extern r_device steffen; +extern r_device elv_em1000; +extern r_device elv_ws2000; +extern r_device lacrossetx; +extern r_device acurite5n1; +extern r_device acurite_rain_gauge; +extern r_device acurite_th; +extern r_device oregon_scientific; +extern r_device mebus433; +extern r_device intertechno; +extern r_device newkaku; +extern r_device alectov1; + +#endif /* INCLUDE_RTL_433_DEVICES_H_ */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 66fbda81..db9f3080 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -72,7 +72,22 @@ add_executable(rtl_test rtl_test.c) add_executable(rtl_fm rtl_fm.c) add_executable(rtl_eeprom rtl_eeprom.c) add_executable(rtl_adsb rtl_adsb.c) -add_executable(rtl_433 rtl_433.c) +add_executable(rtl_433 + rtl_433.c + devices/silvercrest.c + devices/rubicson.c + devices/prologue.c + devices/waveman.c + devices/steffen.c + devices/elv.c + devices/lacrosse.c + devices/acurite.c + devices/oregon_scientific.c + devices/mebus.c + devices/intertechno.c + devices/alecto.c + devices/newkaku.c) + set(INSTALL_TARGETS rtlsdr_shared rtlsdr_static rtl_sdr rtl_tcp rtl_test rtl_fm rtl_eeprom rtl_adsb rtl_433) target_link_libraries(rtl_sdr rtlsdr_shared diff --git a/src/devices/acurite.c b/src/devices/acurite.c new file mode 100644 index 00000000..f412305c --- /dev/null +++ b/src/devices/acurite.c @@ -0,0 +1,205 @@ +#include "rtl_433.h" + +// ** Acurite 5n1 functions ** + +const float acurite_winddirections[] = + { 337.5, 315.0, 292.5, 270.0, 247.5, 225.0, 202.5, 180, + 157.5, 135.0, 112.5, 90.0, 67.5, 45.0, 22.5, 0.0 }; + +static int acurite_raincounter = 0; + +static int acurite_crc(uint8_t row[BITBUF_COLS], int cols) { + // sum of first n-1 bytes modulo 256 should equal nth byte + int i; + int sum = 0; + for ( i=0; i < cols; i++) + sum += row[i]; + if ( sum % 256 == row[cols] ) + return 1; + else + return 0; +} + +static int acurite_detect(uint8_t *pRow) { + int i; + if ( pRow[0] != 0x00 ) { + // invert bits due to wierd issue + for (i = 0; i < 8; i++) + pRow[i] = ~pRow[i] & 0xFF; + pRow[0] |= pRow[8]; // fix first byte that has mashed leading bit + + if (acurite_crc(pRow, 7)) + return 1; // passes crc check + } + return 0; +} + +static float acurite_getTemp (uint8_t highbyte, uint8_t lowbyte) { + // range -40 to 158 F + int highbits = (highbyte & 0x0F) << 7 ; + int lowbits = lowbyte & 0x7F; + int rawtemp = highbits | lowbits; + float temp = (rawtemp - 400) / 10.0; + return temp; +} + +static int acurite_getWindSpeed (uint8_t highbyte, uint8_t lowbyte) { + // range: 0 to 159 kph + // TODO: sensor does not seem to be in kph, e.g., + // a value of 49 here was registered as 41 kph on base unit + // value could be rpm, etc which may need (polynomial) scaling factor?? + int highbits = ( highbyte & 0x1F) << 3; + int lowbits = ( lowbyte & 0x70 ) >> 4; + int speed = highbits | lowbits; + return speed; +} + +static float acurite_getWindDirection (uint8_t byte) { + // 16 compass points, ccw from (NNW) to 15 (N) + int direction = byte & 0x0F; + return acurite_winddirections[direction]; +} + +static int acurite_getHumidity (uint8_t byte) { + // range: 1 to 99 %RH + int humidity = byte & 0x7F; + return humidity; +} + +static int acurite_getRainfallCounter (uint8_t hibyte, uint8_t lobyte) { + // range: 0 to 99.99 in, 0.01 in incr., rolling counter? + int raincounter = ((hibyte & 0x7f) << 7) | (lobyte & 0x7F); + return raincounter; +} + +static int acurite5n1_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { + // acurite 5n1 weather sensor decoding for rtl_433 + // Jens Jensen 2014 + int i; + uint8_t *buf = NULL; + // run through rows til we find one with good crc (brute force) + for (i=0; i < BITBUF_ROWS; i++) { + if (acurite_detect(bb[i])) { + buf = bb[i]; + break; // done + } + } + + if (buf) { + // decode packet here + fprintf(stderr, "Detected Acurite 5n1 sensor, %d bits\n",bits_per_row[1]); + if (debug_output) { + for (i=0; i < 8; i++) + fprintf(stderr, "%02X ", buf[i]); + fprintf(stderr, "CRC OK\n"); + } + + if ((buf[2] & 0x0F) == 1) { + // wind speed, wind direction, rainfall + + float rainfall = 0.00; + int raincounter = acurite_getRainfallCounter(buf[5], buf[6]); + if (acurite_raincounter > 0) { + // track rainfall difference after first run + rainfall = ( raincounter - acurite_raincounter ) * 0.01; + } else { + // capture starting counter + acurite_raincounter = raincounter; + } + + fprintf(stderr, "wind speed: %d kph, ", + acurite_getWindSpeed(buf[3], buf[4])); + fprintf(stderr, "wind direction: %0.1f°, ", + acurite_getWindDirection(buf[4])); + fprintf(stderr, "rain gauge: %0.2f in.\n", rainfall); + + } else if ((buf[2] & 0x0F) == 8) { + // wind speed, temp, RH + fprintf(stderr, "wind speed: %d kph, ", + acurite_getWindSpeed(buf[3], buf[4])); + fprintf(stderr, "temp: %2.1f° F, ", + acurite_getTemp(buf[4], buf[5])); + fprintf(stderr, "humidity: %d%% RH\n", + acurite_getHumidity(buf[6])); + } + } else { + return 0; + } + + if (debug_output) + debug_callback(bb, bits_per_row); + + return 1; +} + +static int acurite_rain_gauge_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) { + // This needs more validation to positively identify correct sensor type, but it basically works if message is really from acurite raingauge and it doesn't have any errors + if ((bb[0][0] != 0) && (bb[0][1] != 0) && (bb[0][2]!=0) && (bb[0][3] == 0) && (bb[0][4] == 0)) { + float total_rain = ((bb[0][1]&0xf)<<8)+ bb[0][2]; + total_rain /= 2; // Sensor reports number of bucket tips. Each bucket tip is .5mm + fprintf(stderr, "AcuRite Rain Gauge Total Rain is %2.1fmm\n", total_rain); + fprintf(stderr, "Raw Message: %02x %02x %02x %02x %02x\n",bb[0][0],bb[0][1],bb[0][2],bb[0][3],bb[0][4]); + return 1; + } + return 0; +} + +static int acurite_th_detect(uint8_t *buf){ + if(buf[5] != 0) return 0; + uint8_t sum = (buf[0] + buf[1] + buf[2] + buf[3]) & 0xff; + if(sum == 0) return 0; + return sum == buf[4]; +} +static float acurite_th_temperature(uint8_t *s){ + uint16_t shifted = (((s[1] & 0x0f) << 8) | s[2]) << 4; // Logical left shift + return (((int16_t)shifted) >> 4) / 10.0; // Arithmetic right shift +} +static int acurite_th_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) { + uint8_t *buf = NULL; + int i; + for(i = 0; i < BITBUF_ROWS; i++){ + if(acurite_th_detect(bb[i])){ + buf = bb[i]; + break; + } + } + if(buf){ + fprintf(stderr, "Temperature event:\n"); + fprintf(stderr, "protocol = Acurite Temp&Humidity\n"); + fprintf(stderr, "temp = %.1f°C\n", acurite_th_temperature(buf)); + fprintf(stderr, "humidity = %d%%\n\n", buf[3]); + return 1; + } + + return 0; +} + +r_device acurite5n1 = { + /* .id = */ 10, + /* .name = */ "Acurite 5n1 Weather Station", + /* .modulation = */ OOK_PWM_P, + /* .short_limit = */ 70, + /* .long_limit = */ 240, + /* .reset_limit = */ 21000, + /* .json_callback = */ &acurite5n1_callback, +}; + +r_device acurite_rain_gauge = { + /* .id = */ 10, + /* .name = */ "Acurite 896 Rain Gauge", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ 1744/4, + /* .long_limit = */ 3500/4, + /* .reset_limit = */ 5000/4, + /* .json_callback = */ &acurite_rain_gauge_callback, +}; + +r_device acurite_th = { + /* .id = */ 11, + /* .name = */ "Acurite Temperature and Humidity Sensor", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ 300, + /* .long_limit = */ 550, + /* .reset_limit = */ 2500, + /* .json_callback = */ &acurite_th_callback, +}; diff --git a/src/devices/alecto.c b/src/devices/alecto.c new file mode 100644 index 00000000..621bcbd0 --- /dev/null +++ b/src/devices/alecto.c @@ -0,0 +1,163 @@ +#include "rtl_433.h" + +/* Documentation also at http://www.tfd.hu/tfdhu/files/wsprotocol/auriol_protocol_v20.pdf + * Message Format: (9 nibbles, 36 bits): + * Please note that bytes need to be reversed before processing! + * + * Format for Temperature Humidity + * AAAAAAAA BBBB CCCC CCCC CCCC DDDDDDDD EEEE + * RC Type Temperature___ Humidity Checksum + * A = Rolling Code / Device ID + * Device ID: AAAABBAA BB is used for channel, base channel is 01 + * When channel selector is used, channel can be 10 (2) and 11 (3) + * B = Message type (xyyz = temp/humidity if yy <> '11') else wind/rain sensor + * x indicates battery status (0 normal, 1 voltage is below ~2.6 V) + * z 0 indicates regular transmission, 1 indicates requested by pushbutton + * C = Temperature (two's complement) + * D = Humidity BCD format + * E = Checksum + * + * Format for Rain + * AAAAAAAA BBBB CCCC DDDD DDDD DDDD DDDD EEEE + * RC Type Rain Checksum + * A = Rolling Code /Device ID + * B = Message type (xyyx = NON temp/humidity data if yy = '11') + * C = fixed to 1100 + * D = Rain (bitvalue * 0.25 mm) + * E = Checksum + * + * Format for Windspeed + * AAAAAAAA BBBB CCCC CCCC CCCC DDDDDDDD EEEE + * RC Type Windspd Checksum + * A = Rolling Code + * B = Message type (xyyx = NON temp/humidity data if yy = '11') + * C = Fixed to 1000 0000 0000 + * D = Windspeed (bitvalue * 0.2 m/s, correction for webapp = 3600/1000 * 0.2 * 100 = 72) + * E = Checksum + * + * Format for Winddirection & Windgust + * AAAAAAAA BBBB CCCD DDDD DDDD EEEEEEEE FFFF + * RC Type Winddir Windgust Checksum + * A = Rolling Code + * B = Message type (xyyx = NON temp/humidity data if yy = '11') + * C = Fixed to 111 + * D = Wind direction + * E = Windgust (bitvalue * 0.2 m/s, correction for webapp = 3600/1000 * 0.2 * 100 = 72) + * F = Checksum + ********************************************************************************************* + */ +uint8_t reverse8(uint8_t x) { + x = (x & 0xF0) >> 4 | (x & 0x0F) << 4; + x = (x & 0xCC) >> 2 | (x & 0x33) << 2; + x = (x & 0xAA) >> 1 | (x & 0x55) << 1; + return x; +} + +uint8_t bcd_decode8(uint8_t x) { + return ((x & 0xF0) >> 4) * 10 + (x & 0x0F); +} + +static int alectov1_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) { + int temperature_before_dec; + int temperature_after_dec; + int16_t temp; + uint8_t humidity, csum = 0, csum2 = 0; + int i; + if (bb[1][0] == bb[5][0] && bb[2][0] == bb[6][0] && (bb[1][4] & 0xf) == 0 && (bb[5][4] & 0xf) == 0 + && (bb[5][0] != 0 && bb[5][1] != 0)) { + + for (i = 0; i < 4; i++) { + uint8_t tmp = reverse8(bb[1][i]); + csum += (tmp & 0xf) + ((tmp & 0xf0) >> 4); + + tmp = reverse8(bb[5][i]); + csum2 += (tmp & 0xf) + ((tmp & 0xf0) >> 4); + } + + csum = ((bb[1][1] & 0x7f) == 0x6c) ? (csum + 0x7) : (0xf - csum); + csum2 = ((bb[5][1] & 0x7f) == 0x6c) ? (csum2 + 0x7) : (0xf - csum2); + + csum = reverse8((csum & 0xf) << 4); + csum2 = reverse8((csum2 & 0xf) << 4); + /* Quit if checksup does not work out */ + if (csum != (bb[1][4] >> 4) || csum2 != (bb[5][4] >> 4)) { + fprintf(stderr, "\nAlectoV1 CRC error"); + return 0; + } //Invalid checksum + + + uint8_t wind = 0; + + if ((bb[1][1] & 0xe0) == 0x60) { + wind = ((bb[1][1] & 0xf) == 0xc) ? 0 : 1; + + fprintf(stderr, "\nSensor = %s event\n", wind ? "Wind" : "Rain gauge"); + fprintf(stderr, "Protocol = AlectoV1 bpr1: %d bpr2: %d\n", bits_per_row[1], bits_per_row[5]); + fprintf(stderr, "Device = %d\n", reverse8(bb[1][0])); + fprintf(stderr, "Button = %d\n", bb[1][1]&0x10 ? 1 : 0); + fprintf(stderr, "Battery = %s\n", bb[1][1]&0x80 ? "Low" : "OK"); + if (wind) { + int skip = -1; + /* Untested code written according to the specification, may not decode correctly */ + if ((bb[1][1]&0xe) == 0x8 && bb[1][2] == 0) { + skip = 0; + } else if ((bb[1][1]&0xe) == 0xe) { + skip = 4; + } //According to supplied data! + if (skip >= 0) { + double speed = reverse8(bb[1 + skip][3]); + double gust = reverse8(bb[5 + skip][3]); + int direction = (reverse8(bb[5 + skip][2]) << 1) | (bb[5 + skip][1] & 0x1); + fprintf(stderr, "Wind speed = %.0f units = %.2f m/s\n", speed, speed * 0.2); + fprintf(stderr, "Wind gust = %.0f units = %.2f m/s\n", gust, gust * 0.2); + fprintf(stderr, "Direction = %.2i degrees\n", direction); + } + } else { + /* Untested code written according to the specification, may not decode correctly */ + double rain_mm = (reverse8(bb[1][2]) + (reverse8(bb[1][3] << 8))) * 0.25; + fprintf(stderr, "Rainfall = %f\n", rain_mm); + } + } else if (bb[2][0] == bb[3][0] && bb[3][0] == bb[4][0] && bb[4][0] == bb[5][0] && + bb[5][0] == bb[6][0] && (bb[3][4] & 0xf) == 0 && (bb[5][4] & 0xf) == 0) { + //static char * temp_states[4] = {"stable", "increasing", "decreasing", "invalid"}; + temp = (int16_t) ((uint16_t) (reverse8(bb[1][1]) >> 4) | (reverse8(bb[1][2]) << 4)); + if ((temp & 0x800) != 0) { + temp |= 0xf000; + } + temperature_before_dec = abs(temp / 10); + temperature_after_dec = abs(temp % 10); + humidity = bcd_decode8(reverse8(bb[1][3])); + fprintf(stderr, "\nSensor = Temperature event\n"); + fprintf(stderr, "Protocol = AlectoV1 bpr1: %d bpr2: %d\n", bits_per_row[1], bits_per_row[5]); + fprintf(stderr, "Device = %d\n", reverse8(bb[1][0])); + fprintf(stderr, "Channel = %d\n", (bb[1][0] & 0xc) >> 2); + fprintf(stderr, "Button = %d\n", bb[1][1]&0x10 ? 1 : 0); + fprintf(stderr, "Battery = %s\n", bb[1][1]&0x80 ? "Low" : "OK"); + fprintf(stderr, "Temp = %s%d.%d\n", temp < 0 ? "-" : "", temperature_before_dec, temperature_after_dec); + fprintf(stderr, "Humidity = %d\n", humidity); + } + fprintf(stderr, "Checksum = %01x (calculated %01x)\n", bb[1][4] >> 4, csum); + + fprintf(stderr, "Received Data = %02x %02x %02x %02x %02x\n", bb[1][0], bb[1][1], bb[1][2], bb[1][3], bb[1][4]); + if (wind) fprintf(stderr, "Rcvd Data 2 = %02x %02x %02x %02x %02x\n", bb[5][0], bb[5][1], bb[5][2], bb[5][3], bb[5][4]); + /* + * fprintf(stderr, "L2M: %02x %02x %02x %02x %02x\n",reverse8(bb[1][0]),reverse8(bb[1][1]),reverse8(bb[1][2]),reverse8(bb[1][3]),reverse8(bb[1][4])); + */ + if (debug_output) + debug_callback(bb, bits_per_row); + + return 1; + } + return 0; +} + +//Timing based on 250000 +r_device alectov1 = { + /* .id = */ 11, + /* .name = */ "AlectoV1 Weather Sensor", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ 3500 / 4, //875 + /* .long_limit = */ 7000 / 4, //1750 + /* .reset_limit = */ 15000 / 4, //3750 + /* .json_callback = */ &alectov1_callback, +}; diff --git a/src/devices/elv.c b/src/devices/elv.c new file mode 100644 index 00000000..03b85f5a --- /dev/null +++ b/src/devices/elv.c @@ -0,0 +1,147 @@ +#include "rtl_433.h" + +uint16_t AD_POP(uint8_t bb[BITBUF_COLS], uint8_t bits, uint8_t bit) { + uint16_t val = 0; + uint8_t i, byte_no, bit_no; + for (i=0;i=1&&dec[0]<=3?types[dec[0]-1]:"?"); + fprintf(stderr, "code = %d\n",dec[1]); + fprintf(stderr, "seqno = %d\n",dec[2]); + fprintf(stderr, "total cnt = %d\n",dec[3]|dec[4]<<8); + fprintf(stderr, "current cnt = %d\n",dec[5]|dec[6]<<8); + fprintf(stderr, "peak cnt = %d\n",dec[7]|dec[8]<<8); + + return 1; +} + +static int ws2000_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { + // based on http://www.dc3yc.privat.t-online.de/protocol.htm + uint8_t dec[13]; + uint8_t nibbles=0; + uint8_t bit=11; // preamble + char* types[]={"!AS3", "AS2000/ASH2000/S2000/S2001A/S2001IA/ASH2200/S300IA", "!S2000R", "!S2000W", "S2001I/S2001ID", "!S2500H", "!Pyrano", "!KS200/KS300"}; + uint8_t check_calculated=0, sum_calculated=0; + uint8_t i; + uint8_t stopbit; + uint8_t sum_received; + + dec[0] = AD_POP (bb[0], 4, bit); bit+=4; + stopbit= AD_POP (bb[0], 1, bit); bit+=1; + if (!stopbit) { +//fprintf(stderr, "!stopbit\n"); + return 0; + } + check_calculated ^= dec[0]; + sum_calculated += dec[0]; + + // read nibbles with stopbit ... + for (i = 1; i <= (dec[0]==4?12:8); i++) { + dec[i] = AD_POP (bb[0], 4, bit); bit+=4; + stopbit= AD_POP (bb[0], 1, bit); bit+=1; + if (!stopbit) { +//fprintf(stderr, "!stopbit %i\n", i); + return 0; + } + check_calculated ^= dec[i]; + sum_calculated += dec[i]; + nibbles++; + } + + if (check_calculated) { +//fprintf(stderr, "check_calculated (%d) != 0\n", check_calculated); + return 0; + } + + // Read sum + sum_received = AD_POP (bb[0], 4, bit); bit+=4; + sum_calculated+=5; + sum_calculated&=0xF; + if (sum_received != sum_calculated) { +//fprintf(stderr, "sum_received (%d) != sum_calculated (%d) ", sum_received, sum_calculated); + return 0; + } + +//for (i = 0; i < nibbles; i++) fprintf(stderr, "%02X ", dec[i]); fprintf(stderr, "\n"); + + fprintf(stderr, "Weather station sensor event:\n"); + fprintf(stderr, "protocol = ELV WS 2000, %d bits\n",bits_per_row[1]); + fprintf(stderr, "type (!=ToDo) = %s\n", dec[0]<=7?types[dec[0]]:"?"); + fprintf(stderr, "code = %d\n", dec[1]&7); + fprintf(stderr, "temp = %s%d.%d\n", dec[1]&8?"-":"", dec[4]*10+dec[3], dec[2]); + fprintf(stderr, "humidity = %d.%d\n", dec[7]*10+dec[6], dec[5]); + if(dec[0]==4) { + fprintf(stderr, "pressure = %d\n", 200+dec[10]*100+dec[9]*10+dec[8]); + } + + return 1; +} + +r_device elv_em1000 = { + /* .id = */ 7, + /* .name = */ "ELV EM 1000", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ 750/4, + /* .long_limit = */ 7250/4, + /* .reset_limit = */ 30000/4, + /* .json_callback = */ &em1000_callback, +}; + +r_device elv_ws2000 = { + /* .id = */ 8, + /* .name = */ "ELV WS 2000", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ (602+(1155-602)/2)/4, + /* .long_limit = */ ((1755635-1655517)/2)/4, // no repetitions + /* .reset_limit = */ ((1755635-1655517)*2)/4, + /* .json_callback = */ &ws2000_callback, +}; diff --git a/src/devices/intertechno.c b/src/devices/intertechno.c new file mode 100644 index 00000000..1c84a81e --- /dev/null +++ b/src/devices/intertechno.c @@ -0,0 +1,39 @@ +#include "rtl_433.h" + +static int intertechno_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) { + + //if (bb[1][1] == 0 && bb[1][0] != 0 && bb[1][3]==bb[2][3]){ + if(bb[0][0]==0 && bb[0][0] == 0 && bb[1][0] == 0x56){ + fprintf(stderr, "Switch event:\n"); + fprintf(stderr, "protocol = Intertechno\n"); + fprintf(stderr, "rid = %x\n",bb[1][0]); + fprintf(stderr, "rid = %x\n",bb[1][1]); + fprintf(stderr, "rid = %x\n",bb[1][2]); + fprintf(stderr, "rid = %x\n",bb[1][3]); + fprintf(stderr, "rid = %x\n",bb[1][4]); + fprintf(stderr, "rid = %x\n",bb[1][5]); + fprintf(stderr, "rid = %x\n",bb[1][6]); + fprintf(stderr, "rid = %x\n",bb[1][7]); + fprintf(stderr, "ADDR Slave = %i\n",bb[1][7] & 0b00001111); + fprintf(stderr, "ADDR Master = %i\n",(bb[1][7] & 0b11110000) >> 4); + fprintf(stderr, "command = %i\n",(bb[1][6] & 0b00000111)); + fprintf(stderr, "%02x %02x %02x %02x %02x\n",bb[1][0],bb[1][1],bb[1][2],bb[1][3],bb[1][4]); + + if (debug_output) + debug_callback(bb, bits_per_row); + + return 1; + } + return 0; +} + +r_device intertechno = { + /* .id = */ 11, + /* .name = */ "Intertechno 433", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ 100, + /* .long_limit = */ 350, + /* .reset_limit = */ 3000, + /* .json_callback = */ &intertechno_callback, + /* .json_callback = */ //&debug_callback, +}; diff --git a/src/devices/lacrosse.c b/src/devices/lacrosse.c new file mode 100644 index 00000000..bea2675f --- /dev/null +++ b/src/devices/lacrosse.c @@ -0,0 +1,199 @@ +/* LaCrosse TX Temperature and Humidity Sensors + * Tested: TX-7U and TX-6U (Temperature only) + * + * Not Tested but should work: TX-3, TX-4 + * + * Protocol Documentation: http://www.f6fbb.org/domo/sensors/tx3_th.php + * + * Message is 44 bits, 11 x 4 bit nybbles: + * + * [00] [cnt = 10] [type] [addr] [addr + parity] [v1] [v2] [v3] [iv1] [iv2] [check] + * + * Notes: + * - Zero Pulses are longer (1,400 uS High, 1,000 uS Low) = 2,400 uS + * - One Pulses are shorter ( 550 uS High, 1,000 uS Low) = 1,600 uS + * - Sensor id changes when the battery is changed + * - Values are BCD with one decimal place: vvv = 12.3 + * - Value is repeated integer only iv = 12 + * - Temperature is in Celsius with 50.0 added (to handle negative values) + * - There is a 4 bit checksum and a parity bit covering the three digit value + * - Parity check for TX-3 and TX-4 might be different. + * - Msg sent with one repeat after 30 mS + * - Temperature and humidity are sent as separate messages + * - Frequency for each sensor may be could be off by as much as 50-75 khz + */ + +#include "rtl_433.h" + +// buffer to hold localized timestamp YYYY-MM-DD HH:MM:SS +#define LOCAL_TIME_BUFLEN 32 + +void local_time_str(time_t time_secs, char *buf) { + time_t etime; + struct tm *tm_info; + + if (time_secs == 0) { + time(&etime); + } else { + etime = time_secs; + } + + tm_info = localtime(&etime); + + strftime(buf, LOCAL_TIME_BUFLEN, "%Y-%m-%d %H:%M:%S", tm_info); +} + +// Check for a valid LaCrosse Packet +// +// written for the version of pwm_p_decode() (OOK_PWM_P) +// pulse width detector with two anomalys: +// 1. bits are inverted +// 2. The first bit is discarded as a start bit +// +// If a fixed pulse width decoder is used this +// routine will need to be changed. +static int lacrossetx_detect(uint8_t *pRow, uint8_t *msg_nybbles) { + int i; + uint8_t rbyte_no, rbit_no, mnybble_no, mbit_no; + uint8_t bit, checksum, parity_bit, parity = 0; + + // Actual Packet should start with 0x0A and be 6 bytes + // actual message is 44 bit, 11 x 4 bit nybbles. + if ((pRow[0] & 0xFE) == 0x14 && pRow[6] == 0 && pRow[7] == 0) { + + for (i = 0; i < 11; i++) { + msg_nybbles[i] = 0; + } + + // Move nybbles into a byte array + // shifted by one to compensate for loss of first bit. + for (i = 0; i < 43; i++) { + rbyte_no = i / 8; + rbit_no = 7 - (i % 8); + mnybble_no = (i + 1) / 4; + mbit_no = 3 - ((i + 1) % 4); + bit = (pRow[rbyte_no] & (1 << rbit_no)) ? 1 : 0; + msg_nybbles[mnybble_no] |= (bit << mbit_no); + + // Check parity on three bytes of data value + // TX3U might calculate parity on all data including + // sensor id and redundant integer data + if (mnybble_no > 4 && mnybble_no < 8) { + parity += bit; + } + + // fprintf(stderr, "recv: [%d/%d] %d -> msg [%d/%d] %02x, Parity: %d %s\n", rbyte_no, rbit_no, + // bit, mnybble_no, mbit_no, msg_nybbles[mnybble_no], parity, + // ( mbit_no == 0 ) ? "\n" : "" ); + } + + parity_bit = msg_nybbles[4] & 0x01; + parity += parity_bit; + + // Validate Checksum (4 bits in last nybble) + checksum = 0; + for (i = 0; i < 10; i++) { + checksum = (checksum + msg_nybbles[i]) & 0x0F; + } + + // fprintf(stderr,"Parity: %d, parity bit %d, Good %d\n", parity, parity_bit, parity % 2); + + if (checksum == msg_nybbles[10] && (parity % 2 == 0)) { + return 1; + } else { + fprintf(stderr, + "LaCrosse Checksum/Parity error: %d != %d, Parity %d\n", + checksum, msg_nybbles[10], parity); + return 0; + } + } + + return 0; +} + +// LaCrosse TX-6u, TX-7u, Temperature and Humidity Sensors +// Temperature and Humidity are sent in different messages bursts. +static int lacrossetx_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], + int16_t bits_per_row[BITBUF_ROWS]) { + + int i, m, valid = 0; + uint8_t *buf; + uint8_t msg_nybbles[11]; + uint8_t sensor_id, msg_type, msg_len, msg_parity, msg_checksum; + int msg_value_int; + float msg_value = 0, temp_c = 0, temp_f = 0; + time_t time_now; + char time_str[25]; + + static float last_msg_value = 0.0; + static uint8_t last_sensor_id = 0; + static uint8_t last_msg_type = 0; + static time_t last_msg_time = 0; + + for (m = 0; m < BITBUF_ROWS; m++) { + valid = 0; + if (lacrossetx_detect(bb[m], msg_nybbles)) { + + msg_len = msg_nybbles[1]; + msg_type = msg_nybbles[2]; + sensor_id = (msg_nybbles[3] << 3) + (msg_nybbles[4] >> 1); + msg_parity = msg_nybbles[4] & 0x01; + msg_value = msg_nybbles[5] * 10 + msg_nybbles[6] + + msg_nybbles[7] / 10.0; + msg_value_int = msg_nybbles[8] * 10 + msg_nybbles[9]; + msg_checksum = msg_nybbles[10]; + + time(&time_now); + + // suppress duplicates + if (sensor_id == last_sensor_id && msg_type == last_msg_type + && last_msg_value == msg_value + && time_now - last_msg_time < 50) { + continue; + } + + local_time_str(time_now, time_str); + + switch (msg_type) { + case 0x00: + temp_c = msg_value - 50.0; + temp_f = temp_c * 1.8 + 32; + printf( + "%s LaCrosse TX Sensor %02x: Temperature %3.1f C / %3.1f F\n", + time_str, sensor_id, temp_c, temp_f); + break; + + case 0x0E: + printf("%s LaCrosse TX Sensor %02x: Humidity %3.1f%%\n", + time_str, sensor_id, msg_value); + break; + + default: + fprintf(stderr, + "%s LaCrosse Sensor %02x: Unknown Reading % 3.1f (%d)\n", + time_str, sensor_id, msg_value, msg_value_int); + } + + time(&last_msg_time); + last_msg_value = msg_value; + last_msg_type = msg_type; + last_sensor_id = sensor_id; + + } else { + return 0; + } + } + + if (debug_output) + debug_callback(bb, bits_per_row); + return 1; +} + +r_device lacrossetx = { +/* .id = */11, +/* .name = */"LaCrosse TX Temperature / Humidity Sensor", +/* .modulation = */OOK_PWM_P, +/* .short_limit = */238, +/* .long_limit = */750, +/* .reset_limit = */8000, +/* .json_callback = */&lacrossetx_callback, }; diff --git a/src/devices/mebus.c b/src/devices/mebus.c new file mode 100644 index 00000000..6be218e5 --- /dev/null +++ b/src/devices/mebus.c @@ -0,0 +1,49 @@ +#include "rtl_433.h" + +static int mebus433_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) { + int temperature_before_dec; + int temperature_after_dec; + int16_t temp; + int8_t hum; + + if (bb[0][0] == 0 && bb[1][4] !=0 && (bb[1][0] & 0b01100000) && bb[1][3]==bb[5][3] && bb[1][4] == bb[12][4]){ + // Upper 4 bits are stored in nibble 1, lower 8 bits are stored in nibble 2 + // upper 4 bits of nibble 1 are reserved for other usages. + temp = (int16_t)((uint16_t)(bb[1][1] << 12 ) | bb[1][2]<< 4); + temp = temp >> 4; + // lower 4 bits of nibble 3 and upper 4 bits of nibble 4 contains + // humidity as decimal value + hum = (bb[1][3] << 4 | bb[1][4] >> 4); + + temperature_before_dec = abs(temp / 10); + temperature_after_dec = abs(temp % 10); + + fprintf(stderr, "Sensor event:\n"); + fprintf(stderr, "protocol = Mebus/433\n"); + fprintf(stderr, "address = %i\n", bb[1][0] & 0b00011111); + fprintf(stderr, "channel = %i\n",((bb[1][1] & 0b00110000) >> 4)+1); + fprintf(stderr, "battery = %s\n", bb[1][1] & 0b10000000?"Ok":"Low"); + fprintf(stderr, "unkown1 = %i\n",(bb[1][1] & 0b01000000) >> 6); // always 0? + fprintf(stderr, "unkown2 = %i\n",(bb[1][3] & 0b11110000) >> 4); // always 1111? + fprintf(stderr, "temperature = %s%d.%d°C\n",temp<0?"-":"",temperature_before_dec, temperature_after_dec); + fprintf(stderr, "humidity = %i%%\n", hum); + fprintf(stderr, "%02x %02x %02x %02x %02x\n",bb[1][0],bb[1][1],bb[1][2],bb[1][3],bb[1][4]); + + if (debug_output) + debug_callback(bb, bits_per_row); + + return 1; + } + return 0; +} + +r_device mebus433 = { + /* .id = */ 10, + /* .name = */ "Mebus 433", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ 300, + /* .long_limit = */ 600, + /* .reset_limit = */ 1500, + /* .json_callback = */ &mebus433_callback, + /* .json_callback = */ //&debug_callback, +}; diff --git a/src/devices/newkaku.c b/src/devices/newkaku.c new file mode 100644 index 00000000..b0b66e0d --- /dev/null +++ b/src/devices/newkaku.c @@ -0,0 +1,127 @@ +#include "rtl_433.h" + +static int newkaku_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) { + /* Two bits map to 2 states, 0 1 -> 0 and 1 1 -> 1 */ + /* Status bit can be 1 1 -> 1 which indicates DIM value. 4 extra bits are present with value */ + /*start pulse: 1T high, 10.44T low */ + /*- 26 bit: Address */ + /*- 1 bit: group bit*/ + /*- 1 bit: Status bit on/off/[dim]*/ + /*- 4 bit: unit*/ + /*- [4 bit: dim level. Present if [dim] is used, but might be present anyway...]*/ + /*- stop pulse: 1T high, 40T low */ + int i; + uint8_t tmp = 0; + uint8_t unit = 0; + uint8_t packet = 0; + uint8_t bitcount = 0; + uint32_t kakuid = 0; + + if (bb[0][0] == 0xac) {//allways starts with ac + // first bit is from startbit sequence, not part of payload! + // check protocol if value is 10 or 01, else stop processing as it is no vallid KAKU packet! + //get id=24bits, remember 1st 1 bit = startbit, no payload! + for (packet = 0; packet < 6; packet++) {//get first part kakuid + tmp = bb[0][packet] << 1; + if ((bb[0][packet + 1]&(1 << 7)) != 0) {// if set add bit to current + tmp++; + } + + for (bitcount = 0; bitcount < 8; bitcount += 2) {//process bitstream, check protocol! + + if (((tmp << bitcount & (0x80)) == 0x80)&((tmp << bitcount & (0x40)) == 0)) { + //add 1 + kakuid = kakuid << 1; + kakuid++; + } else + if (((tmp << bitcount & (0x80)) == 0)&((tmp << bitcount & (0x40)) == 0x40)) { + kakuid = kakuid << 1; + //add 0 + } else { + return 0; //00 and 11 indicates packet error. Do exit, no valid packet + } + } + } + tmp = bb[0][6] << 1; //Get last part ID + for (bitcount = 0; bitcount < 4; bitcount += 2) { + if (((tmp << bitcount & (0x80)) == 0x80)&((tmp << bitcount & (0x40)) == 0)) { + //add 1 + kakuid = kakuid << 1; + kakuid++; + } else + if (((tmp << bitcount & (0x80)) == 0)&((tmp << bitcount & (0x40)) == 0x40)) { + //= add bit on kakuid + kakuid = kakuid << 1; + //add 0 + } else { + //fprintf(stderr, " Packet error, no newkaku!!\n", tmp << bitcount); + return 0; //00 and 11 indicates packet error. no valid packet! do exit + } + } + //Get unit ID + tmp = bb[0][7] << 1; + if ((bb[0][8]&(1 << 7)) != 0) {// if set add bit to current + tmp++; + } + for (bitcount = 0; bitcount < 8; bitcount += 2) {//process bitstream, check protocol! + if (((tmp << bitcount & (0x80)) == 0x80)&((tmp << bitcount & (0x40)) == 0)) { + //add 1 + unit = unit << 1; + unit++; + } else + if (((tmp << bitcount & (0x80)) == 0)&((tmp << bitcount & (0x40)) == 0x40)) { + unit = unit << 1; + //add 0 + } else { + return 0; //00 and 11 indicates packet error. Do exit, no valid packet + } + } + fprintf(stderr, "NewKaku event:\n"); + fprintf(stderr, "Model = NewKaKu on/off/dimmer switch\n"); + fprintf(stderr, "KakuId = %d (H%.2X)\n", kakuid, kakuid); + fprintf(stderr, "Unit = %d (H%.2X)\n", unit, unit); + fprintf(stderr, "Group Call = %s\n", (((bb[0][6] & (0x04)) == 0x04)&((bb[0][6] & (0x02)) == 0)) ? "Yes" : "No"); + fprintf(stderr, "Command = %s\n", (((bb[0][6] & (0x01)) == 0x01)&((bb[0][7] & (0x80)) == 0)) ? "On" : "Off"); + if (((bb[0][6] & (0x01)) == 0x01)&((bb[0][7] & (0x80)) == 0x80)) {//11 indicates DIM command, 4 extra bits indicate DIM value + fprintf(stderr, "Dim = Yes\n"); + tmp = bb[0][8] << 1; // get packet, loose first bit + uint8_t dv = 0; + if ((bb[0][9]&(1 << 7)) != 0) {// if bit is set Add to current packet + tmp++; + for (bitcount = 0; bitcount < 8; bitcount += 2) {//process last bit outside + if (((tmp << bitcount & (0x80)) == 0x80)&((tmp << bitcount & (0x40)) == 0)) { + //add 1 + dv = dv << 1; + dv++; + } else + if (((tmp << bitcount & (0x80)) == 0)&((tmp << bitcount & (0x40)) == 0x40)) { + dv = dv << 1; + //add 0 + } else { + return 0; //00 and 11 indicates packet error. Do exit, no valid packet + } + } + } + fprintf(stderr, "Dim Value = %d\n", dv); + } else { + fprintf(stderr, "Dim = No\n"); + fprintf(stderr, "Dim Value = 0\n"); + } + fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + bb[0][0], bb[0][1], bb[0][2], bb[0][3], bb[0][4], bb[0][5], bb[0][6], bb[0][7], bb[0][8]); + if (debug_output) + debug_callback(bb, bits_per_row); + return 1; + } + return 0; +} + +r_device newkaku = { + /* .id = */ 11, + /* .name = */ "KlikAanKlikUit Wireless Switch", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ 200, + /* .long_limit = */ 800, + /* .reset_limit = */ 4000, + /* .json_callback = */ &newkaku_callback, +}; diff --git a/src/devices/oregon_scientific.c b/src/devices/oregon_scientific.c new file mode 100644 index 00000000..311222d4 --- /dev/null +++ b/src/devices/oregon_scientific.c @@ -0,0 +1,280 @@ +#include "rtl_433.h" + +float get_os_temperature(unsigned char *message, unsigned int sensor_id) { + // sensor ID included to support sensors with temp in different position + float temp_c = 0; + temp_c = (((message[5]>>4)*100)+((message[4]&0x0f)*10) + ((message[4]>>4)&0x0f)) /10.0F; + if (message[5] & 0x0f) + temp_c = -temp_c; + return temp_c; +} +unsigned int get_os_humidity(unsigned char *message, unsigned int sensor_id) { + // sensor ID included to support sensors with temp in different position + int humidity = 0; + humidity = ((message[6]&0x0f)*10)+(message[6]>>4); + return humidity; +} + +static int validate_os_checksum(unsigned char *msg, int checksum_nibble_idx) { + // Oregon Scientific v2.1 and v3 checksum is a 1 byte 'sum of nibbles' checksum. + // with the 2 nibbles of the checksum byte swapped. + int i; + unsigned int checksum, sum_of_nibbles=0; + for (i=0; i<(checksum_nibble_idx-1);i+=2) { + unsigned char val=msg[i>>1]; + sum_of_nibbles += ((val>>4) + (val &0x0f)); + } + if (checksum_nibble_idx & 1) { + sum_of_nibbles += (msg[checksum_nibble_idx>>1]>>4); + checksum = (msg[checksum_nibble_idx>>1] & 0x0f) | (msg[(checksum_nibble_idx+1)>>1]&0xf0); + } else + checksum = (msg[checksum_nibble_idx>>1]>>4) | ((msg[checksum_nibble_idx>>1]&0x0f)<<4); + sum_of_nibbles &= 0xff; + + if (sum_of_nibbles == checksum) + return 0; + else { + fprintf(stderr, "Checksum error in Oregon Scientific message. Expected: %02x Calculated: %02x\n", checksum, sum_of_nibbles); + fprintf(stderr, "Message: "); int i; for (i=0 ;i<((checksum_nibble_idx+4)>>1) ; i++) fprintf(stderr, "%02x ", msg[i]); fprintf(stderr, "\n\n"); + return 1; + } +} + +static int validate_os_v2_message(unsigned char * msg, int bits_expected, int valid_v2_bits_received, + int nibbles_in_checksum) { + // Oregon scientific v2.1 protocol sends each bit using the complement of the bit, then the bit for better error checking. Compare number of valid bits processed vs number expected + if (bits_expected == valid_v2_bits_received) { + return (validate_os_checksum(msg, nibbles_in_checksum)); + } else { + fprintf(stderr, "Bit validation error on Oregon Scientific message. Expected %d bits, received error after bit %d \n", bits_expected, valid_v2_bits_received); + fprintf(stderr, "Message: "); int i; for (i=0 ;i<(bits_expected+7)/8 ; i++) fprintf(stderr, "%02x ", msg[i]); fprintf(stderr, "\n\n"); + } + return 1; +} + +static int oregon_scientific_v2_1_parser(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) { + // Check 2nd and 3rd bytes of stream for possible Oregon Scientific v2.1 sensor data (skip first byte to get past sync/startup bit errors) + if ( ((bb[0][1] == 0x55) && (bb[0][2] == 0x55)) || + ((bb[0][1] == 0xAA) && (bb[0][2] == 0xAA))) { + int i,j; + unsigned char msg[BITBUF_COLS] = {0}; + + // Possible v2.1 Protocol message + int num_valid_v2_bits = 0; + + unsigned int sync_test_val = (bb[0][3]<<24) | (bb[0][4]<<16) | (bb[0][5]<<8) | (bb[0][6]); + int dest_bit = 0; + int pattern_index; + // Could be extra/dropped bits in stream. Look for sync byte at expected position +/- some bits in either direction + for(pattern_index=0; pattern_index<8; pattern_index++) { + unsigned int mask = (unsigned int) (0xffff0000>>pattern_index); + unsigned int pattern = (unsigned int)(0x55990000>>pattern_index); + unsigned int pattern2 = (unsigned int)(0xaa990000>>pattern_index); + + //fprintf(stderr, "OS v2.1 sync byte search - test_val=%08x pattern=%08x mask=%08x\n", sync_test_val, pattern, mask); + + if (((sync_test_val & mask) == pattern) || + ((sync_test_val & mask) == pattern2)) { + // Found sync byte - start working on decoding the stream data. + // pattern_index indicates where sync nibble starts, so now we can find the start of the payload + int start_byte = 5 + (pattern_index>>3); + int start_bit = pattern_index & 0x07; + //fprintf(stderr, "OS v2.1 Sync test val %08x found, starting decode at byte index %d bit %d\n", sync_test_val, start_byte, start_bit); + int bits_processed = 0; + unsigned char last_bit_val = 0; + j=start_bit; + for (i=start_byte;i> j)) >> (7-j)); + + // check if last bit received was the complement of the current bit + if ((num_valid_v2_bits == 0) && (last_bit_val == bit_val)) + num_valid_v2_bits = bits_processed; // record position of first bit in stream that doesn't verify correctly + last_bit_val = bit_val; + + // copy every other bit from source stream to dest packet + msg[dest_bit>>3] |= (((bb[0][i] & (0x80 >> j)) >> (7-j)) << (7-(dest_bit & 0x07))); + + //fprintf(stderr,"i=%d j=%d dest_bit=%02x bb=%02x msg=%02x\n",i, j, dest_bit, bb[0][i], msg[dest_bit>>3]); + if ((dest_bit & 0x07) == 0x07) { + // after assembling each dest byte, flip bits in each nibble to convert from lsb to msb bit ordering + int k = (dest_bit>>3); + unsigned char indata = msg[k]; + // flip the 4 bits in the upper and lower nibbles + msg[k] = ((indata & 0x11) << 3) | ((indata & 0x22) << 1) | + ((indata & 0x44) >> 1) | ((indata & 0x88) >> 3); + } + dest_bit++; + } + else + last_bit_val = ((bb[0][i] & (0x80 >> j)) >> (7-j)); // used for v2.1 bit error detection + bits_processed++; + j++; + } + j=0; + } + break; + } //if (sync_test_val... + } // for (pattern... + + + int sensor_id = (msg[0] << 8) | msg[1]; + if ((sensor_id == 0x1d20) || (sensor_id == 0x1d30)) { + if (validate_os_v2_message(msg, 153, num_valid_v2_bits, 15) == 0) { + int channel = ((msg[2] >> 4)&0x0f); + if (channel == 4) + channel = 3; // sensor 3 channel number is 0x04 + float temp_c = get_os_temperature(msg, sensor_id); + if (sensor_id == 0x1d20) fprintf(stderr, "Weather Sensor THGR122N Channel %d ", channel); + else fprintf(stderr, "Weather Sensor THGR968 Outdoor "); + fprintf(stderr, "Temp: %3.1f¬∞C %3.1f¬∞F Humidity: %d%%\n", temp_c, ((temp_c*9)/5)+32,get_os_humidity(msg, sensor_id)); + } + return 1; + } else if (sensor_id == 0x5d60) { + if (validate_os_v2_message(msg, 185, num_valid_v2_bits, 19) == 0) { + unsigned int comfort = msg[7] >>4; + char *comfort_str="Normal"; + if (comfort == 4) comfort_str = "Comfortable"; + else if (comfort == 8) comfort_str = "Dry"; + else if (comfort == 0xc) comfort_str = "Humid"; + unsigned int forecast = msg[9]>>4; + char *forecast_str="Cloudy"; + if (forecast == 3) forecast_str = "Rainy"; + else if (forecast == 6) forecast_str = "Partly Cloudy"; + else if (forecast == 0xc) forecast_str = "Sunny"; + float temp_c = get_os_temperature(msg, 0x5d60); + fprintf(stderr,"Weather Sensor BHTR968 Indoor Temp: %3.1f¬∞C %3.1f¬∞F Humidity: %d%%", temp_c, ((temp_c*9)/5)+32, get_os_humidity(msg, 0x5d60)); + fprintf(stderr, " (%s) Pressure: %dmbar (%s)\n", comfort_str, ((msg[7] & 0x0f) | (msg[8] & 0xf0))+856, forecast_str); + } + return 1; + } else if (sensor_id == 0x2d10) { + if (validate_os_v2_message(msg, 161, num_valid_v2_bits, 16) == 0) { + float rain_rate = (((msg[4] &0x0f)*100)+((msg[4]>>4)*10) + ((msg[5]>>4)&0x0f)) /10.0F; + float total_rain = (((msg[7]&0xf)*10000)+((msg[7]>>4)*1000) + ((msg[6]&0xf)*100)+((msg[6]>>4)*10) + (msg[5]&0xf))/10.0F; + fprintf(stderr, "Weather Sensor RGR968 Rain Gauge Rain Rate: %2.0fmm/hr Total Rain %3.0fmm\n", rain_rate, total_rain); + } + return 1; + } else if (sensor_id == 0xec40 && num_valid_v2_bits==153) { + if ( validate_os_v2_message(msg, 153, num_valid_v2_bits, 12) == 0) { + int channel = ((msg[2] >> 4)&0x0f); + if (channel == 4) + channel = 3; // sensor 3 channel number is 0x04 + float temp_c = get_os_temperature(msg, sensor_id); + if (sensor_id == 0xec40) fprintf(stderr, "Thermo Sensor THR228N Channel %d ", channel); + fprintf(stderr, "Temp: %3.1f¬∞C %3.1f¬∞F\n", temp_c, ((temp_c*9)/5)+32); + } + return 1; + } else if (sensor_id == 0xec40 && num_valid_v2_bits==129) { + if ( validate_os_v2_message(msg, 129, num_valid_v2_bits, 12) == 0) { + int channel = ((msg[2] >> 4)&0x0f); + if (channel == 4) + channel = 3; // sensor 3 channel number is 0x04 + int battery_low = (msg[3] >> 2 & 0x01); + unsigned char rolling_code = ((msg[2] << 4)&0xF0) | ((msg[3] >> 4)&0x0F); + float temp_c = get_os_temperature(msg, sensor_id); + if (sensor_id == 0xec40) fprintf(stderr, "Thermo Sensor THN132N, Channel %d, Battery: %s, Rolling-code 0x%0X, ", channel, battery_low?"Low":"Ok", rolling_code); + fprintf(stderr, "Temp: %3.1f¬∞C %3.1f¬∞F\n", temp_c, ((temp_c*9)/5)+32); + } + return 1; + } else if (num_valid_v2_bits > 16) { +fprintf(stderr, "%d bit message received from unrecognized Oregon Scientific v2.1 sensor with device ID %x.\n", num_valid_v2_bits, sensor_id); +fprintf(stderr, "Message: "); for (i=0 ; i<20 ; i++) fprintf(stderr, "%02x ", msg[i]); fprintf(stderr,"\n\n"); + } else { +//fprintf(stderr, "\nPossible Oregon Scientific v2.1 message, but sync nibble wasn't found\n"); fprintf(stderr, "Raw Data: "); for (i=0 ; i>pattern_index); + unsigned int pattern = (unsigned int)(0xffa00000>>pattern_index); + unsigned int pattern2 = (unsigned int)(0xff500000>>pattern_index); + unsigned int pattern3 = (unsigned int)(0x00500000>>pattern_index); +//fprintf(stderr, "OS v3 Sync nibble search - test_val=%08x pattern=%08x mask=%08x\n", sync_test_val, pattern, mask); + if (((sync_test_val & mask) == pattern) || + ((sync_test_val & mask) == pattern2) || + ((sync_test_val & mask) == pattern3)) { + // Found sync byte - start working on decoding the stream data. + // pattern_index indicates where sync nibble starts, so now we can find the start of the payload + int start_byte = 3 + (pattern_index>>3); + int start_bit = (pattern_index+4) & 0x07; +//fprintf(stderr, "Oregon Scientific v3 Sync test val %08x ok, starting decode at byte index %d bit %d\n", sync_test_val, start_byte, start_bit); + j = start_bit; + for (i=start_byte;i> j)) >> (7-j)); + + // copy every bit from source stream to dest packet + msg[dest_bit>>3] |= (((bb[0][i] & (0x80 >> j)) >> (7-j)) << (7-(dest_bit & 0x07))); + +//fprintf(stderr,"i=%d j=%d dest_bit=%02x bb=%02x msg=%02x\n",i, j, dest_bit, bb[0][i], msg[dest_bit>>3]); + if ((dest_bit & 0x07) == 0x07) { + // after assembling each dest byte, flip bits in each nibble to convert from lsb to msb bit ordering + int k = (dest_bit>>3); + unsigned char indata = msg[k]; + // flip the 4 bits in the upper and lower nibbles + msg[k] = ((indata & 0x11) << 3) | ((indata & 0x22) << 1) | + ((indata & 0x44) >> 1) | ((indata & 0x88) >> 3); + } + dest_bit++; + j++; + } + j=0; + } + break; + } + } + + if ((msg[0] == 0xf8) && (msg[1] == 0x24)) { + if (validate_os_checksum(msg, 15) == 0) { + int channel = ((msg[2] >> 4)&0x0f); + float temp_c = get_os_temperature(msg, 0xf824); + int humidity = get_os_humidity(msg, 0xf824); + fprintf(stderr,"Weather Sensor THGR810 Channel %d Temp: %3.1f¬∞C %3.1f¬∞F Humidity: %d%%\n", channel, temp_c, ((temp_c*9)/5)+32, humidity); + } + return 1; + } else if ((msg[0] != 0) && (msg[1]!= 0)) { // sync nibble was found and some data is present... +fprintf(stderr, "Message received from unrecognized Oregon Scientific v3 sensor.\n"); +fprintf(stderr, "Message: "); for (i=0 ; i> 4; + fprintf(stderr, "Sensor temperature event:\n"); + fprintf(stderr, "protocol = Prologue, %d bits\n",bits_per_row[1]); + fprintf(stderr, "button = %d\n",bb[1][1]&0x04?1:0); + fprintf(stderr, "battery = %s\n",bb[1][1]&0x08?"Ok":"Low"); + fprintf(stderr, "temp = %s%d.%d\n",temp2<0?"-":"",abs((int16_t)temp2/10),abs((int16_t)temp2%10)); + fprintf(stderr, "humidity = %d\n", ((bb[1][3]&0x0F)<<4)|(bb[1][4]>>4)); + fprintf(stderr, "channel = %d\n",(bb[1][1]&0x03)+1); + fprintf(stderr, "id = %d\n",(bb[1][0]&0xF0)>>4); + rid = ((bb[1][0]&0x0F)<<4)|(bb[1][1]&0xF0)>>4; + fprintf(stderr, "rid = %d\n", rid); + fprintf(stderr, "hrid = %02x\n", rid); + + fprintf(stderr, "%02x %02x %02x %02x %02x\n",bb[1][0],bb[1][1],bb[1][2],bb[1][3],bb[1][4]); + + if (debug_output) + debug_callback(bb, bits_per_row); + + return 1; + } + return 0; +} + +r_device prologue = { + /* .id = */ 2, + /* .name = */ "Prologue Temperature Sensor", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ 3500/4, + /* .long_limit = */ 7000/4, + /* .reset_limit = */ 15000/4, + /* .json_callback = */ &prologue_callback, +}; diff --git a/src/devices/rubicson.c b/src/devices/rubicson.c new file mode 100644 index 00000000..384078ae --- /dev/null +++ b/src/devices/rubicson.c @@ -0,0 +1,59 @@ +#include "rtl_433.h" + +/* Currently this can decode the temperature and id from Rubicson sensors + * + * the sensor sends 36 bits 12 times pwm modulated + * the data is grouped into 9 nibles + * [id0] [id1], [unk0] [temp0], [temp1] [temp2], [unk1] [unk2], [unk3] + * + * The id changes when the battery is changed in the sensor. + * unk0 is always 1 0 0 0, most likely 2 channel bits as the sensor can recevice 3 channels + * unk1-3 changes and the meaning is unknown + * temp is 12 bit signed scaled by 10 + * + * The sensor can be bought at Kjell&Co + */ + +static int rubicson_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { + int temperature_before_dec; + int temperature_after_dec; + int16_t temp; + + /* FIXME validate the received message better, figure out crc */ + if (bb[1][0] == bb[2][0] && bb[2][0] == bb[3][0] && bb[3][0] == bb[4][0] && + bb[4][0] == bb[5][0] && bb[5][0] == bb[6][0] && bb[6][0] == bb[7][0] && bb[7][0] == bb[8][0] && + bb[8][0] == bb[9][0] && (bb[5][0] != 0 && bb[5][1] != 0 && bb[5][2] != 0)) { + + /* Nible 3,4,5 contains 12 bits of temperature + * The temerature is signed and scaled by 10 */ + temp = (int16_t)((uint16_t)(bb[0][1] << 12) | (bb[0][2] << 4)); + temp = temp >> 4; + + temperature_before_dec = abs(temp / 10); + temperature_after_dec = abs(temp % 10); + + fprintf(stderr, "Sensor temperature event:\n"); + fprintf(stderr, "protocol = Rubicson/Auriol, %d bits\n",bits_per_row[1]); + fprintf(stderr, "rid = %x\n",bb[0][0]); + fprintf(stderr, "temp = %s%d.%d\n",temp<0?"-":"",temperature_before_dec, temperature_after_dec); + fprintf(stderr, "%02x %02x %02x %02x %02x\n",bb[1][0],bb[0][1],bb[0][2],bb[0][3],bb[0][4]); + + if (debug_output) + debug_callback(bb, bits_per_row); + + return 1; + } + return 0; +} + +// timings based on samp_rate=1024000 +r_device rubicson = { + /* .id = */ 1, + /* .name = */ "Rubicson Temperature Sensor", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ 1744/4, + /* .long_limit = */ 3500/4, + /* .reset_limit = */ 5000/4, + /* .json_callback = */ &rubicson_callback, +}; + diff --git a/src/devices/silvercrest.c b/src/devices/silvercrest.c new file mode 100644 index 00000000..b0a92f39 --- /dev/null +++ b/src/devices/silvercrest.c @@ -0,0 +1,34 @@ +#include "rtl_433.h" + +static int silvercrest_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { + /* FIXME validate the received message better */ + if (bb[1][0] == 0xF8 && + bb[2][0] == 0xF8 && + bb[3][0] == 0xF8 && + bb[4][0] == 0xF8 && + bb[1][1] == 0x4d && + bb[2][1] == 0x4d && + bb[3][1] == 0x4d && + bb[4][1] == 0x4d) { + /* Pretty sure this is a Silvercrest remote */ + fprintf(stderr, "Remote button event:\n"); + fprintf(stderr, "model = Silvercrest, %d bits\n",bits_per_row[1]); + fprintf(stderr, "%02x %02x %02x %02x %02x\n",bb[1][0],bb[0][1],bb[0][2],bb[0][3],bb[0][4]); + + if (debug_output) + debug_callback(bb, bits_per_row); + + return 1; + } + return 0; +} + +r_device silvercrest = { + /* .id = */ 3, + /* .name = */ "Silvercrest Remote Control", + /* .modulation = */ OOK_PWM_P, + /* .short_limit = */ 600/4, + /* .long_limit = */ 5000/4, + /* .reset_limit = */ 15000/4, + /* .json_callback = */ &silvercrest_callback, +}; diff --git a/src/devices/steffen.c b/src/devices/steffen.c new file mode 100644 index 00000000..580f38ad --- /dev/null +++ b/src/devices/steffen.c @@ -0,0 +1,46 @@ +#include "rtl_433.h" + +static int steffen_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { + + if (bb[0][0]==0x00 && ((bb[1][0]&0x07)==0x07) && bb[1][0]==bb[2][0] && bb[2][0]==bb[3][0]) { + + fprintf(stderr, "Remote button event:\n"); + fprintf(stderr, "model = Steffan Switch Transmitter, %d bits\n",bits_per_row[1]); + fprintf(stderr, "code = %d%d%d%d%d\n", (bb[1][0]&0x80)>>7, (bb[1][0]&0x40)>>6, (bb[1][0]&0x20)>>5, (bb[1][0]&0x10)>>4, (bb[1][0]&0x08)>>3); + + if ((bb[1][2]&0x0f)==0x0e) + fprintf(stderr, "button = A\n"); + else if ((bb[1][2]&0x0f)==0x0d) + fprintf(stderr, "button = B\n"); + else if ((bb[1][2]&0x0f)==0x0b) + fprintf(stderr, "button = C\n"); + else if ((bb[1][2]&0x0f)==0x07) + fprintf(stderr, "button = D\n"); + else if ((bb[1][2]&0x0f)==0x0f) + fprintf(stderr, "button = ALL\n"); + else + fprintf(stderr, "button = unknown\n"); + + if ((bb[1][2]&0xf0)==0xf0) { + fprintf(stderr, "state = OFF\n"); + } else { + fprintf(stderr, "state = ON\n"); + } + + if (debug_output) + debug_callback(bb, bits_per_row); + + return 1; + } + return 0; +} + +r_device steffen = { + /* .id = */ 9, + /* .name = */ "Steffen Switch Transmitter", + /* .modulation = */ OOK_PWM_D, + /* .short_limit = */ 140, + /* .long_limit = */ 270, + /* .reset_limit = */ 1500, + /* .json_callback = */ &steffen_callback, +}; diff --git a/src/devices/waveman.c b/src/devices/waveman.c new file mode 100644 index 00000000..f5451af5 --- /dev/null +++ b/src/devices/waveman.c @@ -0,0 +1,40 @@ +#include "rtl_433.h" + +static int waveman_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { + /* Two bits map to 2 states, 0 1 -> 0 and 1 1 -> 1 */ + int i; + uint8_t nb[3] = {0}; + + if (((bb[0][0]&0x55)==0x55) && ((bb[0][1]&0x55)==0x55) && ((bb[0][2]&0x55)==0x55) && ((bb[0][3]&0x55)==0x00)) { + for (i=0 ; i<3 ; i++) { + nb[i] |= ((bb[0][i]&0xC0)==0xC0) ? 0x00 : 0x01; + nb[i] |= ((bb[0][i]&0x30)==0x30) ? 0x00 : 0x02; + nb[i] |= ((bb[0][i]&0x0C)==0x0C) ? 0x00 : 0x04; + nb[i] |= ((bb[0][i]&0x03)==0x03) ? 0x00 : 0x08; + } + + fprintf(stderr, "Remote button event:\n"); + fprintf(stderr, "model = Waveman Switch Transmitter, %d bits\n",bits_per_row[1]); + fprintf(stderr, "id = %c\n", 'A'+nb[0]); + fprintf(stderr, "channel = %d\n", (nb[1]>>2)+1); + fprintf(stderr, "button = %d\n", (nb[1]&3)+1); + fprintf(stderr, "state = %s\n", (nb[2]==0xe) ? "on" : "off"); + fprintf(stderr, "%02x %02x %02x\n",nb[0],nb[1],nb[2]); + + if (debug_output) + debug_callback(bb, bits_per_row); + + return 1; + } + return 0; +} + +r_device waveman = { + /* .id = */ 6, + /* .name = */ "Waveman Switch Transmitter", + /* .modulation = */ OOK_PWM_P, + /* .short_limit = */ 1000/4, + /* .long_limit = */ 8000/4, + /* .reset_limit = */ 30000/4, + /* .json_callback = */ &waveman_callback, +}; diff --git a/src/rtl_433.c b/src/rtl_433.c old mode 100755 new mode 100644 index b426a318..815a6dd5 --- a/src/rtl_433.c +++ b/src/rtl_433.c @@ -20,133 +20,24 @@ * along with this program. If not, see . */ - -/* Currently this can decode the temperature and id from Rubicson sensors - * - * the sensor sends 36 bits 12 times pwm modulated - * the data is grouped into 9 nibles - * [id0] [id1], [unk0] [temp0], [temp1] [temp2], [unk1] [unk2], [unk3] - * - * The id changes when the battery is changed in the sensor. - * unk0 is always 1 0 0 0, most likely 2 channel bits as the sensor can recevice 3 channels - * unk1-3 changes and the meaning is unknown - * temp is 12 bit signed scaled by 10 - * - * The sensor can be bought at Kjell&Co - */ - -/* Prologue sensor protocol - * - * the sensor sends 36 bits 7 times, before the first packet there is a pulse sent - * the packets are pwm modulated - * - * the data is grouped in 9 nibles - * [id0] [rid0] [rid1] [data0] [temp0] [temp1] [temp2] [humi0] [humi1] - * - * id0 is always 1001,9 - * rid is a random id that is generated when the sensor starts, could include battery status - * the same batteries often generate the same id - * data(3) is 0 the battery status, 1 ok, 0 low, first reading always say low - * data(2) is 1 when the sensor sends a reading when pressing the button on the sensor - * data(1,0)+1 forms the channel number that can be set by the sensor (1-3) - * temp is 12 bit signed scaled by 10 - * humi0 is always 1100,c if no humidity sensor is available - * humi1 is always 1100,c if no humidity sensor is available - * - * The sensor can be bought at Clas Ohlson - */ - - -/* LaCrosse TX Temperature and Humidity Sensors - * Tested: TX-7U and TX-6U (Temperature only) - * - * Not Tested but should work: TX-3, TX-4 - * - * Protocol Documentation: http://www.f6fbb.org/domo/sensors/tx3_th.php - * - * Message is 44 bits, 11 x 4 bit nybbles: - * - * [00] [cnt = 10] [type] [addr] [addr + parity] [v1] [v2] [v3] [iv1] [iv2] [check] - * - * Notes: - * - Zero Pulses are longer (1,400 uS High, 1,000 uS Low) = 2,400 uS - * - One Pulses are shorter ( 550 uS High, 1,000 uS Low) = 1,600 uS - * - Sensor id changes when the battery is changed - * - Values are BCD with one decimal place: vvv = 12.3 - * - Value is repeated integer only iv = 12 - * - Temperature is in Celsius with 50.0 added (to handle negative values) - * - There is a 4 bit checksum and a parity bit covering the three digit value - * - Parity check for TX-3 and TX-4 might be different. - * - Msg sent with one repeat after 30 mS - * - Temperature and humidity are sent as separate messages - * - Frequency for each sensor may be could be off by as much as 50-75 khz - */ - - - -#include -#include -#include -#include -#include -#include - -#ifndef _WIN32 -#include -#else -#include -#include -#include -#include "getopt/getopt.h" -#endif - #include "rtl-sdr.h" - -#define DEFAULT_SAMPLE_RATE 250000 -#define DEFAULT_FREQUENCY 433920000 -#define DEFAULT_HOP_TIME (60*10) -#define DEFAULT_HOP_EVENTS 2 -#define DEFAULT_ASYNC_BUF_NUMBER 32 -#define DEFAULT_BUF_LENGTH (16 * 16384) -#define DEFAULT_LEVEL_LIMIT 10000 -#define DEFAULT_DECIMATION_LEVEL 0 -#define MINIMAL_BUF_LENGTH 512 -#define MAXIMAL_BUF_LENGTH (256 * 16384) -#define FILTER_ORDER 1 -#define MAX_PROTOCOLS 10 -#define SIGNAL_GRABBER_BUFFER (12 * DEFAULT_BUF_LENGTH) -#define BITBUF_COLS 34 -#define BITBUF_ROWS 50 +#include "rtl_433.h" +#include "rtl_433_devices.h" static int do_exit = 0; -static int do_exit_async=0, frequencies=0, events=0; +static int do_exit_async = 0, frequencies = 0, events = 0; uint32_t frequency[MAX_PROTOCOLS]; time_t rawtime_old; int flag; -uint32_t samp_rate=DEFAULT_SAMPLE_RATE; +uint32_t samp_rate = DEFAULT_SAMPLE_RATE; static uint32_t bytes_to_read = 0; static rtlsdr_dev_t *dev = NULL; static uint16_t scaled_squares[256]; -static int debug_output = 0; static int override_short = 0; static int override_long = 0; +int debug_output = 0; -/* Supported modulation types */ -#define OOK_PWM_D 1 /* Pulses are of the same length, the distance varies */ -#define OOK_PWM_P 2 /* The length of the pulses varies */ - - -typedef struct { - unsigned int id; - char name[256]; - unsigned int modulation; - unsigned int short_limit; - unsigned int long_limit; - unsigned int reset_limit; - int (*json_callback)(uint8_t bits_buffer[BITBUF_ROWS][BITBUF_COLS]) ; -} r_device; - -static int debug_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS]) { +int debug_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]) { int i,j,k; int rows_used[BITBUF_ROWS]; int col_max = 0; @@ -201,712 +92,8 @@ static int debug_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS]) { return 0; } -static int silvercrest_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { - /* FIXME validate the received message better */ - if (bb[1][0] == 0xF8 && - bb[2][0] == 0xF8 && - bb[3][0] == 0xF8 && - bb[4][0] == 0xF8 && - bb[1][1] == 0x4d && - bb[2][1] == 0x4d && - bb[3][1] == 0x4d && - bb[4][1] == 0x4d) { - /* Pretty sure this is a Silvercrest remote */ - fprintf(stderr, "Remote button event:\n"); - fprintf(stderr, "model = Silvercrest, %d bits\n",bits_per_row[1]); - fprintf(stderr, "%02x %02x %02x %02x %02x\n",bb[1][0],bb[0][1],bb[0][2],bb[0][3],bb[0][4]); - - if (debug_output) - debug_callback(bb); - - return 1; - } - return 0; -} - -static int rubicson_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { - int temperature_before_dec; - int temperature_after_dec; - int16_t temp; - - /* FIXME validate the received message better, figure out crc */ - if (bb[1][0] == bb[2][0] && bb[2][0] == bb[3][0] && bb[3][0] == bb[4][0] && - bb[4][0] == bb[5][0] && bb[5][0] == bb[6][0] && bb[6][0] == bb[7][0] && bb[7][0] == bb[8][0] && - bb[8][0] == bb[9][0] && (bb[5][0] != 0 && bb[5][1] != 0 && bb[5][2] != 0)) { - - /* Nible 3,4,5 contains 12 bits of temperature - * The temerature is signed and scaled by 10 */ - temp = (int16_t)((uint16_t)(bb[0][1] << 12) | (bb[0][2] << 4)); - temp = temp >> 4; - - temperature_before_dec = abs(temp / 10); - temperature_after_dec = abs(temp % 10); - - fprintf(stderr, "Sensor temperature event:\n"); - fprintf(stderr, "protocol = Rubicson/Auriol, %d bits\n",bits_per_row[1]); - fprintf(stderr, "rid = %x\n",bb[0][0]); - fprintf(stderr, "temp = %s%d.%d\n",temp<0?"-":"",temperature_before_dec, temperature_after_dec); - fprintf(stderr, "%02x %02x %02x %02x %02x\n",bb[1][0],bb[0][1],bb[0][2],bb[0][3],bb[0][4]); - - if (debug_output) - debug_callback(bb); - - return 1; - } - return 0; -} - -static int prologue_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { - int rid; - - int16_t temp2; - - /* FIXME validate the received message better */ - if (((bb[1][0]&0xF0) == 0x90 && (bb[2][0]&0xF0) == 0x90 && (bb[3][0]&0xF0) == 0x90 && (bb[4][0]&0xF0) == 0x90 && - (bb[5][0]&0xF0) == 0x90 && (bb[6][0]&0xF0) == 0x90) || - ((bb[1][0]&0xF0) == 0x50 && (bb[2][0]&0xF0) == 0x50 && (bb[3][0]&0xF0) == 0x50 && (bb[4][0]&0xF0) == 0x50) && - (bb[1][3] == bb[2][3]) && (bb[1][4] == bb[2][4])) { - - /* Prologue sensor */ - temp2 = (int16_t)((uint16_t)(bb[1][2] << 8) | (bb[1][3]&0xF0)); - temp2 = temp2 >> 4; - fprintf(stderr, "Sensor temperature event:\n"); - fprintf(stderr, "protocol = Prologue, %d bits\n",bits_per_row[1]); - fprintf(stderr, "button = %d\n",bb[1][1]&0x04?1:0); - fprintf(stderr, "battery = %s\n",bb[1][1]&0x08?"Ok":"Low"); - fprintf(stderr, "temp = %s%d.%d\n",temp2<0?"-":"",abs((int16_t)temp2/10),abs((int16_t)temp2%10)); - fprintf(stderr, "humidity = %d\n", ((bb[1][3]&0x0F)<<4)|(bb[1][4]>>4)); - fprintf(stderr, "channel = %d\n",(bb[1][1]&0x03)+1); - fprintf(stderr, "id = %d\n",(bb[1][0]&0xF0)>>4); - rid = ((bb[1][0]&0x0F)<<4)|(bb[1][1]&0xF0)>>4; - fprintf(stderr, "rid = %d\n", rid); - fprintf(stderr, "hrid = %02x\n", rid); - - fprintf(stderr, "%02x %02x %02x %02x %02x\n",bb[1][0],bb[1][1],bb[1][2],bb[1][3],bb[1][4]); - - if (debug_output) - debug_callback(bb); - - return 1; - } - return 0; -} - -static int waveman_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { - /* Two bits map to 2 states, 0 1 -> 0 and 1 1 -> 1 */ - int i; - uint8_t nb[3] = {0}; - - if (((bb[0][0]&0x55)==0x55) && ((bb[0][1]&0x55)==0x55) && ((bb[0][2]&0x55)==0x55) && ((bb[0][3]&0x55)==0x00)) { - for (i=0 ; i<3 ; i++) { - nb[i] |= ((bb[0][i]&0xC0)==0xC0) ? 0x00 : 0x01; - nb[i] |= ((bb[0][i]&0x30)==0x30) ? 0x00 : 0x02; - nb[i] |= ((bb[0][i]&0x0C)==0x0C) ? 0x00 : 0x04; - nb[i] |= ((bb[0][i]&0x03)==0x03) ? 0x00 : 0x08; - } - - fprintf(stderr, "Remote button event:\n"); - fprintf(stderr, "model = Waveman Switch Transmitter, %d bits\n",bits_per_row[1]); - fprintf(stderr, "id = %c\n", 'A'+nb[0]); - fprintf(stderr, "channel = %d\n", (nb[1]>>2)+1); - fprintf(stderr, "button = %d\n", (nb[1]&3)+1); - fprintf(stderr, "state = %s\n", (nb[2]==0xe) ? "on" : "off"); - fprintf(stderr, "%02x %02x %02x\n",nb[0],nb[1],nb[2]); - - if (debug_output) - debug_callback(bb); - - return 1; - } - return 0; -} - -static int steffen_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { - - if (bb[0][0]==0x00 && ((bb[1][0]&0x07)==0x07) && bb[1][0]==bb[2][0] && bb[2][0]==bb[3][0]) { - - fprintf(stderr, "Remote button event:\n"); - fprintf(stderr, "model = Steffan Switch Transmitter, %d bits\n",bits_per_row[1]); - fprintf(stderr, "code = %d%d%d%d%d\n", (bb[1][0]&0x80)>>7, (bb[1][0]&0x40)>>6, (bb[1][0]&0x20)>>5, (bb[1][0]&0x10)>>4, (bb[1][0]&0x08)>>3); - - if ((bb[1][2]&0x0f)==0x0e) - fprintf(stderr, "button = A\n"); - else if ((bb[1][2]&0x0f)==0x0d) - fprintf(stderr, "button = B\n"); - else if ((bb[1][2]&0x0f)==0x0b) - fprintf(stderr, "button = C\n"); - else if ((bb[1][2]&0x0f)==0x07) - fprintf(stderr, "button = D\n"); - else if ((bb[1][2]&0x0f)==0x0f) - fprintf(stderr, "button = ALL\n"); - else - fprintf(stderr, "button = unknown\n"); - - if ((bb[1][2]&0xf0)==0xf0) { - fprintf(stderr, "state = OFF\n"); - } else { - fprintf(stderr, "state = ON\n"); - } - - if (debug_output) - debug_callback(bb); - - return 1; - } - return 0; -} - - -uint16_t AD_POP(uint8_t bb[BITBUF_COLS], uint8_t bits, uint8_t bit) { - uint16_t val = 0; - uint8_t i, byte_no, bit_no; - for (i=0;i=1&&dec[0]<=3?types[dec[0]-1]:"?"); - fprintf(stderr, "code = %d\n",dec[1]); - fprintf(stderr, "seqno = %d\n",dec[2]); - fprintf(stderr, "total cnt = %d\n",dec[3]|dec[4]<<8); - fprintf(stderr, "current cnt = %d\n",dec[5]|dec[6]<<8); - fprintf(stderr, "peak cnt = %d\n",dec[7]|dec[8]<<8); - - return 1; -} - -static int ws2000_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { - // based on http://www.dc3yc.privat.t-online.de/protocol.htm - uint8_t dec[13]; - uint8_t nibbles=0; - uint8_t bit=11; // preamble - char* types[]={"!AS3", "AS2000/ASH2000/S2000/S2001A/S2001IA/ASH2200/S300IA", "!S2000R", "!S2000W", "S2001I/S2001ID", "!S2500H", "!Pyrano", "!KS200/KS300"}; - uint8_t check_calculated=0, sum_calculated=0; - uint8_t i; - uint8_t stopbit; - uint8_t sum_received; - - dec[0] = AD_POP (bb[0], 4, bit); bit+=4; - stopbit= AD_POP (bb[0], 1, bit); bit+=1; - if (!stopbit) { -//fprintf(stderr, "!stopbit\n"); - return 0; - } - check_calculated ^= dec[0]; - sum_calculated += dec[0]; - - // read nibbles with stopbit ... - for (i = 1; i <= (dec[0]==4?12:8); i++) { - dec[i] = AD_POP (bb[0], 4, bit); bit+=4; - stopbit= AD_POP (bb[0], 1, bit); bit+=1; - if (!stopbit) { -//fprintf(stderr, "!stopbit %i\n", i); - return 0; - } - check_calculated ^= dec[i]; - sum_calculated += dec[i]; - nibbles++; - } - - if (check_calculated) { -//fprintf(stderr, "check_calculated (%d) != 0\n", check_calculated); - return 0; - } - - // Read sum - sum_received = AD_POP (bb[0], 4, bit); bit+=4; - sum_calculated+=5; - sum_calculated&=0xF; - if (sum_received != sum_calculated) { -//fprintf(stderr, "sum_received (%d) != sum_calculated (%d) ", sum_received, sum_calculated); - return 0; - } - -//for (i = 0; i < nibbles; i++) fprintf(stderr, "%02X ", dec[i]); fprintf(stderr, "\n"); - - fprintf(stderr, "Weather station sensor event:\n"); - fprintf(stderr, "protocol = ELV WS 2000, %d bits\n",bits_per_row[1]); - fprintf(stderr, "type (!=ToDo) = %s\n", dec[0]<=7?types[dec[0]]:"?"); - fprintf(stderr, "code = %d\n", dec[1]&7); - fprintf(stderr, "temp = %s%d.%d\n", dec[1]&8?"-":"", dec[4]*10+dec[3], dec[2]); - fprintf(stderr, "humidity = %d.%d\n", dec[7]*10+dec[6], dec[5]); - if(dec[0]==4) { - fprintf(stderr, "pressure = %d\n", 200+dec[10]*100+dec[9]*10+dec[8]); - } - - return 1; -} - -// ** Acurite 5n1 functions ** - -const float acurite_winddirections[] = - { 337.5, 315.0, 292.5, 270.0, 247.5, 225.0, 202.5, 180, - 157.5, 135.0, 112.5, 90.0, 67.5, 45.0, 22.5, 0.0 }; - -static int acurite_raincounter = 0; - -static int acurite_crc(uint8_t row[BITBUF_COLS], int cols) { - // sum of first n-1 bytes modulo 256 should equal nth byte - int i; - int sum = 0; - for ( i=0; i < cols; i++) - sum += row[i]; - if ( sum % 256 == row[cols] ) - return 1; - else - return 0; -} - -static int acurite_detect(uint8_t *pRow) { - int i; - if ( pRow[0] != 0x00 ) { - // invert bits due to wierd issue - for (i = 0; i < 8; i++) - pRow[i] = ~pRow[i] & 0xFF; - pRow[0] |= pRow[8]; // fix first byte that has mashed leading bit - - if (acurite_crc(pRow, 7)) - return 1; // passes crc check - } - return 0; -} - -static float acurite_getTemp (uint8_t highbyte, uint8_t lowbyte) { - // range -40 to 158 F - int highbits = (highbyte & 0x0F) << 7 ; - int lowbits = lowbyte & 0x7F; - int rawtemp = highbits | lowbits; - float temp = (rawtemp - 400) / 10.0; - return temp; -} - -static int acurite_getWindSpeed (uint8_t highbyte, uint8_t lowbyte) { - // range: 0 to 159 kph - int highbits = ( highbyte & 0x1F) << 3; - int lowbits = ( lowbyte & 0x70 ) >> 4; - int speed = highbits | lowbits; - return speed; -} - -static float acurite_getWindDirection (uint8_t byte) { - // 16 compass points, ccw from (NNW) to 15 (N) - int direction = byte & 0x0F; - return acurite_winddirections[direction]; -} - -static int acurite_getHumidity (uint8_t byte) { - // range: 1 to 99 %RH - int humidity = byte & 0x7F; - return humidity; -} - -static int acurite_getRainfallCounter (uint8_t highbyte, uint8_t lowbyte) { - // range: 0 to 99.99 in, 0.01 in incr., rolling counter? - int highbits = (highbyte & 0x3F) << 7 ; - int lowbits = lowbyte & 0x7F; - int raincounter = highbits | lowbits; - return raincounter; -} - -static int acurite5n1_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]) { - // acurite 5n1 weather sensor decoding for rtl_433 - // Jens Jensen 2014 - int i; - uint8_t *buf = NULL; - // run through rows til we find one with good crc (brute force) - for (i=0; i < BITBUF_ROWS; i++) { - if (acurite_detect(bb[i])) { - buf = bb[i]; - break; // done - } - } - - if (buf) { - // decode packet here - fprintf(stderr, "Detected Acurite 5n1 sensor, %d bits\n",bits_per_row[1]); - if (debug_output) { - for (i=0; i < 8; i++) - fprintf(stderr, "%02X ", buf[i]); - fprintf(stderr, "CRC OK\n"); - } - - if ((buf[2] & 0x0F) == 1) { - // wind speed, wind direction, rainfall - - float rainfall = 0.00; - int raincounter = acurite_getRainfallCounter(buf[5], buf[6]); - if (acurite_raincounter > 0) { - // track rainfall difference after first run - rainfall = ( raincounter - acurite_raincounter ) * 0.01; - } else { - // capture starting counter - acurite_raincounter = raincounter; - } - - fprintf(stderr, "wind speed: %d kph, ", - acurite_getWindSpeed(buf[3], buf[4])); - fprintf(stderr, "wind direction: %0.1f°, ", - acurite_getWindDirection(buf[4])); - fprintf(stderr, "rain gauge: %0.2f in.\n", rainfall); - - } else if ((buf[2] & 0x0F) == 8) { - // wind speed, temp, RH - fprintf(stderr, "wind speed: %d kph, ", - acurite_getWindSpeed(buf[3], buf[4])); - fprintf(stderr, "temp: %2.1f° F, ", - acurite_getTemp(buf[4], buf[5])); - fprintf(stderr, "humidity: %d%% RH\n", - acurite_getHumidity(buf[6])); - } - } - //if (debug_output) - // debug_callback(bb); - return 1; -} - -// buffer to hold localized timestamp YYYY-MM-DD HH:MM:SS -#define LOCAL_TIME_BUFLEN 32 - -void local_time_str(time_t time_secs, char *buf) { - time_t etime; - struct tm *tm_info; - - if (time_secs == 0) { - time(&etime); - } else { - etime = time_secs; - } - - tm_info = localtime(&etime); - - strftime(buf, LOCAL_TIME_BUFLEN, "%Y-%m-%d %H:%M:%S", tm_info); -} - - - -// Check for a valid LaCrosse Packet -// -// written for the version of pwm_p_decode() (OOK_PWM_P) -// pulse width detector with two anomalys: -// 1. bits are inverted -// 2. The first bit is discarded as a start bit -// -// If a fixed pulse width decoder is used this -// routine will need to be changed. -static int lacrossetx_detect(uint8_t *pRow, uint8_t *msg_nybbles) { - int i; - uint8_t rbyte_no, rbit_no, mnybble_no, mbit_no; - uint8_t bit, checksum, parity_bit, parity = 0; - - // Actual Packet should start with 0x0A and be 6 bytes - // actual message is 44 bit, 11 x 4 bit nybbles. - if ( ( pRow[0] & 0xFE ) == 0x14 && - pRow[6] == 0 && pRow[7] == 0 ) { - - - for ( i = 0 ; i < 11 ; i++ ) { - msg_nybbles[i] = 0; - } - - // Move nybbles into a byte array - // shifted by one to compensate for loss of first bit. - for ( i = 0 ; i < 43 ; i++ ) { - rbyte_no = i/8; - rbit_no = 7 - ( i % 8 ); - mnybble_no = ( i + 1 )/4; - mbit_no = 3 - (( i + 1 ) % 4); - bit = ( pRow[rbyte_no] & ( 1 << rbit_no )) ? 1 : 0; - msg_nybbles[mnybble_no] |= ( bit << mbit_no ); - - // Check parity on three bytes of data value - // TX3U might calculate parity on all data including - // sensor id and redundant integer data - if ( mnybble_no > 4 && mnybble_no < 8 ) { - parity += bit; - } - - // fprintf(stderr, "recv: [%d/%d] %d -> msg [%d/%d] %02x, Parity: %d %s\n", rbyte_no, rbit_no, - // bit, mnybble_no, mbit_no, msg_nybbles[mnybble_no], parity, - // ( mbit_no == 0 ) ? "\n" : "" ); - } - - parity_bit = msg_nybbles[4] & 0x01; - parity += parity_bit; - - // Validate Checksum (4 bits in last nybble) - checksum = 0; - for ( i = 0 ; i < 10 ; i++ ) { - checksum = (checksum + msg_nybbles[i]) & 0x0F; - } - - // fprintf(stderr,"Parity: %d, parity bit %d, Good %d\n", parity, parity_bit, parity % 2); - - - if ( checksum == msg_nybbles[10] && ( parity % 2 == 0 ) ) { - return 1; - } else { - fprintf(stderr,"LaCrosse Checksum/Parity error: %d != %d, Parity %d\n", - checksum, msg_nybbles[10], parity); - return 0; - } - } - - - return 0; -} - - - -// LaCrosse TX-6u, TX-7u, Temperature and Humidity Sensors -// Temperature and Humidity are sent in different messages bursts. -static int lacrossetx_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS]) { - - int i, m, valid = 0; - uint8_t *buf; - uint8_t msg_nybbles[11]; - uint8_t sensor_id, msg_type, msg_len, msg_parity, msg_checksum; - int msg_value_int; - float msg_value = 0, temp_c = 0, temp_f = 0; - time_t time_now; - char time_str[25]; - - static float last_msg_value = 0.0; - static uint8_t last_sensor_id = 0; - static uint8_t last_msg_type = 0; - static time_t last_msg_time = 0; - - for ( m = 0; m < BITBUF_ROWS ; m++ ) { - valid = 0; - if ( lacrossetx_detect(bb[m], msg_nybbles) ) { - - msg_len = msg_nybbles[1]; - msg_type = msg_nybbles[2]; - sensor_id = (msg_nybbles[3] << 3) + (msg_nybbles[4] >> 1); - msg_parity = msg_nybbles[4] & 0x01; - msg_value = msg_nybbles[5] * 10 + msg_nybbles[6] + - msg_nybbles[7] / 10.0; - msg_value_int = msg_nybbles[8] * 10 + msg_nybbles[9]; - msg_checksum = msg_nybbles[10]; - - - time(&time_now); - - // suppress duplicates - if ( sensor_id == last_sensor_id && msg_type == last_msg_type && - last_msg_value == msg_value && - time_now - last_msg_time < 50 ) { - continue; - } - - local_time_str(time_now, time_str); - - switch (msg_type) { - case 0x00: - temp_c = msg_value - 50.0; - temp_f = temp_c * 1.8 + 32; - printf("%s LaCrosse TX Sensor %02x: Temperature %3.1f C / %3.1f F\n", - time_str, sensor_id, temp_c, temp_f); - break; - - case 0x0E: - printf("%s LaCrosse TX Sensor %02x: Humidity %3.1f%%\n", - time_str, sensor_id, msg_value); - break; - - default: - fprintf(stderr,"%s LaCrosse Sensor %02x: Unknown Reading % 3.1f (%d)\n", - time_str, sensor_id, msg_value, msg_value_int); - } - - time(&last_msg_time); - last_msg_value = msg_value; - last_msg_type = msg_type; - last_sensor_id = sensor_id; - - - } else { - // fprintf(stderr,"Not a valid LaCrosse msg row %d\n",m); - } - } - - - if (debug_output) - debug_callback(bb); - return 1; -} - - - -// timings based on samp_rate=1024000 -r_device rubicson = { - /* .id = */ 1, - /* .name = */ "Rubicson Temperature Sensor", - /* .modulation = */ OOK_PWM_D, - /* .short_limit = */ 1744/4, - /* .long_limit = */ 3500/4, - /* .reset_limit = */ 5000/4, - /* .json_callback = */ &rubicson_callback, -}; - -r_device prologue = { - /* .id = */ 2, - /* .name = */ "Prologue Temperature Sensor", - /* .modulation = */ OOK_PWM_D, - /* .short_limit = */ 3500/4, - /* .long_limit = */ 7000/4, - /* .reset_limit = */ 15000/4, - /* .json_callback = */ &prologue_callback, -}; - -r_device silvercrest = { - /* .id = */ 3, - /* .name = */ "Silvercrest Remote Control", - /* .modulation = */ OOK_PWM_P, - /* .short_limit = */ 600/4, - /* .long_limit = */ 5000/4, - /* .reset_limit = */ 15000/4, - /* .json_callback = */ &silvercrest_callback, -}; - -r_device tech_line_fws_500 = { - /* .id = */ 4, - /* .name = */ "Tech Line FWS-500 Sensor", - /* .modulation = */ OOK_PWM_D, - /* .short_limit = */ 3500/4, - /* .long_limit = */ 7000/4, - /* .reset_limit = */ 15000/4, - // /* .json_callback = */ &rubicson_callback, -}; - -r_device generic_hx2262 = { - /* .id = */ 5, - /* .name = */ "Window/Door sensor", - /* .modulation = */ OOK_PWM_P, - /* .short_limit = */ 1300/4, - /* .long_limit = */ 10000/4, - /* .reset_limit = */ 40000/4, - // /* .json_callback = */ &silvercrest_callback, -}; - -r_device technoline_ws9118 = { - /* .id = */ 6, - /* .name = */ "Technoline WS9118", - /* .modulation = */ OOK_PWM_D, - /* .short_limit = */ 1800/4, - /* .long_limit = */ 3500/4, - /* .reset_limit = */ 15000/4, - /* .json_callback = */ &debug_callback, -}; - - -r_device elv_em1000 = { - /* .id = */ 7, - /* .name = */ "ELV EM 1000", - /* .modulation = */ OOK_PWM_D, - /* .short_limit = */ 750/4, - /* .long_limit = */ 7250/4, - /* .reset_limit = */ 30000/4, - /* .json_callback = */ &em1000_callback, -}; - -r_device elv_ws2000 = { - /* .id = */ 8, - /* .name = */ "ELV WS 2000", - /* .modulation = */ OOK_PWM_D, - /* .short_limit = */ (602+(1155-602)/2)/4, - /* .long_limit = */ ((1755635-1655517)/2)/4, // no repetitions - /* .reset_limit = */ ((1755635-1655517)*2)/4, - /* .json_callback = */ &ws2000_callback, -}; - -r_device waveman = { - /* .id = */ 6, - /* .name = */ "Waveman Switch Transmitter", - /* .modulation = */ OOK_PWM_P, - /* .short_limit = */ 1000/4, - /* .long_limit = */ 8000/4, - /* .reset_limit = */ 30000/4, - /* .json_callback = */ &waveman_callback, -}; - -r_device steffen = { - /* .id = */ 9, - /* .name = */ "Steffen Switch Transmitter", - /* .modulation = */ OOK_PWM_D, - /* .short_limit = */ 140, - /* .long_limit = */ 270, - /* .reset_limit = */ 1500, - /* .json_callback = */ &steffen_callback, -}; - -r_device acurite5n1 = { - /* .id = */ 10, - /* .name = */ "Acurite 5n1 Weather Station", - /* .modulation = */ OOK_PWM_P, - /* .short_limit = */ 75, - /* .long_limit = */ 220, - /* .reset_limit = */ 20000, - /* .json_callback = */ &acurite5n1_callback, -}; - -r_device lacrossetx = { - /* .id = */ 11, - /* .name = */ "LaCrosse TX Temperature / Humidity Sensor", - /* .modulation = */ OOK_PWM_P, - /* .short_limit = */ 238, - /* .long_limit = */ 750, - /* .reset_limit = */ 8000, - /* .json_callback = */ &lacrossetx_callback, -}; - struct protocol_state { - int (*callback)(uint8_t bits_buffer[BITBUF_ROWS][BITBUF_COLS],int16_t bits_per_row[BITBUF_ROWS]); + int (*callback)(uint8_t bits_buffer[BITBUF_ROWS][BITBUF_COLS], int16_t bits_per_row[BITBUF_ROWS]); /* bits state */ int bits_col_idx; @@ -914,7 +101,7 @@ struct protocol_state { int bits_bit_col_idx; uint8_t bits_buffer[BITBUF_ROWS][BITBUF_COLS]; int16_t bits_per_row[BITBUF_ROWS]; - int bit_rows; + int bit_rows; unsigned int modulation; /* demod state */ @@ -936,13 +123,12 @@ struct protocol_state { }; - struct dm_state { FILE *file; int save_data; int32_t level_limit; int32_t decimation_level; - int16_t filter_buffer[MAXIMAL_BUF_LENGTH+FILTER_ORDER]; + int16_t filter_buffer[MAXIMAL_BUF_LENGTH + FILTER_ORDER]; int16_t* f_buf; int analyze; int debug_mode; @@ -960,33 +146,32 @@ struct dm_state { }; -void usage(void) -{ +void usage(void) { fprintf(stderr, - "rtl_433, an ISM band generic data receiver for RTL2832 based DVB-T receivers\n\n" - "Usage:\t[-d device_index (default: 0)]\n" - "\t[-g gain (default: 0 for auto)]\n" - "\t[-a analyze mode, print a textual description of the signal]\n" - "\t[-t signal auto save, use it together with analyze mode (-a -t)\n" - "\t[-l change the detection level used to determine pulses (0-3200) default: %i]\n" - "\t[-f [-f...] receive frequency[s], default: %i Hz]\n" - "\t[-s samplerate (default: %i Hz)]\n" - "\t[-S force sync output (default: async)]\n" - "\t[-r read data from file instead of from a receiver]\n" - "\t[-p ppm_error (default: 0)]\n" - "\t[-r test file name (indata)]\n" - "\t[-m test file mode (0 rtl_sdr data, 1 rtl_433 data)]\n" - "\t[-D print debug info on event\n" - "\t[-z override short value\n" - "\t[-x override long value\n" - "\tfilename (a '-' dumps samples to stdout)\n\n", DEFAULT_LEVEL_LIMIT, DEFAULT_FREQUENCY, DEFAULT_SAMPLE_RATE); + "rtl_433, an ISM band generic data receiver for RTL2832 based DVB-T receivers\n\n" + "Usage:\t[-d device_index (default: 0)]\n" + "\t[-g gain (default: 0 for auto)]\n" + "\t[-a analyze mode, print a textual description of the signal]\n" + "\t[-t signal auto save, use it together with analyze mode (-a -t)\n" + "\t[-l change the detection level used to determine pulses (0-3200) default: %i]\n" + "\t[-f [-f...] receive frequency[s], default: %i Hz]\n" + "\t[-s samplerate (default: %i Hz)]\n" + "\t[-S force sync output (default: async)]\n" + "\t[-r read data from file instead of from a receiver]\n" + "\t[-p ppm_error (default: 0)]\n" + "\t[-r test file name (indata)]\n" + "\t[-m test file mode (0 rtl_sdr data, 1 rtl_433 data)]\n" + "\t[-D print debug info on event\n" + "\t[-z override short value\n" + "\t[-x override long value\n" + "\tfilename (a '-' dumps samples to stdout)\n\n", DEFAULT_LEVEL_LIMIT, DEFAULT_FREQUENCY, DEFAULT_SAMPLE_RATE); exit(1); } #ifdef _WIN32 + BOOL WINAPI -sighandler(int signum) -{ +sighandler(int signum) { if (CTRL_C_EVENT == signum) { fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; @@ -996,13 +181,9 @@ sighandler(int signum) return FALSE; } #else -static void sighandler(int signum) -{ - if (signum == SIGPIPE) { - signal(SIGPIPE,SIG_IGN); - } else { - fprintf(stderr, "Signal caught, exiting!\n"); - } + +static void sighandler(int signum) { + fprintf(stderr, "Signal caught, exiting!\n"); do_exit = 1; rtlsdr_cancel_async(dev); } @@ -1011,8 +192,8 @@ static void sighandler(int signum) /* precalculate lookup table for envelope detection */ static void calc_squares() { int i; - for (i=0 ; i<256 ; i++) - scaled_squares[i] = (128-i) * (128-i); + for (i = 0; i < 256; i++) + scaled_squares[i] = (128 - i) * (128 - i); } /** This will give a noisy envelope of OOK/ASK signals @@ -1021,21 +202,20 @@ static void calc_squares() { * @returns pointer to the input buffer */ -static void envelope_detect(unsigned char *buf, uint32_t len, int decimate) -{ +static void envelope_detect(unsigned char *buf, uint32_t len, int decimate) { uint16_t* sample_buffer = (uint16_t*) buf; unsigned int i; unsigned op = 0; - unsigned int stride = 1<bits_buffer, 0 ,BITBUF_ROWS*BITBUF_COLS); - memset(p->bits_per_row, 0 ,BITBUF_ROWS); + memset(p->bits_buffer, 0, BITBUF_ROWS * BITBUF_COLS); + memset(p->bits_per_row, 0, BITBUF_ROWS); p->bits_col_idx = 0; p->bits_bit_col_idx = 7; p->bits_row_idx = 0; @@ -1043,14 +223,14 @@ static void demod_reset_bits_packet(struct protocol_state* p) { } static void demod_add_bit(struct protocol_state* p, int bit) { - p->bits_buffer[p->bits_row_idx][p->bits_col_idx] |= bit<bits_bit_col_idx; + p->bits_buffer[p->bits_row_idx][p->bits_col_idx] |= bit << p->bits_bit_col_idx; p->bits_bit_col_idx--; - if (p->bits_bit_col_idx<0) { + if (p->bits_bit_col_idx < 0) { p->bits_bit_col_idx = 7; p->bits_col_idx++; - if (p->bits_col_idx>BITBUF_COLS-1) { - p->bits_col_idx = BITBUF_COLS-1; -// fprintf(stderr, "p->bits_col_idx>%i!\n", BITBUF_COLS-1); + if (p->bits_col_idx > BITBUF_COLS - 1) { + p->bits_col_idx = BITBUF_COLS - 1; + // fprintf(stderr, "p->bits_col_idx>%i!\n", BITBUF_COLS-1); } } p->bits_per_row[p->bit_rows]++; @@ -1060,33 +240,33 @@ static void demod_next_bits_packet(struct protocol_state* p) { p->bits_col_idx = 0; p->bits_row_idx++; p->bits_bit_col_idx = 7; - if (p->bits_row_idx>BITBUF_ROWS-1) { - p->bits_row_idx = BITBUF_ROWS-1; + if (p->bits_row_idx > BITBUF_ROWS - 1) { + p->bits_row_idx = BITBUF_ROWS - 1; //fprintf(stderr, "p->bits_row_idx>%i!\n", BITBUF_ROWS-1); } p->bit_rows++; - if (p->bit_rows > BITBUF_ROWS-1) - p->bit_rows -=1; + if (p->bit_rows > BITBUF_ROWS - 1) + p->bit_rows -= 1; } static void demod_print_bits_packet(struct protocol_state* p) { - int i,j,k; + int i, j, k; fprintf(stderr, "\n"); - for (i=0 ; ibit_rows+1 ; i++) { - fprintf(stderr, "[%02d] {%d} ",i, p->bits_per_row[i]); - for (j=0 ; j<((p->bits_per_row[i]+8)/8) ; j++) { - fprintf(stderr, "%02x ", p->bits_buffer[i][j]); + for (i = 0; i < p->bit_rows + 1; i++) { + fprintf(stderr, "[%02d] {%d} ", i, p->bits_per_row[i]); + for (j = 0; j < ((p->bits_per_row[i] + 8) / 8); j++) { + fprintf(stderr, "%02x ", p->bits_buffer[i][j]); } fprintf(stderr, ": "); - for (j=0 ; j<((p->bits_per_row[i]+8)/8) ; j++) { - for (k=7 ; k>=0 ; k--) { - if (p->bits_buffer[i][j] & 1<bits_per_row[i] + 8) / 8); j++) { + for (k = 7; k >= 0; k--) { + if (p->bits_buffer[i][j] & 1 << k) fprintf(stderr, "1"); else fprintf(stderr, "0"); } -// fprintf(stderr, "=0x%x ",demod->bits_buffer[i][j]); + // fprintf(stderr, "=0x%x ",demod->bits_buffer[i][j]); fprintf(stderr, " "); } fprintf(stderr, "\n"); @@ -1096,21 +276,21 @@ static void demod_print_bits_packet(struct protocol_state* p) { } static void register_protocol(struct dm_state *demod, r_device *t_dev) { - struct protocol_state *p = calloc(1,sizeof(struct protocol_state)); - p->short_limit = (float)t_dev->short_limit/((float)DEFAULT_SAMPLE_RATE/(float)samp_rate); - p->long_limit = (float)t_dev->long_limit /((float)DEFAULT_SAMPLE_RATE/(float)samp_rate); - p->reset_limit = (float)t_dev->reset_limit/((float)DEFAULT_SAMPLE_RATE/(float)samp_rate); - p->modulation = t_dev->modulation; - p->callback = t_dev->json_callback; + struct protocol_state *p = calloc(1, sizeof (struct protocol_state)); + p->short_limit = (float) t_dev->short_limit / ((float) DEFAULT_SAMPLE_RATE / (float) samp_rate); + p->long_limit = (float) t_dev->long_limit / ((float) DEFAULT_SAMPLE_RATE / (float) samp_rate); + p->reset_limit = (float) t_dev->reset_limit / ((float) DEFAULT_SAMPLE_RATE / (float) samp_rate); + p->modulation = t_dev->modulation; + p->callback = t_dev->json_callback; demod_reset_bits_packet(p); demod->r_devs[demod->r_dev_num] = p; demod->r_dev_num++; - fprintf(stderr, "Registering protocol[%02d] %s\n",demod->r_dev_num, t_dev->name); + fprintf(stderr, "Registering protocol[%02d] %s\n", demod->r_dev_num, t_dev->name); if (demod->r_dev_num > MAX_PROTOCOLS) - fprintf(stderr, "Max number of protocols reached %d\n",MAX_PROTOCOLS); + fprintf(stderr, "Max number of protocols reached %d\n", MAX_PROTOCOLS); } @@ -1123,13 +303,13 @@ static unsigned int pulse_start = 0; static unsigned int pulse_end = 0; static unsigned int pulse_avg = 0; static unsigned int signal_start = 0; -static unsigned int signal_end = 0; -static unsigned int signal_pulse_data[4000][3] = {{0}}; +static unsigned int signal_end = 0; +static unsigned int signal_pulse_data[4000][3] = { + {0}}; static unsigned int signal_pulse_counter = 0; - static void classify_signal() { - unsigned int i,k, max=0, min=1000000, t; + unsigned int i, k, max = 0, min = 1000000, t; unsigned int delta, count_min, count_max, min_new, max_new, p_limit; unsigned int a[3], b[2], a_cnt[3], a_new[3], b_new[2]; unsigned int signal_distance_data[4000] = {0}; @@ -1139,7 +319,7 @@ static void classify_signal() { if (!signal_pulse_data[0][0]) return; - for (i=0 ; i<1000 ; i++) { + for (i = 0; i < 1000; i++) { if (signal_pulse_data[i][0] > 0) { //fprintf(stderr, "[%03d] s: %d\t e:\t %d\t l:%d\n", //i, signal_pulse_data[i][0], signal_pulse_data[i][1], @@ -1150,24 +330,25 @@ static void classify_signal() { min = signal_pulse_data[i][2]; } } - t=(max+min)/2; + t = (max + min) / 2; //fprintf(stderr, "\n\nMax: %d, Min: %d t:%d\n", max, min, t); - delta = (max - min)*(max-min); + delta = (max - min)*(max - min); //TODO use Lloyd-Max quantizer instead - k=1; - while((k < 10) && (delta > 0)) { - min_new = 0; count_min = 0; - max_new = 0; count_max = 0; + k = 1; + while ((k < 10) && (delta > 0)) { + min_new = 0; + count_min = 0; + max_new = 0; + count_max = 0; - for (i=0 ; i < 1000 ; i++) { + for (i = 0; i < 1000; i++) { if (signal_pulse_data[i][0] > 0) { if (signal_pulse_data[i][2] < t) { min_new = min_new + signal_pulse_data[i][2]; count_min++; - } - else { + } else { max_new = max_new + signal_pulse_data[i][2]; count_max++; } @@ -1181,67 +362,67 @@ static void classify_signal() { delta = (min - min_new)*(min - min_new) + (max - max_new)*(max - max_new); min = min_new; max = max_new; - t = (min + max)/2; + t = (min + max) / 2; - fprintf(stderr, "Iteration %d. t: %d min: %d (%d) max: %d (%d) delta %d\n", k,t, min, count_min, max, count_max, delta); + fprintf(stderr, "Iteration %d. t: %d min: %d (%d) max: %d (%d) delta %d\n", k, t, min, count_min, max, count_max, delta); k++; } - for (i=0 ; i<1000 ; i++) { + for (i = 0; i < 1000; i++) { if (signal_pulse_data[i][0] > 0) { //fprintf(stderr, "%d\n", signal_pulse_data[i][1]); } } /* 50% decision limit */ - if (min != 0 && max/min > 1) { + if (max / min > 1) { fprintf(stderr, "Pulse coding: Short pulse length %d - Long pulse length %d\n", min, max); signal_type = 2; } else { - fprintf(stderr, "Distance coding: Pulse length %d\n", (min+max)/2); + fprintf(stderr, "Distance coding: Pulse length %d\n", (min + max) / 2); signal_type = 1; } - p_limit = (max+min)/2; + p_limit = (max + min) / 2; /* Initial guesses */ a[0] = 1000000; a[2] = 0; - for (i=1 ; i<1000 ; i++) { + for (i = 1; i < 1000; i++) { if (signal_pulse_data[i][0] > 0) { -// fprintf(stderr, "[%03d] s: %d\t e:\t %d\t l:%d\t d:%d\n", -// i, signal_pulse_data[i][0], signal_pulse_data[i][1], -// signal_pulse_data[i][2], signal_pulse_data[i][0]-signal_pulse_data[i-1][1]); - signal_distance_data[i-1] = signal_pulse_data[i][0]-signal_pulse_data[i-1][1]; - if (signal_distance_data[i-1] > a[2]) - a[2] = signal_distance_data[i-1]; - if (signal_distance_data[i-1] <= a[0]) - a[0] = signal_distance_data[i-1]; + // fprintf(stderr, "[%03d] s: %d\t e:\t %d\t l:%d\t d:%d\n", + // i, signal_pulse_data[i][0], signal_pulse_data[i][1], + // signal_pulse_data[i][2], signal_pulse_data[i][0]-signal_pulse_data[i-1][1]); + signal_distance_data[i - 1] = signal_pulse_data[i][0] - signal_pulse_data[i - 1][1]; + if (signal_distance_data[i - 1] > a[2]) + a[2] = signal_distance_data[i - 1]; + if (signal_distance_data[i - 1] <= a[0]) + a[0] = signal_distance_data[i - 1]; } } min = a[0]; max = a[2]; - a[1] = (a[0]+a[2])/2; -// for (i=0 ; i<1 ; i++) { -// b[i] = (a[i]+a[i+1])/2; -// } - b[0] = (a[0]+a[1])/2; - b[1] = (a[1]+a[2])/2; -// fprintf(stderr, "a[0]: %d\t a[1]: %d\t a[2]: %d\t\n",a[0],a[1],a[2]); -// fprintf(stderr, "b[0]: %d\t b[1]: %d\n",b[0],b[1]); + a[1] = (a[0] + a[2]) / 2; + // for (i=0 ; i<1 ; i++) { + // b[i] = (a[i]+a[i+1])/2; + // } + b[0] = (a[0] + a[1]) / 2; + b[1] = (a[1] + a[2]) / 2; + // fprintf(stderr, "a[0]: %d\t a[1]: %d\t a[2]: %d\t\n",a[0],a[1],a[2]); + // fprintf(stderr, "b[0]: %d\t b[1]: %d\n",b[0],b[1]); - k=1; + k = 1; delta = 10000000; - while((k < 10) && (delta > 0)) { - for (i=0 ; i<3 ; i++) { + while ((k < 10) && (delta > 0)) { + for (i = 0; i < 3; i++) { a_new[i] = 0; a_cnt[i] = 0; } - for (i=0 ; i < 1000 ; i++) { + for (i = 0; i < 1000; i++) { if (signal_distance_data[i] > 0) { if (signal_distance_data[i] < b[0]) { a_new[0] += signal_distance_data[i]; a_cnt[0]++; - } else if (signal_distance_data[i] < b[1] && signal_distance_data[i] >= b[0]){ + } else if (signal_distance_data[i] < b[1] && signal_distance_data[i] >= b[0]) { a_new[1] += signal_distance_data[i]; a_cnt[1]++; } else if (signal_distance_data[i] >= b[1]) { @@ -1251,37 +432,37 @@ static void classify_signal() { } } -// fprintf(stderr, "Iteration %d.", k); + // fprintf(stderr, "Iteration %d.", k); delta = 0; - for (i=0 ; i<3 ; i++) { + for (i = 0; i < 3; i++) { if (a_cnt[i]) a_new[i] /= a_cnt[i]; - delta += (a[i]-a_new[i])*(a[i]-a_new[i]); -// fprintf(stderr, "\ta[%d]: %d (%d)", i, a_new[i], a[i]); + delta += (a[i] - a_new[i])*(a[i] - a_new[i]); + // fprintf(stderr, "\ta[%d]: %d (%d)", i, a_new[i], a[i]); a[i] = a_new[i]; } -// fprintf(stderr, " delta %d\n", delta); + // fprintf(stderr, " delta %d\n", delta); if (a[0] < min) { a[0] = min; -// fprintf(stderr, "Fixing a[0] = %d\n", min); + // fprintf(stderr, "Fixing a[0] = %d\n", min); } if (a[2] > max) { a[0] = max; -// fprintf(stderr, "Fixing a[2] = %d\n", max); + // fprintf(stderr, "Fixing a[2] = %d\n", max); } -// if (a[1] == 0) { -// a[1] = (a[2]+a[0])/2; -// fprintf(stderr, "Fixing a[1] = %d\n", a[1]); -// } + // if (a[1] == 0) { + // a[1] = (a[2]+a[0])/2; + // fprintf(stderr, "Fixing a[1] = %d\n", a[1]); + // } -// fprintf(stderr, "Iteration %d.", k); - for (i=0 ; i<2 ; i++) { -// fprintf(stderr, "\tb[%d]: (%d) ", i, b[i]); - b[i] = (a[i]+a[i+1])/2; -// fprintf(stderr, "%d ", b[i]); + // fprintf(stderr, "Iteration %d.", k); + for (i = 0; i < 2; i++) { + // fprintf(stderr, "\tb[%d]: (%d) ", i, b[i]); + b[i] = (a[i] + a[i + 1]) / 2; + // fprintf(stderr, "%d ", b[i]); } -// fprintf(stderr, "\n"); + // fprintf(stderr, "\n"); k++; } @@ -1294,41 +475,41 @@ static void classify_signal() { a[1] = override_long; } - fprintf(stderr, "\nShort distance: %d, long distance: %d, packet distance: %d\n",a[0],a[1],a[2]); - fprintf(stderr, "\np_limit: %d\n",p_limit); + fprintf(stderr, "\nShort distance: %d, long distance: %d, packet distance: %d\n", a[0], a[1], a[2]); + fprintf(stderr, "\np_limit: %d\n", p_limit); demod_reset_bits_packet(&p); if (signal_type == 1) { - for(i=0 ; i<1000 ; i++){ + for (i = 0; i < 1000; i++) { if (signal_distance_data[i] > 0) { - if (signal_distance_data[i] < (a[0]+a[1])/2) { -// fprintf(stderr, "0 [%d] %d < %d\n",i, signal_distance_data[i], (a[0]+a[1])/2); + if (signal_distance_data[i] < (a[0] + a[1]) / 2) { + // fprintf(stderr, "0 [%d] %d < %d\n",i, signal_distance_data[i], (a[0]+a[1])/2); demod_add_bit(&p, 0); - } else if ((signal_distance_data[i] > (a[0]+a[1])/2) && (signal_distance_data[i] < (a[1]+a[2])/2)) { -// fprintf(stderr, "0 [%d] %d > %d\n",i, signal_distance_data[i], (a[0]+a[1])/2); + } else if ((signal_distance_data[i] > (a[0] + a[1]) / 2) && (signal_distance_data[i] < (a[1] + a[2]) / 2)) { + // fprintf(stderr, "0 [%d] %d > %d\n",i, signal_distance_data[i], (a[0]+a[1])/2); demod_add_bit(&p, 1); - } else if (signal_distance_data[i] > (a[1]+a[2])/2) { -// fprintf(stderr, "0 [%d] %d > %d\n",i, signal_distance_data[i], (a[1]+a[2])/2); + } else if (signal_distance_data[i] > (a[1] + a[2]) / 2) { + // fprintf(stderr, "0 [%d] %d > %d\n",i, signal_distance_data[i], (a[1]+a[2])/2); demod_next_bits_packet(&p); } - } + } } demod_print_bits_packet(&p); } if (signal_type == 2) { - for(i=0 ; i<1000 ; i++){ - if(signal_pulse_data[i][2] > 0) { + for (i = 0; i < 1000; i++) { + if (signal_pulse_data[i][2] > 0) { if (signal_pulse_data[i][2] < p_limit) { -// fprintf(stderr, "0 [%d] %d < %d\n",i, signal_pulse_data[i][2], p_limit); + // fprintf(stderr, "0 [%d] %d < %d\n",i, signal_pulse_data[i][2], p_limit); demod_add_bit(&p, 0); } else { -// fprintf(stderr, "1 [%d] %d > %d\n",i, signal_pulse_data[i][2], p_limit); + // fprintf(stderr, "1 [%d] %d > %d\n",i, signal_pulse_data[i][2], p_limit); demod_add_bit(&p, 1); } - if ((signal_distance_data[i] >= (a[1]+a[2])/2)) { -// fprintf(stderr, "\\n [%d] %d > %d\n",i, signal_distance_data[i], (a[1]+a[2])/2); + if ((signal_distance_data[i] >= (a[1] + a[2]) / 2)) { + // fprintf(stderr, "\\n [%d] %d > %d\n",i, signal_distance_data[i], (a[1]+a[2])/2); demod_next_bits_packet(&p); } @@ -1338,7 +519,7 @@ static void classify_signal() { demod_print_bits_packet(&p); } - for (i=0 ; i<1000 ; i++) { + for (i = 0; i < 1000; i++) { signal_pulse_data[i][0] = 0; signal_pulse_data[i][1] = 0; signal_pulse_data[i][2] = 0; @@ -1347,12 +528,10 @@ static void classify_signal() { }; - -static void pwm_analyze(struct dm_state *demod, int16_t *buf, uint32_t len) -{ +static void pwm_analyze(struct dm_state *demod, int16_t *buf, uint32_t len) { unsigned int i; - for (i=0 ; i demod->level_limit) { if (!signal_start) signal_start = counter; @@ -1362,24 +541,24 @@ static void pwm_analyze(struct dm_state *demod, int16_t *buf, uint32_t len) signal_pulse_data[signal_pulse_counter][0] = counter; signal_pulse_data[signal_pulse_counter][1] = -1; signal_pulse_data[signal_pulse_counter][2] = -1; - if (debug_output) fprintf(stderr, "pulse_distance %d\n",counter-pulse_end); - if (debug_output) fprintf(stderr, "pulse_start distance %d\n",pulse_start-prev_pulse_start); - if (debug_output) fprintf(stderr, "pulse_start[%d] found at sample %d, value = %d\n",pulses_found, counter, buf[i]); + if (debug_output) fprintf(stderr, "pulse_distance %d\n", counter - pulse_end); + if (debug_output) fprintf(stderr, "pulse_start distance %d\n", pulse_start - prev_pulse_start); + if (debug_output) fprintf(stderr, "pulse_start[%d] found at sample %d, value = %d\n", pulses_found, counter, buf[i]); prev_pulse_start = pulse_start; - print =0; + print = 0; print2 = 1; } } counter++; if (buf[i] < demod->level_limit) { if (print2) { - pulse_avg += counter-pulse_start; + pulse_avg += counter - pulse_start; if (debug_output) fprintf(stderr, "pulse_end [%d] found at sample %d, pulse length = %d, pulse avg length = %d\n", - pulses_found, counter, counter-pulse_start, pulse_avg/pulses_found); + pulses_found, counter, counter - pulse_start, pulse_avg / pulses_found); pulse_end = counter; print2 = 0; signal_pulse_data[signal_pulse_counter][1] = counter; - signal_pulse_data[signal_pulse_counter][2] = counter-pulse_start; + signal_pulse_data[signal_pulse_counter][2] = counter - pulse_start; signal_pulse_counter++; if (signal_pulse_counter >= 4000) { signal_pulse_counter = 0; @@ -1389,37 +568,37 @@ static void pwm_analyze(struct dm_state *demod, int16_t *buf, uint32_t len) print = 1; if (signal_start && (pulse_end + 50000 < counter)) { signal_end = counter - 40000; - fprintf(stderr, "*** signal_start = %d, signal_end = %d\n",signal_start-10000, signal_end); - fprintf(stderr, "signal_len = %d, pulses = %d\n", signal_end-(signal_start-10000), pulses_found); + fprintf(stderr, "*** signal_start = %d, signal_end = %d\n", signal_start - 10000, signal_end); + fprintf(stderr, "signal_len = %d, pulses = %d\n", signal_end - (signal_start - 10000), pulses_found); pulses_found = 0; classify_signal(); signal_pulse_counter = 0; if (demod->sg_buf) { - int start_pos, signal_bszie, wlen, wrest=0, sg_idx, idx; + int start_pos, signal_bszie, wlen, wrest = 0, sg_idx, idx; char sgf_name[256] = {0}; FILE *sgfp; - sprintf(sgf_name, "gfile%03d.data",demod->signal_grabber); + sprintf(sgf_name, "gfile%03d.data", demod->signal_grabber); demod->signal_grabber++; - signal_bszie = 2*(signal_end-(signal_start-10000)); - signal_bszie = (131072-(signal_bszie%131072)) + signal_bszie; - sg_idx = demod->sg_index-demod->sg_len; + signal_bszie = 2 * (signal_end - (signal_start - 10000)); + signal_bszie = (131072 - (signal_bszie % 131072)) + signal_bszie; + sg_idx = demod->sg_index - demod->sg_len; if (sg_idx < 0) - sg_idx = SIGNAL_GRABBER_BUFFER-demod->sg_len; - idx = (i-40000)*2; - start_pos = sg_idx+idx-signal_bszie; + sg_idx = SIGNAL_GRABBER_BUFFER - demod->sg_len; + idx = (i - 40000)*2; + start_pos = sg_idx + idx - signal_bszie; fprintf(stderr, "signal_bszie = %d - sg_index = %d\n", signal_bszie, demod->sg_index); fprintf(stderr, "start_pos = %d - buffer_size = %d\n", start_pos, SIGNAL_GRABBER_BUFFER); if (signal_bszie > SIGNAL_GRABBER_BUFFER) fprintf(stderr, "Signal bigger then buffer, signal = %d > buffer %d !!\n", signal_bszie, SIGNAL_GRABBER_BUFFER); if (start_pos < 0) { - start_pos = SIGNAL_GRABBER_BUFFER+start_pos; + start_pos = SIGNAL_GRABBER_BUFFER + start_pos; fprintf(stderr, "restart_pos = %d\n", start_pos); } - fprintf(stderr, "*** Saving signal to file %s\n",sgf_name); + fprintf(stderr, "*** Saving signal to file %s\n", sgf_name); sgfp = fopen(sgf_name, "wb"); if (!sgfp) { fprintf(stderr, "Failed to open %s\n", sgf_name); @@ -1429,12 +608,12 @@ static void pwm_analyze(struct dm_state *demod, int16_t *buf, uint32_t len) wlen = SIGNAL_GRABBER_BUFFER - start_pos; wrest = signal_bszie - wlen; } - fprintf(stderr, "*** Writing data from %d, len %d\n",start_pos, wlen); + fprintf(stderr, "*** Writing data from %d, len %d\n", start_pos, wlen); fwrite(&demod->sg_buf[start_pos], 1, wlen, sgfp); if (wrest) { - fprintf(stderr, "*** Writing data from %d, len %d\n",0, wrest); - fwrite(&demod->sg_buf[0], 1, wrest, sgfp); + fprintf(stderr, "*** Writing data from %d, len %d\n", 0, wrest); + fwrite(&demod->sg_buf[0], 1, wrest, sgfp); } fclose(sgfp); @@ -1457,7 +636,7 @@ err: static void pwm_d_decode(struct dm_state *demod, struct protocol_state* p, int16_t *buf, uint32_t len) { unsigned int i; - for (i=0 ; i demod->level_limit) { p->pulse_count = 1; p->start_c = 1; @@ -1476,17 +655,17 @@ static void pwm_d_decode(struct dm_state *demod, struct protocol_state* p, int16 demod_add_bit(p, 1); } else { demod_next_bits_packet(p); - p->pulse_count = 0; + p->pulse_count = 0; p->sample_counter = 0; } p->pulse_distance = 0; } if (p->sample_counter > p->reset_limit) { - p->start_c = 0; + p->start_c = 0; p->sample_counter = 0; p->pulse_distance = 0; if (p->callback) - events+=p->callback(p->bits_buffer, p->bits_per_row); + events += p->callback(p->bits_buffer, p->bits_per_row); else demod_print_bits_packet(p); @@ -1500,20 +679,19 @@ static void pwm_d_decode(struct dm_state *demod, struct protocol_state* p, int16 static void pwm_p_decode(struct dm_state *demod, struct protocol_state* p, int16_t *buf, uint32_t len) { unsigned int i; - for (i=0 ; i demod->level_limit && !p->start_bit) { /* start bit detected */ - p->start_bit = 1; - p->start_c = 1; + p->start_bit = 1; + p->start_c = 1; p->sample_counter = 0; -// fprintf(stderr, "start bit pulse start detected\n"); + // fprintf(stderr, "start bit pulse start detected\n"); } if (!p->real_bits && p->start_bit && (buf[i] < demod->level_limit)) { /* end of startbit */ p->real_bits = 1; - p->sample_counter = 0; -// fprintf(stderr, "start bit pulse end detected\n"); + // fprintf(stderr, "start bit pulse end detected\n"); } if (p->start_c) p->sample_counter++; @@ -1521,16 +699,16 @@ static void pwm_p_decode(struct dm_state *demod, struct protocol_state* p, int16 if (!p->pulse_start && p->real_bits && (buf[i] > demod->level_limit)) { /* save the pulse start, it will never be zero */ p->pulse_start = p->sample_counter; -// fprintf(stderr, "real bit pulse start detected\n"); + // fprintf(stderr, "real bit pulse start detected\n"); } if (p->real_bits && p->pulse_start && (buf[i] < demod->level_limit)) { /* end of pulse */ - p->pulse_length = p->sample_counter-p->pulse_start; -// fprintf(stderr, "real bit pulse end detected %d\n", p->pulse_length); -// fprintf(stderr, "space duration %d\n", p->sample_counter - p->pulse_length); + p->pulse_length = p->sample_counter - p->pulse_start; + // fprintf(stderr, "real bit pulse end detected %d\n", p->pulse_length); + // fprintf(stderr, "space duration %d\n", p->sample_counter); if (p->pulse_length <= p->short_limit) { demod_add_bit(p, 1); @@ -1538,7 +716,7 @@ static void pwm_p_decode(struct dm_state *demod, struct protocol_state* p, int16 demod_add_bit(p, 0); } p->sample_counter = 0; - p->pulse_start = 0; + p->pulse_start = 0; } if (p->real_bits && p->sample_counter > p->long_limit) { @@ -1553,7 +731,7 @@ static void pwm_p_decode(struct dm_state *demod, struct protocol_state* p, int16 p->sample_counter = 0; //demod_print_bits_packet(p); if (p->callback) - events+=p->callback(p->bits_buffer, p->bits_per_row); + events += p->callback(p->bits_buffer, p->bits_per_row); else demod_print_bits_packet(p); demod_reset_bits_packet(p); @@ -1564,7 +742,56 @@ static void pwm_p_decode(struct dm_state *demod, struct protocol_state* p, int16 } } +/* Machester Decode for Oregon Scientific Weather Sensors + Decode data streams sent by Oregon Scientific v2.1, and v3 weather sensors. + With manchester encoding, both the pulse width and pulse distance vary. Clock sync + is recovered from the data stream based on pulse widths and distances exceeding a + minimum threashold (short limit* 1.5). + */ +static void manchester_decode(struct dm_state *demod, struct protocol_state* p, int16_t *buf, uint32_t len) { + unsigned int i; + if (p->sample_counter == 0) + p->sample_counter = p->short_limit*2; + + for (i=0 ; istart_c) + p->sample_counter++; /* For this decode type, sample counter is count since last data bit recorded */ + + if (!p->pulse_count && (buf[i] > demod->level_limit)) { /* Pulse start (rising edge) */ + p->pulse_count = 1; + if (p->sample_counter > (p->short_limit + (p->short_limit>>1))) { + /* Last bit was recorded more than short_limit*1.5 samples ago */ + /* so this pulse start must be a data edge (rising data edge means bit = 0) */ + demod_add_bit(p, 0); + p->sample_counter=1; + p->start_c++; // start_c counts number of bits received + } + } + if (p->pulse_count && (buf[i] <= demod->level_limit)) { /* Pulse end (falling edge) */ + if (p->sample_counter > (p->short_limit + (p->short_limit>>1))) { + /* Last bit was recorded more than "short_limit*1.5" samples ago */ + /* so this pulse end is a data edge (falling data edge means bit = 1) */ + demod_add_bit(p, 1); + p->sample_counter=1; + p->start_c++; + } + p->pulse_count = 0; + } + + if (p->sample_counter > p->reset_limit) { + //fprintf(stderr, "manchester_decode number of bits received=%d\n",p->start_c); + if (p->callback) + events+=p->callback(p->bits_buffer, p->bits_per_row); + else + demod_print_bits_packet(p); + demod_reset_bits_packet(p); + p->sample_counter = p->short_limit*2; + p->start_c = 0; + } + } +} /** Something that might look like a IIR lowpass filter * @@ -1582,28 +809,25 @@ static uint16_t lp_xmem[FILTER_ORDER] = {0}; #define S_CONST (1<>1) + (b[0]*x_buf[0]>>1) + (b[1]*lp_xmem[0]>>1)) >> (F_SCALE-1); - for (i=1 ; i>1) + (b[0]*x_buf[i]>>1) + (b[1]*x_buf[i-1]>>1)) >> (F_SCALE-1); + y_buf[0] = ((a[1] * y_buf[-1] >> 1) + (b[0] * x_buf[0] >> 1) + (b[1] * lp_xmem[0] >> 1)) >> (F_SCALE - 1); + for (i = 1; i < len; i++) { + y_buf[i] = ((a[1] * y_buf[i - 1] >> 1) + (b[0] * x_buf[i] >> 1) + (b[1] * x_buf[i - 1] >> 1)) >> (F_SCALE - 1); } /* Save last sample */ - memcpy(lp_xmem, &x_buf[len-1-FILTER_ORDER], FILTER_ORDER*sizeof(int16_t)); - memcpy(&y_buf[-FILTER_ORDER], &y_buf[len-1-FILTER_ORDER], FILTER_ORDER*sizeof(int16_t)); + memcpy(lp_xmem, &x_buf[len - 1 - FILTER_ORDER], FILTER_ORDER * sizeof (int16_t)); + memcpy(&y_buf[-FILTER_ORDER], &y_buf[len - 1 - FILTER_ORDER], FILTER_ORDER * sizeof (int16_t)); //fprintf(stderr, "%d\n", y_buf[0]); } - -static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) -{ +static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) { struct dm_state *demod = ctx; uint16_t* sbuf = (uint16_t*) buf; int i; @@ -1620,29 +844,32 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) if (demod->signal_grabber) { //fprintf(stderr, "[%d] sg_index - len %d\n", demod->sg_index, len ); memcpy(&demod->sg_buf[demod->sg_index], buf, len); - demod->sg_len =len; - demod->sg_index +=len; - if (demod->sg_index+len > SIGNAL_GRABBER_BUFFER) + demod->sg_len = len; + demod->sg_index += len; + if (demod->sg_index + len > SIGNAL_GRABBER_BUFFER) demod->sg_index = 0; } if (demod->debug_mode == 0) { envelope_detect(buf, len, demod->decimation_level); - low_pass_filter(sbuf, demod->f_buf, len>>(demod->decimation_level+1)); - } else if (demod->debug_mode == 1){ + low_pass_filter(sbuf, demod->f_buf, len >> (demod->decimation_level + 1)); + } else if (demod->debug_mode == 1) { memcpy(demod->f_buf, buf, len); } if (demod->analyze) { - pwm_analyze(demod, demod->f_buf, len/2); + pwm_analyze(demod, demod->f_buf, len / 2); } else { - for (i=0 ; ir_dev_num ; i++) { + for (i = 0; i < demod->r_dev_num; i++) { switch (demod->r_devs[i]->modulation) { case OOK_PWM_D: - pwm_d_decode(demod, demod->r_devs[i], demod->f_buf, len/2); + pwm_d_decode(demod, demod->r_devs[i], demod->f_buf, len / 2); break; case OOK_PWM_P: - pwm_p_decode(demod, demod->r_devs[i], demod->f_buf, len/2); + pwm_p_decode(demod, demod->r_devs[i], demod->f_buf, len / 2); + break; + case OOK_MANCHESTER: + manchester_decode(demod, demod->r_devs[i], demod->f_buf, len/2); break; default: fprintf(stderr, "Unknown modulation %d in protocol!\n", demod->r_devs[i]->modulation); @@ -1651,7 +878,7 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) } if (demod->save_data) { - if (fwrite(demod->f_buf, 1, len>>demod->decimation_level, demod->file) != len>>demod->decimation_level) { + if (fwrite(demod->f_buf, 1, len >> demod->decimation_level, demod->file) != len >> demod->decimation_level) { fprintf(stderr, "Short write, samples lost, exiting!\n"); rtlsdr_cancel_async(dev); } @@ -1660,21 +887,20 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx) if (bytes_to_read > 0) bytes_to_read -= len; - if(frequencies>1) { + if (frequencies > 1) { time_t rawtime; time(&rawtime); - if(difftime(rawtime, rawtime_old)>DEFAULT_HOP_TIME || events>=DEFAULT_HOP_EVENTS) { - rawtime_old=rawtime; - events=0; - do_exit_async=1; + if (difftime(rawtime, rawtime_old) > DEFAULT_HOP_TIME || events >= DEFAULT_HOP_EVENTS) { + rawtime_old = rawtime; + events = 0; + do_exit_async = 1; rtlsdr_cancel_async(dev); } } } } -int main(int argc, char **argv) -{ +int main(int argc, char **argv) { #ifndef _WIN32 struct sigaction sigact; #endif @@ -1689,113 +915,120 @@ int main(int argc, char **argv) struct dm_state* demod; uint8_t *buffer; uint32_t dev_index = 0; - int frequency_current=0; + int frequency_current = 0; uint32_t out_block_size = DEFAULT_BUF_LENGTH; int device_count; char vendor[256], product[256], serial[256]; - demod = malloc(sizeof(struct dm_state)); - memset(demod,0,sizeof(struct dm_state)); + demod = malloc(sizeof (struct dm_state)); + memset(demod, 0, sizeof (struct dm_state)); /* initialize tables */ calc_squares(); demod->f_buf = &demod->filter_buffer[FILTER_ORDER]; demod->decimation_level = DEFAULT_DECIMATION_LEVEL; - demod->level_limit = DEFAULT_LEVEL_LIMIT; + demod->level_limit = DEFAULT_LEVEL_LIMIT; while ((opt = getopt(argc, argv, "x:z:p:Dtam:r:c:l:d:f:g:s:b:n:S::")) != -1) { switch (opt) { - case 'd': - dev_index = atoi(optarg); - break; - case 'f': - if(frequencieslevel_limit = (uint32_t)atof(optarg); - break; - case 'n': - bytes_to_read = (uint32_t)atof(optarg) * 2; - break; - case 'c': - demod->decimation_level = (uint32_t)atof(optarg); - break; - case 'a': - demod->analyze = 1; - break; - case 'r': - test_mode_file = optarg; - break; - case 't': - demod->signal_grabber = 1; - break; - case 'm': - demod->debug_mode = atoi(optarg); - break; - case 'S': - sync_mode = 1; - break; - case 'D': - debug_output = 1; - break; - case 'z': - override_short = atoi(optarg); - break; - case 'x': - override_long = atoi(optarg); - break; - default: - usage(); - break; + case 'd': + dev_index = atoi(optarg); + break; + case 'f': + if (frequencies < MAX_PROTOCOLS) frequency[frequencies++] = (uint32_t) atof(optarg); + else fprintf(stderr, "Max number of frequencies reached %d\n", MAX_PROTOCOLS); + break; + case 'g': + gain = (int) (atof(optarg) * 10); /* tenths of a dB */ + break; + case 'p': + ppm_error = atoi(optarg); + break; + case 's': + samp_rate = (uint32_t) atof(optarg); + break; + case 'b': + out_block_size = (uint32_t) atof(optarg); + break; + case 'l': + demod->level_limit = (uint32_t) atof(optarg); + break; + case 'n': + bytes_to_read = (uint32_t) atof(optarg) * 2; + break; + case 'c': + demod->decimation_level = (uint32_t) atof(optarg); + break; + case 'a': + demod->analyze = 1; + break; + case 'r': + test_mode_file = optarg; + break; + case 't': + demod->signal_grabber = 1; + break; + case 'm': + demod->debug_mode = atoi(optarg); + break; + case 'S': + sync_mode = 1; + break; + case 'D': + debug_output = 1; + break; + case 'z': + override_short = atoi(optarg); + break; + case 'x': + override_long = atoi(optarg); + break; + default: + usage(); + break; } } /* init protocols somewhat ok */ register_protocol(demod, &rubicson); - register_protocol(demod, &prologue); + // register_protocol(demod, &prologue); register_protocol(demod, &silvercrest); -// register_protocol(demod, &generic_hx2262); -// register_protocol(demod, &technoline_ws9118); + // register_protocol(demod, &generic_hx2262); + // register_protocol(demod, &technoline_ws9118); register_protocol(demod, &elv_em1000); register_protocol(demod, &elv_ws2000); register_protocol(demod, &waveman); register_protocol(demod, &steffen); register_protocol(demod, &acurite5n1); + register_protocol(demod, &acurite_th); + register_protocol(demod, &acurite_rain_gauge); register_protocol(demod, &lacrossetx); + register_protocol(demod, &oregon_scientific); + register_protocol(demod, &newkaku); + register_protocol(demod, &alectov1); + register_protocol(demod, &intertechno); + register_protocol(demod, &mebus433); - if (argc <= optind-1) { + if (argc <= optind - 1) { usage(); } else { filename = argv[optind]; } - if(out_block_size < MINIMAL_BUF_LENGTH || - out_block_size > MAXIMAL_BUF_LENGTH ){ + if (out_block_size < MINIMAL_BUF_LENGTH || + out_block_size > MAXIMAL_BUF_LENGTH) { fprintf(stderr, - "Output block size wrong value, falling back to default\n"); + "Output block size wrong value, falling back to default\n"); fprintf(stderr, - "Minimal length: %u\n", MINIMAL_BUF_LENGTH); + "Minimal length: %u\n", MINIMAL_BUF_LENGTH); fprintf(stderr, - "Maximal length: %u\n", MAXIMAL_BUF_LENGTH); + "Maximal length: %u\n", MAXIMAL_BUF_LENGTH); out_block_size = DEFAULT_BUF_LENGTH; } - buffer = malloc(out_block_size * sizeof(uint8_t)); + buffer = malloc(out_block_size * sizeof (uint8_t)); device_count = rtlsdr_get_device_count(); if (!device_count) { @@ -1812,7 +1045,7 @@ int main(int argc, char **argv) fprintf(stderr, "\n"); fprintf(stderr, "Using device %d: %s\n", - dev_index, rtlsdr_get_device_name(dev_index)); + dev_index, rtlsdr_get_device_name(dev_index)); r = rtlsdr_open(&dev, dev_index); if (r < 0) { @@ -1829,7 +1062,7 @@ int main(int argc, char **argv) sigaction(SIGQUIT, &sigact, NULL); sigaction(SIGPIPE, &sigact, NULL); #else - SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); + SetConsoleCtrlHandler((PHANDLER_ROUTINE) sighandler, TRUE); #endif /* Set the sample rate */ r = rtlsdr_set_sample_rate(dev, samp_rate); @@ -1838,11 +1071,11 @@ int main(int argc, char **argv) else fprintf(stderr, "Sample rate set to %d.\n", rtlsdr_get_sample_rate(dev)); // Unfortunately, doesn't return real rate - fprintf(stderr, "Sample rate decimation set to %d. %d->%d\n",demod->decimation_level, samp_rate, samp_rate>>demod->decimation_level); + fprintf(stderr, "Sample rate decimation set to %d. %d->%d\n", demod->decimation_level, samp_rate, samp_rate >> demod->decimation_level); fprintf(stderr, "Bit detection level set to %d.\n", demod->level_limit); if (0 == gain) { - /* Enable automatic gain */ + /* Enable automatic gain */ r = rtlsdr_set_tuner_gain_mode(dev, 0); if (r < 0) fprintf(stderr, "WARNING: Failed to enable automatic gain.\n"); @@ -1859,7 +1092,7 @@ int main(int argc, char **argv) if (r < 0) fprintf(stderr, "WARNING: Failed to set tuner gain.\n"); else - fprintf(stderr, "Tuner gain set to %f dB.\n", gain/10.0); + fprintf(stderr, "Tuner gain set to %f dB.\n", gain / 10.0); } r = rtlsdr_set_freq_correction(dev, ppm_error); @@ -1867,7 +1100,7 @@ int main(int argc, char **argv) demod->save_data = 1; if (!filename) { demod->save_data = 0; - } else if(strcmp(filename, "-") == 0) { /* Write samples to stdout */ + } else if (strcmp(filename, "-") == 0) { /* Write samples to stdout */ demod->file = stdout; #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); @@ -1886,13 +1119,13 @@ int main(int argc, char **argv) if (test_mode_file) { int i = 0; unsigned char test_mode_buf[DEFAULT_BUF_LENGTH]; - fprintf(stderr, "Test mode active. Reading samples from file: %s\n",test_mode_file); + fprintf(stderr, "Test mode active. Reading samples from file: %s\n", test_mode_file); test_mode = fopen(test_mode_file, "r"); if (!test_mode) { - fprintf(stderr, "Opening file: %s failed!\n",test_mode_file); + fprintf(stderr, "Opening file: %s failed!\n", test_mode_file); goto out; } - while(fread(test_mode_buf, 131072, 1, test_mode) != 0) { + while (fread(test_mode_buf, 131072, 1, test_mode) != 0) { rtlsdr_callback(test_mode_buf, 131072, demod); i++; } @@ -1919,17 +1152,17 @@ int main(int argc, char **argv) break; } - if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t)n_read)) { + if ((bytes_to_read > 0) && (bytes_to_read < (uint32_t) n_read)) { n_read = bytes_to_read; do_exit = 1; } - if (fwrite(buffer, 1, n_read, demod->file) != (size_t)n_read) { + if (fwrite(buffer, 1, n_read, demod->file) != (size_t) n_read) { fprintf(stderr, "Short write, samples lost, exiting!\n"); break; } - if ((uint32_t)n_read < out_block_size) { + if ((uint32_t) n_read < out_block_size) { fprintf(stderr, "Short read, samples lost, exiting!\n"); break; } @@ -1938,25 +1171,25 @@ int main(int argc, char **argv) bytes_to_read -= n_read; } } else { - if(frequencies==0) { - frequency[0] = DEFAULT_FREQUENCY; - frequencies=1; + if (frequencies == 0) { + frequency[0] = DEFAULT_FREQUENCY; + frequencies = 1; } else { - time(&rawtime_old); + time(&rawtime_old); } fprintf(stderr, "Reading samples in async mode...\n"); - while(!do_exit) { + while (!do_exit) { /* Set the frequency */ r = rtlsdr_set_center_freq(dev, frequency[frequency_current]); if (r < 0) fprintf(stderr, "WARNING: Failed to set center freq.\n"); else fprintf(stderr, "Tuned to %u Hz.\n", rtlsdr_get_center_freq(dev)); - r = rtlsdr_read_async(dev, rtlsdr_callback, (void *)demod, - DEFAULT_ASYNC_BUF_NUMBER, out_block_size); - do_exit_async=0; + r = rtlsdr_read_async(dev, rtlsdr_callback, (void *) demod, + DEFAULT_ASYNC_BUF_NUMBER, out_block_size); + do_exit_async = 0; frequency_current++; - if(frequency_current>frequencies-1) frequency_current=0; + if (frequency_current > frequencies - 1) frequency_current = 0; } } @@ -1968,17 +1201,17 @@ int main(int argc, char **argv) if (demod->file && (demod->file != stdout)) fclose(demod->file); - for (i=0 ; ir_dev_num ; i++) + for (i = 0; i < demod->r_dev_num; i++) free(demod->r_devs[i]); if (demod->signal_grabber) free(demod->sg_buf); - if(demod) + if (demod) free(demod); rtlsdr_close(dev); - free (buffer); + free(buffer); out: return r >= 0 ? r : -r; }