Exemplo n.º 1
0
static int elro_db286a_callback(r_device *decoder, bitbuffer_t *bitbuffer)
{
    data_t *data;
    uint8_t *b;
    char id_str[4*2+1];

    // 33 bits expected, 5 minimum packet repetitions (14 expected)
    int row = bitbuffer_find_repeated_row(bitbuffer, 5, 33);

    if (row < 0 || bitbuffer->bits_per_row[row] != 33)
        return 0;

    b = bitbuffer->bb[row];

    // 32 bits, trailing bit is dropped
    sprintf(id_str, "%02x%02x%02x%02x", b[0], b[1], b[2], b[3]);

    data = data_make(
            "model",    "",        DATA_STRING, "Elro-DB286A",
            "id",       "ID",      DATA_STRING, id_str,
            NULL);

    decoder_output_data(decoder, data);

    return 1;

}
Exemplo n.º 2
0
static int silvercrest_callback(r_device *decoder, bitbuffer_t *bitbuffer) {
    uint8_t *b; // bits of a row
    uint8_t cmd;
    data_t *data;

    if (bitbuffer->bits_per_row[1] !=33)
        return 0;

    /* select second row, first might be bad */
    b = bitbuffer->bb[1];
    if ((b[0] == 0x7c) && (b[1] == 0x26)) {
        cmd = b[2] & 0xF;
	// Validate button
        if ((b[3]&0xF) != cmd_lu_tab[cmd])
            return 0;


        data = data_make(
            "model", "", DATA_STRING, "Silvercrest Remote Control",
            "button", "", DATA_INT, cmd,
            NULL);

        decoder_output_data(decoder, data);

        return 1;
    }
    return 0;
}
Exemplo n.º 3
0
static int thermopro_tp11_sensor_callback(r_device *decoder, bitbuffer_t *bitbuffer) {
    int temp_raw, row;
    float temp_c;
    bitrow_t *bb = bitbuffer->bb;
    unsigned int device, value;
    data_t *data;

    // Compare first four bytes of rows that have 32 or 33 bits.
    row = bitbuffer_find_repeated_row(bitbuffer, 2, 32);
    if (row < 0)
        return 0;

    if (bitbuffer->bits_per_row[row] > 33)
        return 0;

    value = (bb[row][0] << 16) + (bb[row][1] << 8) + bb[row][2];
    device = value >> 12;

    // Validate code for known devices.
    if ((device == 0xb34 || device == 0xdb4 ) && !valid(value, bb[row][3]))
        return 0;

    temp_raw = value & 0xfff;
    temp_c = (temp_raw - 200) / 10.;

    data = data_make(
            "model",         "",            DATA_STRING, _X("Thermopro-TP11","Thermopro TP11 Thermometer"),
            "id",            "Id",          DATA_INT,    device,
            "temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp_c,
            NULL);
    decoder_output_data(decoder, data);
    return 1;
}
Exemplo n.º 4
0
/**
The sensor sends a single packet once every hour or twice a second
for 11 minutes when in pairing/test mode (pairing needs 35 sec).
depth reading is in cm, lowest reading is ~3, highest is ~305, 0 is invalid

    IIII IIII IIII IIII 0FFF L0OP DDDD DDDD

The TEK377E might send an additional 8 zero bits.

example packets are:

    010101 01010101 01010111 01101001 10011010 10101001 10100101 10011010 01101010 10011001 10011010 0000
    010101 01010101 01011000 10011010 01010110 01101010 10101010 10100101 01101010 10100110 10101001 1111

Start of frame full preamble is depending on first data bit either

    01 0101 0101 0101 0101 0111 01
    01 0101 0101 0101 0101 1000 10
*/
static int oil_standard_decode(r_device *decoder, bitbuffer_t *bitbuffer, unsigned row, unsigned bitpos)
{
    data_t *data;
    uint8_t *b;
    uint16_t unit_id;
    uint16_t depth             = 0;
    uint16_t binding_countdown = 0;
    uint8_t flags;
    uint8_t alarm;
    bitbuffer_t databits = {0};

    bitpos = bitbuffer_manchester_decode(bitbuffer, row, bitpos, &databits, 41);

    if (databits.bits_per_row[0] < 32 || databits.bits_per_row[0] > 40 || (databits.bb[0][4] & 0xfe) != 0)
        return 0;

    b = databits.bb[0];

    // The unit ID changes when you rebind by holding a magnet to the
    // sensor for long enough.
    unit_id = (b[0] << 8) | b[1];

    // 0x01: Rebinding (magnet held to sensor)
    // 0x02: High-bit for depth
    // 0x04: (always zero?)
    // 0x08: Leak/theft alarm
    // 0x10: (unknown toggle)
    // 0x20: (unknown toggle)
    // 0x40: (unknown toggle)
    // 0x80: (always zero?)
    flags = b[2] & ~0x0A;
    alarm = (b[2] & 0x08) >> 3;

    if (flags & 1)
        // When binding, the countdown counts up from 0x40 to 0x4a
        // (as long as you hold the magnet to it for long enough)
        // before the device ID changes. The receiver unit needs
        // to receive this *strongly* in order to change its
        // allegiance.
        binding_countdown = b[3];
    else
        // A depth reading of zero indicates no reading.
        depth = ((b[2] & 0x02) << 7) | b[3];

    data = data_make(
            "model", "", DATA_STRING, _X("Oil-SonicStd","Oil Ultrasonic STANDARD"),
            "id", "", DATA_FORMAT, "%04x", DATA_INT, unit_id,
            "flags", "", DATA_FORMAT, "%02x", DATA_INT, flags,
            "alarm", "", DATA_INT, alarm,
            "binding_countdown", "", DATA_INT, binding_countdown,
            "depth_cm", "", DATA_INT, depth,
            NULL);
    decoder_output_data(decoder, data);

    return 1;
}
Exemplo n.º 5
0
static int thermopro_tp12_sensor_callback(bitbuffer_t *bitbuffer) {
    int iTemp1, iTemp2, good = -1;
    float fTemp1, fTemp2;
    uint8_t *bytes;
    unsigned int device, value;
    char time_str[LOCAL_TIME_BUFLEN];
    data_t *data;

    // The device transmits 16 rows, let's check for 3 matching.
    // (Really 17 rows, but the last one doesn't match because it's missing a trailing 1.)
    good = bitbuffer_find_repeated_row(bitbuffer, 5, 40);
    if (good < 0) {
        return 0;
    }

    bytes = bitbuffer->bb[good];
    if (!bytes[0] && !bytes[1] && !bytes[2] && !bytes[3]) {
        return 0; // reduce false positives
    }

    // Note: the device ID changes randomly each time you replace the battery, so we can't early out based on it.
    // This is probably to allow multiple devices to be used at once.  When you replace the receiver batteries
    // or long-press its power button, it pairs with the first device ID it hears.
    device = bytes[0];

    if(debug_output) {
        // There is a mysterious checksum in bytes[4].  It may be the same as the checksum used by the TP-11,
        // which consisted of a lookup table containing, for each bit in the message, a byte to be xor-ed into
        // the checksum if the message bit was 1.  It should be possible to solve for that table using Gaussian
        // elimination, so dump some data so we can try this.

        // This format is easily usable by bruteforce-crc, after piping through | grep raw_data | cut -d':' -f2 
        // bruteforce-crc didn't find anything, though - this may not be a CRC algorithm specifically.
        fprintf(stderr,"thermopro_tp12_raw_data:");
        for(int bit_index = 0; bit_index < 40; ++bit_index){
            fputc(bitrow_get_bit(bytes, bit_index) + '0', stderr);
        }
        fputc('\n', stderr);
    }

    iTemp1 = ((bytes[2] & 0xf0) << 4) | bytes[1];
    iTemp2 = ((bytes[2] & 0x0f) << 8) | bytes[3];

    fTemp1 = (iTemp1 - 200) / 10.;
    fTemp2 = (iTemp2 - 200) / 10.;

    local_time_str(0, time_str);
    data = data_make("time",          "",            DATA_STRING, time_str,
                     "model",         "",            DATA_STRING, MODEL,
                     "id",            "Id",          DATA_FORMAT, "\t %d",   DATA_INT,    device,
                     "temperature_1_C", "Temperature 1 (Food)", DATA_FORMAT, "%.01f C", DATA_DOUBLE, fTemp1,
                     "temperature_2_C", "Temperature 2 (Barbecue)", DATA_FORMAT, "%.01f C", DATA_DOUBLE, fTemp2,
                     NULL);
    data_acquired_handler(data);
    return 1;
}
Exemplo n.º 6
0
static int current_cost_callback(bitbuffer_t *bitbuffer) {
    bitbuffer_invert(bitbuffer);
    bitrow_t *bb = bitbuffer->bb;
    uint8_t *b = bb[0];

    char time_str[LOCAL_TIME_BUFLEN];
    data_t *data;
    local_time_str(0, time_str);

    uint8_t init_pattern[] = {
        0b11001100, //8
        0b11001100, //16
        0b11001100, //24
        0b11001110, //32
        0b10010001, //40
        0b01011101, //45 (! last 3 bits is not init)
    };
    unsigned int start_pos = bitbuffer_search(bitbuffer, 0, 0, init_pattern, 45);

    if(start_pos == bitbuffer->bits_per_row[0]){
        return 0;
    }
    start_pos += 45;

    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] & 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,
                //"battery",       "Battery",       DATA_STRING, battery_low ? "LOW" : "OK", //TODO is there some low battery indicator ?
                NULL);
        data_acquired_handler(data);
        return 1;
    }
    return 0;
}
Exemplo n.º 7
0
static int ge_coloreffects_decode(r_device *decoder, bitbuffer_t *bitbuffer, unsigned row, unsigned start_pos)
{
    data_t *data;
    bitbuffer_t packet_bits = {0};
    uint8_t device_id;
    uint8_t command;

    ge_decode(decoder, bitbuffer, row, start_pos, &packet_bits);
    //bitbuffer_print(&packet_bits);

    /* From http://www.deepdarc.com/2010/11/27/hacking-christmas-lights/
     * Decoded frame format is:
     *   Preamble
     *   Two zero bits
     *   6-bit Device ID (Can be modified by adding R15-R20 on the large PCB)
     *   8-bit Command
     *   One zero bit
     */
    
    // Frame should be 17 decoded bits (not including preamble)
    if (packet_bits.bits_per_row[0] != 17)
        return 0;
    
    // First two bits must be 0
    if (*packet_bits.bb[0] & 0xc0)
        return 0;
    
    // Last bit must be 0
    if (bit(packet_bits.bb[0], 16) != 0)
        return 0;
    
    // Extract device ID
    // We want bits [2..8]. Since the first two bits are zero, we'll just take the entire first byte
    device_id = *packet_bits.bb[0];

    // Extract command from the second byte
    bitbuffer_extract_bytes(&packet_bits, 0, 8, &command, 8);
    
    // Format data
    data = data_make(
        "model",         "",     DATA_STRING, "GE Color Effects Remote",
        "id",            "",     DATA_FORMAT, "0x%x", DATA_INT, device_id,
        "command",       "",     DATA_STRING, ge_command_name(command),
        NULL);

    decoder_output_data(decoder, data);
    return 1;

}
Exemplo n.º 8
0
// Acurite 609 Temperature and Humidity Sensor
// 5 byte messages
// II ST TT HH CC
// II - ID byte, changes at each power up
// S - Status bitmask, normally 0x2,
//     0xa - battery low (bit 0x80)
// TTT - Temp in Celsius * 10, 12 bit with complement.
// HH - Humidity
// CC - Checksum
//
// @todo - see if the 3rd nybble is battery/status
//
static int acurite_th_callback(bitbuffer_t *bitbuf) {
    uint8_t *bb = NULL;
    int cksum, battery_low, valid = 0;
    float tempc;
    uint8_t humidity, id, status;
    data_t *data;

    local_time_str(0, time_str);

    for (uint16_t brow = 0; brow < bitbuf->num_rows; ++brow) {
        if (bitbuf->bits_per_row[brow] != 40) {
	    continue;
	}

	bb = bitbuf->bb[brow];

	cksum = (bb[0] + bb[1] + bb[2] + bb[3]);

	if (cksum == 0 || ((cksum & 0xff) != bb[4])) {
	    continue;
	}

	tempc = acurite_th_temperature(bb);
	id = bb[0];
	status = (bb[1] & 0xf0) >> 4;
	battery_low = status & 0x8;
	humidity = bb[3];

	data = data_make(
		     "time",		"",		DATA_STRING,	time_str,
		     "model",		"",		DATA_STRING,	"Acurite 609TXC Sensor",
		     "id",		"",		DATA_INT,	id,
		     "battery",		"",		DATA_STRING,	battery_low ? "LOW" : "OK",
		     "status",		"",		DATA_INT,	status,
		     "temperature_C", 	"Temperature",	DATA_FORMAT,	"%.1f C", DATA_DOUBLE, tempc,
		     "humidity",        "Humidity",	DATA_INT,	humidity,
		     NULL);

	data_acquired_handler(data);
	valid++;
    }

    if (valid)
        return 1;

    return 0;
}
Exemplo n.º 9
0
static int maverick_et73_sensor_callback(r_device *decoder, bitbuffer_t *bitbuffer) {
    int temp1_raw, temp2_raw, row;
    float temp1_c, temp2_c;
    uint8_t *bytes;
    unsigned int device;
    data_t *data;

    // The device transmits many rows, let's check for 3 matching.
    row = bitbuffer_find_repeated_row(bitbuffer, 3, 48);
    if (row < 0) {
        return 0;
    }

    bytes = bitbuffer->bb[row];
    if (!bytes[0] && !bytes[1] && !bytes[2] && !bytes[3]) {
        return 0; // reduce false positives
    }

    if (bitbuffer->bits_per_row[row] != 48)
        return 0;

    device = bytes[0];

    if (decoder->verbose) {
        fprintf(stderr,"maverick_et73_raw_data:");
        bitrow_print(bytes, 48);
    }

    temp1_raw = (bytes[1] << 4) | ((bytes[2] & 0xf0) );
    temp2_raw = ((bytes[2] & 0x0f) << 8) | bytes[3];

    temp1_c = temp1_raw * 0.1;
    temp2_c = temp2_raw * 0.1;

    data = data_make(
            "model",            "",                 DATA_STRING, "Maverick ET73",
            "rid",              "Random Id",        DATA_INT, device,
            "temperature_1_C",  "Temperature 1",    DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp1_c,
            "temperature_2_C",  "Temperature 2",    DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp2_c,
            NULL);
    decoder_output_data(decoder, data);
    return 1;
}
Exemplo n.º 10
0
static int pool_temperature_sensor_callback(bitbuffer_t *bitbuffer) {
	bitrow_t *bb = bitbuffer->bb;
	data_t *data;
	char time_str[LOCAL_TIME_BUFLEN];
    local_time_str(0, time_str);
	int i,device,channel;
	float fTemp;


	for(i=1;i<8;i++){
		if(bitbuffer->bits_per_row[i]!=28){
			/*10 24 bits frame*/
			return 0;
		}
	}

/*
AAAABBBB BBBBCCCC CCCCCCCC DDEE

A: ?
B: device id (changing only after reset)
C: templerature
D: channel number
E: ?
*/

        device=(((bb[1][0]&0xF)<<4)+((bb[1][1]&0xF0)>>4));
        fTemp=((signed short)(((bb[1][1]&0xF)<<8)+bb[1][2])/10.0);
	channel=(signed short)((bb[1][3]&0xC0)>>6);

	data = data_make("time", 	"", 			DATA_STRING, 					time_str,
                     "model",		"", 			DATA_STRING, 	"TFA pool temperature sensor",
		     "id",         	"Id",			DATA_FORMAT,	"\t %d",	DATA_INT,	device,
		     "channel",        	"Channel number",	DATA_FORMAT,	"\t %d",	DATA_INT,	channel,
                     "temperature_C",	"Temperature",		DATA_FORMAT, 	"%.01f C",	DATA_DOUBLE,	fTemp,
                     NULL);
    data_acquired_handler(data);
	
    return 1; 
	
}
Exemplo n.º 11
0
static int generic_temperature_sensor_callback(bitbuffer_t *bitbuffer) {
	bitrow_t *bb = bitbuffer->bb;
	data_t *data;
	char time_str[LOCAL_TIME_BUFLEN];
    local_time_str(0, time_str);
	int i,device,battery;
	float fTemp;


	for(i=1;i<10;i++){
		if(bitbuffer->bits_per_row[i]!=24){
			/*10 24 bits frame*/
			return 0;
		}
	}

	//AAAAAAAA BBCCCCCC CCCCCCCC
	//AAAAAAAA     : ID
	//BBBB         : battery ?
	//CCCCCCCCCCCC : Temp

	device=(bb[1][0]);
	battery=(bb[1][1]&0xF0)>>4;
	fTemp=(float)((signed short)(((bb[1][1]&0x3f)*256+bb[1][2])<<2))/160.0;

	data = data_make("time", 	"", 			DATA_STRING, 					time_str,
                     "model",		"", 			DATA_STRING, 	"Generic temperature sensor 1",
		     "id",         	"Id",			DATA_FORMAT,	"\t %d",	DATA_INT,	device,
                     "temperature_C",	"Temperature",		DATA_FORMAT, 	"%.02f C",	DATA_DOUBLE,	fTemp,
                     "battery",      	"Battery?",		DATA_INT,					battery,
                     NULL);
    data_acquired_handler(data);
	
    return 1; 
	
}
Exemplo n.º 12
0
static int newkaku_callback(bitbuffer_t *bitbuffer) {
    /* 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 */
    data_t *data;
    bitrow_t *bb = bitbuffer->bb;
    int i;
    uint8_t tmp = 0;
    uint8_t unit = 0;
    uint8_t packet = 0;
    uint8_t bitcount = 0;
    uint32_t kakuid = 0;
    uint8_t dv = 0;
    char *group_call, *command, *dim;
    char time_str[LOCAL_TIME_BUFLEN];
    local_time_str(0, time_str);

    if (bb[0][0] == 0xac || bb[0][0] == 0xb2) {//always starts with ac or b2
        // 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 valid 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 {
                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
            }
        }
        group_call = (((bb[0][6] & (0x04)) == 0x04)&((bb[0][6] & (0x02)) == 0)) ? "Yes" : "No";
        command = (((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
            dim = "Yes";
            tmp = bb[0][8] << 1; // get packet, loose first bit

            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
                    }
                }
            }
        } else {
            dim = "No";
        }

        data = data_make("time",          "",            DATA_STRING, time_str,
                         "model",         "",            DATA_STRING, "KlikAanKlikUit Wireless Switch",
                         "id",            "",            DATA_INT, kakuid,
                         "unit",          "Unit",        DATA_INT, unit,
                         "group_call",    "Group Call",  DATA_STRING, group_call,
                         "command",       "Command",     DATA_STRING, command,
                         "dim",           "Dim",         DATA_STRING, dim,
                         "dim_value",     "Dim Value",   DATA_INT, dv,
                         NULL);
        data_acquired_handler(data);

        return 1;
    }
    return 0;
}
Exemplo n.º 13
0
static int steelmate_callback(bitbuffer_t *bitbuffer) {
	//if (debug_output >= 1) {
	//	fprintf(stdout, "Steelmate TPMS decoder\n");
	//	bitbuffer_print(bitbuffer);
	//	fprintf(stdout, "\n");
	//}

	char time_str[LOCAL_TIME_BUFLEN];
	local_time_str(0, time_str);
	bitrow_t *bb = bitbuffer->bb;

	//Loop through each row of data
	for (int i = 0; i < bitbuffer->num_rows; i++)
	{
		//Payload is inverted Manchester encoded, and reversed MSB/LSB order
		uint8_t preAmble, ID1, ID2, p1, tempFahrenheit, tmpbattery_mV, payload_checksum, calculated_checksum;
		uint16_t sensorID, battery_mV;
		float pressurePSI;
		char sensorIDhex[7];
		data_t *data;

		//Length must be 72 bits to be considered a valid packet
		if (bitbuffer->bits_per_row[i] != 72)
			continue;

		//Valid preamble? (Note, the data is still wrong order at this point. Correct pre-amble: 0x00 0x00 0x01)
		if (bb[i][0] != 0x00 || bb[i][1] != 0x00 || bb[i][2] != 0x7f)
			continue;

		//Preamble
		preAmble = ~reverse8(bb[i][2]);

		//Sensor ID
		ID1 = ~reverse8(bb[i][3]);
		ID2 = ~reverse8(bb[i][4]);

		//Pressure is stored as twice the PSI
		p1 = ~reverse8(bb[i][5]);

		//Temperature is stored in Fahrenheit. Note that the datasheet claims operational to -40'C, but can only express values from -17.8'C
		tempFahrenheit = ~reverse8(bb[i][6]);

		//Battery voltage is stored as half the mV
		tmpbattery_mV = ~reverse8(bb[i][7]);

		//Checksum is a sum of all the other values
		payload_checksum = ~reverse8(bb[i][8]);
		calculated_checksum = preAmble + ID1 + ID2 + p1 + tempFahrenheit + tmpbattery_mV;
		if (payload_checksum != calculated_checksum)
			continue;

		sensorID = (ID1 << 8) + ID2;
		sprintf(sensorIDhex, "0x%04x", sensorID);
		pressurePSI = (float)p1 / 2;
		battery_mV = tmpbattery_mV * 2;

		data = data_make("time", "", DATA_STRING, time_str,
			"type", "", DATA_STRING, "TPMS",
			"model", "", DATA_STRING, "Steelmate",
			"id", "", DATA_STRING, sensorIDhex,
			"pressure_PSI", "", DATA_DOUBLE, pressurePSI,
			"temperature_F", "", DATA_DOUBLE, (float)tempFahrenheit,
			"battery_mV", "", DATA_INT, battery_mV,
			"mic", "Integrity", DATA_STRING, "CHECKSUM",
			NULL);
		data_acquired_handler(data);

		return 1;
	}

	//Was not a Steelmate TPMS after all
	return 0;
}
Exemplo n.º 14
0
static int template_callback(bitbuffer_t *bitbuffer) {
    char time_str[LOCAL_TIME_BUFLEN];
    uint8_t *bb;
    uint16_t brow, row_nbytes;
    uint16_t sensor_id = 0;
    uint8_t msg_type, r_crc, c_crc;
    int16_t value;
    data_t *data;
    int valid = 0;


    /*
     * Early debugging aid to see demodulated bits in buffer and
     * to determine if your limit settings are matched and firing
     * this callback.
     *
     * 1. Enable with -D -D (debug level of 2)
     * 2. Delete this block when your decoder is working
     */
    //    if (debug_output > 1) {
    //        fprintf(stderr,"new_tmplate callback:\n");
    //        bitbuffer_print(bitbuffer);
    //    }

    local_time_str(0, time_str);

    /*
     * bit buffer will contain multiple rows, many of them empty.
     * Typically a complete message will be contained in a single
     * row if long and reset limits are set correctly.
     * May contain multiple message repeats.
     * Message might not appear in row 0, if protocol uses
     * start/preamble periods of different lengths.
     */

    for (brow = 0; brow < bitbuffer->num_rows; ++brow) {
    bb = bitbuffer->bb[brow];

    /*
     * Validate message and reject invalid messages as
     * early as possible before attempting to parse data..
     *
     * Check "message envelope"
     * - valid message length
     * - valid preamble/device type/fixed bits if any
     * - Data integrity checks (CRC/Checksum/Parity)
     */

    if (bitbuffer->bits_per_row[brow] != 68)
        continue;

    /*
     * number of bytes in row.
     *
     * Number of decoded bits may not be a multiple of 8.
     * bitbuffer row will have enough bytes to contain
     * all bytes, so round up.
     */
    row_nbytes = (bitbuffer->bits_per_row[brow] + 7)/8;


    /*
     * Reject rows that don't start with the correct start byte
     * Example message should start with 0xAA
     */
    if (bb[0] != MYDEVICE_STARTBYTE)
        continue;

    /*
     * Check message integrity (CRC/Checksum/parity)
     *
     * Example device uses CRC-8
     */
    r_crc = bb[row_nbytes - 1];
    c_crc = crc8(bb, row_nbytes - 1, MYDEVICE_CRC_POLY, MYDEVICE_CRC_INIT);
    if (r_crc != c_crc) {
        // example debugging output
        if (debug_output >= 1)
        fprintf(stderr, "%s new_tamplate bad CRC: calculated %02x, received %02x\n",
            time_str, c_crc, r_crc);

        // reject row
        continue;
    }

    /*
     * Now that message "envelope" has been validated,
     * start parsing data.
     */

    msg_type = bb[1];
    sensor_id = bb[2] << 8 | bb[3];
    value = bb[4] << 8 | bb[5];

    if (msg_type != MYDEVICE_MSG_TYPE) {
        /*
         * received an unexpected message type
         * could be a bad message or a new message not
         * previously seen.  Optionally log debug putput.
         */
        continue;
    }

    data = data_make("time", "", DATA_STRING, time_str,
        "model", "", DATA_STRING, "New Template",
        "id", "", DATA_INT, sensor_id,
        "data","", DATA_INT, value,
        NULL);

    data_acquired_handler(data);

    valid++;
    }

    // Return 1 if message successfully decoded
    if (valid)
    return 1;

    return 0;
}
Exemplo n.º 15
0
static int oil_watchman_callback(bitbuffer_t *bitbuffer) {
	uint8_t *b;
	uint32_t unit_id;
	uint16_t depth = 0;
	uint16_t binding_countdown = 0;
	uint8_t flags;
	uint8_t maybetemp;
	double temperature;
	char time_str[LOCAL_TIME_BUFLEN];
	data_t *data;
	unsigned bitpos = 0;
	bitbuffer_t databits = {0};
	int events = 0;

	local_time_str(0, time_str);

	// Find a preamble with enough bits after it that it could be a complete packet
	while ((bitpos = bitbuffer_search(bitbuffer, 0, bitpos, &preamble_pattern, 6)) + 136 <=
	       bitbuffer->bits_per_row[0]) {

		// Skip the matched preamble bits to point to the data
		bitpos += 6;

		bitpos = bitbuffer_manchester_decode(bitbuffer, 0, bitpos, &databits, 64);
		if (databits.bits_per_row[0] != 64)
			continue;

		b = databits.bb[0];

		// Check for postamble, depending on last data bit
		if (bitbuffer_search(bitbuffer, 0, bitpos, &postamble_pattern[b[7] & 1], 2) != bitpos)
			continue;

		if (b[7] != crc8le(b, 7, 0x31, 0))
			continue;

		// The unit ID changes when you rebind by holding a magnet to the
		// sensor for long enough; it seems to be time-based.
		unit_id = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];

		// 0x01: Rebinding (magnet held to sensor)
		// 0x08: Leak/theft alarm
		// top three bits seem also to vary with temperature (independently of maybetemp)
		flags = b[4];

		// Not entirely sure what this is but it might be inversely
		// proportional to temperature.
		maybetemp = b[5] >> 2;
		temperature = (double)(145.0 - 5.0 * maybetemp) / 3.0;
		if (flags & 1)
			// When binding, the countdown counts up from 0x51 to 0x5a
			// (as long as you hold the magnet to it for long enough)
			// before the device ID changes. The receiver unit needs
			// to receive this *strongly* in order to change its
			// allegiance.
			binding_countdown = b[6];
		else
			// A depth reading of zero indicates no reading. Even with
			// the sensor flat down on a table, it still reads about 13.
			depth = ((b[5] & 3) << 8) | b[6];

		data = data_make("time", "", DATA_STRING, time_str,
			"model", "", DATA_STRING, "Oil Watchman",
			"id", "", DATA_FORMAT, "%06x", DATA_INT, unit_id,
			"flags", "", DATA_FORMAT, "%02x", DATA_INT, flags,
			"maybetemp", "", DATA_INT, maybetemp,
			"temperature_C", "", DATA_DOUBLE, temperature,
			"binding_countdown", "", DATA_INT, binding_countdown,
			"depth", "", DATA_INT, depth,
			NULL);
		data_acquired_handler(data);
		events++;
	}
	return events;
}
Exemplo n.º 16
0
static int efergy_optical_callback(bitbuffer_t *bitbuffer) { 
	unsigned num_bits = bitbuffer->bits_per_row[0];
	uint8_t *bytes = bitbuffer->bb[0];
	double power, n_imp;
	double pulsecount;
	double seconds;
	data_t *data;
        char time_str[LOCAL_TIME_BUFLEN];
 	uint16_t crc;       
	uint16_t csum1;

	if (num_bits < 64 || num_bits > 100){ 
		return 0;
		}

	// The bit buffer isn't always aligned to the transmitted data, so
	// search for data start and shift out the bits which aren't part
	// of the data. The data always starts with 0000 (or 1111 if
	// gaps/pulses are mixed up).
	while ((bytes[0] & 0xf0) != 0xf0 && (bytes[0] & 0xf0) != 0x00) 
		{
		num_bits -= 1;
		if (num_bits < 64)
			{
			return 0;
			}

		for (unsigned i = 0; i < (num_bits + 7) / 8; ++i) 
			{
			bytes[i] <<= 1;
			bytes[i] |= (bytes[i + 1] & 0x80) >> 7;
			}
		}

	// Sometimes pulses and gaps are mixed up. If this happens, invert
	// all bytes to get correct interpretation.
	if (bytes[0] & 0xf0){
		for (unsigned i = 0; i < 12; ++i) 
			{
			bytes[i] = ~bytes[i];
			}
		}

	 if (debug_output){ 
     		fprintf(stdout,"Possible Efergy Optical: ");
     		bitbuffer_print(bitbuffer);
		}
	
	// Calculate checksum for bytes[0..10]
	// crc16 xmodem with start value of 0x00 and polynomic of 0x1021 is same as CRC-CCITT (0x0000)         
	// start of data, length of data=10, polynomic=0x1021, init=0x0000	  

	  csum1 = ((bytes[10]<<8)|(bytes[11]));

   	  crc = crc16_ccitt(bytes, 10, 0x1021, 0x0);

	  if (crc == csum1)
       		{ 
       		if (debug_output) {
		fprintf (stdout, "Checksum OK :) :)\n");
        	fprintf (stdout, "Calculated crc is 0x%02X\n", crc);
        	fprintf (stdout, "Received csum1 is 0x%02X\n", csum1);
		}
		// this setting depends on your electricity meter's optical output	
		n_imp = 3200;

		pulsecount =  bytes[8];
		seconds = bytes[10];

		//some logic for low pulse count not sure how I reached this formula
		if (pulsecount < 3)
			{
			power = ((pulsecount/n_imp) * (3600/seconds));
        		}
         	else
         		{
         		power = ((pulsecount/n_imp) * (3600/30));
         		}
         	/* Get time now */
	        local_time_str(0, time_str);

		 data = data_make("time",          "",            DATA_STRING, time_str,
        			"model",         "",            DATA_STRING, "Efergy Optical",
                 		"power",       "Power KWh",     DATA_FORMAT,"%.03f KWh", DATA_DOUBLE, power,
	               		   NULL);
	 	data_acquired_handler(data);
		return 0;
		}
		else 
			{
			if (debug_output)
				{ 
 				fprintf (stdout, "Checksum not OK !!!\n");
				fprintf(stdout, "Calculated crc is 0x%02X\n", crc);
				fprintf(stdout, "Received csum1 is 0x%02X\n", csum1);
				}
			}
		return 0;
		}
