Skip to content

Commit

Permalink
Added data packet channel with reed solomon outer decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
williamyang98 committed Feb 17, 2024
1 parent 125fa04 commit e55a92f
Show file tree
Hide file tree
Showing 30 changed files with 1,122 additions and 369 deletions.
2 changes: 2 additions & 0 deletions examples/basic_radio_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

#include <argparse/argparse.hpp>
#include <fmt/core.h>
#include "basic_radio/basic_radio.h"
#include "basic_radio/basic_audio_channel.h"
#include "basic_scraper/basic_scraper.h"
#include "./app_helpers/app_io_buffers.h"
#include "./app_helpers/app_ofdm_blocks.h"
Expand Down
132 changes: 81 additions & 51 deletions examples/gui/basic_radio/render_basic_radio.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
#include "./render_basic_radio.h"
#include "./basic_radio_view_controller.h"
#include "dab/database/dab_database_entities.h"
#include "./render_common.h"

#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>
Expand All @@ -12,12 +10,16 @@
#include <algorithm>
#include "../font_awesome_definitions.h"
#include "./formatters.h"
#include "./render_common.h"
#include "./render_basic_radio.h"
#include "./basic_radio_view_controller.h"

#include "basic_radio/basic_radio.h"
#include "basic_radio/basic_slideshow.h"
#include "basic_radio/basic_data_packet_channel.h"
#include "basic_radio/basic_audio_channel.h"
#include "basic_radio/basic_dab_plus_channel.h"
#include "basic_radio/basic_dab_channel.h"
#include "dab/database/dab_database_entities.h"
#include "dab/database/dab_database.h"
#include "dab/database/dab_database_updater.h"

