Add TPMS initial demodulator implementation.

Right now, 2FSK, 19200 baud, +/-38400Hz deviation. No effort is made to check CRC/checksums or decode packets.
This commit is contained in:
Jared Boone 2015-11-10 15:19:56 -08:00
parent 6cdef7026d
commit 9f6c495fef
7 changed files with 227 additions and 0 deletions

View File

@ -503,10 +503,17 @@ void ReceiverView::on_show() {
this->on_packet_ais(*message); this->on_packet_ais(*message);
} }
); );
message_map.register_handler(Message::ID::TPMSPacket,
[this](Message* const p) {
const auto message = static_cast<const TPMSPacketMessage*>(p);
this->on_packet_tpms(*message);
}
);
} }
void ReceiverView::on_hide() { void ReceiverView::on_hide() {
auto& message_map = context().message_map(); auto& message_map = context().message_map();
message_map.unregister_handler(Message::ID::TPMSPacket);
message_map.unregister_handler(Message::ID::AISPacket); message_map.unregister_handler(Message::ID::AISPacket);
} }
@ -519,6 +526,31 @@ void ReceiverView::on_packet_ais(const AISPacketMessage& message) {
} }
} }
void ReceiverView::on_packet_tpms(const TPMSPacketMessage& message) {
auto payload = message.packet.payload;
auto payload_length = message.packet.bits_received;
for(size_t i=0; i<payload_length; i+=2) {
if( payload[i+0] != payload[i+1] ) {
payload[i>>1] = payload[i+1];
} else {
payload[i>>1] = 0;
}
}
std::string hex;
uint8_t c = 0;
for(size_t i=0; i<15*8; i++) {
c = (c << 1) | payload[i];
if( (i & 7) == 7 ) {
hex += to_string_hex(c, 2);
}
}
auto console = reinterpret_cast<Console*>(widget_content.get());
console->writeln(hex);
}
void ReceiverView::focus() { void ReceiverView::focus() {
button_done.focus(); button_done.focus();
} }
@ -547,6 +579,7 @@ void ReceiverView::on_modulation_changed(int32_t modulation) {
/* TODO: This is TERRIBLE!!! */ /* TODO: This is TERRIBLE!!! */
switch(modulation) { switch(modulation) {
case 3: case 3:
case 5:
receiver_model.set_baseband_configuration({ receiver_model.set_baseband_configuration({
.mode = modulation, .mode = modulation,
.sampling_rate = 2457600, .sampling_rate = 2457600,
@ -579,6 +612,7 @@ void ReceiverView::on_modulation_changed(int32_t modulation) {
switch(modulation) { switch(modulation) {
case 3: case 3:
case 5:
widget_content = std::make_unique<Console>(); widget_content = std::make_unique<Console>();
add_child(widget_content.get()); add_child(widget_content.get());
break; break;

View File

@ -416,6 +416,7 @@ private:
{ "NFM ", 1 }, { "NFM ", 1 },
{ "WFM ", 2 }, { "WFM ", 2 },
{ "AIS ", 3 }, { "AIS ", 3 },
{ "TPMS", 5 },
{ "SPEC", 4 }, { "SPEC", 4 },
} }
}; };
@ -473,6 +474,7 @@ private:
void on_edit_frequency(); void on_edit_frequency();
void on_packet_ais(const AISPacketMessage& message); void on_packet_ais(const AISPacketMessage& message);
void on_packet_tpms(const TPMSPacketMessage& message);
}; };
} /* namespace ui */ } /* namespace ui */

View File

@ -139,6 +139,7 @@ CPPSRC = main.cpp \
proc_wfm_audio.cpp \ proc_wfm_audio.cpp \
proc_ais.cpp \ proc_ais.cpp \
proc_wideband_spectrum.cpp \ proc_wideband_spectrum.cpp \
proc_tpms.cpp \
dsp_squelch.cpp \ dsp_squelch.cpp \
clock_recovery.cpp \ clock_recovery.cpp \
packet_builder.cpp \ packet_builder.cpp \

View File

@ -57,6 +57,7 @@
#include "proc_wfm_audio.hpp" #include "proc_wfm_audio.hpp"
#include "proc_ais.hpp" #include "proc_ais.hpp"
#include "proc_wideband_spectrum.hpp" #include "proc_wideband_spectrum.hpp"
#include "proc_tpms.hpp"
#include "clock_recovery.hpp" #include "clock_recovery.hpp"
#include "packet_builder.hpp" #include "packet_builder.hpp"
@ -319,6 +320,10 @@ int main(void) {
baseband_processor = new WidebandSpectrum(); baseband_processor = new WidebandSpectrum();
break; break;
case 5:
baseband_processor = new TPMSProcessor();
break;
default: default:
break; break;
} }

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "proc_tpms.hpp"
#include "portapack_shared_memory.hpp"
#include "i2s.hpp"
using namespace lpc43xx;
void TPMSProcessor::execute(buffer_c8_t buffer) {
/* 2.4576MHz, 2048 samples */
auto decimator_out = decimator.execute(buffer);
/* 76.8kHz, 64 samples */
feed_channel_stats(decimator_out);
/* No spectrum display while FSK decoding.
feed_channel_spectrum(
channel,
decimator_out.sampling_rate * channel_filter_taps.pass_frequency_normalized,
decimator_out.sampling_rate * channel_filter_taps.stop_frequency_normalized
);
*/
for(size_t i=0; i<decimator_out.count; i++) {
// TODO: No idea why implicit cast int16_t->float is not allowed.
const std::complex<float> sample {
static_cast<float>(decimator_out.p[i].real()),
static_cast<float>(decimator_out.p[i].imag())
};
if( mf.execute_once(sample) ) {
clock_recovery(mf.get_output());
}
}
i2s::i2s0::tx_mute();
}
void TPMSProcessor::consume_symbol(
const float raw_symbol
) {
const uint_fast8_t sliced_symbol = (raw_symbol >= 0.0f) ? 1 : 0;
packet_builder.execute(sliced_symbol);
}
void TPMSProcessor::payload_handler(
const std::bitset<1024>& payload,
const size_t bits_received
) {
TPMSPacketMessage message;
message.packet.payload = payload;
message.packet.bits_received = bits_received;
shared_memory.application_queue.push(message);
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc.
*
* This file is part of PortaPack.
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#ifndef __PROC_TPMS_H__
#define __PROC_TPMS_H__
#include "baseband_processor.hpp"
#include "channel_decimator.hpp"
#include "matched_filter.hpp"
#include "clock_recovery.hpp"
#include "symbol_coding.hpp"
#include "packet_builder.hpp"
#include "message.hpp"
#include <cstdint>
#include <cstddef>
#include <bitset>
struct NeverMatch {
bool operator()(const BitHistory&, const size_t) const {
return false;
}
};
struct FixedLength {
bool operator()(const BitHistory&, const size_t symbols_received) const {
return symbols_received >= length;
}
const size_t length;
};
// Translate+rectangular filter
// sample=153.6k, deviation=38400, symbol=19200
// Length: 8 taps, 1 symbols, 2 cycles of sinusoid
constexpr std::array<std::complex<float>, 8> rect_taps_153k6_1t_p { {
{ 1.2500000000e-01f, 0.0000000000e+00f }, { 7.6540424947e-18f, 1.2500000000e-01f },
{ -1.2500000000e-01f, 1.5308084989e-17f }, { -2.2962127484e-17f, -1.2500000000e-01f },
{ 1.2500000000e-01f, -3.0616169979e-17f }, { 3.8270212473e-17f, 1.2500000000e-01f },
{ -1.2500000000e-01f, 4.5924254968e-17f }, { -5.3578297463e-17f, -1.2500000000e-01f },
} };
class TPMSProcessor : public BasebandProcessor {
public:
using payload_t = std::bitset<1024>;
void execute(buffer_c8_t buffer) override;
private:
ChannelDecimator decimator { ChannelDecimator::DecimationFactor::By16 };
dsp::matched_filter::MatchedFilter mf { rect_taps_153k6_1t_p, 4 };
clock_recovery::ClockRecovery<clock_recovery::FixedErrorFilter> clock_recovery {
38400, 19200, { 0.0555f },
[this](const float symbol) { this->consume_symbol(symbol); }
};
PacketBuilder<BitPattern, NeverMatch, FixedLength> packet_builder {
{ 0b010101010101010101010101010110, 30, 1 },
{ },
{ 256 },
[this](const payload_t& payload, const size_t bits_received) {
this->payload_handler(payload, bits_received);
}
};
void consume_symbol(const float symbol);
void payload_handler(const payload_t& payload, const size_t bits_received);
};
#endif/*__PROC_TPMS_H__*/

View File

@ -43,6 +43,7 @@ public:
ChannelSpectrum = 3, ChannelSpectrum = 3,
AudioStatistics = 4, AudioStatistics = 4,
BasebandConfiguration = 5, BasebandConfiguration = 5,
TPMSPacket = 6,
Shutdown = 8, Shutdown = 8,
AISPacket = 7, AISPacket = 7,
MAX MAX
@ -216,6 +217,26 @@ public:
AISPacket packet; AISPacket packet;
}; };
struct TPMSPacket {
std::bitset<1024> payload;
size_t bits_received;
TPMSPacket(
) : bits_received { 0 }
{
}
};
class TPMSPacketMessage : public Message {
public:
TPMSPacketMessage(
) : Message { ID::TPMSPacket }
{
}
TPMSPacket packet;
};
class ShutdownMessage : public Message { class ShutdownMessage : public Message {
public: public:
constexpr ShutdownMessage( constexpr ShutdownMessage(