rtl-wmbus/s1_packet_decoder.h

291 wiersze
9.2 KiB
C

#ifndef S1_PACKET_DECODER_H
#define S1_PACKET_DECODER_H
/*-
* Copyright (c) 2021 <xael.south@yandex.com>
*
* 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 <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
static const uint8_t MANCHESTER_IEEE_802_3[4] = {
0xFF, 0x01, 0x00, 0xFF // According to wireless MBus spec.: "01b” representing a “one”; "10b" representing a "zero".
};
struct s1_packet_decoder_work;
typedef void (*s1_packet_decoder_state)(unsigned bit, struct s1_packet_decoder_work *decoder);
static void s1_idle(unsigned bit, struct s1_packet_decoder_work *decoder);
static void s1_done(unsigned bit, struct s1_packet_decoder_work *decoder);
static void s1_rx_bit(unsigned bit, struct s1_packet_decoder_work *decoder);
static void s1_rx_bit2(unsigned bit, struct s1_packet_decoder_work *decoder);
static void s1_rx_first_mode_bit(unsigned bit, struct s1_packet_decoder_work *decoder);
static void s1_rx_last_mode_bit(unsigned bit, struct s1_packet_decoder_work *decoder);
static void s1_rx_first_lfield_bit(unsigned bit, struct s1_packet_decoder_work *decoder);
static void s1_rx_last_lfield_bit(unsigned bit, struct s1_packet_decoder_work *decoder);
static void s1_rx_first_data_bit(unsigned bit, struct s1_packet_decoder_work *decoder);
static void s1_rx_last_data_bit(unsigned bit, struct s1_packet_decoder_work *decoder);
static const s1_packet_decoder_state s1_decoder_states[] =
{
s1_idle, // 0
s1_rx_first_lfield_bit, // 1
s1_rx_bit2, // 2
s1_rx_bit, // 3
s1_rx_bit2, // 4
s1_rx_bit, // 5
s1_rx_bit2, // 6
s1_rx_bit, // 7
s1_rx_bit2, // 8
s1_rx_bit, // 9
s1_rx_bit2, // 10
s1_rx_bit, // 11
s1_rx_bit2, // 12
s1_rx_bit, // 13
s1_rx_bit2, // 14
s1_rx_bit, // 15
s1_rx_last_lfield_bit, // 16
s1_rx_first_data_bit, // 17
s1_rx_bit2, // 18
s1_rx_bit, // 19
s1_rx_bit2, // 20
s1_rx_bit, // 21
s1_rx_bit2, // 22
s1_rx_bit, // 23
s1_rx_bit2, // 24
s1_rx_bit, // 25
s1_rx_bit2, // 26
s1_rx_bit, // 27
s1_rx_bit2, // 28
s1_rx_bit, // 29
s1_rx_bit2, // 30
s1_rx_bit, // 31
s1_rx_last_data_bit, // 32
s1_done, // 33
};
struct s1_packet_decoder_work
{
const s1_packet_decoder_state *state;
unsigned current_rssi;
unsigned packet_rssi;
union
{
unsigned flags;
struct
{
unsigned unused: 1;
unsigned crc_ok: 1;
};
};
unsigned l;
unsigned L;
unsigned mode;
unsigned byte;
__attribute__((__aligned__(16))) uint8_t packet[290]; // max. packet length with L- and all CRC-Fields
char timestamp[64];
};
static int in_rx_s1_packet_decoder(struct s1_packet_decoder_work *decoder)
{
return (decoder->state == &s1_decoder_states[0]) ? 0 : 1;
}
static void reset_s1_packet_decoder(struct s1_packet_decoder_work *decoder)
{
memset(decoder, 0, sizeof(*decoder));
decoder->state = &s1_decoder_states[0];
}
static void s1_idle(unsigned bit, struct s1_packet_decoder_work *decoder)
{
if (!(bit & PACKET_PREAMBLE_DETECTED_MASK))
{
reset_s1_packet_decoder(decoder);
}
}
static void s1_done(unsigned bit, struct s1_packet_decoder_work *decoder)
{
(void)bit;
(void)decoder;
}
static void s1_rx_bit(unsigned bit, struct s1_packet_decoder_work *decoder)
{
decoder->byte <<= 1;
decoder->byte |= (bit & PACKET_DATABIT_MASK);
}
static void s1_rx_bit2(unsigned bit, struct s1_packet_decoder_work *decoder)
{
decoder->byte <<= 1;
decoder->byte |= (bit & PACKET_DATABIT_MASK);
const unsigned b = MANCHESTER_IEEE_802_3[decoder->byte & 0b11];
if (b == 0xFFu)
{
reset_s1_packet_decoder(decoder);
return;
}
decoder->byte >>= 2;
decoder->byte <<= 1;
decoder->byte |= b;
}
static void s1_rx_first_lfield_bit(unsigned bit, struct s1_packet_decoder_work *decoder)
{
decoder->byte = (bit & PACKET_DATABIT_MASK);
decoder->packet_rssi = decoder->current_rssi;
}
static void s1_rx_last_lfield_bit(unsigned bit, struct s1_packet_decoder_work *decoder)
{
decoder->byte <<= 1;
decoder->byte |= (bit & PACKET_DATABIT_MASK);
const unsigned b = MANCHESTER_IEEE_802_3[decoder->byte & 0b11];
if (b == 0xFFu)
{
reset_s1_packet_decoder(decoder);
return;
}
decoder->byte >>= 2;
decoder->byte <<= 1;
decoder->byte |= b;
decoder->L = decoder->byte;
decoder->l = 0;
decoder->packet[decoder->l++] = decoder->L;
decoder->L = FULL_TLG_LENGTH_FROM_L_FIELD[decoder->L];
}
static void s1_rx_first_data_bit(unsigned bit, struct s1_packet_decoder_work *decoder)
{
decoder->byte = (bit & PACKET_DATABIT_MASK);
}
static void s1_rx_last_data_bit(unsigned bit, struct s1_packet_decoder_work *decoder)
{
decoder->byte <<= 1;
decoder->byte |= (bit & PACKET_DATABIT_MASK);
const unsigned b = MANCHESTER_IEEE_802_3[decoder->byte & 0b11];
if (b == 0xFFu)
{
reset_s1_packet_decoder(decoder);
return;
}
decoder->byte >>= 2;
decoder->byte <<= 1;
decoder->byte |= b;
decoder->packet[decoder->l++] = decoder->byte;
if (decoder->l < decoder->L)
{
decoder->state = &s1_decoder_states[17]; // s1_rx_first_data_bit
}
else
{
time_t now;
time(&now);
struct tm *timeinfo = gmtime(&now);
strftime(decoder->timestamp, sizeof(decoder->timestamp), "%Y-%m-%d %H:%M:%S.000", timeinfo);
}
}
static void s1_packet_decoder(unsigned bit, unsigned rssi, struct s1_packet_decoder_work *decoder, const char *algorithm)
{
decoder->current_rssi = rssi;
(*decoder->state++)(bit, decoder);
if (*decoder->state == s1_idle)
{
// nothing
}
else if (*decoder->state == s1_done)
{
decoder->crc_ok = check_calc_crc_wmbus(decoder->packet, decoder->L) ? 1 : 0;
if (!opts_show_used_algorithm) algorithm = "";
fprintf(stdout, "%s%s;%u;%u;%s;%u;%u;%08X;", algorithm, "S1",
decoder->crc_ok,
1,
decoder->timestamp,
decoder->packet_rssi,
rssi,
get_serial(decoder->packet));
#if 0
fprintf(stdout, "0x");
for (size_t l = 0; l < decoder->L; l++) fprintf(stdout, "%02x", decoder->packet[l]);
fprintf(stdout, ";");
#endif
#if 1
decoder->L = cook_pkt(decoder->packet, decoder->L);
fprintf(stdout, "0x");
for (size_t l = 0; l < decoder->L; l++) fprintf(stdout, "%02x", decoder->packet[l]);
#endif
fprintf(stdout, "\n");
fflush(stdout);
reset_s1_packet_decoder(decoder);
}
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)
{
reset_s1_packet_decoder(decoder);
}
}
}
#endif /* S1_PACKET_DECODER_H */