Exemplo n.º 17
0
static int nexus_callback(bitbuffer_t *bitbuffer) {
    bitrow_t *bb = bitbuffer->bb;
    data_t *data;

    char time_str[LOCAL_TIME_BUFLEN];

    if (debug_output > 1) {
       fprintf(stderr,"Possible Nexus: ");
       bitbuffer_print(bitbuffer);
    }

    uint8_t id;
    uint8_t channel;
    int16_t temp;
    uint8_t humidity;
    int r = bitbuffer_find_repeated_row(bitbuffer, 3, 36);

    /** The nexus protocol will trigger on rubicson data, so calculate the rubicson crc and make sure
      * it doesn't match. By guesstimate it should generate a correct crc 1/255% of the times.
      * So less then 0.5% which should be acceptable.
      */
    if (!rubicson_crc_check(bb) &&
        r >= 0 &&
        bitbuffer->bits_per_row[r] <= 37 && // we expect 36 bits but there might be a trailing 0 bit
        bb[r][0] != 0 &&
        bb[r][1] != 0 &&
        bb[r][2] != 0 &&
        bb[r][3] != 0) {

        /* Get time now */
        local_time_str(0, time_str);

        /* Nibble 0,1 contains id */
        id = bb[r][0];

        channel = (bb[r][1]&0x03) + 1;

        /* Nible 3,4,5 contains 12 bits of temperature
         * The temerature is signed and scaled by 10 */
        temp = (int16_t)((uint16_t)(bb[r][1] << 12) | (bb[r][2] << 4));
        temp = temp >> 4;
        humidity = (uint8_t)(((bb[r][3]&0x0F)<<4)|(bb[r][4]>>4));

        // Thermo
        if (bb[r][3] == 0xF0) {
        data = data_make("time",          "",            DATA_STRING, time_str,
                         "model",         "",            DATA_STRING, "Nexus Temperature",
                         "id",            "House Code",  DATA_INT, id,
                         "channel",       "Channel",     DATA_INT, channel,
                         "temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp/10.0,
                         NULL);
        data_acquired_handler(data);
        }
        // Thermo/Hygro
        else {
        data = data_make("time",          "",            DATA_STRING, time_str,
                         "model",         "",            DATA_STRING, "Nexus Temperature/Humidity",
                         "id",            "House Code",  DATA_INT, id,
                         "channel",       "Channel",     DATA_INT, channel,
                         "temperature_C", "Temperature", DATA_FORMAT, "%.02f C", DATA_DOUBLE, temp/10.0,
                         "humidity",      "Humidity",    DATA_FORMAT, "%u %%", DATA_INT, humidity,
                         NULL);
        data_acquired_handler(data);
        }
        return 1;
    }
Exemplo n.º 18
0
static int tpms_citroen_decode(bitbuffer_t *bitbuffer, unsigned row, unsigned bitpos) {
    char time_str[LOCAL_TIME_BUFLEN];
    data_t *data;
    unsigned int start_pos;
    bitbuffer_t packet_bits = {0};
    uint8_t *b;
    int state;
    char state_str[3];
    unsigned id;
    char id_str[9];
    int flags;
    int repeat;
    int pressure;
    int temperature;
    int battery;
    char code_str[7];
    int crc;

    bitbuffer_invert(bitbuffer);
    start_pos = bitbuffer_manchester_decode(bitbuffer, row, bitpos, &packet_bits, 88);
    b = packet_bits.bb[0];

    if (b[6] == 0 || b[7] == 0) {
        return 0; // sanity check failed
    }

    crc = b[1]^b[2]^b[3]^b[4]^b[5]^b[6]^b[7]^b[8]^b[9];
    if (crc != 0) {
        return 0; // bad checksum
    }

    state = b[0]; // not covered by CRC
    sprintf(state_str, "%02x", state);
    id = b[1]<<24 | b[2]<<16 | b[3]<<8 | b[4];
    sprintf(id_str, "%08x", id);
    flags = b[5]>>4;
    repeat = b[5]&0x0f;
    pressure = b[6];
    temperature = b[7];
    battery = b[8];
    sprintf(code_str, "%02x%02x%02x", pressure, temperature, battery);

    local_time_str(0, time_str);
    data = data_make(
        "time",         "",     DATA_STRING, time_str,
        "model",        "",     DATA_STRING, "Citroen",
        "type",         "",     DATA_STRING, "TPMS",
        "state",        "",     DATA_STRING, state_str,
        "id",           "",     DATA_STRING, id_str,
        "flags",        "",     DATA_INT, flags,
        "repeat",       "",     DATA_INT, repeat,
//        "pressure_bar", "Pressure",    DATA_FORMAT, "%.03f bar", DATA_DOUBLE, (double)pressure*0.0125,
//        "temperature_C", "Temperature", DATA_FORMAT, "%.0f C", DATA_DOUBLE, (double)temperature-50.0,
//        "battery_mV",   "Battery", DATA_INT, battery_mV,
        "code",         "",     DATA_STRING, code_str,
        "mic",          "",     DATA_STRING, "CHECKSUM",
        NULL);

    data_acquired_handler(data);
    return 1;
}
Exemplo n.º 19
0
/*
 * This callback handles several Acurite devices that use a very
 * similar RF encoding and data format:
 *:
 * - 592TXR temperature and humidity sensor
 * - 5-n-1 weather station
 * - 6045M Lightning Detectur with Temperature and Humidity
 */
static int acurite_txr_callback(bitbuffer_t *bitbuf) {
    int browlen, valid = 0;
    uint8_t *bb;
    float tempc, tempf, wind_dird, rainfall = 0.0, wind_speed, wind_speedmph;
    uint8_t humidity, sensor_status, sequence_num, message_type;
    char channel, *wind_dirstr = "";
    char channel_str[2];
    uint16_t sensor_id;
    int raincounter, temp, battery_low;
    uint8_t strike_count, strike_distance;
    data_t *data;


    local_time_str(0, time_str);

    if (debug_output > 1) {
        fprintf(stderr,"acurite_txr\n");
        bitbuffer_print(bitbuf);
    }

    for (uint16_t brow = 0; brow < bitbuf->num_rows; ++brow) {
	browlen = (bitbuf->bits_per_row[brow] + 7)/8;
	bb = bitbuf->bb[brow];

	if (debug_output > 1)
	    fprintf(stderr,"acurite_txr: row %d bits %d, bytes %d \n", brow, bitbuf->bits_per_row[brow], browlen);

	if ((bitbuf->bits_per_row[brow] < ACURITE_TXR_BITLEN ||
	     bitbuf->bits_per_row[brow] > ACURITE_5N1_BITLEN + 1) &&
	    bitbuf->bits_per_row[brow] != ACURITE_6045_BITLEN) {
	    if (debug_output > 1 && bitbuf->bits_per_row[brow] > 16)
		fprintf(stderr,"acurite_txr: skipping wrong len\n");
	    continue;
	}

	// There will be 1 extra false zero bit added by the demod.
	// this forces an extra zero byte to be added
	if (bb[browlen - 1] == 0)
	    browlen--;

	if (!acurite_checksum(bb,browlen - 1)) {
	    if (debug_output) {
		fprintf(stderr, "%s Acurite bad checksum:", time_str);
		for (uint8_t i = 0; i < browlen; i++)
		    fprintf(stderr," 0x%02x",bb[i]);
		fprintf(stderr,"\n");
	    }
	    continue;
	}

	if (debug_output) {
	    fprintf(stderr, "acurite_txr Parity: ");
	    for (uint8_t i = 0; i < browlen; i++) {
		fprintf(stderr,"%d",byteParity(bb[i]));
	    }
	    fprintf(stderr,"\n");
	}


	// tower sensor messages are 7 bytes.
	// @todo - see if there is a type in the message that
	// can be used instead of length to determine type
	if (browlen == ACURITE_TXR_BITLEN / 8) {
	    channel = acurite_getChannel(bb[0]);
	    sensor_id = acurite_txr_getSensorId(bb[0],bb[1]);
	    sensor_status = bb[2]; // @todo, uses parity? & 0x07f
	    humidity = acurite_getHumidity(bb[3]);
	    tempc = acurite_txr_getTemp(bb[4], bb[5]);
            sprintf(channel_str, "%c", channel);
            battery_low = sensor_status >>7;
		
            data = data_make(
                    "time",			"",		DATA_STRING,	time_str,
                    "model",	        	"",		DATA_STRING,	"Acurite tower sensor",
                    "id",			"",		DATA_INT,	sensor_id,
                    "channel",  		"",     	DATA_STRING, 	&channel_str,
                    "temperature_C", 	"Temperature",	DATA_FORMAT,	"%.1f C", DATA_DOUBLE, tempc,
                    "humidity",         "Humidity",	DATA_INT,	humidity,
                    "battery",          "Battery",    	DATA_INT, 	battery_low,
                    "status",		"",		DATA_INT,	sensor_status,
                    NULL);

            data_acquired_handler(data);
            valid++;
	}

	// The 5-n-1 weather sensor messages are 8 bytes.
	if (browlen == ACURITE_5N1_BITLEN / 8) {
        if (debug_output) {
            fprintf(stderr, "Acurite 5n1 raw msg: %02X %02X %02X %02X %02X %02X %02X %02X\n",
                bb[0], bb[1], bb[2], bb[3], bb[4], bb[5], bb[6], bb[7]);
        }
	    channel = acurite_getChannel(bb[0]);
        sprintf(channel_str, "%c", channel);        
	    sensor_id = acurite_5n1_getSensorId(bb[0],bb[1]);
	    sequence_num = acurite_5n1_getMessageCaught(bb[0]);
	    message_type = bb[2] & 0x3f;
        battery_low = (bb[2] & 0x40) >> 6;

	    if (message_type == ACURITE_MSGTYPE_WINDSPEED_WINDDIR_RAINFALL) {
            // Wind speed, wind direction, and rain fall
            wind_speed = acurite_getWindSpeed_kph(bb[3], bb[4]);
            wind_speedmph = kmph2mph(wind_speed);
            wind_dird = acurite_5n1_winddirections[bb[4] & 0x0f];
            wind_dirstr = acurite_5n1_winddirection_str[bb[4] & 0x0f];
            raincounter = acurite_getRainfallCounter(bb[5], bb[6]);
            if (acurite_5n1t_raincounter > 0) {
                // track rainfall difference after first run
                // FIXME when converting to structured output, just output
                // the reading, let consumer track state/wrap around, etc. 
                rainfall = ( raincounter - acurite_5n1t_raincounter ) * 0.01;
                if (raincounter < acurite_5n1t_raincounter) {
                    fprintf(stderr, "%s Acurite 5n1 sensor 0x%04X Ch %c, rain counter reset or wrapped around (old %d, new %d)\n",
                        time_str, sensor_id, channel, acurite_5n1t_raincounter, raincounter);
                    acurite_5n1t_raincounter = raincounter;
                }
            } else {
                // capture starting counter
                acurite_5n1t_raincounter = raincounter;
                fprintf(stderr, "%s Acurite 5n1 sensor 0x%04X Ch %c, Total rain fall since last reset: %0.2f\n",
                time_str, sensor_id, channel, raincounter * 0.01);
            }
                
            data = data_make(
                "time",         "",   DATA_STRING,    time_str,
                "model",        "",   DATA_STRING,    "Acurite 5n1 sensor",
                "sensor_id",    NULL,   DATA_FORMAT,    "0x%02X",   DATA_INT,       sensor_id,   
                "channel",      NULL,   DATA_STRING,    &channel_str,
                "sequence_num",  NULL,   DATA_INT,      sequence_num,
                "battery",      NULL,   DATA_STRING,    battery_low ? "OK" : "LOW",
                "message_type", NULL,   DATA_INT,       message_type,
                "wind_speed",   NULL,   DATA_FORMAT,    "%.1f mph", DATA_DOUBLE,     wind_speedmph,
                "wind_dir_deg", NULL,   DATA_FORMAT,    "%.1f", DATA_DOUBLE,    wind_dird,
                "wind_dir",     NULL,   DATA_STRING,    wind_dirstr,
                "rainfall_accumulation",     NULL,   DATA_FORMAT,    "%.2f in", DATA_DOUBLE,    rainfall,
                "raincounter_raw",  NULL,   DATA_INT,   raincounter,
                NULL);

            data_acquired_handler(data);

	    } else if (message_type == ACURITE_MSGTYPE_WINDSPEED_TEMP_HUMIDITY) {
            // Wind speed, temperature and humidity
            wind_speed = acurite_getWindSpeed_kph(bb[3], bb[4]);
            wind_speedmph = kmph2mph(wind_speed);
            tempf = acurite_getTemp(bb[4], bb[5]);
            tempc = fahrenheit2celsius(tempf);
            humidity = acurite_getHumidity(bb[6]);

            data = data_make(
                "time",         "",   DATA_STRING,    time_str,
                "model",        "",   DATA_STRING,    "Acurite 5n1 sensor",
                "sensor_id",    NULL,   DATA_FORMAT,    "0x%02X",   DATA_INT,       sensor_id,   
                "channel",      NULL,   DATA_STRING,    &channel_str,
                "sequence_num",  NULL,   DATA_INT,      sequence_num,
                "battery",      NULL,   DATA_STRING,    battery_low ? "OK" : "LOW",
                "message_type", NULL,   DATA_INT,       message_type,
                "wind_speed",   NULL,   DATA_FORMAT,    "%.1f mph", DATA_DOUBLE,     wind_speedmph,
                "temperature_F", 	"temperature",	DATA_FORMAT,    "%.1f F", DATA_DOUBLE,    tempf,
                "humidity",     NULL,	DATA_FORMAT,    "%d",   DATA_INT,   humidity,
                NULL);
            data_acquired_handler(data);
            
	    } else {
            fprintf(stderr, "%s Acurite 5n1 sensor 0x%04X Ch %c, Status %02X, Unknown message type 0x%02x\n",
                time_str, sensor_id, channel, bb[3], message_type);
	    }
	}

	if (browlen == ACURITE_6045_BITLEN / 8) {
	    channel = acurite_getChannel(bb[0]);  // same as TXR
	    sensor_id = (bb[1] << 8) | bb[2];     // TBD 16 bits or 20?
	    humidity = acurite_getHumidity(bb[3]);  // same as TXR
	    message_type = bb[4] & 0x7f;
	    temp = bb[5] & 0x7f; // TBD Not sure if this is the temp.
	    strike_count = bb[6] & 0x7f;
	    strike_distance = bb[7] & 0x7f;


	    printf("%s Acurite lightning 0x%04X Ch %c Msg Type 0x%02x: %d C %d %% RH Strikes %d Distance %d -",
		   time_str, sensor_id, channel, message_type, temp, humidity, strike_count, strike_distance);

	    // FIXME Temporarily dump message data until the decoding improves.
	    // Include parity indicator.
	    for (int i=0; i < browlen; i++) {
		char pc;
		pc = byteParity(bb[i]) == 0 ? ' ' : '*';
		fprintf(stdout, " %02x%c", bb[i], pc);
	    }
	    printf("\n");
	}

    }
Exemplo n.º 20
0
/// @param *data : returns the decoded information as a data_t * 
static int decode_xc0324_message(r_device *decoder, bitbuffer_t *bitbuffer,
  unsigned row, uint16_t bitpos, const int latest_event, data_t **data)
{
    uint8_t b[XC0324_MESSAGE_BYTELEN];
    char id [4] = {0};
    double temperature;
    uint8_t flags;
    uint8_t chksum; // == 0x00 for a good message
    
    // Extract the message
    bitbuffer_extract_bytes(bitbuffer, row, bitpos, b, XC0324_MESSAGE_BITLEN);

    // Examine the chksum and bail out now if not OK to save time
    // b[5] is a check byte, the XOR of bytes 0-4.
    // ie a checksum where the sum is "binary add no carry"
    // Effectively, each bit of b[5] is the parity of the bits in the
    // corresponding position of b[0] to b[4]
    // NB : b[0] ^ b[1] ^ b[2] ^ b[3] ^ b[4] ^ b[5] == 0x00 for a clean message
    chksum = xor_bytes(b, 6);
    if (chksum != 0x00) {
        if (decoder->verbose == 1) {
            // Output the "bad" message (only for message level deciphering!)
            decoder_output_bitrowf(decoder, b, XC0324_MESSAGE_BITLEN,
              "chksum = 0x%02X not 0x00 <- XC0324:vv row %d bit %d",
              chksum, row, bitpos);
        }
        return 0;  // No message was able to be decoded
    }
    
    // Extract the id as hex string
    snprintf(id, 3, "%02X", b[1]);
    
    // Decode temperature (b[2]), plus 1st 4 bits b[3], LSB first order!
    // Tenths of degrees C, offset from the minimum possible (-40.0 degrees)
    uint16_t temp = ((uint16_t)(reverse8(b[3]) & 0x0f) << 8) | reverse8(b[2]) ;
    temperature = (temp / 10.0) - 40.0 ;
    
    //Unknown byte, constant as 0x80 in all my data
    // ??maybe battery status??
    flags = b[4];
    
    // Create the data structure, ready for the decoder_output_data function.
    // Separate production output (decoder->verbose == 0)
    // from (simulated) deciphering stage output (decoder->verbose > 0)
    if (!decoder->verbose) { // production output 
        *data = data_make(
            "model",          "Device Type",     DATA_STRING, "Digitech XC0324",
            "id",             "ID",              DATA_STRING, id,
            "temperature_C",  "Temperature C",   DATA_FORMAT, "%.1f", DATA_DOUBLE, temperature,
            "flags",          "Constant ?",      DATA_INT,    flags,
            "mic",            "Integrity",       DATA_STRING, "CHECKSUM",
             NULL);
    }

    // Output (simulated) message level deciphering information..
    if (decoder->verbose == 1) {
        decoder_output_bitrowf(decoder, b, XC0324_MESSAGE_BITLEN,
          "Temp was %4.1f <- XC0324:vv row %03d bit %03d",
          temperature, row, bitpos);
    }
    // Output "finished deciphering" reference values for future regression tests.
    if ((decoder->verbose == 3) & (latest_event == 0)) {
        //info from this first successful message is enough
        decoder_output_messagef(decoder,
          "XC0324:vvvv Reference -> Temperature %4.1f C; sensor id %s",
          temperature, id);
    }
    return 1; // Message successfully decoded
}