示例#1
0
static int danfoss_CFR_callback(bitbuffer_t *bitbuffer) {
	bitrow_t *bb = bitbuffer->bb;

	// Validate package
	unsigned bits = bitbuffer->bits_per_row[0];
	if (bits >= 246 && bits <= 262) {	// Package is likely 254 always
		fprintf(stdout, "Danfoss CFR Thermostat:\n");
		bitbuffer_print(bitbuffer);
		return 1;
	}
	return 0;
}
示例#2
0
int main(int argc, char **argv) {
	fprintf(stderr, "bitbuffer:: test\n");

	bitbuffer_t bits = {0};

	fprintf(stderr, "TEST: bitbuffer:: The empty buffer\n");
	bitbuffer_print(&bits);
	
	fprintf(stderr, "TEST: bitbuffer:: Add 1 bit\n");
	bitbuffer_add_bit(&bits, 1);
	bitbuffer_print(&bits);

	fprintf(stderr, "TEST: bitbuffer:: Add 1 new row\n");
	bitbuffer_add_row(&bits);
	bitbuffer_print(&bits);

	fprintf(stderr, "TEST: bitbuffer:: Fill row\n");
	for (int i=0; i < BITBUF_COLS*8; ++i) {
		bitbuffer_add_bit(&bits, i%2);
	}
	bitbuffer_print(&bits);

	fprintf(stderr, "TEST: bitbuffer:: Add row and fill 1 column too many\n");
	bitbuffer_add_row(&bits);
	for (int i=0; i <= BITBUF_COLS*8; ++i) {
		bitbuffer_add_bit(&bits, i%2);
	}
	bitbuffer_print(&bits);

	fprintf(stderr, "TEST: bitbuffer:: Clear\n");
	bitbuffer_clear(&bits);
	bitbuffer_print(&bits);

	fprintf(stderr, "TEST: bitbuffer:: Add 1 row too many\n");
	for (int i=0; i <= BITBUF_ROWS; ++i) {
		bitbuffer_add_row(&bits);
	}
	bitbuffer_add_bit(&bits, 1);
	bitbuffer_print(&bits);

	return 0;
}
示例#3
0
static int lightwave_rf_callback(bitbuffer_t *bitbuffer) {
	bitrow_t *bb = bitbuffer->bb;

	// Validate package
	// Transmitted pulses are always 72
	// Pulse 72 (delimiting "1" is not demodulated, as gap becomes End-Of-Message - thus expected length is 71
	if ((bitbuffer->bits_per_row[0] == 71)
		&& (bitbuffer->num_rows == 1))		// There should be only one message (and we use the rest...)
	{
		// Polarity is inverted
		bitbuffer_invert(bitbuffer);

		// Expand all "0" to "10" (bit stuffing)
		// row_in = 0, row_out = 1
		bitbuffer_add_row(bitbuffer);
		for (unsigned n=0; n < bitbuffer->bits_per_row[0]; ++n) {
			if (bitrow_get_bit(bb[0], n)) {
				bitbuffer_add_bit(bitbuffer, 1);
			} else {
				bitbuffer_add_bit(bitbuffer, 1);
				bitbuffer_add_bit(bitbuffer, 0);
			}
		}

		// Check length is correct
		// Due to encoding there will be two "0"s per byte, thus message grows to 91 bits
		if (bitbuffer->bits_per_row[1] != 91)	return 0;

		// Check initial delimiter bit is "1"
		unsigned bit_idx = 0;
		uint8_t delimiter_bit = bitrow_get_bit(bb[1], bit_idx++);
		if (delimiter_bit == 0)	return 0;	// Decode error

		// Strip delimiter bits
		// row_in = 1, row_out = 2
		bitbuffer_add_row(bitbuffer);
		for(unsigned n=0; n<10; ++n) {		// We have 10 bytes
			delimiter_bit = bitrow_get_bit(bb[1], bit_idx++);
			if (delimiter_bit == 0)	return 0;	// Decode error

			for(unsigned m=0; m<8; ++m) {
				bitbuffer_add_bit(bitbuffer, bitrow_get_bit(bb[1], bit_idx++));
			}
		}
		// Final delimiter bit will be missing - so do not check...

		// Decode bytes to nibbles
		// row_in = 2, row_out = 3
		bitbuffer_add_row(bitbuffer);
		for(unsigned n=0; n<10; ++n) {		// We have 10 bytes/nibbles
			int nibble = lightwave_rf_nibble_from_byte(bb[2][n]);
			if (nibble < 0) {
				if (debug_output) {
					fprintf(stderr, "LightwaveRF. Nibble decode error %X, idx: %u\n", bb[2][n], n);
					bitbuffer_print(bitbuffer);
				}
				return 0;	// Decode error
			}
			for (unsigned m=0; m<4; ++m) {	// Add nibble one bit at a time...
				bitbuffer_add_bit(bitbuffer, (nibble & (8 >> m)) >> (3-m));
			}
		}

		// Print out generic decode
		// Decoded nibbles are in row 3
		fprintf(stdout, "LightwaveRF:\n");
		fprintf(stdout, "ID = 0x%X%X%X\n", bb[3][2], bb[3][3], bb[3][4]);
		fprintf(stdout, "Subunit = %u\n", (bb[3][1] & 0xF0) >> 4);
		fprintf(stdout, "Command = %u\n", bb[3][1] & 0x0F);
		fprintf(stdout, "Parameter = %u\n", bb[3][0]);

		if (debug_output) {
			bitbuffer_print(bitbuffer);
			fprintf(stderr, "  Row 0 = Input, Row 1 = Zero bit stuffing, Row 2 = Stripped delimiters, Row 3 = Decoded nibbles\n");
		}


		return 1;
	}
示例#4
0
文件: rtl_433.c 项目: dducret/rtl_433
static void classify_signal() {
    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};
    struct protocol_state p = {0};
    unsigned int signal_type;

    if (!signal_pulse_data[0][0])
        return;

    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],
            //signal_pulse_data[i][2]);
            if (signal_pulse_data[i][2] > max)
                max = signal_pulse_data[i][2];
            if (signal_pulse_data[i][2] <= min)
                min = signal_pulse_data[i][2];
        }
    }
    t = (max + min) / 2;
    //fprintf(stderr, "\n\nMax: %d, Min: %d  t:%d\n", max, min, t);

    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;

        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 {
                    max_new = max_new + signal_pulse_data[i][2];
                    count_max++;
                }
            }
        }
        if (count_min != 0 && count_max != 0) {
            min_new = min_new / count_min;
            max_new = max_new / count_max;
        }

        delta = (min - min_new)*(min - min_new) + (max - max_new)*(max - max_new);
        min = min_new;
        max = max_new;
        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);
        k++;
    }

    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) {
        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);
        signal_type = 1;
    }
    p_limit = (max + min) / 2;

    /* Initial guesses */
    a[0] = 1000000;
    a[2] = 0;
    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];
        }
    }
    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]);

    k = 1;
    delta = 10000000;
    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++) {
            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]) {
                    a_new[1] += signal_distance_data[i];
                    a_cnt[1]++;
                } else if (signal_distance_data[i] >= b[1]) {
                    a_new[2] += signal_distance_data[i];
                    a_cnt[2]++;
                }
            }
        }

        //         fprintf(stderr, "Iteration %d.", k);
        delta = 0;
        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]);
            a[i] = a_new[i];
        }
        //         fprintf(stderr, " delta %d\n", delta);

        if (a[0] < min) {
            a[0] = min;
            //             fprintf(stderr, "Fixing a[0] = %d\n", min);
        }
        if (a[2] > max) {
            a[0] = 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]);
        //         }

        //         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");
        k++;
    }

    if (override_short) {
        p_limit = override_short;
        a[0] = override_short;
    }

    if (override_long) {
        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);

    bitbuffer_clear(&p.bits);
    if (signal_type == 1) {
        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);
                    bitbuffer_add_bit(&p.bits, 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);
                    bitbuffer_add_bit(&p.bits, 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);
                    bitbuffer_add_row(&p.bits);
                }

            }

        }
        bitbuffer_print(&p.bits);
    }
    if (signal_type == 2) {
        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);
                    bitbuffer_add_bit(&p.bits, 0);
                } else {
                    //                     fprintf(stderr, "1 [%d] %d > %d\n",i, signal_pulse_data[i][2], p_limit);
                    bitbuffer_add_bit(&p.bits, 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);
                    bitbuffer_add_row(&p.bits);
                }


            }
        }
        bitbuffer_print(&p.bits);
    }

    for (i = 0; i < 1000; i++) {
        signal_pulse_data[i][0] = 0;
        signal_pulse_data[i][1] = 0;
        signal_pulse_data[i][2] = 0;
        signal_distance_data[i] = 0;
    }

};
示例#5
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;
		}
