388 lines
15 KiB
C++
388 lines
15 KiB
C++
#ifndef SYMBOLFORMATION_H
|
|
#define SYMBOLFORMATION_H
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
|
|
#include "Scrambler.h"
|
|
|
|
enum class SymbolType { SYNC_PREAMBLE, UNKNOWN_DATA, PROBE_DATA };
|
|
|
|
static constexpr size_t LONG_PROBE_DATA_BLOCK_SIZE = 20;
|
|
static constexpr size_t SHORT_PROBE_DATA_BLOCK_SIZE = 16;
|
|
static constexpr size_t LONG_UNKNOWN_DATA_BLOCK_SIZE = 32;
|
|
static constexpr size_t SHORT_UNKNOWN_DATA_BLOCK_SIZE = 20;
|
|
static constexpr size_t SET_SIZE_LONG = 360;
|
|
static constexpr size_t SET_SIZE_SHORT = 32;
|
|
|
|
std::vector<uint8_t> Sync_Preamble_0 = {0, 0, 0, 0, 0, 0, 0, 0};
|
|
std::vector<uint8_t> Sync_Preamble_1 = {0, 4, 0, 4, 0, 4, 0, 4};
|
|
std::vector<uint8_t> Sync_Preamble_2 = {0, 0, 4, 4, 0, 0, 4, 4};
|
|
std::vector<uint8_t> Sync_Preamble_3 = {0, 4, 4, 0, 0, 4, 4, 0};
|
|
std::vector<uint8_t> Sync_Preamble_4 = {0, 0, 0, 0, 4, 4, 4, 4};
|
|
std::vector<uint8_t> Sync_Preamble_5 = {0, 4, 0, 4, 4, 0, 4, 0};
|
|
std::vector<uint8_t> Sync_Preamble_6 = {0, 0, 4, 4, 4, 4, 0, 0};
|
|
std::vector<uint8_t> Sync_Preamble_7 = {0, 4, 4, 0, 4, 0, 0, 4};
|
|
|
|
std::vector<uint8_t> baud75_exceptional_0 = {0, 0, 0, 0, 4, 4, 4, 4};
|
|
std::vector<uint8_t> baud75_exceptional_1 = {0, 4, 0, 4, 4, 0, 4, 0};
|
|
std::vector<uint8_t> baud75_exceptional_2 = {0, 0, 4, 4, 4, 4, 0, 0};
|
|
std::vector<uint8_t> baud75_exceptional_3 = {0, 4, 4, 0, 4, 0, 0, 4};
|
|
std::vector<uint8_t> baud75_normal_0 = {0, 0, 0, 0};
|
|
std::vector<uint8_t> baud75_normal_1 = {0, 4, 0, 4};
|
|
std::vector<uint8_t> baud75_normal_2 = {0, 0, 4, 4};
|
|
std::vector<uint8_t> baud75_normal_3 = {0, 4, 4, 0};
|
|
|
|
class SymbolFormation {
|
|
public:
|
|
SymbolFormation(size_t baud_rate, size_t interleave_setting, bool is_voice, bool is_frequency_hopping) : interleave_setting(interleave_setting), baud_rate(baud_rate), is_voice(is_voice), is_frequency_hopping(is_frequency_hopping) {}
|
|
|
|
std::vector<uint8_t> formSymbols(std::vector<uint8_t>& symbol_data) {
|
|
// Generate and scramble the sync preamble
|
|
std::vector<uint8_t> sync_preamble = generateSyncPreamble();
|
|
sync_preamble = scrambler.scrambleSyncPreamble(sync_preamble);
|
|
|
|
size_t unknown_data_block_size = (baud_rate >= 2400) ? LONG_UNKNOWN_DATA_BLOCK_SIZE : SHORT_UNKNOWN_DATA_BLOCK_SIZE;
|
|
size_t interleaver_block_size;
|
|
if (baud_rate == 2400) {
|
|
interleaver_block_size = (interleave_setting == 2) ? (40 * 576) : (40 * 72);
|
|
} else if (baud_rate == 1200) {
|
|
interleaver_block_size = (interleave_setting == 2) ? (40 * 288) : (40 * 36);
|
|
} else if ((baud_rate >= 150) || (baud_rate == 75 && is_frequency_hopping)) {
|
|
interleaver_block_size = (interleave_setting == 2) ? (40 * 144) : (40 * 18);
|
|
} else {
|
|
interleaver_block_size = (interleave_setting == 2) ? (20 * 36) : (10 * 9);
|
|
}
|
|
|
|
size_t set_count = 0;
|
|
size_t symbol_count = 0;
|
|
std::vector<uint8_t> data_stream;
|
|
|
|
size_t current_index = 0;
|
|
while (current_index < symbol_data.size()) {
|
|
// Process unknown data block
|
|
size_t block_size = std::min(unknown_data_block_size, symbol_data.size() - current_index);
|
|
std::vector<uint8_t> unknown_data_block(symbol_data.begin() + current_index, symbol_data.begin() + current_index + block_size);
|
|
current_index += block_size;
|
|
|
|
if (baud_rate == 75) {
|
|
size_t set_size = (interleave_setting == 2) ? SET_SIZE_LONG : SET_SIZE_SHORT;
|
|
for (size_t i = 0; i < unknown_data_block.size(); i += set_size) {
|
|
bool is_exceptional_set = (set_count % ((interleave_setting == 1) ? 45 : 360)) == 0;
|
|
std::vector<uint8_t> mapped_set = map75bpsSet(unknown_data_block, i, set_size, is_exceptional_set);
|
|
data_stream.insert(data_stream.end(), mapped_set.begin(), mapped_set.end());
|
|
set_count++;
|
|
}
|
|
} else {
|
|
std::vector<uint8_t> mapped_unknown_data = mapUnknownData(unknown_data_block);
|
|
symbol_count += mapped_unknown_data.size();
|
|
data_stream.insert(data_stream.end(), mapped_unknown_data.begin(), mapped_unknown_data.end());
|
|
}
|
|
|
|
if (baud_rate > 75) {
|
|
bool inside_block = (symbol_count % interleaver_block_size) != 0;
|
|
std::vector<uint8_t> probe_data = generateProbeData(inside_block);
|
|
data_stream.insert(data_stream.end(), probe_data.begin(), probe_data.end());
|
|
}
|
|
}
|
|
|
|
// Scramble the entire data stream
|
|
data_stream = scrambler.scrambleData(data_stream);
|
|
|
|
// Combine sync preamble and scrambled data stream
|
|
std::vector<uint8_t> symbol_stream;
|
|
symbol_stream.insert(symbol_stream.end(), sync_preamble.begin(), sync_preamble.end());
|
|
symbol_stream.insert(symbol_stream.end(), data_stream.begin(), data_stream.end());
|
|
|
|
return symbol_stream;
|
|
}
|
|
|
|
private:
|
|
int baud_rate;
|
|
int interleave_setting;
|
|
bool is_voice;
|
|
bool is_frequency_hopping;
|
|
Scrambler scrambler = Scrambler();
|
|
|
|
void appendProbeMapping(std::vector<uint8_t>& symbol_stream, uint8_t symbol, size_t repeat_count) {
|
|
switch (symbol) {
|
|
case 0:
|
|
for (int i = 0; i < repeat_count; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), Sync_Preamble_0.begin(), Sync_Preamble_0.end());
|
|
}
|
|
break;
|
|
case 1:
|
|
for (int i = 0; i < repeat_count; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), Sync_Preamble_1.begin(), Sync_Preamble_1.end());
|
|
}
|
|
break;
|
|
case 2:
|
|
for (int i = 0; i < repeat_count; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), Sync_Preamble_2.begin(), Sync_Preamble_2.end());
|
|
}
|
|
break;
|
|
case 3:
|
|
for (int i = 0; i < repeat_count; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), Sync_Preamble_3.begin(), Sync_Preamble_3.end());
|
|
}
|
|
break;
|
|
case 4:
|
|
for (int i = 0; i < repeat_count; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), Sync_Preamble_4.begin(), Sync_Preamble_4.end());
|
|
}
|
|
break;
|
|
case 5:
|
|
for (int i = 0; i < repeat_count; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), Sync_Preamble_5.begin(), Sync_Preamble_5.end());
|
|
}
|
|
break;
|
|
case 6:
|
|
for (int i = 0; i < repeat_count; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), Sync_Preamble_6.begin(), Sync_Preamble_6.end());
|
|
}
|
|
break;
|
|
case 7:
|
|
for (int i = 0; i < repeat_count; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), Sync_Preamble_7.begin(), Sync_Preamble_7.end());
|
|
}
|
|
break;
|
|
default:
|
|
throw std::invalid_argument("Invalid channel symbol");
|
|
}
|
|
}
|
|
|
|
void append75bpsMapping(std::vector<uint8_t>& symbol_stream, uint8_t symbol, bool is_exceptional_set) {
|
|
if (is_exceptional_set) {
|
|
switch (symbol) {
|
|
case 0:
|
|
for (int i = 0; i < 4; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), baud75_exceptional_0.begin(), baud75_exceptional_0.end());
|
|
}
|
|
break;
|
|
case 1:
|
|
for (int i = 0; i < 4; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), baud75_exceptional_1.begin(), baud75_exceptional_1.end());
|
|
}
|
|
break;
|
|
case 2:
|
|
for (int i = 0; i < 4; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), baud75_exceptional_2.begin(), baud75_exceptional_2.end());
|
|
}
|
|
break;
|
|
case 3:
|
|
for (int i = 0; i < 4; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), baud75_exceptional_3.begin(), baud75_exceptional_3.end());
|
|
}
|
|
break;
|
|
default:
|
|
throw std::invalid_argument("Invalid channel symbol");
|
|
}
|
|
} else {
|
|
switch (symbol) {
|
|
case 0:
|
|
for (int i = 0; i < 8; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), baud75_normal_0.begin(), baud75_normal_0.end());
|
|
}
|
|
break;
|
|
case 1:
|
|
for (int i = 0; i < 8; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), baud75_normal_1.begin(), baud75_normal_1.end());
|
|
}
|
|
break;
|
|
case 2:
|
|
for (int i = 0; i < 8; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), baud75_normal_2.begin(), baud75_normal_2.end());
|
|
}
|
|
break;
|
|
case 3:
|
|
for (int i = 0; i < 8; ++i) {
|
|
symbol_stream.insert(symbol_stream.end(), baud75_normal_3.begin(), baud75_normal_3.end());
|
|
}
|
|
break;
|
|
default:
|
|
throw std::invalid_argument("Invalid channel symbol");
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<uint8_t> generateSyncPreamble() {
|
|
std::vector<uint8_t> preamble;
|
|
|
|
size_t num_segments = (interleave_setting == 0) ? 3 : 24;
|
|
|
|
std::vector<uint8_t> segment_sequence = {0,1,3,0,1,3,1,2,0};
|
|
|
|
uint8_t D1, D2;
|
|
if (baud_rate == 4800) {
|
|
D1 = 7; D2 = 6;
|
|
} else if (baud_rate == 2400 && is_voice) {
|
|
D1 = 7; D2 = 7;
|
|
} else if (baud_rate == 2400) {
|
|
D1 = (interleave_setting <= 1) ? 6 : 4;
|
|
D2 = 4;
|
|
} else if (baud_rate == 1200) {
|
|
D1 = (interleave_setting <= 1) ? 6 : 4;
|
|
D2 = 5;
|
|
} else if (baud_rate == 600) {
|
|
D1 = (interleave_setting <= 1) ? 6 : 4;
|
|
D2 = 6;
|
|
} else if (baud_rate == 300) {
|
|
D1 = (interleave_setting <= 1) ? 6 : 4;
|
|
D2 = 7;
|
|
} else if (baud_rate == 150) {
|
|
D1 = (interleave_setting <= 1) ? 7 : 5;
|
|
D2 = 4;
|
|
} else if (baud_rate == 75) {
|
|
D1 = (interleave_setting <= 1) ? 7 : 5;
|
|
D2 = 5;
|
|
} else {
|
|
throw std::invalid_argument("Invalid baud rate for Generate Sync Preamble");
|
|
}
|
|
|
|
segment_sequence.push_back(D1);
|
|
segment_sequence.push_back(D2);
|
|
|
|
uint8_t C1, C2, C3;
|
|
if (interleave_setting == 2) {
|
|
C1 = 5; C2 = 5; C3 = 7;
|
|
} else {
|
|
C1 = 1; C2 = 1; C3 = 2;
|
|
}
|
|
|
|
for (size_t i = 0; i < num_segments; i++) {
|
|
std::vector<uint8_t> full_segment_sequence = segment_sequence;
|
|
|
|
C1 = (1 << 2) | C1;
|
|
C2 = (1 << 2) | C2;
|
|
C3 = (1 << 2) | C3;
|
|
|
|
full_segment_sequence.push_back(C1);
|
|
full_segment_sequence.push_back(C2);
|
|
full_segment_sequence.push_back(C3);
|
|
full_segment_sequence.push_back(0);
|
|
|
|
preamble.insert(preamble.end(), full_segment_sequence.begin(), full_segment_sequence.end());
|
|
|
|
if (C3 > 0) {
|
|
C3--;
|
|
} else if (C2 > 0) {
|
|
C2--;
|
|
C3 = 3;
|
|
} else if (C1 > 0) {
|
|
C1--;
|
|
C2 = 3;
|
|
C3 = 3;
|
|
}
|
|
}
|
|
|
|
std::vector<uint8_t> final_preamble;
|
|
for (auto& symbol : preamble) {
|
|
appendProbeMapping(final_preamble, symbol, 4);
|
|
}
|
|
|
|
return final_preamble;
|
|
}
|
|
|
|
std::vector<uint8_t> generateProbeData(bool is_inside_block) {
|
|
std::vector<uint8_t> probe_data;
|
|
size_t interleaver_block_size;
|
|
if (baud_rate == 2400) {
|
|
interleaver_block_size = (interleave_setting == 2) ? (40 * 576) : (40 * 72);
|
|
} else if (baud_rate == 1200) {
|
|
interleaver_block_size = (interleave_setting == 2) ? (40 * 288) : (40 * 36);
|
|
} else if ((baud_rate >= 150) || (baud_rate == 75 && is_frequency_hopping)) {
|
|
interleaver_block_size = (interleave_setting == 2) ? (40 * 144) : (40 * 18);
|
|
} else {
|
|
interleaver_block_size = (interleave_setting == 2) ? (20 * 36) : (10 * 9);
|
|
}
|
|
|
|
probe_data.resize(interleaver_block_size, 0x00);
|
|
|
|
if (!is_inside_block) {
|
|
// Set the known symbol patterns for D1 and D2 based on Table XI and Table XIII
|
|
uint8_t D1, D2;
|
|
if (baud_rate == 4800) {
|
|
D1 = 7; D2 = 6;
|
|
} else if (baud_rate == 2400 && is_voice) {
|
|
D1 = 7; D2 = 7;
|
|
} else if (baud_rate == 2400) {
|
|
D1 = (interleave_setting <= 1) ? 6 : 4;
|
|
D2 = 4;
|
|
} else if (baud_rate == 1200) {
|
|
D1 = (interleave_setting <= 1) ? 6 : 4;
|
|
D2 = 5;
|
|
} else if (baud_rate == 600) {
|
|
D1 = (interleave_setting <= 1) ? 6 : 4;
|
|
D2 = 6;
|
|
} else if (baud_rate == 300) {
|
|
D1 = (interleave_setting <= 1) ? 6 : 4;
|
|
D2 = 7;
|
|
} else if (baud_rate == 150) {
|
|
D1 = (interleave_setting <= 1) ? 7 : 5;
|
|
D2 = 4;
|
|
} else {
|
|
throw std::invalid_argument("Invalid baud rate for generateProbeData");
|
|
}
|
|
|
|
std::vector<uint8_t> final_probe_data;
|
|
for (auto symbol : probe_data) {
|
|
appendProbeMapping(final_probe_data, symbol, 2);
|
|
}
|
|
}
|
|
|
|
return probe_data;
|
|
}
|
|
|
|
std::vector<uint8_t> map75bpsSet(const std::vector<uint8_t>& data, size_t start_index, size_t set_size, bool is_exceptional_set) {
|
|
std::vector<uint8_t> mapped_set;
|
|
|
|
for (auto symbol : data) {
|
|
append75bpsMapping(mapped_set, symbol, is_exceptional_set);
|
|
}
|
|
|
|
return mapped_set;
|
|
}
|
|
|
|
std::vector<uint8_t> mapUnknownData(const std::vector<uint8_t>& data) {
|
|
std::vector<uint8_t> mapped_data;
|
|
|
|
for (auto symbol : data) {
|
|
|
|
if (baud_rate >= 2400) {
|
|
// Pass tribit symbols as-is
|
|
mapped_data.push_back(symbol);
|
|
} else if (baud_rate == 1200) {
|
|
// Map dibit symbols to tribit symbols 0, 2, 4, 6
|
|
switch (symbol) {
|
|
case 0:
|
|
mapped_data.push_back(0);
|
|
break;
|
|
case 1:
|
|
mapped_data.push_back(2);
|
|
break;
|
|
case 2:
|
|
mapped_data.push_back(4);
|
|
break;
|
|
case 3:
|
|
mapped_data.push_back(6);
|
|
break;
|
|
default:
|
|
throw std::invalid_argument("Invalid dibit symbol for 1200 bps");
|
|
}
|
|
} else if (baud_rate >= 150 && baud_rate <= 600) {
|
|
// Map binary symbols to tribit symbols 0 and 4
|
|
mapped_data.push_back(symbol == 0 ? 0 : 4);
|
|
} else {
|
|
throw std::invalid_argument("Invalid baud rate for mapUnknownData");
|
|
}
|
|
}
|
|
|
|
return mapped_data;
|
|
}
|
|
};
|
|
|
|
#endif |