diff --git a/src/devices/hideki.c b/src/devices/hideki.c index 48b69a30e..956ba5abf 100644 --- a/src/devices/hideki.c +++ b/src/devices/hideki.c @@ -48,169 +48,169 @@ enum sensortypes { HIDEKI_UNKNOWN, HIDEKI_TEMP, HIDEKI_TS04, HIDEKI_WIND, HIDEKI static int hideki_ts04_decode(r_device *decoder, bitbuffer_t *bitbuffer) { for (int row = 0; row < bitbuffer->num_rows; row++) { - int sensortype; - // Expect 8, 9, 10, or 14 unstuffed bytes, allow up to 4 missing bits - int unstuffed_len = (bitbuffer->bits_per_row[row] + 4) / 9; - if (unstuffed_len == 14) - sensortype = HIDEKI_WIND; - else if (unstuffed_len == 10) - sensortype = HIDEKI_TS04; - else if (unstuffed_len == 9) - sensortype = HIDEKI_RAIN; - else if (unstuffed_len == 8) - sensortype = HIDEKI_TEMP; - else - return DECODE_ABORT_LENGTH; - unstuffed_len -= 1; // exclude sync - - uint8_t *b = bitbuffer->bb[row]; - // Expect a start (not inverted) of 00000110 1, but allow missing bits - int sync = b[0] << 1 | b[1] >> 7; - int startpos = -1; - for (int i = 0; i < 4; ++i) { - if (sync == 0x0d) { - startpos = 9 - i; - break; + int sensortype; + // Expect 8, 9, 10, or 14 unstuffed bytes, allow up to 4 missing bits + int unstuffed_len = (bitbuffer->bits_per_row[row] + 4) / 9; + if (unstuffed_len == 14) + sensortype = HIDEKI_WIND; + else if (unstuffed_len == 10) + sensortype = HIDEKI_TS04; + else if (unstuffed_len == 9) + sensortype = HIDEKI_RAIN; + else if (unstuffed_len == 8) + sensortype = HIDEKI_TEMP; + else + return DECODE_ABORT_LENGTH; + unstuffed_len -= 1; // exclude sync + + uint8_t *b = bitbuffer->bb[row]; + // Expect a start (not inverted) of 00000110 1, but allow missing bits + int sync = b[0] << 1 | b[1] >> 7; + int startpos = -1; + for (int i = 0; i < 4; ++i) { + if (sync == 0x0d) { + startpos = 9 - i; + break; + } + sync >>= 1; + } + if (startpos < 0) { + return DECODE_ABORT_EARLY; } - sync >>= 1; - } - if (startpos < 0) { - return DECODE_ABORT_EARLY; - } - // Invert all bits - bitbuffer_invert(bitbuffer); - - uint8_t packet[HIDEKI_MAX_BYTES_PER_ROW]; - // Strip (unstuff) and check parity bit - // TODO: refactor to util function - for (int i = 0; i < unstuffed_len; ++i) { - unsigned int offset = startpos + i * 9; - packet[i] = (b[offset / 8] << (offset % 8)) | (b[offset / 8 + 1] >> (8 - offset % 8)); - // check parity - uint8_t parity = (b[offset / 8 + 1] >> (7 - offset % 8)) & 1; - if (parity != parity8(packet[i])) { + // Invert all bits + bitbuffer_invert(bitbuffer); + + uint8_t packet[HIDEKI_MAX_BYTES_PER_ROW]; + // Strip (unstuff) and check parity bit + // TODO: refactor to util function + for (int i = 0; i < unstuffed_len; ++i) { + unsigned int offset = startpos + i * 9; + packet[i] = (b[offset / 8] << (offset % 8)) | (b[offset / 8 + 1] >> (8 - offset % 8)); + // check parity + uint8_t parity = (b[offset / 8 + 1] >> (7 - offset % 8)) & 1; + if (parity != parity8(packet[i])) { + if (decoder->verbose) + fprintf(stderr, "%s: Parity error at %d\n", __func__, i); + return DECODE_FAIL_MIC; + } + } + + // XOR check all bytes + int chk = xor_bytes(packet, unstuffed_len - 1); + if (chk) { if (decoder->verbose) - fprintf(stderr, "%s: Parity error at %d\n", __func__, i); + fprintf(stderr, "%s: XOR error\n", __func__); return DECODE_FAIL_MIC; } - } - // XOR check all bytes - int chk = xor_bytes(packet, unstuffed_len - 1); - if (chk) { - if (decoder->verbose) - fprintf(stderr, "%s: XOR error\n", __func__); - return DECODE_FAIL_MIC; - } + // CRC-8 poly=0x07 init=0x00 + if (crc8(packet, unstuffed_len, 0x07, 0x00)) { + if (decoder->verbose) + fprintf(stderr, "%s: CRC error\n", __func__); + return DECODE_FAIL_MIC; + } - // CRC-8 poly=0x07 init=0x00 - if (crc8(packet, unstuffed_len, 0x07, 0x00)) { - if (decoder->verbose) - fprintf(stderr, "%s: CRC error\n", __func__); - return DECODE_FAIL_MIC; - } + // Reflect LSB first to LSB last + reflect_bytes(packet, unstuffed_len); - // Reflect LSB first to LSB last - reflect_bytes(packet, unstuffed_len); - - int pkt_len = (packet[1] >> 1) & 0x1f; - //int pkt_seq = packet[2] >> 6; - //int pkt_type = packet[2] & 0x1f; - // 0x0C Anemometer - // 0x0D UV sensor - // 0x0E Rain level meter - // 0x1E Thermo/hygro-sensor - - if (pkt_len + 2 != unstuffed_len) { - if (decoder->verbose) - fprintf(stderr, "%s: LEN error\n", __func__); - return DECODE_ABORT_LENGTH; - } + int pkt_len = (packet[1] >> 1) & 0x1f; + //int pkt_seq = packet[2] >> 6; + //int pkt_type = packet[2] & 0x1f; + // 0x0C Anemometer + // 0x0D UV sensor + // 0x0E Rain level meter + // 0x1E Thermo/hygro-sensor - int channel = (packet[0] >> 5) & 0x0F; - if (channel >= 5) channel -= 1; - int rc = packet[0] & 0x0F; - int temp = (packet[4] & 0x0F) * 100 + ((packet[3] & 0xF0) >> 4) * 10 + (packet[3] & 0x0F); - if (((packet[4]>>7) & 1) == 0) { - temp = -temp; - } - int battery_ok = (packet[4] >> 6) & 1; - - if (sensortype == HIDEKI_TS04) { - int humidity = ((packet[5] & 0xF0) >> 4) * 10 + (packet[5] & 0x0F); - /* clang-format off */ - data_t *data = data_make( - "model", "", DATA_STRING, "Hideki-TS04", - "id", "Rolling Code", DATA_INT, rc, - "channel", "Channel", DATA_INT, channel, - "battery_ok", "Battery", DATA_INT, battery_ok, - "temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp/10.f, - "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity, - "mic", "Integrity", DATA_STRING, "CRC", - NULL); - /* clang-format on */ - decoder_output_data(decoder, data); - return 1; - } - if (sensortype == HIDEKI_WIND) { - int const wd[] = { 0, 15, 13, 14, 9, 10, 12, 11, 1, 2, 4, 3, 8, 7, 5, 6 }; - int wind_direction = wd[((packet[10] & 0xF0) >> 4)] * 225; - int wind_speed = (packet[8] & 0x0F) * 100 + (packet[7] >> 4) * 10 + (packet[7] & 0x0F); - int gust_speed = (packet[9] >> 4) * 100 + (packet[9] & 0x0F) * 10 + (packet[8] >> 4); - int const ad[] = { 0, 1, -1, 2 }; // i.e. None, CW, CCW, invalid - int wind_approach = ad[(packet[10] >> 2) & 0x03]; - - /* clang-format off */ - data_t *data = data_make( - "model", "", DATA_STRING, "Hideki-Wind", - "id", "Rolling Code", DATA_INT, rc, - "channel", "Channel", DATA_INT, channel, - "battery_ok", "Battery", DATA_INT, battery_ok, - "temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp * 0.1f, - "wind_avg_mi_h", "Wind Speed", DATA_FORMAT, "%.02f mi/h", DATA_DOUBLE, wind_speed * 0.1f, - "wind_max_mi_h", "Gust Speed", DATA_FORMAT, "%.02f mi/h", DATA_DOUBLE, gust_speed * 0.1f, - "wind_approach", "Wind Approach", DATA_INT, wind_approach, - "wind_dir_deg", "Wind Direction", DATA_FORMAT, "%.01f", DATA_DOUBLE, wind_direction * 0.1f, - "mic", "Integrity", DATA_STRING, "CRC", - NULL); - /* clang-format on */ - decoder_output_data(decoder, data); - return 1; - } - if (sensortype == HIDEKI_TEMP) { - /* clang-format off */ - data_t *data = data_make( - "model", "", DATA_STRING, "Hideki-Temperature", - "id", "Rolling Code", DATA_INT, rc, - "channel", "Channel", DATA_INT, channel, - "battery_ok", "Battery", DATA_INT, battery_ok, - "temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp * 0.1f, - "mic", "Integrity", DATA_STRING, "CRC", - NULL); - /* clang-format on */ - decoder_output_data(decoder, data); - return 1; - } - if (sensortype == HIDEKI_RAIN) { - int rain_units = (packet[4] << 8) | packet[3]; - battery_ok = (packet[1] >> 6) & 1; - - /* clang-format off */ - data_t *data = data_make( - "model", "", DATA_STRING, "Hideki-Rain", - "id", "Rolling Code", DATA_INT, rc, - "channel", "Channel", DATA_INT, channel, - "battery_ok", "Battery", DATA_INT, battery_ok, - "rain_mm", "Rain", DATA_FORMAT, "%.01f mm", DATA_DOUBLE, rain_units * 0.7f, - "mic", "Integrity", DATA_STRING, "CRC", - NULL); - /* clang-format on */ - decoder_output_data(decoder, data); - return 1; - } - // unknown sensor type - return DECODE_FAIL_SANITY; + if (pkt_len + 2 != unstuffed_len) { + if (decoder->verbose) + fprintf(stderr, "%s: LEN error\n", __func__); + return DECODE_ABORT_LENGTH; + } + + int channel = (packet[0] >> 5) & 0x0F; + if (channel >= 5) channel -= 1; + int rc = packet[0] & 0x0F; + int temp = (packet[4] & 0x0F) * 100 + ((packet[3] & 0xF0) >> 4) * 10 + (packet[3] & 0x0F); + if (((packet[4]>>7) & 1) == 0) { + temp = -temp; + } + int battery_ok = (packet[4] >> 6) & 1; + + if (sensortype == HIDEKI_TS04) { + int humidity = ((packet[5] & 0xF0) >> 4) * 10 + (packet[5] & 0x0F); + /* clang-format off */ + data_t *data = data_make( + "model", "", DATA_STRING, "Hideki-TS04", + "id", "Rolling Code", DATA_INT, rc, + "channel", "Channel", DATA_INT, channel, + "battery_ok", "Battery", DATA_INT, battery_ok, + "temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp/10.f, + "humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity, + "mic", "Integrity", DATA_STRING, "CRC", + NULL); + /* clang-format on */ + decoder_output_data(decoder, data); + return 1; + } + if (sensortype == HIDEKI_WIND) { + int const wd[] = { 0, 15, 13, 14, 9, 10, 12, 11, 1, 2, 4, 3, 8, 7, 5, 6 }; + int wind_direction = wd[((packet[10] & 0xF0) >> 4)] * 225; + int wind_speed = (packet[8] & 0x0F) * 100 + (packet[7] >> 4) * 10 + (packet[7] & 0x0F); + int gust_speed = (packet[9] >> 4) * 100 + (packet[9] & 0x0F) * 10 + (packet[8] >> 4); + int const ad[] = { 0, 1, -1, 2 }; // i.e. None, CW, CCW, invalid + int wind_approach = ad[(packet[10] >> 2) & 0x03]; + + /* clang-format off */ + data_t *data = data_make( + "model", "", DATA_STRING, "Hideki-Wind", + "id", "Rolling Code", DATA_INT, rc, + "channel", "Channel", DATA_INT, channel, + "battery_ok", "Battery", DATA_INT, battery_ok, + "temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp * 0.1f, + "wind_avg_mi_h", "Wind Speed", DATA_FORMAT, "%.02f mi/h", DATA_DOUBLE, wind_speed * 0.1f, + "wind_max_mi_h", "Gust Speed", DATA_FORMAT, "%.02f mi/h", DATA_DOUBLE, gust_speed * 0.1f, + "wind_approach", "Wind Approach", DATA_INT, wind_approach, + "wind_dir_deg", "Wind Direction", DATA_FORMAT, "%.01f", DATA_DOUBLE, wind_direction * 0.1f, + "mic", "Integrity", DATA_STRING, "CRC", + NULL); + /* clang-format on */ + decoder_output_data(decoder, data); + return 1; + } + if (sensortype == HIDEKI_TEMP) { + /* clang-format off */ + data_t *data = data_make( + "model", "", DATA_STRING, "Hideki-Temperature", + "id", "Rolling Code", DATA_INT, rc, + "channel", "Channel", DATA_INT, channel, + "battery_ok", "Battery", DATA_INT, battery_ok, + "temperature_C", "Temperature", DATA_FORMAT, "%.01f C", DATA_DOUBLE, temp * 0.1f, + "mic", "Integrity", DATA_STRING, "CRC", + NULL); + /* clang-format on */ + decoder_output_data(decoder, data); + return 1; + } + if (sensortype == HIDEKI_RAIN) { + int rain_units = (packet[4] << 8) | packet[3]; + battery_ok = (packet[1] >> 6) & 1; + + /* clang-format off */ + data_t *data = data_make( + "model", "", DATA_STRING, "Hideki-Rain", + "id", "Rolling Code", DATA_INT, rc, + "channel", "Channel", DATA_INT, channel, + "battery_ok", "Battery", DATA_INT, battery_ok, + "rain_mm", "Rain", DATA_FORMAT, "%.01f mm", DATA_DOUBLE, rain_units * 0.7f, + "mic", "Integrity", DATA_STRING, "CRC", + NULL); + /* clang-format on */ + decoder_output_data(decoder, data); + return 1; + } + // unknown sensor type + return DECODE_FAIL_SANITY; } return 0; }