예제 #1
0
static int xc0324_callback(r_device *decoder, bitbuffer_t *bitbuffer)
{
    int r; // a row index
    uint16_t bitpos;
    int result;
    int events = 0;
    data_t *data = NULL;
    
    // Only for simulating initial package level deciphering / debug.
    if (decoder->verbose == 2) {
        // Verbosely output the bitbuffer 
        decoder_output_bitbufferf(decoder, bitbuffer, "XC0324:vvv hex(/binary) version of bitbuffer");
        // And then output each row to csv, json or whatever was specified.
        for (r = 0; r < bitbuffer->num_rows; ++r) {
            decoder_output_bitrowf(decoder, bitbuffer->bb[r], bitbuffer->bits_per_row[r],
              "XC0324:vvv row %03d", r);
        }
    }
    //A clean XC0324 transmission contains 3 repeats of a message in a single row.
    //But in case of transmission or demodulation glitches, 
    //loop over all rows and check for salvageable messages.
    for (r = 0; r < bitbuffer->num_rows; ++r) {
        if (bitbuffer->bits_per_row[r] < XC0324_MESSAGE_BITLEN) {
            // bail out of this "too short" row early
            if (decoder->verbose == 1) {
                // Output the bad row, only for message level debug / deciphering.
                decoder_output_bitrowf(decoder, bitbuffer->bb[r], bitbuffer->bits_per_row[r],
                  "Bad message need %d bits got %d <- XC0324:vv row %d bit %d",
                  XC0324_MESSAGE_BITLEN, bitbuffer->bits_per_row[r], r, 0);
            }
            continue; // to the next row  
        }
        // We have enough bits so search for a message preamble followed by 
        // enough bits that it could be a complete message.
        bitpos = 0;
        while ((bitpos = bitbuffer_search(bitbuffer, r, bitpos,
          (const uint8_t *)&preamble_pattern, 8))
          + XC0324_MESSAGE_BITLEN <= bitbuffer->bits_per_row[r]) {
            events += result = decode_xc0324_message(decoder, bitbuffer,
              r, bitpos, events, &data);
            // Keep production output (decoder->verbose == 0) separate from 
            // (simulated) development stage output (decoder->verbose > 0)
            if (result & !decoder->verbose) { // Production output
                data_append(data, "message_num",  "Message repeat count",
                  DATA_INT, events, NULL);
                decoder_output_data(decoder, data);
                return events; // in production, first successful decode is enough
            }
            bitpos += XC0324_MESSAGE_BITLEN;
        }
    }
    // (Only) for future regression tests.
    if ((decoder->verbose == 3) & (events == 0)) {
        decoder_output_messagef(decoder, "XC0324:vvvv Reference -> Bad transmission");
    }
    return events;
}
예제 #2
0
static int oil_standard_callback(r_device *decoder, bitbuffer_t *bitbuffer) {
    unsigned bitpos = 0;
    int events = 0;

    // Find a preamble with enough bits after it that it could be a complete packet
    while ((bitpos = bitbuffer_search(bitbuffer, 0, bitpos, (uint8_t *)&preamble_pattern0, 16)) + 78 <=
            bitbuffer->bits_per_row[0]) {
        events += oil_standard_decode(decoder, bitbuffer, 0, bitpos + 14);
        bitpos += 2;
    }

    bitpos = 0;
    while ((bitpos = bitbuffer_search(bitbuffer, 0, bitpos, (uint8_t *)&preamble_pattern1, 16)) + 78 <=
            bitbuffer->bits_per_row[0]) {
        events += oil_standard_decode(decoder, bitbuffer, 0, bitpos + 14);
        bitpos += 2;
    }
    return events;
}
예제 #3
0
static int tpms_citroen_callback(bitbuffer_t *bitbuffer) {
    unsigned bitpos = 0;
    int events = 0;

    // Find a preamble with enough bits after it that it could be a complete packet
    while ((bitpos = bitbuffer_search(bitbuffer, 0, bitpos, (uint8_t *)&preamble_pattern, 16)) + 178 <=
            bitbuffer->bits_per_row[0]) {
        events += tpms_citroen_decode(bitbuffer, 0, bitpos + 16);
        bitpos += 2;
    }

    return events;
}
예제 #4
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;
}
예제 #5
0
static int ge_coloreffects_callback(r_device *decoder, bitbuffer_t *bitbuffer) {
    unsigned bitpos = 0;
    int events = 0;

    // Find a preamble with enough bits after it that it could be a complete packet
    // (if the device id and command were all zeros)
    while ((bitpos = bitbuffer_search(bitbuffer, 0, bitpos, (uint8_t *)&preamble_pattern, 24)) + 57 <=
            bitbuffer->bits_per_row[0]) {
        events += ge_coloreffects_decode(decoder, bitbuffer, 0, bitpos + 24);
        bitpos++;
    }

    return events;
}
예제 #6
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;
}