Add X10 Dim, Bright, All Lights ON, and All Off commands (#1687)

This commit is contained in:
dfleck
2021-04-13 23:32:42 -07:00
committed by GitHub
parent a81f22e655
commit 25d90161e1

View File

@@ -1,12 +1,43 @@
/** @file
X10 sensor (Stub for decoding test data only).
X10 sensor (Non-security devices).
Copyright (C) 2015 Tommy Vestermark
Mods. by Dave Fleck 2021
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/
/**
X10 sensor decoder.
Each packet starts with a sync pulse of 9000 us (16x a bit time)
and a 4500 us gap.
The message is OOK PPM encoded with 562.5 us pulse and long gap (0 bit)
of 1687.5 us or short gap (1 bit) of 562.5 us.
There are 32bits. The message is repeated 5 times with
a packet gap of 40000 us.
The protocol has a lot of similarities to the NEC IR protocol
The second byte is the inverse of the first.
The fourth byte is the inverse of the third.
Based on protocol informtation found at:
http://www.wgldesigns.com/protocols/w800rf32_protocol.txt
Tested with American sensors operating at 310 MHz
e.g., rtl_433 -f 310M -R 22
Seems to work best with 2 MHz sample rate:
rtl_433 -f 310M -R 22 -s 2M
Tested with HR12A, RMS18, HD23A, MS14A, PMS03, MS12A,
RMS18, Radio Shack 61-2675-T
*/
#include "decoder.h"
@@ -16,29 +47,38 @@ static int x10_rf_callback(r_device *decoder, bitbuffer_t *bitbuffer)
data_t *data;
uint8_t *b = bitbuffer->bb[1];
uint8_t arrbKnownConstBitMask[4] = {0x0B, 0x0B, 0x87, 0x87};
uint8_t arrbKnownConstBitValue[4] = {0x00, 0x0B, 0x00, 0x87};
uint8_t bKnownConstFlag = 1;
uint8_t arrbKnownConstBitMask[4] = {0x0B, 0x0B, 0x07, 0x07};
uint8_t arrbKnownConstBitValue[4] = {0x00, 0x0B, 0x00, 0x07};
// Row [0] is sync pulse
// Validate package
if (bitbuffer->bits_per_row[1] != 32 // Don't waste time on a short package
//|| (b[0] ^ b[1]) != 0xff // Check integrity - apparently some chips may use both bytes..
|| (b[2] ^ b[3]) != 0xff) // Check integrity
// Validate length
if (bitbuffer->bits_per_row[1] != 32) { // Don't waste time on a wrong length package
if (decoder->verbose)
fprintf(stderr, "X10-RF: DECODE_ABORT_LENGTH, Received message length=%i\n", bitbuffer->bits_per_row[1]);
return DECODE_ABORT_LENGTH;
}
unsigned code = (unsigned)b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
// Validate complement values
if ((b[0] ^ b[1]) != 0xff || (b[2] ^ b[3]) != 0xff) {
if (decoder->verbose)
fprintf(stderr, "X10-RF: DECODE_FAIL_SANITY, b0=%02x b1=%02x b2=%02x b3=%02x\n", b[0], b[1], b[2], b[3]);
return DECODE_FAIL_SANITY;
}
// For the CR12A X10 Remote, with the exception of the SCAN buttons, some bits are constant.
// Some bits are constant.
for (int8_t bIdx = 0; bIdx < 4; bIdx++) {
uint8_t bTest = arrbKnownConstBitMask[bIdx] & b[bIdx]; // Mask the appropriate bits
if (bTest != arrbKnownConstBitValue[bIdx]) // If resulting bits are incorrectly set
bKnownConstFlag = 0; // Set flag to 0, so decoding doesn't occur
if (bTest != arrbKnownConstBitValue[bIdx]) { // If resulting bits are incorrectly set
if (decoder->verbose)
fprintf(stderr, "X10-RF: DECODE_FAIL_SANITY, b0=%02x b1=%02x b2=%02x b3=%02x\n", b[0], b[1], b[2], b[3]);
return DECODE_FAIL_SANITY;
}
}
if (bKnownConstFlag != 1) // If constant bits are appropriately set
return DECODE_FAIL_SANITY;
// We have received a valid message, decode it
unsigned code = (unsigned)b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
uint8_t bHouseCode = 0;
uint8_t bDeviceCode = 0;
@@ -61,19 +101,53 @@ static int x10_rf_callback(r_device *decoder, bitbuffer_t *bitbuffer)
bDeviceCode |= (b[2] & 0x40) >> 4;
bDeviceCode |= (b[2] & 0x08) >> 2;
bDeviceCode |= (b[2] & 0x10) >> 4;
bDeviceCode += 1;
char housecode[2] = {0};
*housecode = bHouseCode + 'A';
int state = (b[2] & 0x20) == 0x00;
char *event_str = "UNKNOWN"; // human-readable event
if ((b[2] & 0x80) == 0x80) { // Special event bit
bDeviceCode = 0; // No device for special events
switch (b[2]) {
case 0x98:
event_str = "DIM";
break;
case 0x88:
event_str = "BRI";
break;
case 0x90:
event_str = "ALL LTS ON";
break;
case 0x80:
event_str = "ALL OFF";
break;
}
}
else {
event_str = state ? "ON" : "OFF";
}
// debug output
if (decoder->verbose) {
fprintf(stderr, "X10-RF: id=%s%i event_str=%s\n", housecode, bDeviceCode, event_str);
bitbuffer_print(bitbuffer);
}
/* clang-format off */
data = data_make(
"model", "", DATA_STRING, "X10-RF",
_X("id", "deviceid"), "", DATA_INT, bDeviceCode + 1,
"model", "", DATA_STRING, "X10-RF",
_X("id", "deviceid"), "", DATA_INT, bDeviceCode,
_X("channel", "houseid"), "", DATA_STRING, housecode,
"state", "", DATA_STRING, state ? "ON" : "OFF",
"data", "", DATA_FORMAT, "%08x", DATA_INT, code,
"state", "State", DATA_STRING, event_str,
"data", "Data", DATA_FORMAT, "%08x", DATA_INT, code,
"mic", "Integrity", DATA_STRING, "PARITY",
NULL);
/* clang-format on */
decoder_output_data(decoder, data);
@@ -88,17 +162,18 @@ static char *output_fields[] = {
"deviceid", // TODO: remove ??
"state",
"data",
"mic",
NULL,
};
r_device X10_RF = {
.name = "X10 RF",
.modulation = OOK_PULSE_PPM,
.short_width = 500, // Short gap 500µs
.long_width = 1680, // Long gap 1680µs
.gap_limit = 2800, // Gap after sync is 4.5ms (1125)
.short_width = 562, // Short gap 562.5 µs
.long_width = 1687, // Long gap 1687.5 µs
.gap_limit = 2200, // Gap after sync is 4.5ms (1125)
.reset_limit = 6000, // Gap seen between messages is ~40ms so let's get them individually
.decode_fn = &x10_rf_callback,
.disabled = 1,
.disabled = 0,
.fields = output_fields,
};