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; }
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; }
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; }
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; }
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; }
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; }