Expand All @@ -34,6 +36,7 @@ static void RenderSimple_Service(BasicRadio& radio, BasicRadioViewController& co
static void RenderSimple_ServiceComponentList(BasicRadio& radio, BasicRadioViewController& controller, Service* service);
static void RenderSimple_ServiceComponent(BasicRadio& radio, BasicRadioViewController& controller, ServiceComponent& component);
static void RenderSimple_Basic_Audio_Channel(BasicRadio& radio, BasicRadioViewController& controller, Basic_Audio_Channel& channel, const subchannel_id_t subchannel_id);
static void RenderSimple_Basic_Data_Channel(BasicRadio& radio, BasicRadioViewController& controller, Basic_Data_Packet_Channel& channel, const subchannel_id_t subchannel_id);
static void RenderSimple_BasicSlideshowSelected(BasicRadio& radio, BasicRadioViewController& controller);
static void RenderSimple_LinkServices(BasicRadio& radio, BasicRadioViewController& controller, Service* service);
static void RenderSimple_LinkService(BasicRadio& radio, BasicRadioViewController& controller, const LinkService& link_service);
Expand Down Expand Up @@ -267,60 +270,32 @@ void RenderSimple_ServiceComponent(BasicRadio& radio, BasicRadioViewController&

auto* audio_channel = radio.Get_Audio_Channel(subchannel_id);
if (audio_channel != nullptr) {
if (ImGui::Begin("Audio Channel")) {
const auto ascty = audio_channel->GetType();
const char* channel_name = "Unknown";
switch (ascty) {
case AudioServiceType::DAB_PLUS: channel_name = "DAB+"; break;
case AudioServiceType::DAB: channel_name = "DAB"; break;
default: channel_name = "Unknown"; break;
}
auto label = fmt::format("{} Channel###Channel", channel_name);
if (ImGui::Begin(label.c_str())) {
RenderSimple_Basic_Audio_Channel(radio, controller, *audio_channel, subchannel_id);
}
ImGui::End();
}
}

void RenderSimple_Basic_Audio_Channel(BasicRadio& radio, BasicRadioViewController& controller, Basic_Audio_Channel& channel, subchannel_id_t subchannel_id) {
// Channel controls
auto& controls = channel.GetControls();
if (ImGui::Button("Run All")) {
controls.RunAll();
}
ImGui::SameLine();
if (ImGui::Button("Stop All")) {
controls.StopAll();
}
bool v = false;
v = controls.GetIsDecodeAudio();
ImGui::SameLine();
if (ImGui::Checkbox("Decode audio", &v)) {
controls.SetIsDecodeAudio(v);
}
v = controls.GetIsDecodeData();
ImGui::SameLine();
if (ImGui::Checkbox("Decode data", &v)) {
controls.SetIsDecodeData(v);
}
v = controls.GetIsPlayAudio();
ImGui::SameLine();
if (ImGui::Checkbox("Play audio", &v)) {
controls.SetIsPlayAudio(v);
return;
}

const auto ascty = channel.GetType();
switch (ascty) {
case AudioServiceType::DAB_PLUS:
RenderSimple_Basic_DAB_Plus_Channel_Status(dynamic_cast<Basic_DAB_Plus_Channel&>(channel));
break;
case AudioServiceType::DAB:
RenderSimple_Basic_DAB_Channel_Status(dynamic_cast<Basic_DAB_Channel&>(channel));
break;
case AudioServiceType::UNDEFINED:
default:
break;
auto* data_channel = radio.Get_Data_Packet_Channel(subchannel_id);
if (data_channel != nullptr) {
if (ImGui::Begin("Data Channel###Channel")) {
RenderSimple_Basic_Data_Channel(radio, controller, *data_channel, subchannel_id);
}
ImGui::End();
return;
}
}

// Programme associated data
// 1. Dynamic label
// 2. MOT slideshow
auto label = channel.GetDynamicLabel();
ImGui::Text("Dynamic label: %.*s", int(label.length()), label.data());

auto& slideshow_manager = channel.GetSlideshowManager();
static void RenderSimple_Slideshow_Manager(BasicRadioViewController& controller, Basic_Slideshow_Manager& slideshow_manager, subchannel_id_t subchannel_id) {
ImGuiChildFlags child_flags = ImGuiChildFlags_Border;
ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
if (ImGui::BeginChild("Slideshow", ImVec2(0, 0), child_flags, window_flags)) {
Expand Down Expand Up @@ -372,6 +347,61 @@ void RenderSimple_Basic_Audio_Channel(BasicRadio& radio, BasicRadioViewControlle
ImGui::EndChild();
}

void RenderSimple_Basic_Audio_Channel(BasicRadio& radio, BasicRadioViewController& controller, Basic_Audio_Channel& channel, subchannel_id_t subchannel_id) {
// Channel controls
auto& controls = channel.GetControls();
if (ImGui::Button("Run All")) {
controls.RunAll();
}
ImGui::SameLine();
if (ImGui::Button("Stop All")) {
controls.StopAll();
}
bool v = false;
v = controls.GetIsDecodeAudio();
ImGui::SameLine();
if (ImGui::Checkbox("Decode audio", &v)) {
controls.SetIsDecodeAudio(v);
}
v = controls.GetIsDecodeData();
ImGui::SameLine();
if (ImGui::Checkbox("Decode data", &v)) {
controls.SetIsDecodeData(v);
}
v = controls.GetIsPlayAudio();
ImGui::SameLine();
if (ImGui::Checkbox("Play audio", &v)) {
controls.SetIsPlayAudio(v);
}

const auto ascty = channel.GetType();
switch (ascty) {
case AudioServiceType::DAB_PLUS:
RenderSimple_Basic_DAB_Plus_Channel_Status(dynamic_cast<Basic_DAB_Plus_Channel&>(channel));
break;
case AudioServiceType::DAB:
RenderSimple_Basic_DAB_Channel_Status(dynamic_cast<Basic_DAB_Channel&>(channel));
break;
case AudioServiceType::UNDEFINED:
default:
break;
}

// Programme associated data
// 1. Dynamic label
// 2. MOT slideshow
auto label = channel.GetDynamicLabel();
ImGui::Text("Dynamic label: %.*s", int(label.length()), label.data());

auto& slideshow_manager = channel.GetSlideshowManager();
RenderSimple_Slideshow_Manager(controller, slideshow_manager, subchannel_id);
}

void RenderSimple_Basic_Data_Channel(BasicRadio& radio, BasicRadioViewController& controller, Basic_Data_Packet_Channel& channel, const subchannel_id_t subchannel_id) {
auto& slideshow_manager = channel.GetSlideshowManager();
RenderSimple_Slideshow_Manager(controller, slideshow_manager, subchannel_id);
}

static void render_error_indicator(const char* label, bool is_error) {
static const auto COLOR_NO_ERROR = ImColor(0,255,0).Value;
static const auto COLOR_ERROR = ImColor(255,0,0).Value;
Expand Down
2 changes: 2 additions & 0 deletions examples/gui/basic_radio/render_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
#include <imgui.h>
#include <fmt/core.h>
#include "basic_radio/basic_radio.h"
#include "basic_radio/basic_audio_channel.h"
#include "dab/database/dab_database.h"
#include "dab/database/dab_database_updater.h"
#include "dab/dab_misc_info.h"
#include "./formatters.h"

template <typename T, typename F>
Expand Down
2 changes: 2 additions & 0 deletions examples/radio_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <imgui.h>
#include <argparse/argparse.hpp>
#include <fmt/core.h>
#include "basic_radio/basic_radio.h"
#include "basic_radio/basic_audio_channel.h"
#include "basic_scraper/basic_scraper.h"
#include "./block_frequencies.h"
#include "./app_helpers/app_io_buffers.h"
Expand Down
1 change: 1 addition & 0 deletions src/basic_radio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ add_library(basic_radio STATIC
${SRC_DIR}/basic_audio_channel.cpp
${SRC_DIR}/basic_dab_plus_channel.cpp
${SRC_DIR}/basic_dab_channel.cpp
${SRC_DIR}/basic_data_packet_channel.cpp
${SRC_DIR}/basic_slideshow.cpp)
set_target_properties(basic_radio PROPERTIES CXX_STANDARD 17)
target_include_directories(basic_radio PRIVATE ${SRC_DIR} ${ROOT_DIR})
Expand Down
4 changes: 3 additions & 1 deletion src/basic_radio/basic_audio_channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
#include "dab/database/dab_database_entities.h"
#include "dab/msc/msc_decoder.h"
#include "dab/mot/MOT_slideshow_processor.h"
#include <fmt/core.h>
#include <assert.h>

#include <fmt/core.h>
#include "./basic_radio_logging.h"
#define LOG_MESSAGE(...) BASIC_RADIO_LOG_MESSAGE(fmt::format(__VA_ARGS__))
#define LOG_ERROR(...) BASIC_RADIO_LOG_ERROR(fmt::format(__VA_ARGS__))

Basic_Audio_Channel::Basic_Audio_Channel(const DAB_Parameters& params, const Subchannel subchannel, const AudioServiceType audio_service_type)
: m_params(params), m_subchannel(subchannel), m_audio_service_type(audio_service_type) {
assert(subchannel.is_complete);
m_msc_decoder = std::make_unique<MSC_Decoder>(m_subchannel);
m_slideshow_manager = std::make_unique<Basic_Slideshow_Manager>();
}
Expand Down
7 changes: 4 additions & 3 deletions src/basic_radio/basic_audio_channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vector>
#include <memory>

#include "./basic_msc_runner.h"
#include "./basic_audio_params.h"
#include "./basic_audio_controls.h"
#include "dab/constants/dab_parameters.h"
Expand All @@ -20,7 +21,7 @@ struct Basic_Slideshow;
class Basic_Slideshow_Manager;

// Shared interface for DAB+/DAB channels
class Basic_Audio_Channel
class Basic_Audio_Channel: public Basic_MSC_Runner
{
protected:
const DAB_Parameters m_params;
Expand All @@ -38,8 +39,8 @@ class Basic_Audio_Channel
Observable<MOT_Entity> m_obs_MOT_entity;
public:
explicit Basic_Audio_Channel(const DAB_Parameters& params, const Subchannel subchannel, const AudioServiceType audio_service_type);
virtual ~Basic_Audio_Channel();
virtual void Process(tcb::span<const viterbi_bit_t> msc_bits_buf) = 0;
virtual ~Basic_Audio_Channel() override;
virtual void Process(tcb::span<const viterbi_bit_t> msc_bits_buf) override = 0;
AudioServiceType GetType(void) const { return m_audio_service_type; }
auto& GetControls(void) { return m_controls; }
std::string_view GetDynamicLabel(void) const { return m_dynamic_label; }
Expand Down
83 changes: 83 additions & 0 deletions src/basic_radio/basic_data_packet_channel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#include "./basic_data_packet_channel.h"
#include <stdint.h>
#include <assert.h>
#include "dab/database/dab_database_entities.h"
#include "dab/msc/msc_decoder.h"
#include "dab/msc/msc_data_packet_processor.h"
#include "dab/msc/msc_reed_solomon_data_packet_processor.h"
#include "dab/mot/MOT_processor.h"
#include "./basic_slideshow.h"

#include <fmt/core.h>
#include "./basic_radio_logging.h"
#define LOG_MESSAGE(...) BASIC_RADIO_LOG_MESSAGE(fmt::format(__VA_ARGS__))
#define LOG_ERROR(...) BASIC_RADIO_LOG_ERROR(fmt::format(__VA_ARGS__))

Basic_Data_Packet_Channel::Basic_Data_Packet_Channel(const DAB_Parameters& params, Subchannel subchannel, DataServiceType type)
: m_params(params), m_subchannel(subchannel), m_type(type)
{
assert(subchannel.is_complete);
assert(subchannel.fec_scheme != FEC_Scheme::UNDEFINED);
m_msc_rs_data_packet_processor = nullptr;
m_msc_decoder = std::make_unique<MSC_Decoder>(m_subchannel);
m_msc_data_packet_processor = std::make_unique<MSC_Data_Packet_Processor>();
m_slideshow_manager = std::make_unique<Basic_Slideshow_Manager>();
if (m_subchannel.fec_scheme == FEC_Scheme::REED_SOLOMON) {
m_msc_rs_data_packet_processor = std::make_unique<MSC_Reed_Solomon_Data_Packet_Processor>();
m_msc_rs_data_packet_processor->SetCallback([this](tcb::span<const uint8_t> buf, bool is_fec) {
ProcessNonFECPackets(buf);
});
}
m_msc_data_packet_processor->Get_MOT_Processor().OnEntityComplete().Attach([this](MOT_Entity entity) {
auto slideshow = m_slideshow_manager->Process_MOT_Entity(entity);
if (slideshow == nullptr) {
m_obs_MOT_entity.Notify(entity);
}
});

// Where do we use this?
(void)m_type;
}

Basic_Data_Packet_Channel::~Basic_Data_Packet_Channel() = default;

void Basic_Data_Packet_Channel::Process(tcb::span<const viterbi_bit_t> msc_bits_buf) {
BASIC_RADIO_SET_THREAD_NAME(fmt::format("MSC-data-packet-subchannel-{}", m_subchannel.id));

const int nb_msc_bits = (int)msc_bits_buf.size();
if (nb_msc_bits != m_params.nb_msc_bits) {
LOG_ERROR("Got incorrect number of MSC bits {}/{}", nb_msc_bits, m_params.nb_msc_bits);
return;
}

for (int i = 0; i < m_params.nb_cifs; i++) {
const auto cif_buf = msc_bits_buf.subspan(i*m_params.nb_cif_bits, m_params.nb_cif_bits);
auto buf = m_msc_decoder->DecodeCIF(cif_buf);
// The MSC decoder can have 0 bytes if the deinterleaver is still collecting frames
if (buf.empty()) {
continue;
}

if (m_msc_rs_data_packet_processor) {
ProcessFECPackets(buf);
} else {
ProcessNonFECPackets(buf);
}
}
}

void Basic_Data_Packet_Channel::ProcessFECPackets(tcb::span<const uint8_t> buf) {
while (!buf.empty()) {
const size_t total_read = m_msc_rs_data_packet_processor->ReadPacket(buf);
assert(total_read <= buf.size());
buf = buf.subspan(total_read);
}
}

void Basic_Data_Packet_Channel::ProcessNonFECPackets(tcb::span<const uint8_t> buf) {
while (!buf.empty()) {
const size_t total_read = m_msc_data_packet_processor->ReadPacket(buf);
assert(total_read <= buf.size());
buf = buf.subspan(total_read);
}
}
38 changes: 38 additions & 0 deletions src/basic_radio/basic_data_packet_channel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include <memory>
#include "./basic_msc_runner.h"
#include "dab/constants/dab_parameters.h"
#include "dab/database/dab_database_entities.h"
#include "dab/database/dab_database_types.h"
#include "utility/span.h"
#include "viterbi_config.h"
#include "utility/observable.h"

class MSC_Decoder;
class MSC_Data_Packet_Processor;
class MSC_Reed_Solomon_Data_Packet_Processor;
class Basic_Slideshow_Manager;
struct MOT_Entity;

class Basic_Data_Packet_Channel: public Basic_MSC_Runner
{
private:
const DAB_Parameters m_params;
const Subchannel m_subchannel;
const DataServiceType m_type;
std::unique_ptr<MSC_Decoder> m_msc_decoder;
std::unique_ptr<MSC_Data_Packet_Processor> m_msc_data_packet_processor;
std::unique_ptr<MSC_Reed_Solomon_Data_Packet_Processor> m_msc_rs_data_packet_processor;
std::unique_ptr<Basic_Slideshow_Manager> m_slideshow_manager;
Observable<MOT_Entity> m_obs_MOT_entity;
public:
explicit Basic_Data_Packet_Channel(const DAB_Parameters& params, Subchannel subchannel, DataServiceType type);
~Basic_Data_Packet_Channel() override;
void Process(tcb::span<const viterbi_bit_t> msc_bits_buf) override;
auto& GetSlideshowManager() { return *m_slideshow_manager; }
auto& OnMOTEntity() { return m_obs_MOT_entity; }
private:
void ProcessNonFECPackets(tcb::span<const uint8_t> buf);
void ProcessFECPackets(tcb::span<const uint8_t> buf);
};
10 changes: 10 additions & 0 deletions src/basic_radio/basic_msc_runner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

#include "utility/span.h"
#include "viterbi_config.h"

class Basic_MSC_Runner {
public:
virtual ~Basic_MSC_Runner() {};
virtual void Process(tcb::span<const viterbi_bit_t> msc_bits_buf) = 0;
};
Loading

0 comments on commit e55a92f

Please sign in to comment.