diff --git a/CMakeLists.txt b/CMakeLists.txt index ffd4474..51bfd18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,6 @@ add_executable(tetra-decoder src/l2/broadcast_synchronization_channel.cpp src/l2/logical_link_control.cpp src/l2/lower_mac.cpp - src/l2/lower_mac_coding.cpp src/l2/timebase_counter.cpp src/l2/upper_mac.cpp src/l2/upper_mac_fragmentation.cpp diff --git a/include/l2/access_assignment_channel.hpp b/include/l2/access_assignment_channel.hpp index 32b24c0..3c3b91c 100644 --- a/include/l2/access_assignment_channel.hpp +++ b/include/l2/access_assignment_channel.hpp @@ -10,10 +10,9 @@ #include "burst_type.hpp" #include "l2/timebase_counter.hpp" -#include +#include "utils/bit_vector.hpp" #include #include -#include enum DownlinkUsage { CommonControl, Unallocated, AssignedControl, CommonAndAssignedControl, Traffic }; @@ -22,7 +21,8 @@ struct AccessAssignmentChannel { std::optional downlink_traffic_usage_marker; AccessAssignmentChannel() = delete; - AccessAssignmentChannel(BurstType burst_type, const TimebaseCounter& time, const std::vector& data); + + AccessAssignmentChannel(BurstType burst_type, const TimebaseCounter& time, BitVector&& vec); friend auto operator<<(std::ostream& stream, const AccessAssignmentChannel& aac) -> std::ostream&; }; diff --git a/include/l2/broadcast_synchronization_channel.hpp b/include/l2/broadcast_synchronization_channel.hpp index 150ab1a..237bd86 100644 --- a/include/l2/broadcast_synchronization_channel.hpp +++ b/include/l2/broadcast_synchronization_channel.hpp @@ -10,8 +10,8 @@ #include "burst_type.hpp" #include "l2/timebase_counter.hpp" +#include "utils/bit_vector.hpp" #include -#include struct BroadcastSynchronizationChannel { public: @@ -29,11 +29,11 @@ struct BroadcastSynchronizationChannel { uint32_t mobile_network_code = 0; uint8_t dNwrk_broadcast_broadcast_supported = 0; uint8_t dNwrk_broadcast_enquiry_supported = 0; - uint8_t cell_load_ca = 0; + unsigned _BitInt(2) cell_load_ca = 0; uint8_t late_entry_supported = 0; BroadcastSynchronizationChannel() = default; - BroadcastSynchronizationChannel(const BurstType burst_type, const std::vector& data); + BroadcastSynchronizationChannel(const BurstType burst_type, BitVector&& vec); friend auto operator<<(std::ostream& stream, const BroadcastSynchronizationChannel& bsc) -> std::ostream&; }; diff --git a/include/l2/logical_channel.hpp b/include/l2/logical_channel.hpp new file mode 100644 index 0000000..ac645e9 --- /dev/null +++ b/include/l2/logical_channel.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include "utils/bit_vector.hpp" + +enum class LogicalChannel { + kSignalingChannelHalfDownlink, + kSignalingChannelHalfUplink, + kTrafficChannel, + kSignalingChannelFull, + kStealingChannel +}; + +struct LogicalChannelDataAndCrc { + /// the logical channel + LogicalChannel channel; + /// the data on the logical channel + BitVector data; + /// true if the crc of the signaling channels is ok + bool crc_ok; +}; \ No newline at end of file diff --git a/include/l2/lower_mac.hpp b/include/l2/lower_mac.hpp index 3305ee3..63a6b86 100644 --- a/include/l2/lower_mac.hpp +++ b/include/l2/lower_mac.hpp @@ -10,7 +10,9 @@ #pragma once #include "l2/broadcast_synchronization_channel.hpp" +#include "l2/slot.hpp" #include "l2/timebase_counter.hpp" +#include #include #include #include @@ -62,6 +64,8 @@ class LowerMacPrometheusCounters { /// The counter for the too many bursts in the downlink lower MAC prometheus::Counter& lower_mac_burst_too_many_count_; + /// TODO: add gauge for the synchronization burst time + public: LowerMacPrometheusCounters(std::shared_ptr& prometheus_exporter) : burst_received_count_family_(prometheus_exporter->burst_received_count()) @@ -167,11 +171,10 @@ class LowerMac { std::optional scrambling_code = std::nullopt); ~LowerMac() = default; - // does the signal processing and then returns a list of function that need to be executed for data to be passed - // to upper mac sequentially. + // does the signal processing and then returns the slots containing the correct logical channels and their + // associated data to be passed to the upper mac and further processed in a sequential order. [[nodiscard]] auto processChannels(const std::vector& frame, BurstType burst_type, - const BroadcastSynchronizationChannel& bsc) - -> std::vector>; + const BroadcastSynchronizationChannel& bsc) -> Slots; /// handles the decoding of the synchronization bursts and once synchronized passes the data to the decoding of the /// channels. keeps track of the current network time @@ -179,9 +182,9 @@ class LowerMac { -> std::vector>; private: - std::shared_ptr reporter_{}; - std::shared_ptr viter_bi_codec_1614_{}; - std::shared_ptr upper_mac_{}; + std::shared_ptr reporter_; + const ViterbiCodec viter_bi_codec_1614_; + std::shared_ptr upper_mac_; std::unique_ptr metrics_; @@ -189,13 +192,4 @@ class LowerMac { /// This include the current scrambling code. Set by Synchronization Burst on downlink or injected from the side for /// uplink processing, as we decouple it from the downlink for data/control packets. std::optional sync_; - - static auto descramble(const uint8_t* data, uint8_t* res, std::size_t len, uint32_t scramblingCode) noexcept - -> void; - static auto deinterleave(const uint8_t* data, uint8_t* res, std::size_t K, std::size_t a) noexcept -> void; - [[nodiscard]] static auto depuncture23(const uint8_t* data, uint32_t len) noexcept -> std::vector; - static auto reed_muller_3014_decode(const uint8_t* data, uint8_t* res) noexcept -> void; - [[nodiscard]] static auto check_crc_16_ccitt(const uint8_t* data, std::size_t len) noexcept -> bool; - - [[nodiscard]] auto viter_bi_decode_1614(const std::vector& data) const noexcept -> std::vector; }; \ No newline at end of file diff --git a/include/l2/lower_mac_coding.hpp b/include/l2/lower_mac_coding.hpp new file mode 100644 index 0000000..cd02616 --- /dev/null +++ b/include/l2/lower_mac_coding.hpp @@ -0,0 +1,362 @@ +/* + * tetra-kit + * Copyright (C) 2020 LarryTh + * + * 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 3 of the License, 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. If not, see . + * + */ +#include "utils/viter_bi_codec.hpp" +#include +#include +#include +#include + +struct LowerMacCoding { + + /** + * @brief Fibonacci LFSR descrambling - 8.2.5 + * + */ + template + static auto descramble(const std::array& input, uint32_t scrambling_code) noexcept + -> std::array { + static std::map> table_by_scrambling_code; + std::array output{}; + + static_assert(Size <= 432); + + if (table_by_scrambling_code.count(scrambling_code) == 0) { + auto& table = table_by_scrambling_code[scrambling_code]; + table.resize(432); + const uint8_t poly[14] = {32, 26, 23, 22, 16, 12, 11, + 10, 8, 7, 5, 4, 2, 1}; // Feedback polynomial - see 8.2.5.2 (8.39) + + uint32_t lfsr = scrambling_code; // linear feedback shift register initialization (=0 + 3 + // for BSCH, calculated from Color code ch 19 otherwise) + for (std::size_t i = 0; i < 432; i++) { + uint32_t bit = 0; + // apply poly (Xj + ...) + for (std::size_t j = 0; j < 14; j++) { + bit = bit ^ (lfsr >> (32 - poly[j])); + } + bit = bit & 1; // finish apply feedback polynomial (+ 1) + lfsr = (lfsr >> 1) | (bit << 31); + + table[i] = bit; + } + } + + auto& table = table_by_scrambling_code[scrambling_code]; + + for (std::size_t i = 0; i < Size; i++) { + output[i] = input[i] ^ table[i]; + } + + return output; + } + + /** + * @brief (K,a) block deinterleaver - 8.2.4 + * + */ + template + static auto deinterleave(const std::array& data, const std::size_t a) noexcept + -> std::array { + std::array res{}; + for (std::size_t i = 0; i < Size; i++) { + auto k = 1 + (a * (i + 1)) % Size; + res[i] = data[k - 1]; // to interleave: DataOut[i-1] = DataIn[k-1] + } + + return res; + } + + /** + * @brief Depuncture with 2/3 rate - 8.2.3.1.3 + * + */ + template + [[nodiscard]] static auto depuncture23(const std::array& data) noexcept + -> std::array { + const uint8_t P[] = {0, 1, 2, 5}; // 8.2.3.1.3 - P[1..t] + std::array res{0}; // 8.2.3.1.2 with flag 0 for erase bit in Viterbi routine + + uint8_t t = 3; // 8.2.3.1.3 + uint8_t period = 8; // 8.2.3.1.2 + + for (uint32_t j = 1; j <= InSize; j++) { + uint32_t i = j; // punct->i_func(j); + uint32_t k = + period * ((i - 1) / t) + P[i - t * ((i - 1) / t)]; // punct->period * ((i-1)/t) + P[i - t*((i-1)/t)]; + res[k - 1] = data[j - 1] ? 1 : -1; + } + + return res; + } + + /** + * @brief Viterbi decoding of RCPC code 16-state mother code of rate 1/4 + * - 8.2.3.1.1 + * + */ + template + [[nodiscard]] static auto viter_bi_decode_1614(const ViterbiCodec& codec, + const std::array& data) noexcept + -> std::array { + auto decoded = codec.Decode(std::vector(data.cbegin(), data.cend())); + std::array out{}; + for (auto i = 0; i < decoded.size(); i++) { + for (auto j = 0; j < 8; j++) { + out[i * 8 + j] = (decoded[i] & (1 << (7 - j))) ? 1 : 0; + } + } + + return out; + } + + /** + * @brief Reed-Muller decoder and FEC correction 30 bits in, 14 bits out + * + * FEC thanks to Lollo Gollo @logollo see "issue #21" + * + */ + + static auto reed_muller_3014_decode(const std::array& input) noexcept -> std::array { + std::array output; + uint8_t q[14][5]; + + q[0][0] = input[0]; + q[0][1] = (input[13 + 3] + input[13 + 5] + input[13 + 6] + input[13 + 7] + input[13 + 11]) % 2; + q[0][2] = (input[13 + 1] + input[13 + 2] + input[13 + 5] + input[13 + 6] + input[13 + 8] + input[13 + 9]) % 2; + q[0][3] = (input[13 + 2] + input[13 + 3] + input[13 + 4] + input[13 + 5] + input[13 + 9] + input[13 + 10]) % 2; + q[0][4] = (input[13 + 1] + input[13 + 4] + input[13 + 5] + input[13 + 7] + input[13 + 8] + input[13 + 10] + + input[13 + 11]) % + 2; + output[0] = (q[0][0] + q[0][1] + q[0][2] + q[0][3] + q[0][4]) >= 3; + + q[1][0] = input[1]; + q[1][1] = (input[13 + 1] + input[13 + 4] + input[13 + 5] + input[13 + 9] + input[13 + 11]) % 2; + q[1][2] = (input[13 + 1] + input[13 + 2] + input[13 + 5] + input[13 + 6] + input[13 + 7] + input[13 + 10]) % 2; + q[1][3] = (input[13 + 2] + input[13 + 3] + input[13 + 4] + input[13 + 5] + input[13 + 7] + input[13 + 8]) % 2; + q[1][4] = (input[13 + 3] + input[13 + 5] + input[13 + 6] + input[13 + 8] + input[13 + 9] + input[13 + 10] + + input[13 + 11]) % + 2; + output[1] = (q[1][0] + q[1][1] + q[1][2] + q[1][3] + q[1][4]) >= 3; + + q[2][0] = input[2]; + q[2][1] = (input[13 + 2] + input[13 + 5] + input[13 + 8] + input[13 + 10] + input[13 + 11]) % 2; + q[2][2] = (input[13 + 1] + input[13 + 3] + input[13 + 5] + input[13 + 7] + input[13 + 9] + input[13 + 10]) % 2; + q[2][3] = (input[13 + 4] + input[13 + 5] + input[13 + 6] + input[13 + 7] + input[13 + 8] + input[13 + 9]) % 2; + q[2][4] = (input[13 + 1] + input[13 + 2] + input[13 + 3] + input[13 + 4] + input[13 + 5] + input[13 + 6] + + input[13 + 11]) % + 2; + output[2] = (q[2][0] + q[2][1] + q[2][2] + q[2][3] + q[2][4]) >= 3; + + q[3][0] = input[3]; + q[3][1] = + (input[13 + 7] + input[13 + 8] + input[13 + 9] + input[13 + 12] + input[13 + 13] + input[13 + 14]) % 2; + q[3][2] = (input[13 + 1] + input[13 + 2] + input[13 + 3] + input[13 + 11] + input[13 + 12] + input[13 + 13] + + input[13 + 14]) % + 2; + q[3][3] = (input[13 + 2] + input[13 + 4] + input[13 + 6] + input[13 + 8] + input[13 + 10] + input[13 + 11] + + input[13 + 12] + input[13 + 13] + input[13 + 14]) % + 2; + q[3][4] = (input[13 + 1] + input[13 + 3] + input[13 + 4] + input[13 + 6] + input[13 + 7] + input[13 + 9] + + input[13 + 10] + input[13 + 12] + input[13 + 13] + input[13 + 14]) % + 2; + output[3] = (q[3][0] + q[3][1] + q[3][2] + q[3][3] + q[3][4]) >= 3; + + q[4][0] = input[4]; + q[4][1] = (input[13 + 1] + input[13 + 4] + input[13 + 5] + input[13 + 11] + input[13 + 12] + input[13 + 13] + + input[13 + 15]) % + 2; + q[4][2] = (input[13 + 3] + input[13 + 5] + input[13 + 6] + input[13 + 8] + input[13 + 10] + input[13 + 11] + + input[13 + 12] + input[13 + 13] + input[13 + 15]) % + 2; + q[4][3] = (input[13 + 1] + input[13 + 2] + input[13 + 5] + input[13 + 6] + input[13 + 7] + input[13 + 9] + + input[13 + 10] + input[13 + 12] + input[13 + 13] + input[13 + 15]) % + 2; + q[4][4] = (input[13 + 2] + input[13 + 3] + input[13 + 4] + input[13 + 5] + input[13 + 7] + input[13 + 8] + + input[13 + 9] + input[13 + 12] + input[13 + 13] + input[13 + 15]) % + 2; + output[4] = (q[4][0] + q[4][1] + q[4][2] + q[4][3] + q[4][4]) >= 3; + + q[5][0] = input[5]; + q[5][1] = + (input[13 + 7] + input[13 + 9] + input[13 + 10] + input[13 + 12] + input[13 + 14] + input[13 + 15]) % 2; + q[5][2] = (input[13 + 2] + input[13 + 4] + input[13 + 6] + input[13 + 11] + input[13 + 12] + input[13 + 14] + + input[13 + 15]) % + 2; + q[5][3] = (input[13 + 1] + input[13 + 2] + input[13 + 3] + input[13 + 8] + input[13 + 10] + input[13 + 11] + + input[13 + 12] + input[13 + 14] + input[13 + 15]) % + 2; + q[5][4] = (input[13 + 1] + input[13 + 3] + input[13 + 4] + input[13 + 6] + input[13 + 7] + input[13 + 8] + + input[13 + 9] + input[13 + 12] + input[13 + 14] + input[13 + 15]) % + 2; + output[5] = (q[5][0] + q[5][1] + q[5][2] + q[5][3] + q[5][4]) >= 3; + + q[6][0] = input[6]; + q[6][1] = (input[13 + 3] + input[13 + 5] + input[13 + 6] + input[13 + 11] + input[13 + 13] + input[13 + 14] + + input[13 + 15]) % + 2; + q[6][2] = (input[13 + 1] + input[13 + 4] + input[13 + 5] + input[13 + 8] + input[13 + 10] + input[13 + 11] + + input[13 + 13] + input[13 + 14] + input[13 + 15]) % + 2; + q[6][3] = (input[13 + 1] + input[13 + 2] + input[13 + 5] + input[13 + 6] + input[13 + 7] + input[13 + 8] + + input[13 + 9] + input[13 + 13] + input[13 + 14] + input[13 + 15]) % + 2; + q[6][4] = (input[13 + 2] + input[13 + 3] + input[13 + 4] + input[13 + 5] + input[13 + 7] + input[13 + 9] + + input[13 + 10] + input[13 + 13] + input[13 + 14] + input[13 + 15]) % + 2; + output[6] = (q[6][0] + q[6][1] + q[6][2] + q[6][3] + q[6][4]) >= 3; + + q[7][0] = input[7]; + q[7][1] = (input[13 + 2] + input[13 + 5] + input[13 + 7] + input[13 + 9] + input[13 + 12] + input[13 + 13] + + input[13 + 14] + input[13 + 15] + input[13 + 16]) % + 2; + q[7][2] = (input[13 + 1] + input[13 + 3] + input[13 + 5] + input[13 + 8] + input[13 + 11] + input[13 + 12] + + input[13 + 13] + input[13 + 14] + input[13 + 15] + input[13 + 16]) % + 2; + q[7][3] = (input[13 + 4] + input[13 + 5] + input[13 + 6] + input[13 + 10] + input[13 + 11] + input[13 + 12] + + input[13 + 13] + input[13 + 14] + input[13 + 15] + input[13 + 16]) % + 2; + q[7][4] = (input[13 + 1] + input[13 + 2] + input[13 + 3] + input[13 + 4] + input[13 + 5] + input[13 + 6] + + input[13 + 7] + input[13 + 8] + input[13 + 9] + input[13 + 10] + input[13 + 12] + input[13 + 13] + + input[13 + 14] + input[13 + 15] + input[13 + 16]) % + 2; + output[7] = (q[7][0] + q[7][1] + q[7][2] + q[7][3] + q[7][4]) >= 3; + + q[8][0] = input[8]; + q[8][1] = + (input[13 + 2] + input[13 + 3] + input[13 + 9] + input[13 + 12] + input[13 + 13] + input[13 + 16]) % 2; + q[8][2] = (input[13 + 1] + input[13 + 7] + input[13 + 8] + input[13 + 11] + input[13 + 12] + input[13 + 13] + + input[13 + 16]) % + 2; + q[8][3] = (input[13 + 3] + input[13 + 4] + input[13 + 6] + input[13 + 7] + input[13 + 10] + input[13 + 11] + + input[13 + 12] + input[13 + 13] + input[13 + 16]) % + 2; + q[8][4] = (input[13 + 1] + input[13 + 2] + input[13 + 4] + input[13 + 6] + input[13 + 8] + input[13 + 9] + + input[13 + 10] + input[13 + 12] + input[13 + 13] + input[13 + 16]) % + 2; + output[8] = (q[8][0] + q[8][1] + q[8][2] + q[8][3] + q[8][4]) >= 3; + + q[9][0] = input[9]; + q[9][1] = + (input[13 + 1] + input[13 + 3] + input[13 + 8] + input[13 + 12] + input[13 + 14] + input[13 + 16]) % 2; + q[9][2] = + (input[13 + 4] + input[13 + 6] + input[13 + 10] + input[13 + 12] + input[13 + 14] + input[13 + 16]) % 2; + q[9][3] = (input[13 + 2] + input[13 + 7] + input[13 + 9] + input[13 + 11] + input[13 + 12] + input[13 + 14] + + input[13 + 16]) % + 2; + q[9][4] = (input[13 + 1] + input[13 + 2] + input[13 + 3] + input[13 + 4] + input[13 + 6] + input[13 + 7] + + input[13 + 8] + input[13 + 9] + input[13 + 10] + input[13 + 11] + input[13 + 12] + input[13 + 14] + + input[13 + 16]) % + 2; + output[9] = (q[9][0] + q[9][1] + q[9][2] + q[9][3] + q[9][4]) >= 3; + + q[10][0] = input[10]; + q[10][1] = + (input[13 + 1] + input[13 + 2] + input[13 + 7] + input[13 + 13] + input[13 + 14] + input[13 + 16]) % 2; + q[10][2] = (input[13 + 3] + input[13 + 8] + input[13 + 9] + input[13 + 11] + input[13 + 13] + input[13 + 14] + + input[13 + 16]) % + 2; + q[10][3] = (input[13 + 1] + input[13 + 4] + input[13 + 6] + input[13 + 9] + input[13 + 10] + input[13 + 11] + + input[13 + 13] + input[13 + 14] + input[13 + 16]) % + 2; + q[10][4] = (input[13 + 2] + input[13 + 3] + input[13 + 4] + input[13 + 6] + input[13 + 7] + input[13 + 8] + + input[13 + 10] + input[13 + 13] + input[13 + 14] + input[13 + 16]) % + 2; + output[10] = (q[10][0] + q[10][1] + q[10][2] + q[10][3] + q[10][4]) >= 3; + + q[11][0] = input[11]; + q[11][1] = + (input[13 + 2] + input[13 + 6] + input[13 + 9] + input[13 + 12] + input[13 + 15] + input[13 + 16]) % 2; + q[11][2] = (input[13 + 4] + input[13 + 7] + input[13 + 10] + input[13 + 11] + input[13 + 12] + input[13 + 15] + + input[13 + 16]) % + 2; + q[11][3] = (input[13 + 1] + input[13 + 3] + input[13 + 6] + input[13 + 7] + input[13 + 8] + input[13 + 11] + + input[13 + 12] + input[13 + 15] + input[13 + 16]) % + 2; + q[11][4] = (input[13 + 1] + input[13 + 2] + input[13 + 3] + input[13 + 4] + input[13 + 8] + input[13 + 9] + + input[13 + 10] + input[13 + 12] + input[13 + 15] + input[13 + 16]) % + 2; + output[11] = (q[11][0] + q[11][1] + q[11][2] + q[11][3] + q[11][4]) >= 3; + + q[12][0] = input[12]; + q[12][1] = (input[13 + 5] + input[13 + 8] + input[13 + 10] + input[13 + 11] + input[13 + 13] + input[13 + 15] + + input[13 + 16]) % + 2; + q[12][2] = (input[13 + 1] + input[13 + 3] + input[13 + 4] + input[13 + 5] + input[13 + 6] + input[13 + 11] + + input[13 + 13] + input[13 + 15] + input[13 + 16]) % + 2; + q[12][3] = (input[13 + 1] + input[13 + 2] + input[13 + 3] + input[13 + 5] + input[13 + 7] + input[13 + 9] + + input[13 + 10] + input[13 + 13] + input[13 + 15] + input[13 + 16]) % + 2; + q[12][4] = (input[13 + 2] + input[13 + 4] + input[13 + 5] + input[13 + 6] + input[13 + 7] + input[13 + 8] + + input[13 + 9] + input[13 + 13] + input[13 + 15] + input[13 + 16]) % + 2; + output[12] = (q[12][0] + q[12][1] + q[12][2] + q[12][3] + q[12][4]) >= 3; + + q[13][0] = input[13]; + q[13][1] = + (input[13 + 2] + input[13 + 4] + input[13 + 7] + input[13 + 14] + input[13 + 15] + input[13 + 16]) % 2; + q[13][2] = (input[13 + 6] + input[13 + 9] + input[13 + 10] + input[13 + 11] + input[13 + 14] + input[13 + 15] + + input[13 + 16]) % + 2; + q[13][3] = (input[13 + 1] + input[13 + 3] + input[13 + 4] + input[13 + 8] + input[13 + 9] + input[13 + 11] + + input[13 + 14] + input[13 + 15] + input[13 + 16]) % + 2; + q[13][4] = (input[13 + 1] + input[13 + 2] + input[13 + 3] + input[13 + 6] + input[13 + 7] + input[13 + 8] + + input[13 + 10] + input[13 + 14] + input[13 + 15] + input[13 + 16]) % + 2; + output[13] = (q[13][0] + q[13][1] + q[13][2] + q[13][3] + q[13][4]) >= 3; + + // check deviation from input + // int deviation = 0; + // for (int cnt = 0; cnt < 14; cnt++) + // { + // deviation += (input[cnt] != output[cnt]) ? 1 : 0; + // } + // printf("FEC correction %.2f\n", deviation / 14.); + // print_vector(data, 14); + // print_vector(res, 14); + + // return vector_extract(data, 0, 14); + + return output; + } + + /** + * @brief Calculated CRC16 ITU-T X.25 - CCITT + * + */ + template + [[nodiscard]] static auto check_crc_16_ccitt(const std::array& data) noexcept -> bool { + uint16_t crc = 0xFFFF; // CRC16-CCITT initial value + + for (std::size_t i = 0; i < CheckSize; i++) { + auto bit = static_cast(data[i]); + + crc ^= bit << 15; + if (crc & 0x8000) { + crc <<= 1; + crc ^= 0x1021; // CRC16-CCITT polynomial + } else { + crc <<= 1; + } + } + + return crc == 0x1D0F; // CRC16-CCITT reminder value + } +}; \ No newline at end of file diff --git a/include/l2/slot.hpp b/include/l2/slot.hpp new file mode 100644 index 0000000..b1117de --- /dev/null +++ b/include/l2/slot.hpp @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2024 Transit Live Mapping Solutions + * All rights reserved. + * + * Authors: + * Marenz Schmidl + */ + +#pragma once + +#include "burst_type.hpp" +#include "l2/logical_channel.hpp" +#include +#include +#include + +/// describe a slot (full or half) and its content with data and logical channels. it can be non concreate i.e., +/// multiple logical channels are present and the correct one still needs to be selected +class Slot { + private: + std::vector data_; + + public: + Slot() = delete; + + /// construct a slot with a defined channel and data + explicit Slot(LogicalChannelDataAndCrc&& data) + : data_({std::move(data)}){}; + + /// construct a slot with any of two input data and different channel + explicit Slot(std::vector data) + : data_(std::move(data)) { + std::set channels_in_data; + for (const auto& channel_data : data_) { + const auto& channel = channel_data.channel; + channels_in_data.insert(channel); + } + + if (data_.size() != channels_in_data.size()) { + throw std::runtime_error("Found duplicate entries of channels in initilization of Slot"); + } + }; + + /// if there is only one possibility for a logical channel, the the slot is concreate + [[nodiscard]] auto is_concreate() const noexcept -> bool { return data_.size() == 1; }; + + /// get the concreate logical channel, data and crc + [[nodiscard]] auto get_logical_channel_data_and_crc() -> LogicalChannelDataAndCrc& { + if (!is_concreate()) { + throw std::runtime_error("Attempted to get a concreate channel that is not concreate."); + } + return data_.front(); + } + + /// get the set of potential logical channels + [[nodiscard]] auto get_logical_channels() const noexcept -> std::set { + std::set channels; + for (const auto& channel_data : data_) { + const auto& channel = channel_data.channel; + channels.insert(channel); + }; + return channels; + } + + /// select a specific logical channel and make the slot concreate + auto select_logical_channel(LogicalChannel channel) -> void { + for (auto it = data_.begin(); it != data_.end();) { + if (it->channel != channel) { + it = data_.erase(it); + } else { + ++it; + } + } + if (!is_concreate()) { + throw std::runtime_error("Attempted to select a channel that is not availabe."); + } + } +}; + +/// defines the number and types of slots in a packet +enum class SlotsType { kOneSubslot, kTwoSubslots, kFullSlot }; + +/// defines the slots in a packet +class Slots { + private: + /// which burst type ths slots originated from + BurstType burst_type_; + /// the number and types of slots + SlotsType slot_type_; + /// the slots, either one half or full slot or two half slots + std::vector slots_; + + public: + Slots() = delete; + + /// constructor for one subslot or a full slot + Slots(BurstType burst_type, SlotsType slot_type, Slot&& slot) + : burst_type_(burst_type) + , slot_type_(slot_type) + , slots_({std::move(slot)}) { + if (slot_type_ == SlotsType::kTwoSubslots) { + throw std::runtime_error("Two subslots need to to have two subslots"); + } + + /// If we processes the normal uplink burst assume that the slot is signalling and not traffic. We would need + /// the information from the access assignment from the corresponding downlink timeslot to make the right + /// decision here. + if (burst_type_ == BurstType::NormalUplinkBurst) { + get_first_slot().select_logical_channel(LogicalChannel::kSignalingChannelFull); + } + + if (!get_first_slot().is_concreate()) { + throw std::runtime_error("The first or only slot is not concreate."); + } + }; + + /// construct for two half slot + Slots(BurstType burst_type, SlotsType slot_type, Slot&& first_slot, Slot&& second_slot) + : burst_type_(burst_type) + , slot_type_(slot_type) + , slots_({std::move(first_slot), std::move(second_slot)}) { + if (slot_type_ != SlotsType::kTwoSubslots) { + throw std::runtime_error("Only two subslots is allowed to have two subslots"); + } + + if (!get_first_slot().is_concreate()) { + throw std::runtime_error("The first subslot is not concreate."); + } + + const auto& first_slot_data = get_first_slot().get_logical_channel_data_and_crc().data; + if (get_first_slot().get_logical_channel_data_and_crc().channel == LogicalChannel::kStealingChannel) { + // The first subslot is stolen, now we need to decide if the second is also stolen or traffic + auto second_half_slot_stolen = false; + + if (burst_type_ == BurstType::NormalUplinkBurstSplit) { + auto pdu_type = first_slot_data.look<2>(0); + // read the stolen flag from the MAC-DATA + // 21.4.2.3 MAC-DATA + if (pdu_type == 0b00) { + auto address_type = first_slot_data.look<2>(4); + auto length_indication_or_capacity_request_offset = 6 + (address_type == 0b01 ? 10 : 24); + auto length_indication_or_capacity_request = + first_slot_data.look<1>(length_indication_or_capacity_request_offset); + if (length_indication_or_capacity_request == 0b0) { + auto length_indication = + first_slot_data.look<6>(length_indication_or_capacity_request_offset + 1); + if (length_indication == 0b111110 || length_indication == 0b111111) { + second_half_slot_stolen = true; + } + } + } + + // read the stolen flag from the MAC-U-SIGNAL PDU + // 21.4.5 TMD-SAP: MAC PDU structure for U-plane signalling + if (pdu_type == 0b11) { + if (first_slot_data.look<1>(2)) { + second_half_slot_stolen = true; + }; + } + } + + if (burst_type_ == BurstType::NormalDownlinkBurstSplit) { + auto pdu_type = first_slot_data.look<2>(0); + // read the sloten flag from the MAC-RESOURCE PDU + // 21.4.3.1 MAC-RESOURCE + if (pdu_type == 0b00) { + auto length_indication = first_slot_data.look<6>(7); + if (length_indication == 0b111110 || length_indication == 0b111111) { + second_half_slot_stolen = true; + } + } + + // read the stolen flag from the MAC-U-SIGNAL PDU + // 21.4.5 TMD-SAP: MAC PDU structure for U-plane signalling + if (pdu_type == 0b11) { + if (first_slot_data.look<1>(2)) { + second_half_slot_stolen = true; + }; + } + } + + get_second_slot().select_logical_channel(second_half_slot_stolen ? LogicalChannel::kStealingChannel + : LogicalChannel::kTrafficChannel); + } + + if (!get_second_slot().is_concreate()) { + throw std::runtime_error("The second slot is not concreate."); + } + }; + + /// access the first slot + [[nodiscard]] auto get_first_slot() noexcept -> Slot& { return slots_.front(); }; + + /// access the second slot + [[nodiscard]] auto get_second_slot() -> Slot& { + if (!has_second_slot()) { + throw std::runtime_error("Attempted to accesses the second slot, but we do not have two slots."); + } + return slots_.at(1); + }; + + /// check if we have two subslots + [[nodiscard]] auto has_second_slot() const noexcept -> bool { return slots_.size() == 2; } + + // check if there was any crc mismatch on the signalling or stealing channels + [[nodiscard]] auto has_crc_error() -> bool { + auto error = false; + + const auto& first_slot = slots_.front().get_logical_channel_data_and_crc(); + if (first_slot.channel != LogicalChannel::kTrafficChannel) { + error |= !first_slot.crc_ok; + } + + if (has_second_slot()) { + const auto& second_slot = slots_.at(1).get_logical_channel_data_and_crc(); + if (second_slot.channel != LogicalChannel::kTrafficChannel) { + error |= !first_slot.crc_ok; + } + } + + return error; + }; +}; \ No newline at end of file diff --git a/include/l2/upper_mac.hpp b/include/l2/upper_mac.hpp index 887e895..9564fff 100644 --- a/include/l2/upper_mac.hpp +++ b/include/l2/upper_mac.hpp @@ -9,6 +9,7 @@ #pragma once +#include "utils/bit_vector.hpp" #include #include #include @@ -32,13 +33,13 @@ class UpperMac { ~UpperMac() noexcept = default; // Signalling CHannel for mapping onto Half-bursts on the Downlink - void process_SCH_HD(BurstType burst_type, const std::vector& data); + void process_SCH_HD(BurstType burst_type, BitVector& vec); // Signalling CHannel for mapping onto Half-bursts on the Uplink - void process_SCH_HU(BurstType burst_type, const std::vector& data); + void process_SCH_HU(BurstType burst_type, BitVector& vec); // Signalling CHannel for mapping onto Full bursts - void process_SCH_F(BurstType burst_type, const std::vector& data); + void process_SCH_F(BurstType burst_type, BitVector& vec); // STealing CHannel - void process_STCH(BurstType burst_type, const std::vector& data); + void process_STCH(BurstType burst_type, BitVector& vec); [[nodiscard]] auto downlink_frequency() const noexcept -> int32_t { return downlink_frequency_; } [[nodiscard]] auto uplink_frequency() const noexcept -> int32_t { return uplink_frequency_; } @@ -49,9 +50,9 @@ class UpperMac { private: std::shared_ptr reporter_{}; - void process_signalling_channel(BurstType burst_type, const std::vector& data, bool isHalfChannel, - bool isStolenChannel); void process_signalling_channel(BurstType burst_type, BitVector& vec, bool isHalfChannel, bool isStolenChannel); + void process_signalling_channel_internal(BurstType burst_type, BitVector& vec, bool isHalfChannel, + bool isStolenChannel); void process_broadcast(BitVector& vec); void process_supplementary_mac_pdu(BurstType burst_type, BitVector& vec); diff --git a/include/utils/bit_vector.hpp b/include/utils/bit_vector.hpp index d60caa0..cfbe23c 100644 --- a/include/utils/bit_vector.hpp +++ b/include/utils/bit_vector.hpp @@ -9,53 +9,117 @@ #pragma once +#include +#include #include #include #include +/// Construct a vector of bits that allows taking ranges of bits from the internal representation. The internal +/// representation is not copied if bits are taken. class BitVector { private: - std::vector data_; - std::size_t len_; - std::size_t read_offset_; + /// The bits we hold + std::vector data_; + /// The length of the currently viewed data to support taking bits from the back. + std::size_t len_ = 0; + /// The current read offset to support taking bits from the front. + std::size_t read_offset_ = 0; public: - BitVector() - : data_() - , len_(0) - , read_offset_(0){}; - explicit BitVector(const std::vector& vec) + BitVector() = default; + explicit BitVector(const std::vector& vec) : data_(vec) - , len_(vec.size()) - , read_offset_(0){}; - BitVector(const BitVector& other) - : data_() - , len_(0) - , read_offset_(0) { - append(other); - }; - BitVector(const uint8_t* const data, const std::size_t len) - : data_(data, data + len) - , len_(len) - , read_offset_(0){}; + , len_(data_.size()){}; + explicit BitVector(std::vector&& vec) + : data_(std::move(vec)) + , len_(data_.size()){}; + + BitVector(const BitVector&) = default; + auto operator=(const BitVector&) -> BitVector& = default; + BitVector(BitVector&&) = default; + auto operator=(BitVector&&) -> BitVector& = default; + ~BitVector() noexcept = default; + [[nodiscard]] inline auto bits_left() const noexcept -> auto{ return len_; }; + + /// Append another bitvector to the current one. This will cause data to be copied. auto append(const BitVector& other) -> void; - [[nodiscard]] auto take(std::size_t numberBits) -> uint64_t; + + /// Take N unsigned bits from the start of the bitvector view. N is known at compile time. + // TODO: assert N != 0 + template [[nodiscard]] auto take() -> unsigned _BitInt(N) { + if (N > bits_left()) { + throw std::runtime_error(std::to_string(N) + " bits not left in BitVec (" + std::to_string(bits_left()) + + ")"); + } + + const auto bits = data_.begin() + read_offset_; + + // delete first n entries + read_offset_ += N; + len_ -= N; + + return to_bit_int(bits); + }; + + /// Take N unsigned bits from the end of the bitvector view. N is known at compile time. + // TODO: assert N != 0 + template [[nodiscard]] auto take_last() -> unsigned _BitInt(N) { + if (N > bits_left()) { + throw std::runtime_error(std::to_string(N) + " bits not left in BitVec (" + std::to_string(bits_left()) + + ")"); + } + + const auto bits = data_.begin() + bits_left() - N; + + // delete last n entries + len_ -= N; + + return to_bit_int(bits); + } + + /// look at N bits with an offset to the bitvector + template [[nodiscard]] auto look(std::size_t offset) const -> unsigned _BitInt(N) { + if (N + offset > bits_left()) { + throw std::runtime_error(std::to_string(N + offset) + " bits not left in BitVec (" + + std::to_string(bits_left()) + ")"); + } + + const auto bits = data_.begin() + read_offset_ + N + offset; + + return to_bit_int(bits); + } + [[nodiscard]] auto compute_fcs() -> uint32_t; - [[nodiscard]] auto take_vector(std::size_t numberBits) -> const uint8_t* const; + /// bite of a bitvector from the current bitvector + [[nodiscard]] auto take_vector(std::size_t number_bits) -> BitVector; - private: - [[nodiscard]] auto take_last_vector(std::size_t numberBits) -> const uint8_t* const; + /// take all the remaining bits + [[nodiscard]] auto take_all() -> uint64_t; - public: - [[nodiscard]] auto take_last(std::size_t numberBits) -> uint64_t; - [[nodiscard]] auto take_last() -> uint8_t; - [[nodiscard]] inline auto bits_left() const noexcept -> std::size_t { return len_; }; [[nodiscard]] auto is_mac_padding() const noexcept -> bool; friend auto operator<<(std::ostream& stream, const BitVector& vec) -> std::ostream&; + + private: + template + [[nodiscard]] auto to_bit_int(const std::vector::const_iterator iterator) const -> unsigned _BitInt(N) { + unsigned _BitInt(N) ret = iterator[0]; + + // This condition is implicitly there on the first iteation of the loop, but not detected by some compilers + // leading to a false warning: shift count >= width of type [-Wshift-count-overflow] with N == 1 + if (N > 1) { + for (auto i = 1; i < N; i++) { + ret <<= 1; + ret |= iterator[i]; + } + } + + return ret; + } }; auto operator<<(std::ostream& stream, const BitVector& vec) -> std::ostream&; \ No newline at end of file diff --git a/include/utils/viter_bi_codec.hpp b/include/utils/viter_bi_codec.hpp index 96670b1..cfdee60 100644 --- a/include/utils/viter_bi_codec.hpp +++ b/include/utils/viter_bi_codec.hpp @@ -18,21 +18,21 @@ #include "viterbi/x86/viterbi_decoder_sse_u16.h" // clang-format on -constexpr size_t K = 5; -constexpr size_t R = 4; - class ViterbiCodec { public: - ViterbiCodec(){}; - [[nodiscard]] std::vector Decode(const std::vector& bits) const; + ViterbiCodec() = default; + [[nodiscard]] auto Decode(const std::vector& bits) const -> std::vector; + + static constexpr size_t K = 5; + static constexpr size_t R = 4; private: const std::vector G = {19, 29, 23, 27}; const int16_t soft_decision_high = +1; const int16_t soft_decision_low = -1; - const uint16_t max_error = uint16_t(soft_decision_high - soft_decision_low) * uint16_t(R); - const uint16_t error_margin = max_error * uint16_t(3u); + const uint16_t max_error = static_cast(soft_decision_high - soft_decision_low) * static_cast(R); + const uint16_t error_margin = max_error * static_cast(3u); const ViterbiDecoder_Config config = { .soft_decision_max_error = max_error, diff --git a/src/l2/access_assignment_channel.cpp b/src/l2/access_assignment_channel.cpp index cc0b5b8..093b262 100644 --- a/src/l2/access_assignment_channel.cpp +++ b/src/l2/access_assignment_channel.cpp @@ -11,15 +11,13 @@ #include AccessAssignmentChannel::AccessAssignmentChannel(const BurstType burst_type, const TimebaseCounter& time, - const std::vector& data) { - assert(data.size() == 14); + BitVector&& vec) { + assert(vec.bits_left() == 14); assert(is_downlink_burst(burst_type)); - auto vec = BitVector(data); - - auto header = vec.take(2); - auto field1 = vec.take(6); - auto _field2 = vec.take(6); + auto header = vec.take<2>(); + auto field1 = vec.take<6>(); + auto _field2 = vec.take<6>(); // TODO: parse uplink marker and some other things relevant for the uplink if (time.frame_number() == 18) { diff --git a/src/l2/broadcast_synchronization_channel.cpp b/src/l2/broadcast_synchronization_channel.cpp index 887899a..d47e22f 100644 --- a/src/l2/broadcast_synchronization_channel.cpp +++ b/src/l2/broadcast_synchronization_channel.cpp @@ -12,35 +12,30 @@ #include #include -BroadcastSynchronizationChannel::BroadcastSynchronizationChannel(const BurstType burst_type, - const std::vector& data) { - assert(data.size() == 60); - assert(is_downlink_burst(burst_type)); - - auto vec = BitVector(data); - +BroadcastSynchronizationChannel::BroadcastSynchronizationChannel(const BurstType burst_type, BitVector&& vec) { assert(vec.bits_left() == 60); + assert(is_downlink_burst(burst_type)); - system_code = vec.take(4); - color_code = vec.take(6); - auto time_slot = vec.take(2) + 1; - auto frame_number = vec.take(5); - auto multi_frame_number = vec.take(6); + system_code = vec.take<4>(); + color_code = vec.take<6>(); + auto time_slot = vec.take<2>() + 1u; + auto frame_number = vec.take<5>(); + auto multi_frame_number = vec.take<6>(); time = TimebaseCounter(time_slot, frame_number, multi_frame_number); - sharing_mode = vec.take(2); - time_slot_reserved_frames = vec.take(3); - up_lane_dtx = vec.take(1); - frame_18_extension = vec.take(1); - auto _reserved = vec.take(1); + sharing_mode = vec.take<2>(); + time_slot_reserved_frames = vec.take<3>(); + up_lane_dtx = vec.take<1>(); + frame_18_extension = vec.take<1>(); + auto _reserved = vec.take<1>(); assert(vec.bits_left() == 29); - mobile_country_code = vec.take(10); - mobile_network_code = vec.take(14); - dNwrk_broadcast_broadcast_supported = vec.take(1); - dNwrk_broadcast_enquiry_supported = vec.take(1); - cell_load_ca = vec.take(2); - late_entry_supported = vec.take(1); + mobile_country_code = vec.take<10>(); + mobile_network_code = vec.take<14>(); + dNwrk_broadcast_broadcast_supported = vec.take<1>(); + dNwrk_broadcast_enquiry_supported = vec.take<1>(); + cell_load_ca = vec.take<2>(); + late_entry_supported = vec.take<1>(); // 10 MSB of MCC uint16_t lmcc = mobile_country_code & 0x03ff; @@ -94,8 +89,6 @@ auto operator<<(std::ostream& stream, const BroadcastSynchronizationChannel& bsc case 0b11: stream << "High cell load"; break; - default: - break; } stream << std::endl; stream << " Late entry supported: " diff --git a/src/l2/logical_link_control.cpp b/src/l2/logical_link_control.cpp index 06f399b..c881eb8 100644 --- a/src/l2/logical_link_control.cpp +++ b/src/l2/logical_link_control.cpp @@ -5,14 +5,14 @@ auto LogicalLinkControl::check_fcs(BitVector& vec) -> bool { // remove last 32 bits - auto fcs = vec.take_last(32); + std::bitset<32> fcs = vec.take_last<32>(); - auto computed_fcs = vec.compute_fcs(); + std::bitset<32> computed_fcs = vec.compute_fcs(); if (fcs != computed_fcs) { std::cout << " FCS error" << std::endl; - std::cout << " FCS 0b" << std::bitset<32>(fcs) << std::endl; - std::cout << " computed FCS: 0b" << std::bitset<32>(computed_fcs) << std::endl; + std::cout << " FCS 0b" << fcs << std::endl; + std::cout << " computed FCS: 0b" << computed_fcs << std::endl; return false; } else { std::cout << " FCS good" << std::endl; @@ -42,7 +42,7 @@ void LogicalLinkControl::process(const AddressType address, BitVector& vec) { "Layer 2 signalling PDU", "AL-DISC"}; - auto pdu_type = vec.take(4); + auto pdu_type = vec.take<4>(); std::cout << " " << llc_pdu[pdu_type] << std::endl; @@ -87,8 +87,8 @@ void LogicalLinkControl::process(const AddressType address, BitVector& vec) { } void LogicalLinkControl::process_bl_adata_without_fcs(const AddressType address, BitVector& vec) { - auto n_r = vec.take(1); - auto n_s = vec.take(1); + auto n_r = vec.take<1>(); + auto n_s = vec.take<1>(); std::cout << " N(R) = 0b" << std::bitset<1>(n_r) << std::endl; std::cout << " N(S) = 0b" << std::bitset<1>(n_s) << std::endl; @@ -97,7 +97,7 @@ void LogicalLinkControl::process_bl_adata_without_fcs(const AddressType address, } void LogicalLinkControl::process_bl_data_without_fcs(const AddressType address, BitVector& vec) { - auto n_s = vec.take(1); + auto n_s = vec.take<1>(); std::cout << " N(S) = 0b" << std::bitset<1>(n_s) << std::endl; mle_->service_user_pdu(address, vec); @@ -108,15 +108,15 @@ void LogicalLinkControl::process_bl_udata_without_fcs(const AddressType address, } void LogicalLinkControl::process_bl_ack_without_fcs(const AddressType address, BitVector& vec) { - auto n_r = vec.take(1); + auto n_r = vec.take<1>(); std::cout << " N(R) = 0b" << std::bitset<1>(n_r) << std::endl; mle_->service_user_pdu(address, vec); } void LogicalLinkControl::process_bl_adata_with_fcs(const AddressType address, BitVector& vec) { - auto n_r = vec.take(1); - auto n_s = vec.take(1); + auto n_r = vec.take<1>(); + auto n_s = vec.take<1>(); std::cout << " N(R) = 0b" << std::bitset<1>(n_r) << std::endl; std::cout << " N(S) = 0b" << std::bitset<1>(n_s) << std::endl; @@ -127,7 +127,7 @@ void LogicalLinkControl::process_bl_adata_with_fcs(const AddressType address, Bi } void LogicalLinkControl::process_bl_data_with_fcs(const AddressType address, BitVector& vec) { - auto n_s = vec.take(1); + auto n_s = vec.take<1>(); std::cout << " N(S) = 0b" << std::bitset<1>(n_s) << std::endl; if (LogicalLinkControl::check_fcs(vec)) { @@ -142,7 +142,7 @@ void LogicalLinkControl::process_bl_udata_with_fcs(const AddressType address, Bi } void LogicalLinkControl::process_bl_ack_with_fcs(const AddressType address, BitVector& vec) { - auto n_r = vec.take(1); + auto n_r = vec.take<1>(); std::cout << " N(R) = 0b" << std::bitset<1>(n_r) << std::endl; if (LogicalLinkControl::check_fcs(vec)) { @@ -154,7 +154,7 @@ void LogicalLinkControl::process_supplementary_llc_pdu(const AddressType address std::string supplementary_llc_pdu[] = {"AL-X-DATA/AL-X-DATA-AR/AL-X-FINAL/AL-X-FINAL-AR", "AL-X-UDATA/AL-X-UFINAL", "AL-X-UDATA/AL-X-UFINAL", "AL-X-ACK/AL-X-RNR", "Reserved"}; - auto pdu_type = vec.take(2); + auto pdu_type = vec.take<2>(); std::cout << " " << supplementary_llc_pdu[pdu_type] << std::endl; std::cout << " Data: " << vec << std::endl; @@ -168,8 +168,6 @@ void LogicalLinkControl::process_supplementary_llc_pdu(const AddressType address break; case 0b11: break; - default: - break; } } diff --git a/src/l2/lower_mac.cpp b/src/l2/lower_mac.cpp index 896e2d6..49c3602 100644 --- a/src/l2/lower_mac.cpp +++ b/src/l2/lower_mac.cpp @@ -1,16 +1,22 @@ #include "burst_type.hpp" #include "l2/access_assignment_channel.hpp" #include "l2/broadcast_synchronization_channel.hpp" +#include "l2/logical_channel.hpp" +#include "l2/lower_mac_coding.hpp" +#include "utils/bit_vector.hpp" +#include +#include +#include #include +#include +#include #include #include LowerMac::LowerMac(std::shared_ptr reporter, std::shared_ptr& prometheus_exporter, std::optional scrambling_code) - : reporter_(reporter) { - viter_bi_codec_1614_ = std::make_shared(); - + : reporter_(std::move(reporter)) { // For decoupled uplink processing we need to inject a scrambling code. Inject it into the correct place that would // normally be filled by a Synchronization Burst if (scrambling_code.has_value()) { @@ -25,18 +31,9 @@ LowerMac::LowerMac(std::shared_ptr reporter, std::shared_ptr& vec, std::vector& res, std::size_t pos, - std::size_t length) -> void { - std::copy(vec.begin() + pos, vec.begin() + pos + length, std::back_inserter(res)); -} - auto LowerMac::processChannels(const std::vector& frame, BurstType burst_type, - const BroadcastSynchronizationChannel& bsc) -> std::vector> { - std::vector bkn1{}; - std::vector bkn2{}; - std::vector cb{}; - - std::vector> functions{}; + const BroadcastSynchronizationChannel& bsc) -> Slots { + std::optional slots; // The BLCH may be mapped onto block 2 of the downlink slots, when a SCH/HD, // SCH-P8/HD or a BSCH is mapped onto block 1. The number of BLCH occurrences @@ -52,195 +49,235 @@ auto LowerMac::processChannels(const std::vector& frame, BurstType burs if (burst_type == BurstType::SynchronizationBurst) { // bb contains AACH // ✅ done - uint8_t bb_desc[30]; - descramble(frame.data() + 252, bb_desc, 30, bsc.scrambling_code); - std::vector bb_rm(14); - reed_muller_3014_decode(bb_desc, bb_rm.data()); - auto _aach = AccessAssignmentChannel(burst_type, bsc.time, bb_rm); + std::array bb_input{}; + for (auto i = 0; i < 30; i++) { + bb_input[i] = frame[252 + i]; + } + + auto bb_rm = LowerMacCoding::reed_muller_3014_decode(LowerMacCoding::descramble(bb_input, bsc.scrambling_code)); + auto _aach = + AccessAssignmentChannel(burst_type, bsc.time, BitVector(std::vector(bb_rm.cbegin(), bb_rm.cend()))); // bkn2 block // ✅ done // any off SCH/HD, BNCH, STCH // see ETSI EN 300 392-2 V3.8.1 (2016-08) Figure 8.6: Error control // structure for π4DQPSK logical channels (part 2) - uint8_t bkn2_desc[216]; - descramble(frame.data() + 282, bkn2_desc, 216, bsc.scrambling_code); - uint8_t bkn2_dei[216]; - deinterleave(bkn2_desc, bkn2_dei, 216, 101); - bkn2 = viter_bi_decode_1614(depuncture23(bkn2_dei, 216)); - if (check_crc_16_ccitt(bkn2.data(), 140)) { - bkn2 = std::vector(bkn2.begin(), bkn2.begin() + 124); - - // SCH/HD or BNCH mapped - functions.emplace_back(std::bind(&UpperMac::process_SCH_HD, upper_mac_, burst_type, bkn2)); + std::array bkn2_input{}; + for (auto i = 0; i < 216; i++) { + bkn2_input[i] = frame[282 + i]; } + + auto bkn2_bits = LowerMacCoding::viter_bi_decode_1614( + viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave( + LowerMacCoding::descramble(bkn2_input, bsc.scrambling_code), 101))); + + slots = Slots(burst_type, SlotsType::kOneSubslot, + Slot(LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kSignalingChannelHalfDownlink, + .data = BitVector(std::vector(bkn2_bits.cbegin(), bkn2_bits.cbegin() + 124)), + .crc_ok = LowerMacCoding::check_crc_16_ccitt<140>(bkn2_bits), + })); } else if (burst_type == BurstType::NormalDownlinkBurst) { // bb contains AACH - // ✅ done - std::vector bb{}; - vectorAppend(frame, bb, 230, 14); - vectorAppend(frame, bb, 266, 16); - uint8_t bb_des[30]; - descramble(bb.data(), bb_des, 30, bsc.scrambling_code); - std::vector bb_rm(14); - reed_muller_3014_decode(bb_des, bb_rm.data()); - auto aach = AccessAssignmentChannel(burst_type, bsc.time, bb_rm); + // ✅ + std::array bb_input{}; + for (auto i = 0; i < 30; i++) { + auto offset = i > 14 ? 266 - 14 : 230; + bb_input[i] = frame[offset + i]; + } + + auto bb_rm = LowerMacCoding::reed_muller_3014_decode(LowerMacCoding::descramble(bb_input, bsc.scrambling_code)); + auto aach = AccessAssignmentChannel(burst_type, bsc.time, BitVector(std::vector(bb_rm.cbegin(), bb_rm.cend()))); // TCH or SCH/F - vectorAppend(frame, bkn1, 14, 216); - vectorAppend(frame, bkn1, 282, 216); - uint8_t bkn1_desc[432]; - descramble(bkn1.data(), bkn1_desc, 432, bsc.scrambling_code); - uint8_t bkn1_dei[432]; - deinterleave(bkn1_desc, bkn1_dei, 432, 103); - bkn1 = viter_bi_decode_1614(depuncture23(bkn1_dei, 432)); + std::array bkn1_input{}; + for (auto i = 0; i < 432; i++) { + auto offset = i > 216 ? 282 - 216 : 14; + bkn1_input[i] = frame[offset + i]; + }; + + auto bkn1_descrambled = LowerMacCoding::descramble(bkn1_input, bsc.scrambling_code); + + auto bkn1_bits = LowerMacCoding::viter_bi_decode_1614( + viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(bkn1_descrambled, 103))); if (aach.downlink_usage == DownlinkUsage::Traffic) { - // TODO: handle TCH - functions.emplace_back([aach]() { - std::cout << "AACH indicated traffic with usagemarker: " - << std::to_string(*aach.downlink_traffic_usage_marker) << std::endl; - }); + // Full slot traffic channel defined type 4 bits (only descrambling) + slots = Slots(burst_type, SlotsType::kFullSlot, + Slot(LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kTrafficChannel, + .data = BitVector(std::vector(bkn1_descrambled.cbegin(), bkn1_descrambled.cend())), + .crc_ok = true, + })); } else { // control channel // ✅done - if (check_crc_16_ccitt(bkn1.data(), 284)) { - bkn1 = std::vector(bkn1.begin(), bkn1.begin() + 268); - functions.emplace_back(std::bind(&UpperMac::process_SCH_F, upper_mac_, burst_type, bkn1)); - } + slots = Slots(burst_type, SlotsType::kFullSlot, + Slot(LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kSignalingChannelFull, + .data = BitVector(std::vector(bkn1_bits.cbegin(), bkn1_bits.cbegin() + 268)), + .crc_ok = LowerMacCoding::check_crc_16_ccitt<284>(bkn1_bits), + })); } } else if (burst_type == BurstType::NormalDownlinkBurstSplit) { // bb contains AACH // ✅ done - std::vector bb{}; - vectorAppend(frame, bb, 230, 14); - vectorAppend(frame, bb, 266, 16); - uint8_t bb_desc[30]; - descramble(bb.data(), bb_desc, 30, bsc.scrambling_code); - std::vector bb_rm(14); - reed_muller_3014_decode(bb_desc, bb_rm.data()); - auto aach = AccessAssignmentChannel(burst_type, bsc.time, bb_rm); - - uint8_t bkn1_desc[216]; - uint8_t bkn2_desc[216]; - descramble(frame.data() + 14, bkn1_desc, 216, bsc.scrambling_code); - descramble(frame.data() + 282, bkn2_desc, 216, bsc.scrambling_code); - - // We precompute as much as possible. Only when all computations are done we schedule the task. - uint8_t bkn1_dei[216]; - deinterleave(bkn1_desc, bkn1_dei, 216, 101); - bkn1 = viter_bi_decode_1614(depuncture23(bkn1_dei, 216)); - uint8_t bkn2_dei[216]; - deinterleave(bkn2_desc, bkn2_dei, 216, 101); - bkn2 = viter_bi_decode_1614(depuncture23(bkn2_dei, 216)); - - if (check_crc_16_ccitt(bkn1.data(), 140)) { - bkn1 = std::vector(bkn1.begin(), bkn1.begin() + 124); - if (aach.downlink_usage == DownlinkUsage::Traffic) { - // STCH + TCH - // STCH + STCH - functions.emplace_back(std::bind(&UpperMac::process_STCH, upper_mac_, burst_type, bkn1)); - } else { - // SCH/HD + SCH/HD - // SCH/HD + BNCH - // ✅done - functions.emplace_back(std::bind(&UpperMac::process_SCH_HD, upper_mac_, burst_type, bkn1)); - } + std::array bb_input{}; + for (auto i = 0; i < 30; i++) { + auto offset = i > 14 ? 266 - 14 : 230; + bb_input[i] = frame[offset + i]; + } + + auto bb_rm = LowerMacCoding::reed_muller_3014_decode(LowerMacCoding::descramble(bb_input, bsc.scrambling_code)); + auto aach = AccessAssignmentChannel(burst_type, bsc.time, BitVector(std::vector(bb_rm.cbegin(), bb_rm.cend()))); + + std::array bkn1_input{}; + for (auto i = 0; i < 216; i++) { + bkn1_input[i] = frame[14 + i]; + }; + + auto bkn1_bits = LowerMacCoding::viter_bi_decode_1614( + viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave( + LowerMacCoding::descramble(bkn1_input, bsc.scrambling_code), 101))); + + std::array bkn2_input{}; + for (auto i = 0; i < 216; i++) { + bkn2_input[i] = frame[282 + i]; } - auto bkn2_crc = check_crc_16_ccitt(bkn2.data(), 140); - bkn2 = std::vector(bkn2.begin(), bkn2.begin() + 124); + auto bkn2_deinterleaved = + LowerMacCoding::deinterleave(LowerMacCoding::descramble(bkn2_input, bsc.scrambling_code), 101); + auto bkn2_bits = LowerMacCoding::viter_bi_decode_1614(viter_bi_codec_1614_, + LowerMacCoding::depuncture23(bkn2_deinterleaved)); + + // Half slot traffic channel defines type 3 bits (deinterleaved) if (aach.downlink_usage == DownlinkUsage::Traffic) { - functions.emplace_back([this, burst_type, aach, bkn2, bkn2_crc]() { - if (upper_mac_->second_slot_stolen()) { - if (bkn2_crc) { - upper_mac_->process_STCH(burst_type, bkn2); - } - } else { - // TODO: handle this TCH - std::cout << "AACH indicated traffic with usagemarker: " - << std::to_string(*aach.downlink_traffic_usage_marker) << std::endl; - } - }); + // STCH + TCH + // STCH + STCH + slots = + Slots(burst_type, SlotsType::kTwoSubslots, + Slot(LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kStealingChannel, + .data = BitVector(std::vector(bkn1_bits.cbegin(), bkn1_bits.cbegin() + 124)), + .crc_ok = LowerMacCoding::check_crc_16_ccitt<140>(bkn1_bits), + }), + Slot({LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kStealingChannel, + .data = BitVector(std::vector(bkn2_bits.cbegin(), bkn2_bits.cbegin() + 124)), + .crc_ok = LowerMacCoding::check_crc_16_ccitt<140>(bkn2_bits), + }, + LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kTrafficChannel, + .data = BitVector(std::vector(bkn2_deinterleaved.cbegin(), bkn2_deinterleaved.cend())), + .crc_ok = true, + }})); } else { - // control channel - if (bkn2_crc) { - functions.emplace_back(std::bind(&UpperMac::process_SCH_HD, upper_mac_, burst_type, bkn2)); - } + // SCH/HD + SCH/HD + // SCH/HD + BNCH + slots = Slots(burst_type, SlotsType::kTwoSubslots, + Slot(LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kSignalingChannelHalfDownlink, + .data = BitVector(std::vector(bkn1_bits.cbegin(), bkn1_bits.cbegin() + 124)), + .crc_ok = LowerMacCoding::check_crc_16_ccitt<140>(bkn1_bits), + }), + Slot(LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kSignalingChannelHalfDownlink, + .data = BitVector(std::vector(bkn2_bits.cbegin(), bkn2_bits.cbegin() + 124)), + .crc_ok = LowerMacCoding::check_crc_16_ccitt<140>(bkn2_bits), + })); } } else if (burst_type == BurstType::ControlUplinkBurst) { - vectorAppend(frame, cb, 4, 84); - vectorAppend(frame, cb, 118, 84); - uint8_t cb_desc[168]; - descramble(cb.data(), cb_desc, 168, bsc.scrambling_code); - - // XXX: assume to be control channel - uint8_t cb_dei[168]; - deinterleave(cb_desc, cb_dei, 168, 13); - cb = viter_bi_decode_1614(depuncture23(cb_dei, 168)); - if (check_crc_16_ccitt(cb.data(), 108)) { - cb = std::vector(cb.begin(), cb.begin() + 92); - functions.emplace_back(std::bind(&UpperMac::process_SCH_HU, upper_mac_, burst_type, cb)); - } + std::array cb_input{}; + for (auto i = 0; i < 168; i++) { + auto offset = i > 84 ? 118 - 84 : 4; + cb_input[i] = frame[offset + i]; + }; + + auto cb_bits = LowerMacCoding::viter_bi_decode_1614( + viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave( + LowerMacCoding::descramble(cb_input, bsc.scrambling_code), 13))); + + // SCH/HU + slots = Slots(burst_type, SlotsType::kOneSubslot, + Slot(LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kSignalingChannelHalfUplink, + .data = BitVector(std::vector(cb_bits.cbegin(), cb_bits.cbegin() + 92)), + .crc_ok = LowerMacCoding::check_crc_16_ccitt<108>(cb_bits), + })); } else if (burst_type == BurstType::NormalUplinkBurst) { - vectorAppend(frame, bkn1, 4, 216); - vectorAppend(frame, bkn1, 242, 216); - uint8_t bkn1_desc[432]; - descramble(bkn1.data(), bkn1_desc, 432, bsc.scrambling_code); + std::array bkn1_input{}; + for (auto i = 0; i < 432; i++) { + auto offset = i > 216 ? 242 - 216 : 4; + bkn1_input[i] = frame[offset + i]; + } // TODO: this can either be a SCH_H or a TCH, depending on the uplink usage marker, but the uplink // and downlink processing are seperated. We assume a SCH_H here. - uint8_t bkn1_dei[432]; - deinterleave(bkn1_desc, bkn1_dei, 432, 103); - bkn1 = viter_bi_decode_1614(depuncture23(bkn1_dei, 432)); - if (check_crc_16_ccitt(bkn1.data(), 284)) { - bkn1 = std::vector(bkn1.begin(), bkn1.begin() + 268); - // fmt::print("NUB Burst crc good\n"); - functions.emplace_back(std::bind(&UpperMac::process_SCH_F, upper_mac_, burst_type, bkn1)); - } else { - // Either we have a faulty burst or a TCH here. - } + auto bkn1_descrambled = LowerMacCoding::descramble(bkn1_input, bsc.scrambling_code); + + auto bkn1_bits = LowerMacCoding::viter_bi_decode_1614( + viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave(bkn1_descrambled, 103))); + + slots = Slots(burst_type, SlotsType::kFullSlot, + Slot({ + LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kSignalingChannelFull, + .data = BitVector(std::vector(bkn1_bits.cbegin(), bkn1_bits.cbegin() + 268)), + .crc_ok = LowerMacCoding::check_crc_16_ccitt<284>(bkn1_bits), + }, + LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kTrafficChannel, + .data = BitVector(std::vector(bkn1_descrambled.cbegin(), bkn1_descrambled.cend())), + .crc_ok = true, + }, + })); } else if (burst_type == BurstType::NormalUplinkBurstSplit) { - uint8_t bkn1_desc[216]; - uint8_t bkn2_desc[216]; - descramble(frame.data() + 4, bkn1_desc, 216, bsc.scrambling_code); - descramble(frame.data() + 242, bkn2_desc, 216, bsc.scrambling_code); - - uint8_t bkn1_dei[216]; - deinterleave(bkn1_desc, bkn1_dei, 216, 101); - bkn1 = viter_bi_decode_1614(depuncture23(bkn1_dei, 216)); - // STCH + TCH - // STCH + STCH - if (check_crc_16_ccitt(bkn1.data(), 140)) { - bkn1 = std::vector(bkn1.begin(), bkn1.begin() + 124); - // fmt::print("NUB_S 1 Burst crc good\n"); - functions.emplace_back(std::bind(&UpperMac::process_STCH, upper_mac_, burst_type, bkn1)); + std::array bkn1_input{}; + for (auto i = 0; i < 216; i++) { + bkn1_input[i] = frame[4 + i]; } - uint8_t bkn2_dei[216]; - deinterleave(bkn2_desc, bkn2_dei, 216, 101); - bkn2 = viter_bi_decode_1614(depuncture23(bkn2_dei, 216)); - if (check_crc_16_ccitt(bkn2.data(), 140)) { - bkn2 = std::vector(bkn2.begin(), bkn2.begin() + 124); - functions.emplace_back([this, burst_type, bkn2]() { - if (upper_mac_->second_slot_stolen()) { - // fmt::print("NUB_S 2 Burst crc good\n"); - upper_mac_->process_STCH(burst_type, bkn2); - } else { - // TODO: handle this TCH - } - }); - } + auto bkn1_bits = LowerMacCoding::viter_bi_decode_1614( + viter_bi_codec_1614_, LowerMacCoding::depuncture23(LowerMacCoding::deinterleave( + LowerMacCoding::descramble(bkn1_input, bsc.scrambling_code), 101))); + + std::array bkn2_input{}; + for (auto i = 0; i < 216; i++) { + bkn2_input[i] = frame[242 + i]; + }; + + auto bkn2_deinterleaved = + LowerMacCoding::deinterleave(LowerMacCoding::descramble(bkn2_input, bsc.scrambling_code), 101); + auto bkn2_bits = LowerMacCoding::viter_bi_decode_1614(viter_bi_codec_1614_, + LowerMacCoding::depuncture23(bkn2_deinterleaved)); + + // STCH + TCH + // STCH + STCH + slots = Slots(burst_type, SlotsType::kTwoSubslots, + Slot(LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kStealingChannel, + .data = BitVector(std::vector(bkn1_bits.cbegin(), bkn1_bits.cbegin() + 124)), + .crc_ok = LowerMacCoding::check_crc_16_ccitt<140>(bkn1_bits), + }), + Slot({LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kStealingChannel, + .data = BitVector(std::vector(bkn2_bits.cbegin(), bkn2_bits.cbegin() + 124)), + .crc_ok = LowerMacCoding::check_crc_16_ccitt<140>(bkn2_bits), + }, + LogicalChannelDataAndCrc{ + .channel = LogicalChannel::kTrafficChannel, + .data = BitVector(std::vector(bkn2_deinterleaved.cbegin(), bkn2_deinterleaved.cend())), + .crc_ok = true, + }})); } else { throw std::runtime_error("LowerMac does not implement the burst type supplied"); } - return functions; + return *slots; } auto LowerMac::process(const std::vector& frame, BurstType burst_type) -> std::vector> { - std::vector sb{}; - // Set to true if there was some decoding error in the lower MAC bool decode_error = false; @@ -257,14 +294,18 @@ auto LowerMac::process(const std::vector& frame, BurstType burst_type) // sb contains BSCH // ✅ done - uint8_t sb_desc[120]; - descramble(frame.data() + 94, sb_desc, 120, 0x0003); - uint8_t sb_dei[120]; - deinterleave(sb_desc, sb_dei, 120, 11); - sb = viter_bi_decode_1614(depuncture23(sb_dei, 120)); - if (check_crc_16_ccitt(sb.data(), 76)) { - sb = std::vector(sb.begin(), sb.begin() + 60); - current_sync = BroadcastSynchronizationChannel(burst_type, sb); + std::array sb_input{}; + for (auto i = 0; i < 120; i++) { + sb_input[i] = frame[94 + i]; + }; + + auto sb_bits = LowerMacCoding::viter_bi_decode_1614( + viter_bi_codec_1614_, LowerMacCoding::depuncture23( + LowerMacCoding::deinterleave(LowerMacCoding::descramble(sb_input, 0x0003), 11))); + + if (LowerMacCoding::check_crc_16_ccitt<76>(sb_bits)) { + current_sync = BroadcastSynchronizationChannel( + burst_type, BitVector(std::vector(sb_bits.cbegin(), sb_bits.cbegin() + 60))); } else { decode_error |= true; } @@ -277,27 +318,37 @@ auto LowerMac::process(const std::vector& frame, BurstType burst_type) } std::vector> callbacks{}; + // We got a sync, continue with further processing of channels if (sync_) { - callbacks = processChannels(frame, burst_type, *sync_); - - // We assume to encountered an error decoding in the lower MAC if we do not get the correct number of callbacks - // back. For normal channels this is one. For split channels this is two. - std::size_t correct_number_of_callbacks; - switch (burst_type) { - case BurstType::ControlUplinkBurst: - case BurstType::NormalUplinkBurst: - case BurstType::NormalDownlinkBurst: - case BurstType::SynchronizationBurst: - correct_number_of_callbacks = 1; - break; - case BurstType::NormalDownlinkBurstSplit: - case BurstType::NormalUplinkBurstSplit: - correct_number_of_callbacks = 2; - break; + auto slots = processChannels(frame, burst_type, *sync_); + + // check if we have crc decode errors in the lower mac + decode_error |= slots.has_crc_error(); + + // construct the callbacks for the slots + std::map logical_channel_to_function_map({ + {LogicalChannel::kSignalingChannelHalfDownlink, &UpperMac::process_SCH_HD}, + {LogicalChannel::kSignalingChannelHalfUplink, &UpperMac::process_SCH_HU}, + {LogicalChannel::kSignalingChannelFull, &UpperMac::process_SCH_F}, + {LogicalChannel::kStealingChannel, &UpperMac::process_STCH}, + }); + + { + auto& first_slot = slots.get_first_slot().get_logical_channel_data_and_crc(); + if (logical_channel_to_function_map.count(first_slot.channel) && first_slot.crc_ok) { + auto& function = logical_channel_to_function_map[first_slot.channel]; + callbacks.emplace_back(std::bind(function, upper_mac_, burst_type, first_slot.data)); + } } - decode_error |= callbacks.size() != correct_number_of_callbacks; + if (slots.has_second_slot()) { + auto& second_slot = slots.get_second_slot().get_logical_channel_data_and_crc(); + if (logical_channel_to_function_map.count(second_slot.channel) && second_slot.crc_ok) { + auto& function = logical_channel_to_function_map[second_slot.channel]; + callbacks.emplace_back(std::bind(function, upper_mac_, burst_type, second_slot.data)); + } + } } // Update the received burst type metrics @@ -306,4 +357,4 @@ auto LowerMac::process(const std::vector& frame, BurstType burst_type) } return callbacks; -} +} \ No newline at end of file diff --git a/src/l2/lower_mac_coding.cpp b/src/l2/lower_mac_coding.cpp deleted file mode 100644 index 71fbf7e..0000000 --- a/src/l2/lower_mac_coding.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/* - * tetra-kit - * Copyright (C) 2020 LarryTh - * - * 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 3 of the License, 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. If not, see . - * - */ -#include - -/** - * @brief Fibonacci LFSR descrambling - 8.2.5 - * - */ -static void xor_kernel(uint8_t* const res, const uint8_t* const data, const uint8_t* const table, - const std::size_t len) { - for (std::size_t i = 0; i < len; i++) - res[i] = data[i] ^ table[i]; -} - -auto LowerMac::descramble(const uint8_t* const data, uint8_t* const res, const std::size_t len, - const uint32_t scramblingCode) noexcept -> void { - - static std::map> tableByScramblingCode; - - assert(len <= 432); - - if (tableByScramblingCode.count(scramblingCode) == 0) { - auto& table = tableByScramblingCode[scramblingCode]; - table.resize(432); - const uint8_t poly[14] = {32, 26, 23, 22, 16, 12, 11, - 10, 8, 7, 5, 4, 2, 1}; // Feedback polynomial - see 8.2.5.2 (8.39) - - uint32_t lfsr = scramblingCode; // linear feedback shift register initialization (=0 + 3 - // for BSCH, calculated from Color code ch 19 otherwise) - for (std::size_t i = 0; i < 432; i++) { - uint32_t bit = 0; - // apply poly (Xj + ...) - for (std::size_t j = 0; j < 14; j++) { - bit = bit ^ (lfsr >> (32 - poly[j])); - } - bit = bit & 1; // finish apply feedback polynomial (+ 1) - lfsr = (lfsr >> 1) | (bit << 31); - - table[i] = bit & 0xff; - } - } - - xor_kernel(res, data, tableByScramblingCode[scramblingCode].data(), len); -} - -/** - * @brief (K,a) block deinterleaver - 8.2.4 - * - */ -auto LowerMac::deinterleave(const uint8_t* const data, uint8_t* const res, const std::size_t K, - const std::size_t a) noexcept -> void { - for (std::size_t i = 0; i < K; i++) { - auto k = 1 + (a * (i + 1)) % K; - res[i] = data[k - 1]; // to interleave: DataOut[i-1] = DataIn[k-1] - } -} - -/** - * @brief Depuncture with 2/3 rate - 8.2.3.1.3 - * - */ -auto LowerMac::depuncture23(const uint8_t* const data, const uint32_t len) noexcept -> std::vector { - const uint8_t P[] = {0, 1, 2, 5}; // 8.2.3.1.3 - P[1..t] - std::vector res(4 * len * 2 / 3, - 0); // 8.2.3.1.2 with flag 0 for erase bit in Viterbi routine - - uint8_t t = 3; // 8.2.3.1.3 - uint8_t period = 8; // 8.2.3.1.2 - - for (uint32_t j = 1; j <= len; j++) { - uint32_t i = j; // punct->i_func(j); - uint32_t k = - period * ((i - 1) / t) + P[i - t * ((i - 1) / t)]; // punct->period * ((i-1)/t) + P[i - t*((i-1)/t)]; - res[k - 1] = data[j - 1] ? 1 : -1; - } - - return res; -} - -/** - * @brief Viterbi decoding of RCPC code 16-state mother code of rate 1/4 - * - 8.2.3.1.1 - * - */ -auto LowerMac::viter_bi_decode_1614(const std::vector& data) const noexcept -> std::vector { - auto decoded = viter_bi_codec_1614_->Decode(data); - std::vector out(decoded.size() * 8); - for (auto i = 0; i < decoded.size(); i++) - for (auto j = 0; j < 8; j++) - out[i * 8 + j] = (decoded[i] & (1 << (7 - j))) ? 1 : 0; - - return out; -} - -/** - * @brief Reed-Muller decoder and FEC correction 30 bits in, 14 bits out - * - * FEC thanks to Lollo Gollo @logollo see "issue #21" - * - */ - -auto LowerMac::reed_muller_3014_decode(const uint8_t* const data, uint8_t* const res) noexcept -> void { - uint8_t q[14][5]; - - q[0][0] = data[0]; - q[0][1] = (data[13 + 3] + data[13 + 5] + data[13 + 6] + data[13 + 7] + data[13 + 11]) % 2; - q[0][2] = (data[13 + 1] + data[13 + 2] + data[13 + 5] + data[13 + 6] + data[13 + 8] + data[13 + 9]) % 2; - q[0][3] = (data[13 + 2] + data[13 + 3] + data[13 + 4] + data[13 + 5] + data[13 + 9] + data[13 + 10]) % 2; - q[0][4] = - (data[13 + 1] + data[13 + 4] + data[13 + 5] + data[13 + 7] + data[13 + 8] + data[13 + 10] + data[13 + 11]) % 2; - res[0] = (q[0][0] + q[0][1] + q[0][2] + q[0][3] + q[0][4]) >= 3 ? 1 : 0; - - q[1][0] = data[1]; - q[1][1] = (data[13 + 1] + data[13 + 4] + data[13 + 5] + data[13 + 9] + data[13 + 11]) % 2; - q[1][2] = (data[13 + 1] + data[13 + 2] + data[13 + 5] + data[13 + 6] + data[13 + 7] + data[13 + 10]) % 2; - q[1][3] = (data[13 + 2] + data[13 + 3] + data[13 + 4] + data[13 + 5] + data[13 + 7] + data[13 + 8]) % 2; - q[1][4] = - (data[13 + 3] + data[13 + 5] + data[13 + 6] + data[13 + 8] + data[13 + 9] + data[13 + 10] + data[13 + 11]) % 2; - res[1] = (q[1][0] + q[1][1] + q[1][2] + q[1][3] + q[1][4]) >= 3 ? 1 : 0; - - q[2][0] = data[2]; - q[2][1] = (data[13 + 2] + data[13 + 5] + data[13 + 8] + data[13 + 10] + data[13 + 11]) % 2; - q[2][2] = (data[13 + 1] + data[13 + 3] + data[13 + 5] + data[13 + 7] + data[13 + 9] + data[13 + 10]) % 2; - q[2][3] = (data[13 + 4] + data[13 + 5] + data[13 + 6] + data[13 + 7] + data[13 + 8] + data[13 + 9]) % 2; - q[2][4] = - (data[13 + 1] + data[13 + 2] + data[13 + 3] + data[13 + 4] + data[13 + 5] + data[13 + 6] + data[13 + 11]) % 2; - res[2] = (q[2][0] + q[2][1] + q[2][2] + q[2][3] + q[2][4]) >= 3 ? 1 : 0; - - q[3][0] = data[3]; - q[3][1] = (data[13 + 7] + data[13 + 8] + data[13 + 9] + data[13 + 12] + data[13 + 13] + data[13 + 14]) % 2; - q[3][2] = - (data[13 + 1] + data[13 + 2] + data[13 + 3] + data[13 + 11] + data[13 + 12] + data[13 + 13] + data[13 + 14]) % - 2; - q[3][3] = (data[13 + 2] + data[13 + 4] + data[13 + 6] + data[13 + 8] + data[13 + 10] + data[13 + 11] + - data[13 + 12] + data[13 + 13] + data[13 + 14]) % - 2; - q[3][4] = (data[13 + 1] + data[13 + 3] + data[13 + 4] + data[13 + 6] + data[13 + 7] + data[13 + 9] + data[13 + 10] + - data[13 + 12] + data[13 + 13] + data[13 + 14]) % - 2; - res[3] = (q[3][0] + q[3][1] + q[3][2] + q[3][3] + q[3][4]) >= 3 ? 1 : 0; - - q[4][0] = data[4]; - q[4][1] = - (data[13 + 1] + data[13 + 4] + data[13 + 5] + data[13 + 11] + data[13 + 12] + data[13 + 13] + data[13 + 15]) % - 2; - q[4][2] = (data[13 + 3] + data[13 + 5] + data[13 + 6] + data[13 + 8] + data[13 + 10] + data[13 + 11] + - data[13 + 12] + data[13 + 13] + data[13 + 15]) % - 2; - q[4][3] = (data[13 + 1] + data[13 + 2] + data[13 + 5] + data[13 + 6] + data[13 + 7] + data[13 + 9] + data[13 + 10] + - data[13 + 12] + data[13 + 13] + data[13 + 15]) % - 2; - q[4][4] = (data[13 + 2] + data[13 + 3] + data[13 + 4] + data[13 + 5] + data[13 + 7] + data[13 + 8] + data[13 + 9] + - data[13 + 12] + data[13 + 13] + data[13 + 15]) % - 2; - res[4] = (q[4][0] + q[4][1] + q[4][2] + q[4][3] + q[4][4]) >= 3 ? 1 : 0; - - q[5][0] = data[5]; - q[5][1] = (data[13 + 7] + data[13 + 9] + data[13 + 10] + data[13 + 12] + data[13 + 14] + data[13 + 15]) % 2; - q[5][2] = - (data[13 + 2] + data[13 + 4] + data[13 + 6] + data[13 + 11] + data[13 + 12] + data[13 + 14] + data[13 + 15]) % - 2; - q[5][3] = (data[13 + 1] + data[13 + 2] + data[13 + 3] + data[13 + 8] + data[13 + 10] + data[13 + 11] + - data[13 + 12] + data[13 + 14] + data[13 + 15]) % - 2; - q[5][4] = (data[13 + 1] + data[13 + 3] + data[13 + 4] + data[13 + 6] + data[13 + 7] + data[13 + 8] + data[13 + 9] + - data[13 + 12] + data[13 + 14] + data[13 + 15]) % - 2; - res[5] = (q[5][0] + q[5][1] + q[5][2] + q[5][3] + q[5][4]) >= 3 ? 1 : 0; - - q[6][0] = data[6]; - q[6][1] = - (data[13 + 3] + data[13 + 5] + data[13 + 6] + data[13 + 11] + data[13 + 13] + data[13 + 14] + data[13 + 15]) % - 2; - q[6][2] = (data[13 + 1] + data[13 + 4] + data[13 + 5] + data[13 + 8] + data[13 + 10] + data[13 + 11] + - data[13 + 13] + data[13 + 14] + data[13 + 15]) % - 2; - q[6][3] = (data[13 + 1] + data[13 + 2] + data[13 + 5] + data[13 + 6] + data[13 + 7] + data[13 + 8] + data[13 + 9] + - data[13 + 13] + data[13 + 14] + data[13 + 15]) % - 2; - q[6][4] = (data[13 + 2] + data[13 + 3] + data[13 + 4] + data[13 + 5] + data[13 + 7] + data[13 + 9] + data[13 + 10] + - data[13 + 13] + data[13 + 14] + data[13 + 15]) % - 2; - res[6] = (q[6][0] + q[6][1] + q[6][2] + q[6][3] + q[6][4]) >= 3 ? 1 : 0; - - q[7][0] = data[7]; - q[7][1] = (data[13 + 2] + data[13 + 5] + data[13 + 7] + data[13 + 9] + data[13 + 12] + data[13 + 13] + - data[13 + 14] + data[13 + 15] + data[13 + 16]) % - 2; - q[7][2] = (data[13 + 1] + data[13 + 3] + data[13 + 5] + data[13 + 8] + data[13 + 11] + data[13 + 12] + - data[13 + 13] + data[13 + 14] + data[13 + 15] + data[13 + 16]) % - 2; - q[7][3] = (data[13 + 4] + data[13 + 5] + data[13 + 6] + data[13 + 10] + data[13 + 11] + data[13 + 12] + - data[13 + 13] + data[13 + 14] + data[13 + 15] + data[13 + 16]) % - 2; - q[7][4] = (data[13 + 1] + data[13 + 2] + data[13 + 3] + data[13 + 4] + data[13 + 5] + data[13 + 6] + data[13 + 7] + - data[13 + 8] + data[13 + 9] + data[13 + 10] + data[13 + 12] + data[13 + 13] + data[13 + 14] + - data[13 + 15] + data[13 + 16]) % - 2; - res[7] = (q[7][0] + q[7][1] + q[7][2] + q[7][3] + q[7][4]) >= 3 ? 1 : 0; - - q[8][0] = data[8]; - q[8][1] = (data[13 + 2] + data[13 + 3] + data[13 + 9] + data[13 + 12] + data[13 + 13] + data[13 + 16]) % 2; - q[8][2] = - (data[13 + 1] + data[13 + 7] + data[13 + 8] + data[13 + 11] + data[13 + 12] + data[13 + 13] + data[13 + 16]) % - 2; - q[8][3] = (data[13 + 3] + data[13 + 4] + data[13 + 6] + data[13 + 7] + data[13 + 10] + data[13 + 11] + - data[13 + 12] + data[13 + 13] + data[13 + 16]) % - 2; - q[8][4] = (data[13 + 1] + data[13 + 2] + data[13 + 4] + data[13 + 6] + data[13 + 8] + data[13 + 9] + data[13 + 10] + - data[13 + 12] + data[13 + 13] + data[13 + 16]) % - 2; - res[8] = (q[8][0] + q[8][1] + q[8][2] + q[8][3] + q[8][4]) >= 3 ? 1 : 0; - - q[9][0] = data[9]; - q[9][1] = (data[13 + 1] + data[13 + 3] + data[13 + 8] + data[13 + 12] + data[13 + 14] + data[13 + 16]) % 2; - q[9][2] = (data[13 + 4] + data[13 + 6] + data[13 + 10] + data[13 + 12] + data[13 + 14] + data[13 + 16]) % 2; - q[9][3] = - (data[13 + 2] + data[13 + 7] + data[13 + 9] + data[13 + 11] + data[13 + 12] + data[13 + 14] + data[13 + 16]) % - 2; - q[9][4] = (data[13 + 1] + data[13 + 2] + data[13 + 3] + data[13 + 4] + data[13 + 6] + data[13 + 7] + data[13 + 8] + - data[13 + 9] + data[13 + 10] + data[13 + 11] + data[13 + 12] + data[13 + 14] + data[13 + 16]) % - 2; - res[9] = (q[9][0] + q[9][1] + q[9][2] + q[9][3] + q[9][4]) >= 3 ? 1 : 0; - - q[10][0] = data[10]; - q[10][1] = (data[13 + 1] + data[13 + 2] + data[13 + 7] + data[13 + 13] + data[13 + 14] + data[13 + 16]) % 2; - q[10][2] = - (data[13 + 3] + data[13 + 8] + data[13 + 9] + data[13 + 11] + data[13 + 13] + data[13 + 14] + data[13 + 16]) % - 2; - q[10][3] = (data[13 + 1] + data[13 + 4] + data[13 + 6] + data[13 + 9] + data[13 + 10] + data[13 + 11] + - data[13 + 13] + data[13 + 14] + data[13 + 16]) % - 2; - q[10][4] = (data[13 + 2] + data[13 + 3] + data[13 + 4] + data[13 + 6] + data[13 + 7] + data[13 + 8] + - data[13 + 10] + data[13 + 13] + data[13 + 14] + data[13 + 16]) % - 2; - res[10] = (q[10][0] + q[10][1] + q[10][2] + q[10][3] + q[10][4]) >= 3 ? 1 : 0; - - q[11][0] = data[11]; - q[11][1] = (data[13 + 2] + data[13 + 6] + data[13 + 9] + data[13 + 12] + data[13 + 15] + data[13 + 16]) % 2; - q[11][2] = - (data[13 + 4] + data[13 + 7] + data[13 + 10] + data[13 + 11] + data[13 + 12] + data[13 + 15] + data[13 + 16]) % - 2; - q[11][3] = (data[13 + 1] + data[13 + 3] + data[13 + 6] + data[13 + 7] + data[13 + 8] + data[13 + 11] + - data[13 + 12] + data[13 + 15] + data[13 + 16]) % - 2; - q[11][4] = (data[13 + 1] + data[13 + 2] + data[13 + 3] + data[13 + 4] + data[13 + 8] + data[13 + 9] + - data[13 + 10] + data[13 + 12] + data[13 + 15] + data[13 + 16]) % - 2; - res[11] = (q[11][0] + q[11][1] + q[11][2] + q[11][3] + q[11][4]) >= 3 ? 1 : 0; - - q[12][0] = data[12]; - q[12][1] = - (data[13 + 5] + data[13 + 8] + data[13 + 10] + data[13 + 11] + data[13 + 13] + data[13 + 15] + data[13 + 16]) % - 2; - q[12][2] = (data[13 + 1] + data[13 + 3] + data[13 + 4] + data[13 + 5] + data[13 + 6] + data[13 + 11] + - data[13 + 13] + data[13 + 15] + data[13 + 16]) % - 2; - q[12][3] = (data[13 + 1] + data[13 + 2] + data[13 + 3] + data[13 + 5] + data[13 + 7] + data[13 + 9] + - data[13 + 10] + data[13 + 13] + data[13 + 15] + data[13 + 16]) % - 2; - q[12][4] = (data[13 + 2] + data[13 + 4] + data[13 + 5] + data[13 + 6] + data[13 + 7] + data[13 + 8] + data[13 + 9] + - data[13 + 13] + data[13 + 15] + data[13 + 16]) % - 2; - res[12] = (q[12][0] + q[12][1] + q[12][2] + q[12][3] + q[12][4]) >= 3 ? 1 : 0; - - q[13][0] = data[13]; - q[13][1] = (data[13 + 2] + data[13 + 4] + data[13 + 7] + data[13 + 14] + data[13 + 15] + data[13 + 16]) % 2; - q[13][2] = - (data[13 + 6] + data[13 + 9] + data[13 + 10] + data[13 + 11] + data[13 + 14] + data[13 + 15] + data[13 + 16]) % - 2; - q[13][3] = (data[13 + 1] + data[13 + 3] + data[13 + 4] + data[13 + 8] + data[13 + 9] + data[13 + 11] + - data[13 + 14] + data[13 + 15] + data[13 + 16]) % - 2; - q[13][4] = (data[13 + 1] + data[13 + 2] + data[13 + 3] + data[13 + 6] + data[13 + 7] + data[13 + 8] + - data[13 + 10] + data[13 + 14] + data[13 + 15] + data[13 + 16]) % - 2; - res[13] = (q[13][0] + q[13][1] + q[13][2] + q[13][3] + q[13][4]) >= 3 ? 1 : 0; - - // check deviation from input - // int deviation = 0; - // for (int cnt = 0; cnt < 14; cnt++) - // { - // deviation += (data[cnt] != res[cnt]) ? 1 : 0; - // } - // printf("FEC correction %.2f\n", deviation / 14.); - // print_vector(data, 14); - // print_vector(res, 14); - - // return vector_extract(data, 0, 14); -} - -/** - * @brief Calculated CRC16 ITU-T X.25 - CCITT - * - */ -auto LowerMac::check_crc_16_ccitt(const uint8_t* const data, const std::size_t len) noexcept -> bool { - uint16_t crc = 0xFFFF; // CRC16-CCITT initial value - - for (std::size_t i = 0; i < len; i++) { - auto bit = static_cast(data[i]); - - crc ^= bit << 15; - if (crc & 0x8000) { - crc <<= 1; - crc ^= 0x1021; // CRC16-CCITT polynomial - } else { - crc <<= 1; - } - } - - return crc == 0x1D0F; // CRC16-CCITT reminder value -} diff --git a/src/l2/upper_mac.cpp b/src/l2/upper_mac.cpp index f49b0e7..7f3365b 100644 --- a/src/l2/upper_mac.cpp +++ b/src/l2/upper_mac.cpp @@ -4,30 +4,30 @@ #include #include -void UpperMac::process_SCH_HD(const BurstType burst_type, const std::vector& data) { +void UpperMac::process_SCH_HD(const BurstType burst_type, BitVector& vec) { assert(is_downlink_burst(burst_type)); std::cout << "[Channel] SCH_HD" << std::endl; - process_signalling_channel(burst_type, data, true, false); + process_signalling_channel(burst_type, vec, true, false); } -void UpperMac::process_SCH_HU(const BurstType burst_type, const std::vector& data) { - assert(data.size() == 92); +void UpperMac::process_SCH_HU(const BurstType burst_type, BitVector& vec) { + assert(vec.bits_left() == 92); assert(is_uplink_burst(burst_type)); try { fragmentation_start_burst(); last_address_type_ = AddressType(); - auto vec = BitVector(data); - std::cout << "[Channel] SCH_HU" << std::endl; - auto pduType = vec.take(1); - auto fill_bit_indication = vec.take(1); + auto pduType = vec.take<1>(); + auto fill_bit_indication = vec.take<1>(); remove_fill_bits_ = true; - remove_fill_bits(vec); + if (fill_bit_indication == 0b1) { + remove_fill_bits(vec); + } if (pduType == 0b0) { process_mac_access(vec); @@ -43,36 +43,34 @@ void UpperMac::process_SCH_HU(const BurstType burst_type, const std::vector& data) { +void UpperMac::process_SCH_F(const BurstType burst_type, BitVector& vec) { std::cout << "[Channel] SCH_F" << std::endl; - process_signalling_channel(burst_type, data, false, false); + process_signalling_channel(burst_type, vec, false, false); } -void UpperMac::process_STCH(const BurstType burst_type, const std::vector& data) { +void UpperMac::process_STCH(const BurstType burst_type, BitVector& vec) { std::cout << "[Channel] STCH" << std::endl; second_slot_stolen_ = false; - process_signalling_channel(burst_type, data, true, true); + process_signalling_channel(burst_type, vec, true, true); } -void UpperMac::process_signalling_channel(const BurstType burst_type, const std::vector& data, - bool isHalfChannel, bool isStolenChannel) { - auto vec = BitVector(data); - +void UpperMac::process_signalling_channel(const BurstType burst_type, BitVector& vec, bool isHalfChannel, + bool isStolenChannel) { remove_fill_bits_ = true; try { fragmentation_start_burst(); - process_signalling_channel(burst_type, vec, isHalfChannel, isStolenChannel); + process_signalling_channel_internal(burst_type, vec, isHalfChannel, isStolenChannel); fragmentation_end_burst(); } catch (std::exception& e) { std::cout << "Error with decoding: " << e.what() << std::endl; } } -void UpperMac::process_signalling_channel(const BurstType burst_type, BitVector& vec, bool isHalfChannel, - bool isStolenChannel) { - auto pduType = vec.take(2); +void UpperMac::process_signalling_channel_internal(const BurstType burst_type, BitVector& vec, bool isHalfChannel, + bool isStolenChannel) { + auto pduType = vec.take<2>(); if (pduType == 0b00) { // MAC-RESOURCE (downlink) or MAC-DATA (uplink) @@ -85,7 +83,7 @@ void UpperMac::process_signalling_channel(const BurstType burst_type, BitVector& } else if (pduType == 0b01) { // MAC-END or MAC-FRAG // TMA-SAP - auto subtype = vec.take(1); + auto subtype = vec.take<1>(); if (subtype == 0b0) { if (is_downlink_burst(burst_type)) { process_mac_frag_downlink(vec); @@ -126,13 +124,13 @@ void UpperMac::process_signalling_channel(const BurstType burst_type, BitVector& if (vec.bits_left() > 0) { std::cout << "BitsLeft(): " << std::to_string(vec.bits_left()) << " " << vec << std::endl; if (!vec.is_mac_padding()) { - process_signalling_channel(burst_type, vec, isHalfChannel, isStolenChannel); + process_signalling_channel_internal(burst_type, vec, isHalfChannel, isStolenChannel); } } } void UpperMac::process_broadcast(BitVector& vec) { - auto broadcastType = vec.take(2); + auto broadcastType = vec.take<2>(); switch (broadcastType) { case 0b00: // SYSINFO PDU @@ -151,14 +149,11 @@ void UpperMac::process_broadcast(BitVector& vec) { // Reserved // TODO: print unimplemented error break; - default: - // TODO: what should happen here panic ? - break; } } void UpperMac::process_supplementary_mac_pdu(const BurstType burst_type, BitVector& vec) { - auto subtype = vec.take(1); + auto subtype = vec.take<1>(); switch (subtype) { case 0b0: @@ -172,64 +167,61 @@ void UpperMac::process_supplementary_mac_pdu(const BurstType burst_type, BitVect // Reserved // TODO: print unimplemented error break; - default: - // TODO: what should happen ? - break; } } void UpperMac::process_system_info_pdu(BitVector& vec) { - auto mainCarrier = vec.take(12); - auto frequency_band = vec.take(4); - auto offset = vec.take(2); - auto duplexSpacing = vec.take(3); - auto reverseOperation = vec.take(1); - number_secondary_control_channels_main_carrier_ = vec.take(2); - ms_txpwr_max_cell_ = vec.take(3); - rxlev_access_min_ = vec.take(4); - access_parameter_ = vec.take(4); - radio_downlink_timeout_ = vec.take(4); - hyper_frame_cipher_key_flag_ = vec.take(1); + auto mainCarrier = vec.take<12>(); + auto frequency_band = vec.take<4>(); + auto offset = vec.take<2>(); + auto duplexSpacing = vec.take<3>(); + auto reverseOperation = vec.take<1>(); + number_secondary_control_channels_main_carrier_ = vec.take<2>(); + ms_txpwr_max_cell_ = vec.take<3>(); + rxlev_access_min_ = vec.take<4>(); + access_parameter_ = vec.take<4>(); + radio_downlink_timeout_ = vec.take<4>(); + hyper_frame_cipher_key_flag_ = vec.take<1>(); if (hyper_frame_cipher_key_flag_ == 0) { - hyper_frame_number_ = vec.take(16); + hyper_frame_number_ = vec.take<16>(); } else { - common_cipher_key_identifier_or_static_cipher_key_version_number_ = vec.take(16); + common_cipher_key_identifier_or_static_cipher_key_version_number_ = vec.take<16>(); } - auto optionalFieldFlag = vec.take(2); + auto optionalFieldFlag = vec.take<2>(); if (optionalFieldFlag == 0b00) { - *even_multi_frame_definition_for_ts_mode_ = vec.take(20); + *even_multi_frame_definition_for_ts_mode_ = vec.take<20>(); } else if (optionalFieldFlag == 0b01) { - *odd_multi_frame_definition_for_ts_mode_ = vec.take(20); + *odd_multi_frame_definition_for_ts_mode_ = vec.take<20>(); } else if (optionalFieldFlag == 0b10) { - defaults_for_access_code_a_.immediate_ = vec.take(4); - defaults_for_access_code_a_.waiting_time_ = vec.take(4); - defaults_for_access_code_a_.number_of_random_access_transmissions_on_up_link_ = vec.take(4); - defaults_for_access_code_a_.frame_length_factor_ = vec.take(1); - defaults_for_access_code_a_.timeslot_pointer_ = vec.take(4); - defaults_for_access_code_a_.minimum_pdu_priority_ = vec.take(3); + defaults_for_access_code_a_.immediate_ = vec.take<4>(); + defaults_for_access_code_a_.waiting_time_ = vec.take<4>(); + defaults_for_access_code_a_.number_of_random_access_transmissions_on_up_link_ = vec.take<4>(); + defaults_for_access_code_a_.frame_length_factor_ = vec.take<1>(); + defaults_for_access_code_a_.timeslot_pointer_ = vec.take<4>(); + defaults_for_access_code_a_.minimum_pdu_priority_ = vec.take<3>(); defaults_for_access_code_a_.system_info_ = true; } else if (optionalFieldFlag == 0b11) { - extended_service_broadcast_.security_information_ = vec.take(8); - extended_service_broadcast_.sdstl_addressing_method_ = vec.take(2); - extended_service_broadcast_.gck_supported_ = vec.take(1); - auto section = vec.take(2); + extended_service_broadcast_.security_information_ = vec.take<8>(); + extended_service_broadcast_.sdstl_addressing_method_ = vec.take<2>(); + extended_service_broadcast_.gck_supported_ = vec.take<1>(); + auto section = vec.take<2>(); if (section == 0b00) { - extended_service_broadcast_.data_priority_supported_ = vec.take(1); - extended_service_broadcast_.extended_advanced_links_and_max_ublck_supported_ = vec.take(1); - extended_service_broadcast_.qos_negotiation_supported_ = vec.take(1); - extended_service_broadcast_.d8psk_service_ = vec.take(1); - auto _sectionInformation = vec.take(3); + extended_service_broadcast_.data_priority_supported_ = vec.take<1>(); + extended_service_broadcast_.extended_advanced_links_and_max_ublck_supported_ = vec.take<1>(); + extended_service_broadcast_.qos_negotiation_supported_ = vec.take<1>(); + extended_service_broadcast_.d8psk_service_ = vec.take<1>(); + auto _sectionInformation = vec.take<3>(); extended_service_broadcast_.system_info_section_1_ = true; } else if (section == 0b01) { - extended_service_broadcast_.service_25Qam_ = vec.take(1); - extended_service_broadcast_.service_50Qam_ = vec.take(1); - extended_service_broadcast_.service_100Qam_ = vec.take(1); - extended_service_broadcast_.service_150Qam_ = vec.take(1); - auto _reserved = vec.take(3); + extended_service_broadcast_.service_25Qam_ = vec.take<1>(); + extended_service_broadcast_.service_50Qam_ = vec.take<1>(); + extended_service_broadcast_.service_100Qam_ = vec.take<1>(); + extended_service_broadcast_.service_150Qam_ = vec.take<1>(); + auto _reserved = vec.take<3>(); extended_service_broadcast_.system_info_section_2_ = true; } else { // TODO: Section 2 and 3 are reserved - auto _reserved = vec.take(7); + auto _reserved = vec.take<7>(); } extended_service_broadcast_.system_info_ = true; } @@ -263,7 +255,7 @@ void UpperMac::process_system_info_pdu(BitVector& vec) { // This element shall be present when the PDU is sent using π/8-D8PSK // modulation. This element shall not be present when the PDU is sent using // π/4-DQPSK modulation. - // auto reserved = vec.take(28); + // auto reserved = vec.take<28>(); mobile_link_entity_->service_DMle_system_info(vec); @@ -271,38 +263,38 @@ void UpperMac::process_system_info_pdu(BitVector& vec) { } void UpperMac::process_access_define_pdu(BitVector& vec) { - auto _ = vec.take(23); - auto optional_field_flag = vec.take(2); + auto _ = vec.take<23>(); + auto optional_field_flag = vec.take<2>(); if (optional_field_flag == 0b01) { - auto _subscriber_class_bitmap = vec.take(16); + auto _subscriber_class_bitmap = vec.take<16>(); } else if (optional_field_flag == 0b10) { - auto _gssi = vec.take(24); + auto _gssi = vec.take<24>(); } - auto _filter_bits = vec.take(3); + auto _filter_bits = vec.take<3>(); } void UpperMac::process_mac_usignal(BitVector& vec) { - second_slot_stolen_ = (vec.take(1) == 1); + second_slot_stolen_ = (vec.take<1>() == 1); // TODO: TM-SDU auto bits_left = vec.bits_left(); - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << "MAC U-SIGNAL" << std::endl; std::cout << " Second subslot is stolen: " << (second_slot_stolen_ ? "true" : "false") << std::endl; std::cout << " TM-SDU: size = " << std::to_string(tm_sdu.bits_left()) << ": " << tm_sdu << std::endl; } void UpperMac::process_mac_d_blck(BitVector& vec) { - auto fill_bit_indication = vec.take(1); - auto encrypted = vec.take(2); - auto event_label = vec.take(10); + auto fill_bit_indication = vec.take<1>(); + auto encrypted = vec.take<2>(); + auto event_label = vec.take<10>(); auto address = AddressType(); address.set_event_label(event_label); - auto immediate_napping_permission_flag = vec.take(1); - auto slot_granting_flag = vec.take(1); + auto immediate_napping_permission_flag = vec.take<1>(); + auto slot_granting_flag = vec.take<1>(); auto basic_slot_granting_element = 0; if (slot_granting_flag == 0b1) { - basic_slot_granting_element = vec.take(8); + basic_slot_granting_element = vec.take<8>(); } if (fill_bit_indication == 0b1) { @@ -310,7 +302,7 @@ void UpperMac::process_mac_d_blck(BitVector& vec) { } auto bits_left = vec.bits_left(); - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << "MAC D-BLCK" << std::endl; std::cout << " TM-SDU: size = " << std::to_string(tm_sdu.bits_left()) << ": " << tm_sdu << std::endl; std::cout << " Address: " << address << std::endl; @@ -319,19 +311,19 @@ void UpperMac::process_mac_d_blck(BitVector& vec) { } void UpperMac::process_mac_u_blck(BitVector& vec) { - auto fill_bit_indication = vec.take(1); - auto encrypted = vec.take(1); - auto event_label = vec.take(10); + auto fill_bit_indication = vec.take<1>(); + auto encrypted = vec.take<1>(); + auto event_label = vec.take<10>(); auto address = AddressType(); address.set_event_label(event_label); - auto reservation_requirement = vec.take(4); + auto reservation_requirement = vec.take<4>(); if (fill_bit_indication == 0b1) { remove_fill_bits(vec); } auto bits_left = vec.bits_left(); - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << "MAC U-BLCK" << std::endl; std::cout << " TM-SDU: size = " << std::to_string(tm_sdu.bits_left()) << ": " << tm_sdu << std::endl; std::cout << " encrypted: 0b" << std::bitset<1>(encrypted) << std::endl; @@ -342,14 +334,14 @@ void UpperMac::process_mac_u_blck(BitVector& vec) { } void UpperMac::process_mac_frag_downlink(BitVector& vec) { - auto fill_bit_indication = vec.take(1); + auto fill_bit_indication = vec.take<1>(); if (fill_bit_indication == 0b1) { remove_fill_bits(vec); } auto bits_left = vec.bits_left(); - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << "MAC FRAG" << std::endl; std::cout << " TM-SDU: size = " << std::to_string(tm_sdu.bits_left()) << ": " << tm_sdu << std::endl; @@ -357,14 +349,14 @@ void UpperMac::process_mac_frag_downlink(BitVector& vec) { } void UpperMac::process_mac_frag_uplink(BitVector& vec) { - auto fill_bit_indication = vec.take(1); + auto fill_bit_indication = vec.take<1>(); if (fill_bit_indication == 0b1) { remove_fill_bits(vec); } auto bits_left = vec.bits_left(); - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << "MAC FRAG" << std::endl; std::cout << " TM-SDU: size = " << std::to_string(tm_sdu.bits_left()) << ": " << tm_sdu << std::endl; @@ -376,61 +368,61 @@ void UpperMac::process_mac_end_downlink(BitVector& vec) { auto pre_processing_bit_count = vec.bits_left() + 3; - auto fill_bit_indication = vec.take(1); - auto position_of_grant = vec.take(1); - auto length_indictaion = vec.take(6); + auto fill_bit_indication = vec.take<1>(); + auto position_of_grant = vec.take<1>(); + auto length_indictaion = vec.take<6>(); // The immediate napping permission flag shall be present when the PDU is sent // using π/8-D8PSK or QAM modulation. It shall not be present when the PDU is - // sent using π/4-DQPSK modulation. auto immediateNapping = vec.take(1); - auto slot_granting_flag = vec.take(1); + // sent using π/4-DQPSK modulation. auto immediateNapping = vec.take<1>(); + auto slot_granting_flag = vec.take<1>(); // The multiple slot granting flag shall be present when the slot granting // flag is set to 1 and the PDU is sent using QAM modulation. It shall not be // present when the slot granting flag is set to 0 or the PDU is sent using - // π/4-DQPSK or π/8-D8PSK modulation auto multipleSlotGranting = vec.take(1); + // π/4-DQPSK or π/8-D8PSK modulation auto multipleSlotGranting = vec.take<1>(); // The basic slot granting element shall be present when the slot granting // flag is set to 1 and either the PDU is sent using π/4-DQPSK or π/8-D8PSK // modulation, or the PDU is sent using QAM modulation and the multiple slot // granting flag is set to 0. auto basic_slot_granting_element = 0; if (slot_granting_flag == 0b1) { - basic_slot_granting_element = vec.take(8); + basic_slot_granting_element = vec.take<8>(); } - auto channel_allocation_flag = vec.take(1); + auto channel_allocation_flag = vec.take<1>(); if (channel_allocation_flag == 0b1) { - auto channel_allocation1 = vec.take(22); - auto extended_carrier_numbering_flag = vec.take(1); + auto channel_allocation1 = vec.take<22>(); + auto extended_carrier_numbering_flag = vec.take<1>(); if (extended_carrier_numbering_flag == 0b1) { - auto channel_allocation2 = vec.take(9); + auto channel_allocation2 = vec.take<9>(); } - auto monitoring_pattern = vec.take(2); + auto monitoring_pattern = vec.take<2>(); if (monitoring_pattern == 0b00) { - auto frame18_monitoring_pattern = vec.take(2); - auto up_downlink_assigned_for_augmented_channel_allocation = vec.take(2); - auto bandwidth_of_allocated_channel = vec.take(3); - auto modulation_mode_of_allocated_channel = vec.take(3); + auto frame18_monitoring_pattern = vec.take<2>(); + auto up_downlink_assigned_for_augmented_channel_allocation = vec.take<2>(); + auto bandwidth_of_allocated_channel = vec.take<3>(); + auto modulation_mode_of_allocated_channel = vec.take<3>(); if (modulation_mode_of_allocated_channel == 0b010) { - auto maximum_uplink_qam_modulation_level = vec.take(3); - auto reserved = vec.take(3); + auto maximum_uplink_qam_modulation_level = vec.take<3>(); + auto reserved = vec.take<3>(); } - auto channel_allocation3 = vec.take(12); - auto napping_status = vec.take(2); + auto channel_allocation3 = vec.take<12>(); + auto napping_status = vec.take<2>(); if (napping_status == 0b01) { - auto napping_information = vec.take(11); + auto napping_information = vec.take<11>(); } - auto reserved = vec.take(4); + auto reserved = vec.take<4>(); // taking optional element a - auto conditional_element_a_flag = vec.take(1); + auto conditional_element_a_flag = vec.take<1>(); if (conditional_element_a_flag == 0b1) { - auto conditional_element_a = vec.take(16); + auto conditional_element_a = vec.take<16>(); } // taking optional element b - auto conditional_element_b_flag = vec.take(1); + auto conditional_element_b_flag = vec.take<1>(); if (conditional_element_b_flag == 0b1) { - auto conditional_element_b = vec.take(16); + auto conditional_element_b = vec.take<16>(); } - auto further_augmentation_flag = vec.take(1); + auto further_augmentation_flag = vec.take<1>(); } } @@ -441,7 +433,7 @@ void UpperMac::process_mac_end_downlink(BitVector& vec) { remove_fill_bits(vec); } - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << "MAC END" << std::endl; std::cout << " length_indictaion: 0b" << std::bitset<6>(length_indictaion) << std::endl; std::cout << " TM-SDU: size = " << std::to_string(bits_left) << ": " << tm_sdu << std::endl; @@ -453,8 +445,8 @@ void UpperMac::process_mac_end_downlink(BitVector& vec) { void UpperMac::process_mac_end_uplink(BitVector& vec) { auto pre_processing_bit_count = vec.bits_left() + 3; - auto fill_bit_indication = vec.take(1); - auto length_indictaion = vec.take(6); + auto fill_bit_indication = vec.take<1>(); + auto length_indictaion = vec.take<6>(); auto mac_header_length = pre_processing_bit_count - vec.bits_left(); auto bits_left = length_indictaion * 8 - mac_header_length; @@ -463,7 +455,7 @@ void UpperMac::process_mac_end_uplink(BitVector& vec) { remove_fill_bits(vec); } - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << "MAC END" << std::endl; std::cout << " length_indictaion: 0b" << std::bitset<6>(length_indictaion) << std::endl; std::cout << " TM-SDU: size = " << std::to_string(bits_left) << ": " << tm_sdu << std::endl; @@ -477,17 +469,17 @@ void UpperMac::process_mac_resource(BitVector& vec) { auto preprocessing_bit_count = vec.bits_left() + 2; - auto fill_bit_indication = vec.take(1); - auto position_of_grant = vec.take(1); - auto encryption_mode = vec.take(2); - auto random_access_flag = vec.take(1); - auto length_indictaion = vec.take(6); + auto fill_bit_indication = vec.take<1>(); + auto position_of_grant = vec.take<1>(); + auto encryption_mode = vec.take<2>(); + auto random_access_flag = vec.take<1>(); + auto length_indictaion = vec.take<6>(); if (length_indictaion == 0b111110 || length_indictaion == 0b111111) { second_slot_stolen_ = true; } std::cout << " Second subslot is stolen: " << (second_slot_stolen_ ? "true" : "false") << std::endl; std::cout << " length_indictaion: 0b" << std::bitset<6>(length_indictaion) << std::endl; - auto address_type = vec.take(3); + auto address_type = vec.take<3>(); auto address = AddressType(); std::cout << " address_type: 0b" << std::bitset<3>(address_type) << std::endl; if (address_type == 0b000) { @@ -503,84 +495,84 @@ void UpperMac::process_mac_resource(BitVector& vec) { // << std::endl; return; } else if (address_type == 0b001) { - address.set_ssi(vec.take(24)); + address.set_ssi(vec.take<24>()); } else if (address_type == 0b010) { - address.set_event_label(vec.take(10)); + address.set_event_label(vec.take<10>()); } else if (address_type == 0b011) { - address.set_ussi(vec.take(24)); + address.set_ussi(vec.take<24>()); } else if (address_type == 0b100) { - address.set_smi(vec.take(24)); + address.set_smi(vec.take<24>()); } else if (address_type == 0b101) { - address.set_ssi(vec.take(24)); - address.set_event_label(vec.take(10)); + address.set_ssi(vec.take<24>()); + address.set_event_label(vec.take<10>()); } else if (address_type == 0b110) { - address.set_ssi(vec.take(24)); - address.set_usage_marker(vec.take(6)); + address.set_ssi(vec.take<24>()); + address.set_usage_marker(vec.take<6>()); } else if (address_type == 0b111) { - address.set_smi(vec.take(24)); - address.set_event_label(vec.take(10)); + address.set_smi(vec.take<24>()); + address.set_event_label(vec.take<10>()); } // The immediate napping permission flag shall be present when the PDU is sent // using π/8-D8PSK or QAM modulation. It shall not be present when the PDU is // sent using π/4-DQPSK modulation. auto immediateNappingPermisionFlag = - // vec.take(1); - auto power_control_flag = vec.take(1); + // vec.take<1>(); + auto power_control_flag = vec.take<1>(); if (power_control_flag == 0b1) { - auto power_control_element = vec.take(4); + auto power_control_element = vec.take<4>(); } - auto slot_granting_flag = vec.take(1); + auto slot_granting_flag = vec.take<1>(); // The multiple slot granting flag shall be present when the slot granting // flag is set to 1 and the PDU is sent using QAM modulation. It shall not be // present when the slot granting flag is set to 0 or the PDU is sent using // π/4-DQPSK or π/8-D8PSK modulation. auto multipleSlotGrantingFlag = - // vec.take(1); The basic slot granting element shall be present when the slot + // vec.take<1>(); The basic slot granting element shall be present when the slot // granting flag is set to 1 and either the PDU is sent using π/4-DQPSK or // π/8-D8PSK modulation, or the PDU is sent using QAM modulation and the // multiple slot granting flag is set to 0. if (slot_granting_flag == 0b1) { - auto basic_slot_granting_element = vec.take(8); + auto basic_slot_granting_element = vec.take<8>(); } - auto channel_allocation_flag = vec.take(1); + auto channel_allocation_flag = vec.take<1>(); std::cout << " channel_allocation_flag = 0b" << std::bitset<1>(channel_allocation_flag) << std::endl; if (channel_allocation_flag == 0b1) { - auto allocation_type = vec.take(2); - auto time_slot_assigned = vec.take(4); - auto up_downlink_assigned = vec.take(2); - auto clch_permission = vec.take(1); - auto cell_change_flag = vec.take(1); - auto carrier_number = vec.take(12); - auto extended_carrier_numbering_flag = vec.take(1); + auto allocation_type = vec.take<2>(); + auto time_slot_assigned = vec.take<4>(); + auto up_downlink_assigned = vec.take<2>(); + auto clch_permission = vec.take<1>(); + auto cell_change_flag = vec.take<1>(); + auto carrier_number = vec.take<12>(); + auto extended_carrier_numbering_flag = vec.take<1>(); if (extended_carrier_numbering_flag == 0b1) { - auto channel_allocation_2 = vec.take(10); + auto channel_allocation_2 = vec.take<10>(); } - auto monitoring_pattern = vec.take(2); + auto monitoring_pattern = vec.take<2>(); if (monitoring_pattern == 0b00) { - auto frame18_monitoring_pattern = vec.take(2); + auto frame18_monitoring_pattern = vec.take<2>(); } if (up_downlink_assigned == 0b00) { - auto up_downlink_assigned_for_augmented_channel_allocation = vec.take(2); - auto bandwidth_of_allocated_channel = vec.take(3); - auto modulation_mode_of_allocated_channel = vec.take(3); + auto up_downlink_assigned_for_augmented_channel_allocation = vec.take<2>(); + auto bandwidth_of_allocated_channel = vec.take<3>(); + auto modulation_mode_of_allocated_channel = vec.take<3>(); if (modulation_mode_of_allocated_channel == 0b010) { - auto maximumUplinkQamModulationLevel = vec.take(3); + auto maximumUplinkQamModulationLevel = vec.take<3>(); } else { - auto reserved = vec.take(3); + auto reserved = vec.take<3>(); } - auto channel_allocation3 = vec.take(12); - auto napping_status = vec.take(2); + auto channel_allocation3 = vec.take<12>(); + auto napping_status = vec.take<2>(); if (napping_status == 0b01) { - auto napping_information = vec.take(11); + auto napping_information = vec.take<11>(); } - auto reserved = vec.take(4); - auto conditional_element_a_flag = vec.take(1); + auto reserved = vec.take<4>(); + auto conditional_element_a_flag = vec.take<1>(); if (conditional_element_a_flag == 0b1) { - auto conditional_element_a = vec.take(16); + auto conditional_element_a = vec.take<16>(); } - auto conditional_element_b_flag = vec.take(1); + auto conditional_element_b_flag = vec.take<1>(); if (conditional_element_b_flag == 0b1) { - auto conditional_element_b = vec.take(16); + auto conditional_element_b = vec.take<16>(); } - auto further_augmentation_flag = vec.take(1); + auto further_augmentation_flag = vec.take<1>(); } } @@ -607,7 +599,7 @@ void UpperMac::process_mac_resource(BitVector& vec) { bits_left = vec.bits_left(); } - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << " TM-SDU: size = " << std::to_string(bits_left) << ": " << tm_sdu << std::endl; std::cout << " mac_header_length = " << std::to_string(mac_header_length) << std::endl; std::cout << " fill_bit_indication: 0b" << std::bitset<1>(fill_bit_indication) << std::endl; @@ -625,29 +617,29 @@ void UpperMac::process_mac_resource(BitVector& vec) { void UpperMac::process_mac_data(BitVector& vec) { auto preprocessing_bit_count = vec.bits_left() + 2; - auto fill_bit_indication = vec.take(1); - auto encrypted_flag = vec.take(1); - auto address_type = vec.take(2); + auto fill_bit_indication = vec.take<1>(); + auto encrypted_flag = vec.take<1>(); + auto address_type = vec.take<2>(); std::cout << "MAC DATA" << std::endl; std::cout << " encrypted: 0b" << std::bitset<1>(encrypted_flag) << std::endl; auto address = AddressType(); if (address_type == 0b00) { - address.set_ssi(vec.take(24)); + address.set_ssi(vec.take<24>()); } else if (address_type == 0b01) { - address.set_event_label(vec.take(10)); + address.set_event_label(vec.take<10>()); } else if (address_type == 0b11) { - address.set_ussi(vec.take(24)); + address.set_ussi(vec.take<24>()); } else if (address_type == 0b11) { - address.set_smi(vec.take(24)); + address.set_smi(vec.take<24>()); } - auto length_indication_or_capacity_request = vec.take(1); + auto length_indication_or_capacity_request = vec.take<1>(); auto fragmentation = false; uint64_t length_indication{}; if (length_indication_or_capacity_request == 0b0) { - length_indication = vec.take(6); + length_indication = vec.take<6>(); std::cout << " length indication: 0b" << std::bitset<6>(length_indication) << std::endl; if (length_indication == 0b111110) { std::cout << " Second half slot stolen on STCH" << std::endl; @@ -659,12 +651,12 @@ void UpperMac::process_mac_data(BitVector& vec) { fragmentation = true; } } else { - auto fragmentation_flag = vec.take(1); + auto fragmentation_flag = vec.take<1>(); if (fragmentation_flag == 0b1) { fragmentation = true; } - auto reservation_requirement = vec.take(4); - auto reserved = vec.take(1); + auto reservation_requirement = vec.take<4>(); + auto reserved = vec.take<1>(); if (reservation_requirement == 0b0000) { last_address_type_end_hu_ = address; @@ -687,7 +679,7 @@ void UpperMac::process_mac_data(BitVector& vec) { } } - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << " TM-SDU: size = " << std::to_string(tm_sdu.bits_left()) << ": " << tm_sdu << std::endl; std::cout << " Address: " << address << std::endl; @@ -705,38 +697,38 @@ void UpperMac::process_mac_access(BitVector& vec) { auto preprocessing_bit_count = vec.bits_left() + 2; std::cout << "MAC-ACCESS" << std::endl; - auto encrypted_flag = vec.take(1); - auto address_type = vec.take(2); + auto encrypted_flag = vec.take<1>(); + auto address_type = vec.take<2>(); std::cout << " encrypted: 0b" << std::bitset<1>(encrypted_flag) << std::endl; auto address = AddressType(); if (address_type == 0b00) { - address.set_ssi(vec.take(24)); + address.set_ssi(vec.take<24>()); } else if (address_type == 0b01) { - address.set_event_label(vec.take(10)); + address.set_event_label(vec.take<10>()); } else if (address_type == 0b11) { - address.set_ussi(vec.take(24)); + address.set_ussi(vec.take<24>()); } else if (address_type == 0b11) { - address.set_smi(vec.take(24)); + address.set_smi(vec.take<24>()); } - auto optional_field_flag = vec.take(1); + auto optional_field_flag = vec.take<1>(); uint64_t length_indication{}; uint64_t length_indication_or_capacity_request{}; auto fragmentation = false; if (optional_field_flag == 0b1) { - length_indication_or_capacity_request = vec.take(1); + length_indication_or_capacity_request = vec.take<1>(); if (length_indication_or_capacity_request == 0b0) { - length_indication = vec.take(5); + length_indication = vec.take<5>(); std::cout << " length indication: 0b" << std::bitset<5>(length_indication) << std::endl; } else { - auto fragmentation_flag = vec.take(1); + auto fragmentation_flag = vec.take<1>(); if (fragmentation_flag == 0b1) { fragmentation = true; } - auto reservation_requirement = vec.take(4); + auto reservation_requirement = vec.take<4>(); if (reservation_requirement == 0b0000) { last_address_type_end_hu_ = address; @@ -754,7 +746,7 @@ void UpperMac::process_mac_access(BitVector& vec) { bits_left = length_indication * 8 - mac_header_length; } - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << " TM-SDU: size = " << std::to_string(tm_sdu.bits_left()) << ": " << tm_sdu << std::endl; std::cout << " Address: " << address << std::endl; @@ -769,14 +761,14 @@ void UpperMac::process_mac_end_hu(BitVector& vec) { auto preprocessing_bit_count = vec.bits_left() + 2; std::cout << "MAC-END-HU" << std::endl; - auto length_indictaion_or_capacity_request = vec.take(1); + auto length_indictaion_or_capacity_request = vec.take<1>(); uint64_t length_indictaion; if (length_indictaion_or_capacity_request == 0b0) { // TODO: parse this - length_indictaion = vec.take(4); + length_indictaion = vec.take<4>(); std::cout << " length indication: 0b" << std::bitset<4>(length_indictaion) << std::endl; } else { - auto reservation_requirement = vec.take(4); + auto reservation_requirement = vec.take<4>(); std::cout << " reservation requirement: 0b" << std::bitset<4>(reservation_requirement) << std::endl; } @@ -787,7 +779,7 @@ void UpperMac::process_mac_end_hu(BitVector& vec) { bits_left = length_indictaion * 8 - mac_header_length; } - auto tm_sdu = BitVector(vec.take_vector(bits_left), bits_left); + auto tm_sdu = vec.take_vector(bits_left); std::cout << " TM-SDU: size = " << std::to_string(tm_sdu.bits_left()) << ": " << tm_sdu << std::endl; // XXX: implement combination of uplink and downlink std::cout << " Last fragment sent on reserved subslot. Cannot process! Taking the last MAC-ACCESS or MAC-DATA as " @@ -801,7 +793,7 @@ void UpperMac::process_mac_end_hu(BitVector& vec) { void UpperMac::remove_fill_bits(BitVector& vec) { if (remove_fill_bits_) { - while (vec.take_last() == 0b0) + while (vec.take_last<1>() == 0b0) ; } remove_fill_bits_ = false; diff --git a/src/l2/upper_mac_fragmentation.cpp b/src/l2/upper_mac_fragmentation.cpp index 880c9a6..b0b1cc2 100644 --- a/src/l2/upper_mac_fragmentation.cpp +++ b/src/l2/upper_mac_fragmentation.cpp @@ -1,3 +1,4 @@ +#include "utils/bit_vector.hpp" #include void UpperMac::fragmentation_start_burst() { @@ -86,7 +87,7 @@ void UpperMac::fragmentation_end_burst() { } void UpperMac::fragmentation_push_tm_sdu_start(const AddressType address_type, BitVector& vec) { - fragment_map_[address_type] = std::vector({vec}); + fragment_map_[address_type] = std::vector({BitVector(vec)}); last_address_type_ = address_type; fragment_list_.clear(); std::cout << "MAC frag start inserting Address: " << address_type << std::endl; diff --git a/src/l3/circuit_mode_control_entity.cpp b/src/l3/circuit_mode_control_entity.cpp index 055a0ff..cd01708 100644 --- a/src/l3/circuit_mode_control_entity.cpp +++ b/src/l3/circuit_mode_control_entity.cpp @@ -1,4 +1,3 @@ -#include #include #include @@ -30,7 +29,7 @@ void CircuitModeControlEntity::process(bool is_downlink, const AddressType addre "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "CMCE FUNCTION NOT SUPPORTED"}; - auto pdu_type = vec.take(5); + auto pdu_type = vec.take<5>(); if (is_downlink) { std::cout << "CMCE " << cmce_downlink_pdu[pdu_type] << std::endl; @@ -54,25 +53,25 @@ void CircuitModeControlEntity::process(bool is_downlink, const AddressType addre } void CircuitModeControlEntity::process_d_sds_data(const AddressType to_address, BitVector& vec) { - auto calling_party_type_identifier = vec.take(2); + auto calling_party_type_identifier = vec.take<2>(); AddressType from_address; if (calling_party_type_identifier == 1 || calling_party_type_identifier == 2) { - from_address.set_ssi(vec.take(24)); + from_address.set_ssi(vec.take<24>()); } if (calling_party_type_identifier == 2) { - from_address.set_country_code(vec.take(10)); - from_address.set_network_code(vec.take(14)); + from_address.set_country_code(vec.take<10>()); + from_address.set_network_code(vec.take<14>()); } - auto short_data_type_identifier = vec.take(2); + auto short_data_type_identifier = vec.take<2>(); std::cout << " Address: " << from_address << std::endl; - std::cout << " short_data_type_identifier: " << short_data_type_identifier << std::endl; + std::cout << " short_data_type_identifier: " << static_cast(short_data_type_identifier) << std::endl; if (short_data_type_identifier == 3) { - auto length_identifier = vec.take(11); - std::cout << " length_identifier: " << length_identifier << std::endl; + auto length_identifier = vec.take<11>(); + std::cout << " length_identifier: " << static_cast(length_identifier) << std::endl; /// XXX: we do not account for the length identifier. External subscriber number or DM-MS address could be /// present here. The problem is that the fragmentation is somehow broken, we do not know the reason yet. // auto sds = BitVector(vec.take_vector(length_identifier), length_identifier); @@ -86,29 +85,29 @@ void CircuitModeControlEntity::process_d_sds_data(const AddressType to_address, } void CircuitModeControlEntity::process_u_sds_data(const AddressType from_address, BitVector& vec) { - auto area_selection = vec.take(4); - auto calling_party_type_identifier = vec.take(2); + auto area_selection = vec.take<4>(); + auto calling_party_type_identifier = vec.take<2>(); AddressType to_address; if (calling_party_type_identifier == 0) { - to_address.set_sna(vec.take(8)); + to_address.set_sna(vec.take<8>()); } if (calling_party_type_identifier == 1 || calling_party_type_identifier == 2) { - to_address.set_ssi(vec.take(24)); + to_address.set_ssi(vec.take<24>()); } if (calling_party_type_identifier == 2) { - to_address.set_country_code(vec.take(10)); - to_address.set_network_code(vec.take(14)); + to_address.set_country_code(vec.take<10>()); + to_address.set_network_code(vec.take<14>()); } - auto short_data_type_identifier = vec.take(2); + auto short_data_type_identifier = vec.take<2>(); std::cout << " Address: " << to_address << std::endl; - std::cout << " short_data_type_identifier: " << short_data_type_identifier << std::endl; + std::cout << " short_data_type_identifier: " << static_cast(short_data_type_identifier) << std::endl; if (short_data_type_identifier == 3) { - auto length_identifier = vec.take(11); - std::cout << " length_identifier: " << length_identifier << std::endl; + auto length_identifier = vec.take<11>(); + std::cout << " length_identifier: " << static_cast(length_identifier) << std::endl; /// XXX: we do not account for the length identifier. External subscriber number or DM-MS address could be /// present here. The problem is that the fragmentation is somehow broken, we do not know the reason yet. // auto sds = BitVector(vec.take_vector(length_identifier), length_identifier); diff --git a/src/l3/mobile_link_entity.cpp b/src/l3/mobile_link_entity.cpp index e3213e2..c91c7aa 100644 --- a/src/l3/mobile_link_entity.cpp +++ b/src/l3/mobile_link_entity.cpp @@ -7,21 +7,21 @@ void MobileLinkEntity::service_DMle_system_info(BitVector& vec) { assert(vec.bits_left() == 42); // Location area (14) - location_area_ = vec.take(14); + location_area_ = vec.take<14>(); // Subscriber class (16) - subscriber_class_ = vec.take(16); + subscriber_class_ = vec.take<16>(); // BS service details (12) - registration_ = vec.take(1); - deregistration_ = vec.take(1); - priority_cell_ = vec.take(1); - minimum_mode_service_ = vec.take(1); - migration_ = vec.take(1); - system_wide_service_ = vec.take(1); - tetra_voice_service_ = vec.take(1); - circuit_mode_data_service_ = vec.take(1); - sndcp_service_ = vec.take(1); - air_interface_encryption_service_ = vec.take(1); - advanced_link_supported_ = vec.take(1); + registration_ = vec.take<1>(); + deregistration_ = vec.take<1>(); + priority_cell_ = vec.take<1>(); + minimum_mode_service_ = vec.take<1>(); + migration_ = vec.take<1>(); + system_wide_service_ = vec.take<1>(); + tetra_voice_service_ = vec.take<1>(); + circuit_mode_data_service_ = vec.take<1>(); + sndcp_service_ = vec.take<1>(); + air_interface_encryption_service_ = vec.take<1>(); + advanced_link_supported_ = vec.take<1>(); system_info_received_ = true; @@ -38,7 +38,7 @@ void MobileLinkEntity::service_user_pdu(const AddressType address, BitVector& ve "TETRA management entity protocol", "Reserved for testing"}; - auto pdu_type = vec.take(3); + auto pdu_type = vec.take<3>(); std::cout << "MLE " << mle_pdu[pdu_type] << " " << vec << std::endl; @@ -87,7 +87,7 @@ void MobileLinkEntity::service_data_pdu(const AddressType address, BitVector& ve "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", "Reserved", }; - auto pdu_type = vec.take(3); + auto pdu_type = vec.take<3>(); std::cout << " " << mle_uplink_pdu_type[pdu_type] << " or " << mle_downlink_pdu_type[pdu_type] << std::endl; std::cout << " " << vec << std::endl; diff --git a/src/l3/mobile_management.cpp b/src/l3/mobile_management.cpp index 6220d16..f3026f1 100644 --- a/src/l3/mobile_management.cpp +++ b/src/l3/mobile_management.cpp @@ -38,7 +38,7 @@ void MobileManagement::process(bool is_downlink, const AddressType address, BitV "Reserved", "MM PDU/FUNCTION NOT SUPPORTED"}; - auto pdu_type = vec.take(4); + auto pdu_type = vec.take<4>(); if (is_downlink) { std::cout << "MM " << mm_downlink_pdu[pdu_type] << std::endl; diff --git a/src/l3/short_data_service.cpp b/src/l3/short_data_service.cpp index bbf1fac..f79e4c9 100644 --- a/src/l3/short_data_service.cpp +++ b/src/l3/short_data_service.cpp @@ -13,7 +13,7 @@ void ShortDataService::process(const AddressType to_address, const AddressType f message_["to"] = to_address; message_["from"] = from_address; - auto protocol_identifier = vec.take(8); + uint8_t protocol_identifier = vec.take<8>(); message_["protocol_identifier"] = protocol_identifier; @@ -21,18 +21,17 @@ void ShortDataService::process(const AddressType to_address, const AddressType f std::cout << " From: " << from_address << "To: " << to_address << std::endl; { - auto vec_copy = BitVector(); - vec_copy.append(vec); + auto vec_copy = BitVector(vec); message_["data"] = nlohmann::json::array(); for (uint64_t bits; vec_copy.bits_left() >= 8;) { - bits = vec_copy.take(8); + bits = vec_copy.take<8>(); message_["data"].push_back(bits); } message_["bits_in_last_byte"] = vec_copy.bits_left(); - message_["data"].push_back(vec_copy.take(vec_copy.bits_left())); + message_["data"].push_back(vec_copy.take_all()); } switch (protocol_identifier) { @@ -54,7 +53,7 @@ void ShortDataService::process_default(const AddressType to_address, const Addre std::stringstream stream; for (uint64_t bits; vec.bits_left() >= 8;) { - bits = vec.take(8); + bits = vec.take<8>(); stream << " " << std::hex << std::setw(2) << std::setfill('0') << bits; } @@ -64,12 +63,12 @@ void ShortDataService::process_default(const AddressType to_address, const Addre void ShortDataService::process_simple_text_messaging(const AddressType to_address, const AddressType from_address, BitVector& vec) { - auto reserved = vec.take(1); - auto text_coding_scheme = vec.take(7); + auto reserved = vec.take<1>(); + auto text_coding_scheme = vec.take<7>(); std::stringstream stream; for (uint64_t bits; vec.bits_left() >= 8;) { - bits = vec.take(8); + bits = vec.take<8>(); stream << " " << std::hex << std::setw(2) << std::setfill('0') << bits; } @@ -138,18 +137,18 @@ static auto decode_direction_of_travel(uint64_t v) -> std::string { void ShortDataService::process_location_information_protocol(const AddressType to_address, const AddressType from_address, BitVector& vec) { - auto pdu_type = vec.take(2); + auto pdu_type = vec.take<2>(); if (pdu_type == 0b00) { // Short location report - auto time_elapsed = vec.take(2); - auto longitude = decode_longitude(vec.take(25)); - auto latitude = decode_latitude(vec.take(24)); - auto position_error = decode_position_error(vec.take(3)); - auto horizontal_velocity = decode_horizontal_velocity(vec.take(7)); - auto direction_of_travel = decode_direction_of_travel(vec.take(4)); - auto type_of_addition_data = vec.take(1); - auto additional_data = vec.take(8); + auto time_elapsed = vec.take<2>(); + auto longitude = decode_longitude(vec.take<25>()); + auto latitude = decode_latitude(vec.take<24>()); + auto position_error = decode_position_error(vec.take<3>()); + auto horizontal_velocity = decode_horizontal_velocity(vec.take<7>()); + auto direction_of_travel = decode_direction_of_travel(vec.take<4>()); + auto type_of_addition_data = vec.take<1>(); + auto additional_data = vec.take<8>(); std::cout << " Short Location Report" << std::endl; std::cout << " Time elapsed: " << std::bitset<2>(time_elapsed) << " Lon: " << longitude << " Lat: " << latitude << " Position error: " << position_error << " horizontal_velocity: " << horizontal_velocity @@ -158,7 +157,7 @@ void ShortDataService::process_location_information_protocol(const AddressType t << " additional_data: " << std::bitset<8>(additional_data) << std::endl; } else if (pdu_type == 0b01) { // Location protocol PDU with extension - auto pdu_type_extension = vec.take(4); + auto pdu_type_extension = vec.take<4>(); std::cout << " Location Information Protocol extension: 0b" << std::bitset<4>(pdu_type_extension) << std::endl; } else { // reserved diff --git a/src/utils/bit_vector.cpp b/src/utils/bit_vector.cpp index 6656ab9..8ed3562 100644 --- a/src/utils/bit_vector.cpp +++ b/src/utils/bit_vector.cpp @@ -7,9 +7,12 @@ * Tassilo Tanneberger */ -#include +#include +#include +#include #include #include +#include #include #include @@ -21,7 +24,7 @@ auto BitVector::compute_fcs() -> uint32_t { } for (auto i = 0; i < len_; i++) { - uint8_t bit = (data_[read_offset_ + i] ^ (crc >> 31)) & 1; + bool bit = (static_cast(data_[read_offset_ + i]) ^ (crc >> 31)) & 1; crc <<= 1; if (bit) { crc = crc ^ 0x04C11DB7; @@ -30,88 +33,59 @@ auto BitVector::compute_fcs() -> uint32_t { return ~crc; } -auto BitVector::take_vector(const size_t numberBits) -> const uint8_t* const { - if (numberBits > bits_left()) { - throw std::runtime_error(std::to_string(numberBits) + " bits not left in BitVec (" + - std::to_string(bits_left()) + ")"); - } - - auto res = data_.data() + read_offset_; - - // delete first n entries - read_offset_ += numberBits; - len_ -= numberBits; - - return res; -} - -auto BitVector::take_last_vector(const size_t numberBits) -> const uint8_t* const { - if (numberBits > bits_left()) { - throw std::runtime_error(std::to_string(numberBits) + " bits not left in BitVec (" + - std::to_string(bits_left()) + ")"); - } - - auto res = data_.data() + bits_left() - numberBits; - - // take from the back - len_ -= numberBits; - - return res; -} - void BitVector::append(const BitVector& other) { // actually need to do a copy here! if (read_offset_ > 0) { // copy to front - std::memcpy(data_.data(), data_.data() + read_offset_, sizeof(uint8_t) * len_); + data_ = std::vector(data_.begin() + read_offset_, data_.begin() + read_offset_ + len_); read_offset_ = 0; } // shrink the size data_.resize(len_); // copy in other - data_.resize(len_ + other.len_); - std::memcpy(data_.data() + len_, other.data_.data() + other.read_offset_, sizeof(uint8_t) * other.len_); + data_.insert(data_.end(), other.data_.begin() + other.read_offset_, + other.data_.begin() + other.read_offset_ + other.len_); len_ += other.len_; } -auto BitVector::take(const size_t numberBits) -> uint64_t { - auto bits = take_vector(numberBits); - - uint64_t ret = 0; +auto BitVector::take_vector(std::size_t number_bits) -> BitVector { + const auto bits = data_.begin() + read_offset_; - for (auto i = 0; i < numberBits; i++) { - if (i != 0) - ret <<= 1; - ret |= (bits[i] & 0x1); + if (number_bits > bits_left()) { + throw std::runtime_error(std::to_string(number_bits) + " bits not left in BitVec (" + + std::to_string(bits_left()) + ")"); } - return ret; -} + // delete all entries + read_offset_ += number_bits; + len_ -= number_bits; -auto BitVector::take_last(const size_t numberBits) -> uint64_t { - auto bits = take_last_vector(numberBits); + return BitVector(std::vector(bits, bits + number_bits)); +} - uint64_t ret = 0; +auto BitVector::take_all() -> uint64_t { + const auto bits = data_.begin() + read_offset_; + const auto len = bits_left(); - for (auto i = 0; i < numberBits; i++) { - if (i != 0) - ret <<= 1; - ret |= (bits[i] & 0x1); + if (len > 64) { + throw std::runtime_error("Can only extract 64 bits remaining bits from BitVec, but it contains " + + std::to_string(len) + "."); } - return ret; -} + // delete all entries + read_offset_ += len; + len_ -= len; -auto BitVector::take_last() -> uint8_t { - if (1 > bits_left()) { - throw std::runtime_error("1 bit not left in BitVec (" + std::to_string(bits_left()) + ")"); - } + auto ret = static_cast(bits[0]); - len_ -= 1; + for (std::size_t i = 1; i < len; i++) { + ret <<= 1; + ret |= static_cast(bits[i]); + } - return data_[read_offset_ + len_]; -} + return ret; +}; auto BitVector::is_mac_padding() const noexcept -> bool { if (len_ == 0) diff --git a/src/utils/viter_bi_codec.cpp b/src/utils/viter_bi_codec.cpp index beaf7c1..c6bd1b5 100644 --- a/src/utils/viter_bi_codec.cpp +++ b/src/utils/viter_bi_codec.cpp @@ -9,7 +9,7 @@ #include -std::vector ViterbiCodec::Decode(const std::vector& bits) const { +auto ViterbiCodec::Decode(const std::vector& bits) const -> std::vector { auto vitdec = ViterbiDecoder_Core(branch_table, config); using Decoder = ViterbiDecoder_SSE_u16;