#ifndef T1_C1_PACKET_DECODER_H #define T1_C1_PACKET_DECODER_H /*- * Copyright (c) 2017 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #if !defined(PACKET_CAPTURE_THRESHOLD) #define PACKET_CAPTURE_THRESHOLD 5u #endif #define C1_MODE_A 0b010101001100 #define C1_MODE_B 0b010101000011 #define C1_MODE_AB_TRAILER 0b1101 #define PACKET_DATABIT_SHIFT (0u) #define PACKET_PREAMBLE_DETECTED_SHIFT (1u) #define PACKET_DATABIT_MASK (1u<> 8)] ^ (crc << 8); crc = ~crc; return crc; } static bool check_calc_crc_wmbus(const uint8_t *data, size_t datalen) { bool crc_ok = false; uint16_t crc1, crc2; if (datalen >= 12) { crc1 = calc_crc_wmbus(data, 10); crc2 = (data[10] << 8) | (data[11]); data += 12; datalen -= 12; crc_ok = (crc1 == crc2); while (crc_ok && datalen) { if (datalen >= 18) { crc1 = calc_crc_wmbus(data, 16); crc2 = (data[16] << 8) | (data[17]); data += 18; datalen -= 18; crc_ok = (crc1 == crc2); } else { crc1 = calc_crc_wmbus(data, datalen-2); crc2 = (data[datalen-2] << 8) | (data[datalen-1]); data += datalen; datalen -= datalen; crc_ok = (crc1 == crc2); } } } return crc_ok; } /** @brief Strip CRCs in place. */ static unsigned cook_pkt(uint8_t *data, unsigned datalen) { uint8_t *dst = data; unsigned dstlen = 0; if (datalen >= 12) { dst += 10; dstlen += 10; data += 12; datalen -= 12; while (datalen) { if (datalen >= 18) { memmove(dst, data, 16); dst += 16; dstlen += 16; data += 18; datalen -= 18; } else { memmove(dst, data, datalen-2); dst += (datalen-2); dstlen += (datalen-2); data += datalen; datalen -= datalen; } } } return dstlen; } static inline uint32_t get_serial(const uint8_t *const packet) { uint32_t serial; memcpy(&serial, &packet[4], sizeof(serial)); return serial; } static void t1_c1_packet_decoder(unsigned bit, unsigned rssi) { t1_c1_packet_decoder_work.current_rssi = rssi; (*t1_c1_packet_decoder_work.state++)(bit); if (*t1_c1_packet_decoder_work.state == idle) { // nothing } else if (*t1_c1_packet_decoder_work.state == done) { t1_c1_packet_decoder_work.crc_ok = check_calc_crc_wmbus(t1_c1_packet_decoder_work.packet, t1_c1_packet_decoder_work.L) ? 1 : 0; fprintf(stdout, "%s;%u;%u;%s;%u;%u;%08X;", t1_c1_packet_decoder_work.c1_packet ? "C1": "T1", t1_c1_packet_decoder_work.crc_ok, t1_c1_packet_decoder_work.err_3outof^1, t1_c1_packet_decoder_work.timestamp, t1_c1_packet_decoder_work.packet_rssi, rssi, get_serial(t1_c1_packet_decoder_work.packet)); #if 0 fprintf(stdout, "0x"); for (size_t l = 0; l < t1_c1_packet_decoder_work.L; l++) fprintf(stdout, "%02x", t1_c1_packet_decoder_work.packet[l]); fprintf(stdout, ";"); #endif #if 1 t1_c1_packet_decoder_work.L = cook_pkt(t1_c1_packet_decoder_work.packet, t1_c1_packet_decoder_work.L); fprintf(stdout, "0x"); for (size_t l = 0; l < t1_c1_packet_decoder_work.L; l++) fprintf(stdout, "%02x", t1_c1_packet_decoder_work.packet[l]); #endif fprintf(stdout, "\n"); fflush(stdout); t1_c1_packet_decoder_work.state = &states[0]; // idle } else { // Stop receiving packet if current rssi below threshold. // The current packet seems to be collided with an another one. if (rssi < PACKET_CAPTURE_THRESHOLD) { t1_c1_packet_decoder_work.state = &states[0]; // idle } } } #endif /* T1_C1_PACKET_DECODER_H */