kopia lustrzana https://github.com/xaelsouth/rtl-wmbus
291 wiersze
9.2 KiB
C
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 */
|
|
|