示例#6
0
static int acurite_986_callback(bitbuffer_t *bitbuf) {
    int browlen;
    uint8_t *bb, sensor_num, status, crc, crcc;
    uint8_t br[8];
    int8_t tempf; // Raw Temp is 8 bit signed Fahrenheit
    float tempc;
    uint16_t sensor_id, valid_cnt = 0;
    char sensor_type;

    local_time_str(0, time_str);

    if (debug_output > 1) {
        fprintf(stderr,"acurite_986\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_986: row %d bits %d, bytes %d \n", brow, bitbuf->bits_per_row[brow], browlen);

	if (bitbuf->bits_per_row[brow] < 39 ||
	    bitbuf->bits_per_row[brow] > 43 ) {
	    if (debug_output > 1 && bitbuf->bits_per_row[brow] > 16)
		fprintf(stderr,"acurite_986: skipping wrong len\n");
	    continue;
	}

	// Reduce false positives
	// may eliminate these with a beter PPM (precise?) demod.
	if ((bb[0] == 0xff && bb[1] == 0xff && bb[2] == 0xff) ||
	   (bb[0] == 0x00 && bb[1] == 0x00 && bb[2] == 0x00)) {
	    continue;
	}

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

	// Reverse the bits
	for (uint8_t i = 0; i < browlen; i++)
	    br[i] = reverse8(bb[i]);

	if (debug_output > 0) {
	    fprintf(stderr,"Acurite 986 reversed: ");
	    for (uint8_t i = 0; i < browlen; i++)
		fprintf(stderr," %02x",br[i]);
	    fprintf(stderr,"\n");
	}

	tempf = br[0];
	sensor_id = (br[1] << 8) + br[2];
	status = br[3];
	sensor_num = (status & 0x01) + 1;
	status = status >> 1;
	// By default Sensor 1 is the Freezer, 2 Refrigerator
	sensor_type = sensor_num == 2 ? 'F' : 'R';
	crc = br[4];

	if ((crcc = crc8le(br, 5, 0x07, 0)) != 0) {
	    // XXX make debug
	    if (debug_output) {
		fprintf(stderr,"%s Acurite 986 sensor bad CRC: %02x -",
			time_str, crc8le(br, 4, 0x07, 0));
		for (uint8_t i = 0; i < browlen; i++)
		    fprintf(stderr," %02x", br[i]);
		fprintf(stderr,"\n");
	    }
	    continue;
	}

	if ((status & 1) == 1) {
	    fprintf(stderr, "%s Acurite 986 sensor 0x%04x - %d%c: low battery, status %02x\n",
		    time_str, sensor_id, sensor_num, sensor_type, status);
	}

	// catch any status bits that haven't been decoded yet
	if ((status & 0xFE) != 0) {
	    fprintf(stderr, "%s Acurite 986 sensor 0x%04x - %d%c: Unexpected status %02x\n",
		    time_str, sensor_id, sensor_num, sensor_type, status);
	}

	if (tempf & 0x80) {
	    tempf = (tempf & 0x7f) * -1;
	}
	tempc = fahrenheit2celsius(tempf);


	printf("%s Acurite 986 sensor 0x%04x - %d%c: %3.1f C %d F\n",
	       time_str, sensor_id, sensor_num, sensor_type,
	       tempc, tempf);

	valid_cnt++;

    }

    if (valid_cnt)
	return 1;

    return 0;
}
示例#7
0
static int acurite_txr_callback(bitbuffer_t *bitbuf) {
    int browlen;
    uint8_t *bb;
    float tempc, tempf, wind_dird, rainfall = 0.0, wind_speedmph;
    uint8_t humidity, sensor_status, repeat_no, message_type;
    char channel, *wind_dirstr = "";
    uint16_t sensor_id;
    int wind_speed, raincounter;


    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) {
	    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_crc(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]);
	    tempf = celsius2fahrenheit(tempc);

	    printf("%s Acurite tower sensor 0x%04X Ch %c: %3.1F C %3.1F F %d %% RH\n",
		   time_str, sensor_id, channel, tempc, tempf, humidity);

	    // currently 0x44 seens to be a normal status and/or type
	    // for tower sensors.  Battery OK/Normal == 0x40
	    if (sensor_status != 0x44)
		printf("%s Acurite tower sensor 0x%04X Ch %c, Status %02X\n",
		       time_str, sensor_id, channel, sensor_status);

	}

	// The 5-n-1 weather sensor messages are 8 bytes.
	if (browlen == ACURITE_5N1_BITLEN / 8) {
	    channel = acurite_getChannel(bb[0]);
	    sensor_id = acurite_5n1_getSensorId(bb[0],bb[1]);
	    repeat_no = acurite_5n1_getMessageCaught(bb[0]);
	    message_type = bb[2] & 0x3f;


	    if (message_type == 0x31) {
		// Wind speed, wind direction, and rain fall
	        wind_speed = acurite_getWindSpeed(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_raincounter > 0) {
		    // track rainfall difference after first run
		    rainfall = ( raincounter - acurite_raincounter ) * 0.01;
		    if (raincounter < acurite_raincounter) {
			printf("%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_raincounter, raincounter);
			acurite_raincounter = raincounter;
		    }
		} else {
		    // capture starting counter
		    acurite_raincounter = raincounter;
		    printf("%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);
		}

		printf("%s Acurite 5n1 sensor 0x%04X Ch %c, Msg %02x, Wind %d kmph / %0.1f mph %0.1f° %s (%d), rain gauge %0.2f in.\n",
		       time_str, sensor_id, channel, message_type,
		       wind_speed, wind_speedmph,
		       wind_dird, wind_dirstr, bb[4] & 0x0f, rainfall);

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

		printf("%s Acurite 5n1 sensor 0x%04X Ch %c, Msg %02x, Wind %d kmph / %0.1f mph, %3.1F C %3.1F F %d %% RH\n",
		       time_str, sensor_id, channel, message_type,
		       wind_speed, wind_speedmph, tempc, tempf, humidity);
	    } else {
		printf("%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);
	    }
	}
    }

    return 0;
}
示例#8
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");
	}

    }
示例#9
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;
    }