#ifndef SYMBOLFORMATION_H #define SYMBOLFORMATION_H #include #include #include #include #include #include #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 Sync_Preamble_0 = {0, 0, 0, 0, 0, 0, 0, 0}; std::vector Sync_Preamble_1 = {0, 4, 0, 4, 0, 4, 0, 4}; std::vector Sync_Preamble_2 = {0, 0, 4, 4, 0, 0, 4, 4}; std::vector Sync_Preamble_3 = {0, 4, 4, 0, 0, 4, 4, 0}; std::vector Sync_Preamble_4 = {0, 0, 0, 0, 4, 4, 4, 4}; std::vector Sync_Preamble_5 = {0, 4, 0, 4, 4, 0, 4, 0}; std::vector Sync_Preamble_6 = {0, 0, 4, 4, 4, 4, 0, 0}; std::vector Sync_Preamble_7 = {0, 4, 4, 0, 4, 0, 0, 4}; std::vector baud75_exceptional_0 = {0, 0, 0, 0, 4, 4, 4, 4}; std::vector baud75_exceptional_1 = {0, 4, 0, 4, 4, 0, 4, 0}; std::vector baud75_exceptional_2 = {0, 0, 4, 4, 4, 4, 0, 0}; std::vector baud75_exceptional_3 = {0, 4, 4, 0, 4, 0, 0, 4}; std::vector baud75_normal_0 = {0, 0, 0, 0}; std::vector baud75_normal_1 = {0, 4, 0, 4}; std::vector baud75_normal_2 = {0, 0, 4, 4}; std::vector 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 formSymbols(std::vector& symbol_data) { // Generate and scramble the sync preamble std::vector 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 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 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 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 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 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 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& 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& 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 generateSyncPreamble() { std::vector preamble; size_t num_segments = (interleave_setting == 0) ? 3 : 24; std::vector 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 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 final_preamble; for (auto& symbol : preamble) { appendProbeMapping(final_preamble, symbol, 4); } return final_preamble; } std::vector generateProbeData(bool is_inside_block) { std::vector 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 final_probe_data; for (auto symbol : probe_data) { appendProbeMapping(final_probe_data, symbol, 2); } } return probe_data; } std::vector map75bpsSet(const std::vector& data, size_t start_index, size_t set_size, bool is_exceptional_set) { std::vector mapped_set; for (auto symbol : data) { append75bpsMapping(mapped_set, symbol, is_exceptional_set); } return mapped_set; } std::vector mapUnknownData(const std::vector& data) { std::vector 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