Convert oil_watchman to bitbuffer_search() + bitbuffer_manchester_decode()

It turns out the framing in pulse_demod_manchester_framed() is not done
by the RFM01/Si4320 modules themselves; it's device-specific. See discussion
in issue .

So convert to use FSK_PULSE_PCM and then look for the preamble/postamble,
and do the Manchester decoding, in the bitbuffer domain.
This commit is contained in:
David Woodhouse 2015-12-10 10:17:02 +00:00
parent ba621888ca
commit 29cda5b7f5

View file

@ -14,9 +14,15 @@
#include "pulse_demod.h"
#include "util.h"
// Start of frame preamble is 111000xx
static const unsigned char preamble_pattern = 0xe0;
// End of frame is 00xxxxxx or 11xxxxxx depending on final data bit
static const unsigned char postamble_pattern[2] = { 0x00, 0xc0 };
static int oil_watchman_callback(bitbuffer_t *bitbuffer) {
bitrow_t *bb = bitbuffer->bb;
uint8_t *b = bb[0];
uint8_t *b;
uint32_t unit_id;
uint16_t depth = 0;
uint16_t binding_countdown = 0;
@ -25,48 +31,67 @@ static int oil_watchman_callback(bitbuffer_t *bitbuffer) {
time_t time_now;
char time_str[LOCAL_TIME_BUFLEN];
data_t *data;
if (bitbuffer->bits_per_row[0] != 64 ||
b[0] != 0x28 || b[7] != crc8le(b, 7, 0x31, 0))
return 0;
unsigned bitpos = 0;
bitbuffer_t databits = {0};
time(&time_now);
local_time_str(time_now, time_str);
// 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[1] << 16) | (b[2] << 8) | b[3];
// 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]) {
// 0x01: Rebinding (magnet held to sensor)
// 0x08: Leak/theft alarm
flags = b[4];
// Skip the matched preamble bits to point to the data
bitpos += 6;
// Not entirely sure what this is but it might be inversely
// proportional to temperature.
maybetemp = b[5] >> 2;
bitpos = bitbuffer_manchester_decode(bitbuffer, 0, bitpos, &databits, 64);
if (databits.bits_per_row[0] != 64)
continue;
if (flags & 1)
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[0] != 0x28 || 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[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;
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
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[6] | ((((uint16_t)b[5]) & 3) << 8);
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,
"binding_countdown", "", DATA_INT, binding_countdown,
"depth", "", DATA_INT, depth,
NULL);
data_acquired_handler(data);
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,
"binding_countdown", "", DATA_INT, binding_countdown,
"depth", "", DATA_INT, depth,
NULL);
data_acquired_handler(data);
}
return 0;
};
@ -83,8 +108,10 @@ static char *output_fields[] = {
r_device oil_watchman = {
.name = "Ultrasonic oil monitor",
.modulation = FSK_PULSE_MANCHESTER_FRAMED,
.modulation = FSK_PULSE_PCM,
.short_limit = 250,
.long_limit = 250, // NRZ
.reset_limit = 1000,
.json_callback = &oil_watchman_callback,
.disabled = 0,
.fields = output_fields,