diff --git a/include/bitbuffer.h b/include/bitbuffer.h index 9bacd172..827eae9d 100644 --- a/include/bitbuffer.h +++ b/include/bitbuffer.h @@ -66,6 +66,6 @@ unsigned bitbuffer_manchester_decode(bitbuffer_t *inbuf, unsigned row, unsigned /// Find a repeated row that has a minimum count of bits. /// Return the row index or -1. -int bitbuffer_find_repeated_row(bitbuffer_t *bits, int min_repeats, int min_bits); +int bitbuffer_find_repeated_row(bitbuffer_t *bits, unsigned min_repeats, unsigned min_bits); #endif /* INCLUDE_BITBUFFER_H_ */ diff --git a/include/rtl_433.h b/include/rtl_433.h index 9ba3adce..2c4afeaa 100755 --- a/include/rtl_433.h +++ b/include/rtl_433.h @@ -35,7 +35,7 @@ #define DEFAULT_LEVEL_LIMIT 8000 // Theoretical high level at I/Q saturation is 128x128 = 16384 (above is ripple) #define MINIMAL_BUF_LENGTH 512 #define MAXIMAL_BUF_LENGTH (256 * 16384) -#define MAX_PROTOCOLS 45 +#define MAX_PROTOCOLS 46 #define SIGNAL_GRABBER_BUFFER (12 * DEFAULT_BUF_LENGTH) /* Supported modulation types */ diff --git a/include/rtl_433_devices.h b/include/rtl_433_devices.h index 3ec93dd7..3d8f36be 100755 --- a/include/rtl_433_devices.h +++ b/include/rtl_433_devices.h @@ -48,7 +48,8 @@ DECL(oil_watchman) \ DECL(current_cost) \ DECL(emontx) \ - DECL(ht680) + DECL(ht680) \ + DECL(s3318p) typedef struct { char name[256]; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4df093e7..b094802e 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,6 +64,7 @@ add_executable(rtl_433 devices/waveman.c devices/wt450.c devices/x10_rf.c + devices/s3318p.c ) diff --git a/src/Makefile.am b/src/Makefile.am index ed1acdcf..83807bd3 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,7 +26,7 @@ rtl_433_SOURCES = baseband.c \ devices/emontx.c \ devices/esperanza_ews.c \ devices/fineoffset.c \ - devices/fineoffset_wh1080 \ + devices/fineoffset_wh1080.c \ devices/generic_remote.c \ devices/generic_temperature_sensor.c \ devices/gt_wt_02.c \ @@ -49,7 +49,8 @@ rtl_433_SOURCES = baseband.c \ devices/valeo.c \ devices/waveman.c \ devices/wt450.c \ - devices/x10_rf.c + devices/x10_rf.c \ + devices/s3318p.c rtl_433_LDADD = $(LIBRTLSDR) $(LIBM) diff --git a/src/bitbuffer.c b/src/bitbuffer.c index fc7e7d31..4140c698 100644 --- a/src/bitbuffer.c +++ b/src/bitbuffer.c @@ -184,7 +184,7 @@ static unsigned count_repeats(bitbuffer_t *bits, unsigned row) { return cnt; } -int bitbuffer_find_repeated_row(bitbuffer_t *bits, int min_repeats, int min_bits) { +int bitbuffer_find_repeated_row(bitbuffer_t *bits, unsigned min_repeats, unsigned min_bits) { for (int i = 0; i < bits->num_rows; ++i) { if (bits->bits_per_row[i] >= min_bits && count_repeats(bits, i) >= min_repeats) { diff --git a/src/data.c b/src/data.c old mode 100644 new mode 100755 index 7fad5852..c0fa4479 --- a/src/data.c +++ b/src/data.c @@ -302,6 +302,7 @@ void data_free(data_t *data) { data_t *prev_data = data; if (dmt[data->type].value_release) dmt[data->type].value_release(data->value); + free(data->format); free(data->pretty_key); free(data->key); data = data->next; @@ -316,7 +317,10 @@ void data_print(data_t* data, FILE *file, data_printer_t *printer, void *aux) .aux = aux }; ctx.printer->print_data(&ctx, data, NULL, file); - fputc('\n', file); + if (file) { + fputc('\n', file); + fflush(file); + } } static void print_value(data_printer_context_t *printer_ctx, FILE *file, data_type_t type, void *value, char *format) { @@ -390,7 +394,7 @@ static void print_json_string(data_printer_context_t *printer_ctx, const char *s static void print_json_double(data_printer_context_t *printer_ctx, double data, char *format, FILE *file) { - fprintf(file, "%f", data); + fprintf(file, "%.3f", data); } static void print_json_int(data_printer_context_t *printer_ctx, int data, char *format, FILE *file) @@ -420,7 +424,7 @@ static void print_kv_data(data_printer_context_t *printer_ctx, data_t *data, cha } } if (!strcmp(data->key, "time")) - fprintf(file, ""); + /* fprintf(file, "") */ ; else if (!strcmp(data->key, "model")) fprintf(file, ":\t"); else @@ -436,7 +440,7 @@ static void print_kv_data(data_printer_context_t *printer_ctx, data_t *data, cha static void print_kv_double(data_printer_context_t *printer_ctx, double data, char *format, FILE *file) { - fprintf(file, format ? format : "%f", data); + fprintf(file, format ? format : "%.3f", data); } static void print_kv_int(data_printer_context_t *printer_ctx, int data, char *format, FILE *file) diff --git a/src/devices/current_cost.c b/src/devices/current_cost.c index 7c748e8f..c3e06377 100644 --- a/src/devices/current_cost.c +++ b/src/devices/current_cost.c @@ -30,15 +30,19 @@ static int current_cost_callback(bitbuffer_t *bitbuffer) { bitbuffer_t packet_bits = {0}; start_pos = bitbuffer_manchester_decode(bitbuffer, 0, start_pos, &packet_bits, 0); + uint8_t *packet = packet_bits.bb[0]; // Read data - if(packet_bits.bits_per_row[0] >= 56 && packet[0] == 0x0d){ + if(packet_bits.bits_per_row[0] >= 56 && ((packet[0] & 0xf0) == 0) ){ + uint16_t device_id = (packet[0] & 0x0f) << 8 | packet[1]; + uint16_t watt0 = (packet[2] & 0x7F) << 8 | packet[3] ; uint16_t watt1 = (packet[4] & 0x7F) << 8 | packet[5] ; uint16_t watt2 = (packet[6] & 0x7F) << 8 | packet[7] ; data = data_make("time", "", DATA_STRING, time_str, "model", "", DATA_STRING, "CurrentCost TX", //TODO: it may have different CC Model ? any ref ? //"rc", "Rolling Code", DATA_INT, rc, //TODO: add rolling code b[1] ? test needed + "dev_id", "Device Id", DATA_FORMAT, "%d", DATA_INT, device_id, "power0", "Power 0", DATA_FORMAT, "%d W", DATA_INT, watt0, "power1", "Power 1", DATA_FORMAT, "%d W", DATA_INT, watt1, "power2", "Power 2", DATA_FORMAT, "%d W", DATA_INT, watt2, diff --git a/src/devices/ht680.c b/src/devices/ht680.c index 47e55dfe..500484cc 100644 --- a/src/devices/ht680.c +++ b/src/devices/ht680.c @@ -20,9 +20,26 @@ static int ht680_callback(bitbuffer_t *bitbuffer) { (b[3] & 0x82) == 0x82 && //Buttons(4,3) always mask 10000010 (b[4] & 0x0A) == 0x0A){ //Buttons(2,1) always mask 00001010 b[0] = b[0] & 0x0F; //Clear sync + + // Tristate coding + char tristate[21]; + char *p = tristate; + for(uint8_t byte = 0; byte < 5; byte++){ + for(int8_t bit = 7; bit > 0; bit -= 2){ + switch ((b[byte] >> (bit-1)) & 0x03){ + case 0x00: *p++ = '0'; break; + case 0x01: *p++ = '?'; break; //Invalid code 01 + case 0x02: *p++ = 'Z'; break; //Floating state Z is 10 + case 0x03: *p++ = '1'; break; + default: *p++ = '!'; break; //Unknown error + } + } + } + *p = '\0'; data = data_make("model", "", DATA_STRING, "HT680 Remote control", - "addres", "Addres code", DATA_FORMAT, "%06X", DATA_INT, (b[0]<<16)+(b[1]<<8)+b[2], + "tristate","Tristate code",DATA_STRING, tristate, + "address", "Address", DATA_FORMAT, "0x%06X", DATA_INT, (b[0]<<16)+(b[1]<<8)+b[2], "button1", "Button 1", DATA_STRING, (((b[4]>>4) & 0x03) == 3) ? "PRESSED" : "", "button2", "Button 2", DATA_STRING, (((b[4]>>6) & 0x03) == 3) ? "PRESSED" : "", "button3", "Button 3", DATA_STRING, ((((b[3]&0x7D)>>2) & 0x03) == 3) ? "PRESSED" : "", @@ -38,7 +55,8 @@ static int ht680_callback(bitbuffer_t *bitbuffer) { static char *output_fields[] = { "model", - "adress", + "tristate", + "address", "data", "button1", "button2", diff --git a/src/devices/lacrossews.c b/src/devices/lacrossews.c index d3815e58..a4b2bf44 100755 --- a/src/devices/lacrossews.c +++ b/src/devices/lacrossews.c @@ -19,6 +19,7 @@ #include "rtl_433.h" #include "util.h" +#include "data.h" #define LACROSSE_WS_BITLEN 52 @@ -84,7 +85,8 @@ static int lacrossews_callback(bitbuffer_t *bitbuffer) { uint8_t ws_id, msg_type, sensor_id, msg_data, msg_unknown, msg_checksum; int msg_value_bcd, msg_value_bcd2, msg_value_bin; float temp_c, temp_f, wind_dir, wind_spd, rain_mm, rain_in; - char time_str[LOCAL_TIME_BUFLEN]; + char time_str[LOCAL_TIME_BUFLEN], *wind_key, *wind_label; + data_t *data; for (m = 0; m < BITBUF_ROWS; m++) { // break out the message nybbles into separate bytes @@ -102,7 +104,7 @@ static int lacrossews_callback(bitbuffer_t *bitbuffer) { local_time_str(0, time_str); - if (debug_output) + if (debug_output) fprintf(stderr, "%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X%1X ", msg_nybbles[0], msg_nybbles[1], msg_nybbles[2], msg_nybbles[3], msg_nybbles[4], msg_nybbles[5], msg_nybbles[6], msg_nybbles[7], @@ -113,27 +115,41 @@ static int lacrossews_callback(bitbuffer_t *bitbuffer) { // Temperature case 0: temp_c = (msg_value_bcd - 300.0) / 10.0; - temp_f = temp_c * 1.8 + 32; - printf("%s LaCrosse WS %02X-%02X: Temperature %3.1f C / %3.1f F\n", - time_str, ws_id, sensor_id, temp_c, temp_f); + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, "LaCrosse WS", + "ws_id", "", DATA_INT, ws_id, + "id", "", DATA_INT, sensor_id, + "temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temp_c, + NULL); + data_acquired_handler(data); events++; + break; // Humidity case 1: if(msg_nybbles[7] == 0xA && msg_nybbles[8] == 0xA) - printf("%s LaCrosse WS %02X-%02X: Humidity Error\n", + fprintf(stderr, "%s LaCrosse WS %02X-%02X: Humidity Error\n", time_str, ws_id, sensor_id); - else - printf("%s LaCrosse WS %02X-%02X: Humidity %2d %%\n", - time_str, ws_id, sensor_id, msg_value_bcd2); + else { + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, "LaCrosse WS", + "ws_id", "", DATA_INT, ws_id, + "id", "", DATA_INT, sensor_id, + "humidity", "Humidity", DATA_INT, msg_value_bcd2, + NULL); + data_acquired_handler(data); events++; + } break; // Rain case 2: rain_mm = 0.5180 * msg_value_bin; - rain_in = 0.0204 * msg_value_bin; - printf("%s LaCrosse WS %02X-%02X: Rain %3.2f mm / %3.2f in\n", - time_str, ws_id, sensor_id, rain_mm, rain_in); + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, "LaCrosse WS", + "ws_id", "", DATA_INT, ws_id, + "id", "", DATA_INT, sensor_id, + "rainfall_mm", "Rainfall", DATA_FORMAT, "%3.2f mm", DATA_DOUBLE, rain_mm, NULL); + data_acquired_handler(data); events++; break; // Wind @@ -143,11 +159,18 @@ static int lacrossews_callback(bitbuffer_t *bitbuffer) { wind_dir = msg_nybbles[9] * 22.5; wind_spd = (msg_nybbles[7] * 16 + msg_nybbles[8])/ 10.0; if(msg_nybbles[7] == 0xF && msg_nybbles[8] == 0xE) - printf("%s LaCrosse WS %02X-%02X: %s Not Connected\n", + fprintf(stderr, "%s LaCrosse WS %02X-%02X: %s Not Connected\n", time_str, ws_id, sensor_id, msg_type == 3 ? "Wind":"Gust"); else { - printf("%s LaCrosse WS %02X-%02X: %s Dir %3.1f Speed %3.1f m/s / %3.1f mph\n", - time_str, ws_id, sensor_id, msg_type == 3 ? "Wind":"Gust", wind_dir, wind_spd, wind_spd * 2.236936292054); + wind_key = msg_type == 3 ? "wind_speed_ms":"gust_speed_ms"; + wind_label = msg_type == 3 ? "Wind speed":"Gust speed"; + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, "LaCrosse WS", + "ws_id", "", DATA_INT, ws_id, + "id", "", DATA_INT, sensor_id, + wind_key, wind_label, DATA_FORMAT, "%3.1f m/s", DATA_DOUBLE, wind_spd, + "wind_direction", "Direction", DATA_DOUBLE, wind_dir, NULL); + data_acquired_handler(data); events++; } break; @@ -163,13 +186,28 @@ static int lacrossews_callback(bitbuffer_t *bitbuffer) { return events; } +static char *output_fields[] = { + "time", + "model", + "ws_id", + "id", + "temperature_C", + "humidity", + "rainfall_mm", + "wind_speed_ms", + "gust_speed_ms", + "wind_direction", + NULL +}; + r_device lacrossews = { .name = "LaCrosse WS-2310 Weather Station", .modulation = OOK_PULSE_PWM_RAW, .short_limit = 952, .long_limit = 3000, .reset_limit = 8000, - .json_callback = &lacrossews_callback, + .json_callback = &lacrossews_callback, .disabled = 0, .demod_arg = 0, + .fields = output_fields }; diff --git a/src/devices/oregon_scientific.c b/src/devices/oregon_scientific.c old mode 100644 new mode 100755 index acf50e80..5b74a575 --- a/src/devices/oregon_scientific.c +++ b/src/devices/oregon_scientific.c @@ -119,8 +119,10 @@ static int validate_os_checksum(unsigned char *msg, int checksum_nibble_idx) { 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(stdout, "%02x ", msg[i]); fprintf(stdout, "\n\n"); + if(debug_output) { + 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(stdout, "%02x ", msg[i]); fprintf(stdout, "\n\n"); + } return 1; } } @@ -131,8 +133,10 @@ static int validate_os_v2_message(unsigned char * msg, int bits_expected, int va 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(stdout, "%02x ", msg[i]); fprintf(stdout, "\n\n"); + if(debug_output) { + 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(stdout, "%02x ", msg[i]); fprintf(stdout, "\n\n"); + } } return 1; } @@ -413,6 +417,7 @@ static int oregon_scientific_v3_parser(bitbuffer_t *bitbuffer) { return 1; } else if ((msg[0] == 0x19) && (msg[1] == 0x84)) { if (validate_os_checksum(msg, 17) == 0) { + // 8 Direction, Not BCD – binary value from 0..15. Direction in degrees is value * 22.5 degrees. // 13..11 Current Speed, meters per second, LSD is 0.1 m/s // 16..14 Average speed, meters per second, LSD is 0.1 m/s /* @@ -425,7 +430,7 @@ static int oregon_scientific_v3_parser(bitbuffer_t *bitbuffer) { float gustWindspeed = (msg[5]&0x0f) /10.0F + ((msg[6]>>4)&0x0f) *1.0F + (msg[6]&0x0f) * 10.0F; float avgWindspeed = ((msg[7]>>4)&0x0f) / 10.0F + (msg[7]&0x0f) *1.0F + ((msg[8]>>4)&0x0f) * 10.0F; int battery = get_os_battery(msg, ID_WGR800); - float quadrant = (0x0f&(msg[5]>>4))*22.5; + float quadrant = (0x0f&(msg[4]>>4))*22.5F; data = data_make("time", "", DATA_STRING, time_str, "model", "", DATA_STRING, "Weather Sensor WGR800 Wind Gauge", "id", "House Code", DATA_INT, get_os_rollingcode(msg, ID_WGR800), @@ -460,9 +465,11 @@ static int oregon_scientific_v3_parser(bitbuffer_t *bitbuffer) { fprintf(stdout,"Energy Sensor CM180 Id %x%x power: %dW\n", msg[0], msg[1], ipower); } 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 Temp/Hum/Ch:23.2/46/1 + * + * Temperature: + * Sensor sends data in °F, lowest supported value is 90°F + * 12 bit uingned and scaled by 10 (Nibbles: 6,5,4) + * in this case "011001100101" = 1637/10 - 90 = 73.7 °F (23.17 °C) + * + * Humidity: + * 8 bit unsigned (Nibbles 8,7) + * in this case "00101110" = 46 + * + * Channel number: (Bits 10,11) + 1 + * in this case "00" --> "00" +1 = Channel1 + * + * Battery status: (Bit 33) (0 normal, 1 voltage is below ~2.7 V) + * TX-Button: (Bit 32) (0 indicates regular transmission, 1 indicates requested by pushbutton) + * + * Rolling Code / Device ID: (Nibble 1) + * changes on every battery change + * + * Unknown1: (Bits 8,9) changes not so often + * Unknown2: (Bits 36-39) changes with every packet, probably checksum + * Unknown3: (Bits 34,35) changes not so often, mayby also part of the checksum + * + */ + + +static int s3318p_callback(bitbuffer_t *bitbuffer) { + bitrow_t *bb = bitbuffer->bb; + data_t *data; + char time_str[LOCAL_TIME_BUFLEN]; + + /* Get time now */ + local_time_str(0, time_str); + + /* Reject codes of wrong length */ + if ( 42 != bitbuffer->bits_per_row[1]) + return 0; + + /* shift all the bits left 2 to align the fields */ + int i; + for (i = 0; i < BITBUF_COLS-1; i++) { + uint8_t bits1 = bb[1][i] << 2; + uint8_t bits2 = (bb[1][i+1] & 0xC0) >> 6; + bits1 |= bits2; + bb[1][i] = bits1; + } + + uint8_t humidity; + uint8_t button; + uint8_t battery_low; + uint8_t channel; + uint8_t sensor_id; + uint16_t temperature_with_offset; + float temperature_f; + + /* IIIIIIII ??CCTTTT TTTTTTTT HHHHHHHH XB?????? PP */ + humidity = (uint8_t)(((bb[1][3] & 0x0F) << 4) | ((bb[1][3] & 0xF0) >> 4)); + button = (uint8_t)(bb[1][4] >> 7); + battery_low = (uint8_t)((bb[1][4] & 0x40) >> 6); + channel = (uint8_t)(((bb[1][1] & 0x30) >> 4) + 1); + sensor_id = (uint8_t)(bb[1][0]); + + temperature_with_offset = (uint16_t)(((bb[1][2] & 0x0F) << 8) | (bb[1][2] & 0xF0) | (bb[1][1] & 0x0F)); + temperature_f = (float)((temperature_with_offset - 900) / 10.0); + + if (debug_output) { + bitbuffer_print(bitbuffer); + fprintf(stderr, "Sensor ID = %2x\n", sensor_id); + fprintf(stdout, "Bitstream HEX = %02x %02x %02x %02x %02x %02x\n",bb[1][0],bb[1][1],bb[1][2],bb[1][3],bb[1][4],bb[1][5]); + fprintf(stdout, "Humidity HEX = %02x\n", bb[1][3]); + fprintf(stdout, "Humidity DEC = %u\n", humidity); + fprintf(stdout, "Button = %d\n", button); + fprintf(stdout, "Battery Low = %d\n", battery_low); + fprintf(stdout, "Channel HEX = %02x\n", bb[1][1]); + fprintf(stdout, "Channel = %u\n", channel); + fprintf(stdout, "temp_with_offset HEX = %02x\n", temperature_with_offset); + fprintf(stdout, "temp_with_offset = %d\n", temperature_with_offset); + fprintf(stdout, "TemperatureF = %.1f\n", temperature_f); + } + + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, "S3318P Temperature & Humidity Sensor", + "id", "House Code", DATA_INT, sensor_id, + "channel", "Channel", DATA_INT, channel, + "battery", "Battery", DATA_STRING, battery_low ? "LOW" : "OK", + "button", "Button", DATA_INT, button, + "temperature_F", "Temperature", DATA_FORMAT, "%.02f F", DATA_DOUBLE, temperature_f, + "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity, + NULL); + + data_acquired_handler(data); + + return 0; +} + +static char *output_fields[] = { + "time", + "model", + "id", + "channel", + "battery", + "button", + "temperature_C", + "humidity", + NULL +}; + + +r_device s3318p = { + .name = "S3318P Temperature & Humidity Sensor", + .modulation = OOK_PULSE_PPM_RAW, + .short_limit = 2800, + .long_limit = 4400, + .reset_limit = 8000, + .json_callback = &s3318p_callback, + .disabled = 0, + .demod_arg = 0, + .fields = output_fields +}; + diff --git a/src/devices/tfa_twin_plus_30.3049.c b/src/devices/tfa_twin_plus_30.3049.c index 5a28bc1c..29990eca 100644 --- a/src/devices/tfa_twin_plus_30.3049.c +++ b/src/devices/tfa_twin_plus_30.3049.c @@ -1,5 +1,6 @@ #include "rtl_433.h" #include "util.h" +#include "data.h" /* * TFA-Twin-Plus-30.3049 @@ -55,6 +56,7 @@ inline static uint8_t reverse_byte(uint8_t byte) static int tfa_twin_plus_303049_process_row(int row, const bitbuffer_t *bitbuffer) { + data_t *data; const uint8_t *b = bitbuffer->bb[row]; const uint16_t length = bitbuffer->bits_per_row[row]; @@ -91,10 +93,15 @@ static int tfa_twin_plus_303049_process_row(int row, const bitbuffer_t *bitbuffe char time_str[LOCAL_TIME_BUFLEN]; local_time_str(0, time_str); - /* @todo make temperature unit configurable, not printing both */ - fprintf(stdout, "%s TFA-Twin-Plus-30.3049 Sensor %02x: battery %s, channel %d, temperature %3.1f C / %3.1f F, humidity %2d%%\n" - , time_str, sensor_id, battery_low ? "low" : "OK", channel, tempC, celsius2fahrenheit(tempC), humidity - ); + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, "TFA-Twin-Plus-30.3049", + "id", "", DATA_INT, sensor_id, + "channel", "", DATA_INT, channel, + "battery", "Battery", DATA_STRING, battery_low ? "LOW" : "OK", + "temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, tempC, + "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity, + NULL); + data_acquired_handler(data); } return 1; @@ -359,6 +366,17 @@ Passed 74/74 positive tests #endif +static char *output_fields[] = { + "time", + "model", + "id", + "channel", + "battery", + "temperature_C", + "humidity", + NULL +}; + r_device tfa_twin_plus_303049 = { .name = "TFA-Twin-Plus-30.3049 and Ea2 BL999", .modulation = OOK_PULSE_PPM_RAW, @@ -368,4 +386,5 @@ r_device tfa_twin_plus_303049 = { .json_callback = &tfa_twin_plus_303049_callback, .disabled = 0, .demod_arg = 0, + .fields = output_fields }; diff --git a/src/devices/x10_rf.c b/src/devices/x10_rf.c old mode 100644 new mode 100755 index 810d6cf7..b01ffeca --- a/src/devices/x10_rf.c +++ b/src/devices/x10_rf.c @@ -17,7 +17,7 @@ static int X10_RF_callback(bitbuffer_t *bitbuffer) { // Validate package if ((bitbuffer->bits_per_row[1] == 32) // Dont waste time on a short package // && (bb[1][0] == (uint8_t)(~bb[1][1])) // Check integrity - apparently some chips may use both bytes.. - && (bb[1][2] == (uint8_t)(~bb[1][3])) // Check integrity + && (bb[1][2] == ((0xff & (~bb[1][3])))) // Check integrity ) { fprintf(stdout, "X10 RF:\n"); diff --git a/src/rtl_433.c b/src/rtl_433.c old mode 100644 new mode 100755 index 0771fda1..3ec2f1ab --- a/src/rtl_433.c +++ b/src/rtl_433.c @@ -193,13 +193,16 @@ static unsigned int signal_end = 0; static unsigned int signal_pulse_data[4000][3] = { {0}}; static unsigned int signal_pulse_counter = 0; -typedef enum { - OUTPUT_KV, - OUTPUT_JSON, - OUTPUT_CSV -} output_format_t; -static output_format_t output_format; -void *csv_aux_data; + +typedef struct output_handler { + /*data_printer_t*/ void *printer; + void (*aux_free)(void *aux); + FILE *file; + void *aux; + struct output_handler *next; +} output_handler_t; +static output_handler_t *output_handler = NULL; +static output_handler_t **next_output_handler = &output_handler; /* handles incoming structured data by dumping it */ void data_acquired_handler(data_t *data) @@ -209,6 +212,8 @@ void data_acquired_handler(data_t *data) if ((d->type == DATA_DOUBLE) && !strcmp(d->key, "temperature_F")) { *(double*)d->value = fahrenheit2celsius(*(double*)d->value); + free(d->key); + d->key = strdup("temperature_C"); char *pos; if (d->format && (pos = strrchr(d->format, 'F'))) { @@ -222,6 +227,8 @@ void data_acquired_handler(data_t *data) if ((d->type == DATA_DOUBLE) && !strcmp(d->key, "temperature_C")) { *(double*)d->value = celsius2fahrenheit(*(double*)d->value); + free(d->key); + d->key = strdup("temperature_F"); char *pos; if (d->format && (pos = strrchr(d->format, 'C'))) { @@ -231,18 +238,9 @@ void data_acquired_handler(data_t *data) } } - switch (output_format) { - case OUTPUT_KV: { - data_print(data, stdout, &data_kv_printer, NULL); - } break; - case OUTPUT_JSON: { - data_print(data, stdout, &data_json_printer, NULL); - } break; - case OUTPUT_CSV: { - data_print(data, stdout, &data_csv_printer, csv_aux_data); - } break; + for (output_handler_t *output = output_handler; output; output = output->next) { + data_print(data, output->file, output->printer, output->aux); } - fflush(stdout); data_free(data); } @@ -748,6 +746,51 @@ void *determine_csv_fields(r_device* devices, int num_devices) return csv_aux; } +void add_json_output() +{ + output_handler_t *output = calloc(1, sizeof(output_handler_t)); + if (!output) { + fprintf(stderr, "rtl_433: failed to allocate memory for output handler\n"); + exit(1); + } + output->printer = &data_json_printer; + output->file = stdout; + *next_output_handler = output; + next_output_handler = &output->next; +} + +void add_csv_output(void *aux_data) +{ + if (!aux_data) { + fprintf(stderr, "rtl_433: failed to allocate memory for CSV auxiliary data\n"); + exit(1); + } + output_handler_t *output = calloc(1, sizeof(output_handler_t)); + if (!output) { + fprintf(stderr, "rtl_433: failed to allocate memory for output handler\n"); + exit(1); + } + output->printer = &data_csv_printer; + output->aux_free = &data_csv_free; + output->file = stdout; + output->aux = aux_data; + *next_output_handler = output; + next_output_handler = &output->next; +} + +void add_kv_output() +{ + output_handler_t *output = calloc(1, sizeof(output_handler_t)); + if (!output) { + fprintf(stderr, "rtl_433: failed to allocate memory for output handler\n"); + exit(1); + } + output->printer = &data_kv_printer; + output->file = stdout; + *next_output_handler = output; + next_output_handler = &output->next; +} + int main(int argc, char **argv) { #ifndef _WIN32 struct sigaction sigact; @@ -756,7 +799,7 @@ int main(int argc, char **argv) { char *in_filename = NULL; FILE *in_file; int n_read; - int r, opt; + int r = 0, opt; int i, gain = 0; int sync_mode = 0; int ppm_error = 0; @@ -862,11 +905,11 @@ int main(int argc, char **argv) { break; case 'F': if (strcmp(optarg, "json") == 0) { - output_format = OUTPUT_JSON; + add_json_output(); } else if (strcmp(optarg, "csv") == 0) { - output_format = OUTPUT_CSV; + add_csv_output(determine_csv_fields(devices, num_r_devices)); } else if (strcmp(optarg, "kv") == 0) { - output_format = OUTPUT_KV; + add_kv_output(); } else { fprintf(stderr, "Invalid output format %s\n", optarg); usage(devices); @@ -900,12 +943,8 @@ int main(int argc, char **argv) { out_filename = argv[optind]; } - if (output_format == OUTPUT_CSV) { - csv_aux_data = determine_csv_fields(devices, num_r_devices); - if (!csv_aux_data) { - fprintf(stderr, "rtl_433: failed to allocate memory for CSV auxiliary data\n"); - exit(1); - } + if (!output_handler) { + add_kv_output(); } for (i = 0; i < num_r_devices; i++) { @@ -1152,8 +1191,10 @@ int main(int argc, char **argv) { rtlsdr_close(dev); out: - if (csv_aux_data) { - data_csv_free(csv_aux_data); + for (output_handler_t *output = output_handler; output; output = output->next) { + if (output->aux_free) { + output->aux_free(output->aux); + } } return r >= 0 ? r : -r; }