X-Git-Url: https://git.rvb.name/rtl-433.git/blobdiff_plain/ca13278b24eb61443559bcb61e64627fba3d8823..6d15c6f967221af825cf84e3ed12b96c763b127b:/src/devices/maverick_et73x.c diff --git a/src/devices/maverick_et73x.c b/src/devices/maverick_et73x.c new file mode 100755 index 0000000..20a2e47 --- /dev/null +++ b/src/devices/maverick_et73x.c @@ -0,0 +1,250 @@ +/* Maverick ET-73x BBQ Sensor + * + * Copyright © 2016 gismo2004 + * Credits to all users of mentioned forum below! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. +*/ + +/**The thermometer transmits 4 identical messages every 12 seconds at 433.92 MHz, + * using on-off keying and 2000bps Manchester encoding, + * with each message preceded by 8 carrier pulses 230uS wide and 5ms apart. + * + * Each message consists of 26 nibbles (104 bits total), + * which can each only have the value of 0x5, 0x6, 0x9, or 0xA. + * For nibble 24 some devices are sending 0x1 or 0x2 + * + * Assuming MSB first and falling edge = 1. + * + * quarternary conversion of message needed: + * 0x05 = 0 + * 0x06 = 1 + * 0x09 = 2 + * 0x0A = 3 + * + * Message looks like this: + * a = Header (0xAA9995) + * b = device state (2=default; 7=init) + * c = temp1 (need to substract 532) + * d = temp2 (need to substract 532) + * e = checksum (the checksum gets renewed on a device reset, and represents a kind of session_id) + * + * nibble: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 + * msg: a a a a a a b b c c c c c d d d d d e e e e e e e e + * + * further information can be found here: https://forums.adafruit.com/viewtopic.php?f=8&t=25414 +**/ + + +#include "rtl_433.h" +#include "util.h" + +#define MAV_MESSAGE_LENGTH 104 +#define TEMPERATURE_START_POSITION_S1 8 +#define TEMPERATURE_START_POSITION_S2 13 +#define TEMPERATURE_NIBBLE_COUNT 5 + + +//here we extract bitbuffer values, for easy data handling +static void convert_bitbuffer(bitbuffer_t *bitbuffer, unsigned int *msg_converted, char *msg_hex_combined) { + //quarternary convertion + unsigned int quart_convert[16] ={0,0,0,0,0,0,1,0,0,2,3,0,0,0,0,0}; + int i; + for(i = 0; i < 13; i++) { + char temp[2]; + sprintf(temp, "%02x", bitbuffer->bb[0][i]); + msg_hex_combined[i*2] = temp[0]; + msg_hex_combined[i*2+1] = temp[1]; + + msg_converted[i*2] = quart_convert[bitbuffer->bb[0][i] >> 4]; + msg_converted[i*2+1] = quart_convert[bitbuffer->bb[0][i] & 0xF]; + } + + msg_hex_combined[26]='\0'; + if(debug_output) { + fprintf(stderr, "final hex string: %s\n",msg_hex_combined); + fprintf(stderr, "final converted message: "); + for(i = 0; i <= 25; i++) fprintf(stderr, "%d",msg_converted[i]); + fprintf(stderr, "\n"); + } +} + +static float get_temperature(unsigned int *msg_converted, unsigned int temp_start_index){ + //default offset + float temp_c = -532.0; + int i; + + for(i=0; i < TEMPERATURE_NIBBLE_COUNT; i++) { + temp_c += msg_converted[temp_start_index+i] * (1<<(2*(4-i))); + } + + return temp_c; +} + + +//changes when thermometer reset button is pushed or powered on. +static char* get_status(unsigned int *msg_converted) { + int stat = 0; + char* retval = "unknown"; + + //nibble 6 - 7 used for status + stat += msg_converted[6] * (1<<(2*(1))); + stat += msg_converted[7] * (1<<(2*(0))); + + if(stat == 2) + retval = "default"; + + if(stat == 7) + retval = "init"; + + if(debug_output) + fprintf(stderr, "device status: \"%s\" (%d)\n", retval, stat); + + return retval; +} + + +static uint32_t checksum_data(unsigned int *msg_converted) { + int32_t checksum = 0; + int i; + + //nibble 6 - 17 used for checksum + for(i=0; i<=11; i++) { + checksum |= msg_converted[6+i] << (22 - 2*i); + } + + if(debug_output) + fprintf(stderr, "checksum data = %x\n", checksum); + + return checksum; +} + + +static uint32_t checksum_received(unsigned int *msg_converted, char *msg_hex_combined) { + uint32_t checksum = 0; + int i; + + //nibble 18 - 25 checksum info from device + for(i=0; i<=7; i++) { + checksum |= msg_converted[18+i] << (14 - 2*i); + } + + if(msg_hex_combined[24]=='1' || msg_hex_combined[24]=='2') { + checksum |= (msg_converted[25]&1) << 3; + checksum |= (msg_converted[25]&2) << 1; + + if(msg_hex_combined[24]=='2') + checksum |= 0x02; + } + else { + checksum |= msg_converted[24] << 2; + checksum |= msg_converted[25]; + } + + if(debug_output) + fprintf(stderr, "checksum received= %x\n", checksum); + + return checksum; +} + +static uint16_t shiftreg(uint16_t currentValue) { + uint8_t msb = (currentValue >> 15) & 1; + currentValue <<= 1; + + // Toggle pattern for feedback bits + // Toggle, if MSB is 1 + if (msb == 1) + currentValue ^= 0x1021; + + return currentValue; +} + +static uint16_t calculate_checksum(uint32_t data) { + //initial value of linear feedback shift register + uint16_t mask = 0x3331; + uint16_t csum = 0x0; + int i; + for(i = 0; i < 24; ++i) { + //data bit at current position is "1" + //do XOR with mask + if((data >> i) & 0x01) + csum ^= mask; + + mask = shiftreg(mask); + } + return csum; +} + +static int maverick_et73x_callback(bitbuffer_t *bitbuffer) { + data_t *data; + char time_str[LOCAL_TIME_BUFLEN]; + int32_t session_id; + char msg_hex_combined[27]; + unsigned int msg_converted[26]; + + //we need an inverted bitbuffer + bitbuffer_invert(bitbuffer); + + if(bitbuffer->num_rows != 1) + return 0; + + //check correct data length + if(bitbuffer->bits_per_row[0] != MAV_MESSAGE_LENGTH) + return 0; + + //check for correct header (0xAA9995) + if((bitbuffer->bb[0][0] != 0xAA || bitbuffer->bb[0][0] != 0xaa ) || bitbuffer->bb[0][1] != 0x99 || bitbuffer->bb[0][2] != 0x95) + return 0; + + //convert hex values into quardinary values + convert_bitbuffer(bitbuffer, msg_converted, msg_hex_combined); + + //checksum is used to represent a session. This means, we get a new session_id if a reset or battery exchange is done. + session_id = (calculate_checksum(checksum_data(msg_converted)) & 0xffff) ^ checksum_received(msg_converted, msg_hex_combined); + + if(debug_output) + fprintf(stderr, "checksum xor: %x\n", session_id); + + local_time_str(0, time_str); + + data = data_make("time", "", DATA_STRING, time_str, + "brand", "", DATA_STRING, "Maverick", + "model", "", DATA_STRING, "ET-732/ET-733", + "id", "Session_ID", DATA_INT, session_id, + "status", "Status", DATA_STRING, get_status(msg_converted), + "temperature_C1", "TemperatureSensor1", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_temperature(msg_converted,TEMPERATURE_START_POSITION_S1), + "temperature_C2", "TemperatureSensor2", DATA_FORMAT, "%.02f C", DATA_DOUBLE, get_temperature(msg_converted,TEMPERATURE_START_POSITION_S2), + "crc", "", DATA_STRING, "ok", + NULL); + data_acquired_handler(data); + + return bitbuffer->num_rows; +} + +static char *output_fields[] = { + "time", + "brand" + "model" + "id" + "status", + "temperature_C1", + "temperature_C2", + "crc", + NULL +}; + + +r_device maverick_et73x = { + .name = "Maverick ET-732/733 BBQ Sensor", + .modulation = OOK_PULSE_MANCHESTER_ZEROBIT, + .short_limit = 230, + .long_limit = 0, //not used + .reset_limit = 4000, + .json_callback = &maverick_et73x_callback, + .disabled = 0, + .demod_arg = 0, + .fields = output_fields +};