| 
									
										
										
										
											2022-07-20 09:07:00 +02:00
										 |  |  | // Copyright 2021 Mobilinkd LLC.
 | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-06 07:01:42 +02:00
										 |  |  | #include <QDebug>
 | 
					
						
							|  |  |  | #include <QString>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | #include "M17Randomizer.h"
 | 
					
						
							|  |  |  | #include "PolynomialInterleaver.h"
 | 
					
						
							|  |  |  | #include "Trellis.h"
 | 
					
						
							|  |  |  | #include "Viterbi.h"
 | 
					
						
							|  |  |  | #include "CRC16.h"
 | 
					
						
							|  |  |  | #include "LinkSetupFrame.h"
 | 
					
						
							|  |  |  | #include "Golay24.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <algorithm>
 | 
					
						
							|  |  |  | #include <array>
 | 
					
						
							|  |  |  | #include <cstddef>
 | 
					
						
							|  |  |  | #include <functional>
 | 
					
						
							|  |  |  | #include <iostream>
 | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  | #include <iomanip>
 | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-04 23:03:07 +02:00
										 |  |  | namespace modemm17 | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <typename C, size_t N> | 
					
						
							| 
									
										
										
										
											2022-07-06 07:01:42 +02:00
										 |  |  | QString dump(const std::array<C,N>& data, char header = 'D') | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-07-06 07:01:42 +02:00
										 |  |  |     QString s(header); | 
					
						
							|  |  |  |     s += "="; | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (auto c : data) { | 
					
						
							| 
									
										
										
										
											2022-07-06 07:01:42 +02:00
										 |  |  |         s += QString("%1 ").arg((int) c, 2, 16, QChar('0')); | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-06 07:01:42 +02:00
										 |  |  |     return s; | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct M17FrameDecoder | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-07-27 23:38:35 +02:00
										 |  |  |     static const size_t MAX_LICH_FRAGMENT = 5; | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-31 04:54:39 +02:00
										 |  |  |     M17Randomizer derandomize_; | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  |     PolynomialInterleaver<45, 92, 368> interleaver_; | 
					
						
							|  |  |  |     Trellis<4,2> trellis_{makeTrellis<4, 2>({031,027})}; | 
					
						
							| 
									
										
										
										
											2022-08-02 23:42:50 +02:00
										 |  |  |     Viterbi<decltype(trellis_), 4> viterbi_{trellis_}; | 
					
						
							| 
									
										
										
										
											2022-07-27 18:15:47 +02:00
										 |  |  |     CRC16 crc_; | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     enum class State { LSF, STREAM, BASIC_PACKET, FULL_PACKET, BERT }; | 
					
						
							|  |  |  |     enum class SyncWordType { LSF, STREAM, PACKET, BERT }; | 
					
						
							|  |  |  |     enum class DecodeResult { FAIL, OK, EOS, INCOMPLETE, PACKET_INCOMPLETE }; | 
					
						
							|  |  |  |     enum class FrameType { LSF, LICH, STREAM, BASIC_PACKET, FULL_PACKET, BERT }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     State state_ = State::LSF; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     using input_buffer_t = std::array<int8_t, 368>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     using lsf_conv_buffer_t = std::array<uint8_t, 46>; | 
					
						
							|  |  |  |     using audio_conv_buffer_t = std::array<uint8_t, 34>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     using lsf_buffer_t = std::array<uint8_t, 30>; | 
					
						
							|  |  |  |     using lich_buffer_t = std::array<uint8_t, 6>; | 
					
						
							|  |  |  |     using audio_buffer_t = std::array<uint8_t, 18>; | 
					
						
							|  |  |  |     using packet_buffer_t = std::array<uint8_t, 26>; | 
					
						
							|  |  |  |     using bert_buffer_t = std::array<uint8_t, 25>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     using output_buffer_t = struct { | 
					
						
							|  |  |  |         FrameType type; | 
					
						
							|  |  |  |         union { | 
					
						
							|  |  |  |             lich_buffer_t lich; | 
					
						
							|  |  |  |             audio_buffer_t stream; | 
					
						
							|  |  |  |             packet_buffer_t packet; | 
					
						
							|  |  |  |             bert_buffer_t bert; | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |         lsf_buffer_t lsf; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     using depunctured_buffer_t = union { | 
					
						
							|  |  |  |         std::array<int8_t, 488> lsf; | 
					
						
							|  |  |  |         std::array<int8_t, 296> stream; | 
					
						
							|  |  |  |         std::array<int8_t, 420> packet; | 
					
						
							|  |  |  |         std::array<int8_t, 402> bert; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     using decode_buffer_t = union { | 
					
						
							|  |  |  |         std::array<uint8_t, 240> lsf; | 
					
						
							|  |  |  |         std::array<uint8_t, 144> stream; | 
					
						
							|  |  |  |         std::array<uint8_t, 206> packet; | 
					
						
							|  |  |  |         std::array<uint8_t, 197> bert; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Callback function for frame types.  The caller is expected to return | 
					
						
							|  |  |  |      * true if the data was good or unknown and false if the data is known | 
					
						
							|  |  |  |      * to be bad. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     using callback_t = std::function<bool(const output_buffer_t&, int)>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     callback_t callback_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     output_buffer_t output_buffer; | 
					
						
							|  |  |  |     decode_buffer_t decode_buffer; | 
					
						
							|  |  |  |     uint16_t frame_number = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     uint8_t lich_segments{0};       ///< one bit per received LICH fragment.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  |     M17FrameDecoder(callback_t callback) : | 
					
						
							| 
									
										
										
										
											2022-07-27 18:15:47 +02:00
										 |  |  |         crc_(0x5935, 0xFFFF), | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  |         callback_(callback) | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  |     {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void update_state(std::array<uint8_t, 240>& lsf_output) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (lsf_output[111]) // LSF type bit 0
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (lsf_output[109] != 0) { | 
					
						
							|  |  |  |                 state_ = State::STREAM; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else    // packet frame comes next.
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             uint8_t packet_type = (lsf_output[109] << 1) | lsf_output[110]; | 
					
						
							|  |  |  |             switch (packet_type) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 1: // RAW -- ignore LSF.
 | 
					
						
							|  |  |  |                 state_ = State::BASIC_PACKET; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 2: // ENCAPSULATED
 | 
					
						
							|  |  |  |                 state_ = State::FULL_PACKET; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 state_ = State::FULL_PACKET; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void reset() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         state_ = State::LSF; | 
					
						
							|  |  |  |         frame_number = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Decode the LSF and, if it is valid, transition to the next state. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * The LSF is returned for STREAM mode, dropped for BASIC_PACKET mode, | 
					
						
							|  |  |  |      * and captured for FULL_PACKET mode. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param buffer | 
					
						
							|  |  |  |      * @param viterbi_cost | 
					
						
							|  |  |  |      * @return | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  |     DecodeResult decode_lsf(input_buffer_t& buffer, int& viterbi_cost) | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  |         depunctured_buffer_t depuncture_buffer; | 
					
						
							| 
									
										
										
										
											2022-08-02 23:42:50 +02:00
										 |  |  |         depuncture<368, 488, 61>(buffer, depuncture_buffer.lsf, P1); | 
					
						
							|  |  |  |         viterbi_cost = viterbi_.decode(depuncture_buffer.lsf, decode_buffer.lsf); | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  |         to_byte_array(decode_buffer.lsf, output_buffer.lsf); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-06 07:01:42 +02:00
										 |  |  |         // qDebug() << "modemm17::M17FrameDecoder::decode_lsf: vierbi:" << viterbi_cost <<dump(output_buffer.lsf);
 | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         crc_.reset(); | 
					
						
							|  |  |  |         for (auto c : output_buffer.lsf) crc_(c); | 
					
						
							|  |  |  |         auto checksum = crc_.get(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (checksum == 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             update_state(decode_buffer.lsf); | 
					
						
							|  |  |  |             output_buffer.type = FrameType::LSF; | 
					
						
							|  |  |  |             callback_(output_buffer, viterbi_cost); | 
					
						
							|  |  |  |             return DecodeResult::OK; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2022-07-06 07:01:42 +02:00
										 |  |  |             qDebug() << "modemm17::M17FrameDecoder::decode_lsf: bad CRC:" << dump(output_buffer.lsf); | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         lich_segments = 0; | 
					
						
							|  |  |  |         output_buffer.lsf.fill(0); | 
					
						
							|  |  |  |         return DecodeResult::FAIL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Unpack  & decode LICH fragments into tmp_buffer.
 | 
					
						
							|  |  |  |     bool unpack_lich(input_buffer_t& buffer) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         size_t index = 0; | 
					
						
							|  |  |  |         // Read the 4 24-bit codewords from LICH
 | 
					
						
							|  |  |  |         for (size_t i = 0; i != 4; ++i) // for each codeword
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             uint32_t codeword = 0; | 
					
						
							|  |  |  |             for (size_t j = 0; j != 24; ++j) // for each bit in codeword
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 codeword <<= 1; | 
					
						
							|  |  |  |                 codeword |= (buffer[i * 24 + j] > 0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             uint32_t decoded = 0; | 
					
						
							|  |  |  |             if (!Golay24::decode(codeword, decoded)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             decoded >>= 12; // Remove check bits and parity.
 | 
					
						
							|  |  |  |             // append codeword.
 | 
					
						
							|  |  |  |             if (i & 1) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 output_buffer.lich[index++] |= (decoded >> 8);     // upper 4 bits
 | 
					
						
							|  |  |  |                 output_buffer.lich[index++] = (decoded & 0xFF);    // lower 8 bits
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 output_buffer.lich[index++] |= (decoded >> 4);     // upper 8 bits
 | 
					
						
							|  |  |  |                 output_buffer.lich[index] = (decoded & 0x0F) << 4; // lower 4 bits
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     DecodeResult decode_lich(input_buffer_t& buffer, int& viterbi_cost) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         output_buffer.lich.fill(0); | 
					
						
							|  |  |  |         // Read the 4 12-bit codewords from LICH into buffers.lich.
 | 
					
						
							|  |  |  |         if (!unpack_lich(buffer)) return DecodeResult::FAIL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         output_buffer.type = FrameType::LICH; | 
					
						
							|  |  |  |         callback_(output_buffer, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         uint8_t fragment_number = output_buffer.lich[5];   // Get fragment number.
 | 
					
						
							|  |  |  |         fragment_number = (fragment_number >> 5) & 7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (fragment_number > MAX_LICH_FRAGMENT) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             viterbi_cost = -1; | 
					
						
							|  |  |  |             return DecodeResult::INCOMPLETE;    // More to go...
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Copy decoded LICH to superframe buffer.
 | 
					
						
							|  |  |  |         std::copy(output_buffer.lich.begin(), output_buffer.lich.begin() + 5, | 
					
						
							|  |  |  |             output_buffer.lsf.begin() + (fragment_number * 5)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         lich_segments |= (1 << fragment_number);        // Indicate segment received.
 | 
					
						
							|  |  |  |         if ((lich_segments & 0x3F) != 0x3F) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             viterbi_cost = -1; | 
					
						
							|  |  |  |             return DecodeResult::INCOMPLETE;        // More to go...
 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         crc_.reset(); | 
					
						
							|  |  |  |         for (auto c : output_buffer.lsf) crc_(c); | 
					
						
							|  |  |  |         auto checksum = crc_.get(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (checksum == 0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         	lich_segments = 0; | 
					
						
							|  |  |  |             state_ = State::STREAM; | 
					
						
							|  |  |  |             viterbi_cost = 0; | 
					
						
							|  |  |  |             output_buffer.type = FrameType::LSF; | 
					
						
							|  |  |  |             callback_(output_buffer, viterbi_cost); | 
					
						
							|  |  |  |             return DecodeResult::OK; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Failed CRC... try again.
 | 
					
						
							|  |  |  |         // lich_segments = 0;
 | 
					
						
							|  |  |  |         // output_buffer.lsf.fill(0);
 | 
					
						
							|  |  |  |         viterbi_cost = 128; | 
					
						
							|  |  |  |         return DecodeResult::INCOMPLETE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-06 07:01:42 +02:00
										 |  |  |     DecodeResult decode_bert(input_buffer_t& buffer, int& viterbi_cost) | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  |         depunctured_buffer_t depuncture_buffer; | 
					
						
							| 
									
										
										
										
											2022-08-02 23:42:50 +02:00
										 |  |  |         depuncture<368, 402, 12>(buffer, depuncture_buffer.bert, P2); | 
					
						
							|  |  |  |         viterbi_cost = viterbi_.decode(depuncture_buffer.bert, decode_buffer.bert); | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  |         to_byte_array(decode_buffer.bert, output_buffer.bert); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         output_buffer.type = FrameType::BERT; | 
					
						
							|  |  |  |         callback_(output_buffer, viterbi_cost); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return DecodeResult::OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     DecodeResult decode_stream(input_buffer_t& buffer, int& viterbi_cost) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         std::array<int8_t, 272> tmp; | 
					
						
							|  |  |  |         std::copy(buffer.begin() + 96, buffer.end(), tmp.begin()); | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  |         depunctured_buffer_t depuncture_buffer; | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-02 23:42:50 +02:00
										 |  |  |         depuncture<272, 296, 12>(tmp, depuncture_buffer.stream, P2); | 
					
						
							|  |  |  |         viterbi_cost = viterbi_.decode(depuncture_buffer.stream, decode_buffer.stream); | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  |         to_byte_array(decode_buffer.stream, output_buffer.stream); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((viterbi_cost < 60) && (output_buffer.stream[0] & 0x80)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // fputs("\nEOS\n", stderr);
 | 
					
						
							|  |  |  |             state_ = State::LSF; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         output_buffer.type = FrameType::STREAM; | 
					
						
							|  |  |  |         callback_(output_buffer, viterbi_cost); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return state_ == State::LSF ? DecodeResult::EOS : DecodeResult::OK; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Capture packet frames until an EOF bit is found. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      * @param buffer the demodulated M17 symbols in LLR format. | 
					
						
							|  |  |  |      * @param viterbi_cost the cost of traversing the trellis. | 
					
						
							|  |  |  |      * @param frame_type is either BASIC_PACKET or FULL_PACKET. | 
					
						
							|  |  |  |      * @return the result of decoding the packet frame. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  |     DecodeResult decode_packet(input_buffer_t& buffer, int& viterbi_cost, FrameType type) | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-06-17 02:25:34 +02:00
										 |  |  |         depunctured_buffer_t depuncture_buffer; | 
					
						
							| 
									
										
										
										
											2022-08-02 23:42:50 +02:00
										 |  |  |         depuncture<368, 420, 8>(buffer, depuncture_buffer.packet, P3); | 
					
						
							|  |  |  |         viterbi_cost = viterbi_.decode(depuncture_buffer.packet, decode_buffer.packet); | 
					
						
							| 
									
										
										
										
											2022-06-07 03:22:18 +02:00
										 |  |  |         to_byte_array(decode_buffer.packet, output_buffer.packet); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         output_buffer.type = type; | 
					
						
							|  |  |  |         auto result = callback_(output_buffer, viterbi_cost); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (output_buffer.packet[25] & 0x80) // last packet;
 | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             state_ = State::LSF; | 
					
						
							|  |  |  |             return result ? DecodeResult::OK : DecodeResult::FAIL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return DecodeResult::PACKET_INCOMPLETE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /**
 | 
					
						
							|  |  |  |      * Decode M17 frames.  The decoder uses the sync word to determine frame | 
					
						
							|  |  |  |      * type and to update its state machine. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * The decoder receives M17 frame type indicator (based on sync word) and | 
					
						
							|  |  |  |      * frames from the M17 demodulator. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * If the frame is an LSF, the state immediately changes to LSF. When | 
					
						
							|  |  |  |      * in LSF mode, the state machine can transition to: | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      *  - LSF if the CRC is bad. | 
					
						
							|  |  |  |      *  - STREAM if the LSF type field indicates Stream. | 
					
						
							|  |  |  |      *  - BASIC_PACKET if the LSF type field indicates Packet and the packet | 
					
						
							|  |  |  |      *    type is RAW. | 
					
						
							|  |  |  |      *  - FULL_PACKET if the LSF type field indicates Packet and the packet | 
					
						
							|  |  |  |      *    type is ENCAPSULATED or RESERVED. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * When in LSF mode, if an LSF frame is received it is parsed as an LSF. | 
					
						
							|  |  |  |      * When a STREAM frame is received, it attempts to recover an LSF from | 
					
						
							|  |  |  |      * the LICH.  PACKET frame types are ignored when state is LSF. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * When in STREAM mode, the state machine can transition to either: | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      *  - STREAM when a any stream frame is received. | 
					
						
							|  |  |  |      *  - LSF when the EOS indicator is set, or when a packet frame is received. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * When in BASIC_PACKET mode, the state machine can transition to either: | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      *  - BASIC_PACKET when any packet frame is received. | 
					
						
							|  |  |  |      *  - LSF when the EOS indicator is set, or when a stream frame is received. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * When in FULL_PACKET mode, the state machine can transition to either: | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      *  - FULL_PACKET when any packet frame is received. | 
					
						
							|  |  |  |      *  - LSF when the EOS indicator is set, or when a stream frame is received. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     DecodeResult operator()(SyncWordType frame_type, input_buffer_t& buffer, int& viterbi_cost) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         derandomize_(buffer); | 
					
						
							|  |  |  |         interleaver_.deinterleave(buffer); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // This is out state machined.
 | 
					
						
							|  |  |  |         switch(frame_type) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case SyncWordType::LSF: | 
					
						
							|  |  |  |             state_ = State::LSF; | 
					
						
							|  |  |  |             return decode_lsf(buffer, viterbi_cost); | 
					
						
							|  |  |  |         case SyncWordType::STREAM: | 
					
						
							|  |  |  |             switch (state_) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case State::LSF: | 
					
						
							|  |  |  |                 return decode_lich(buffer, viterbi_cost); | 
					
						
							|  |  |  |             case State::STREAM: | 
					
						
							|  |  |  |                 return decode_stream(buffer, viterbi_cost); | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 state_ = State::LSF; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case SyncWordType::PACKET: | 
					
						
							|  |  |  |             switch (state_) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case State::BASIC_PACKET: | 
					
						
							|  |  |  |                 return decode_packet(buffer, viterbi_cost, FrameType::BASIC_PACKET); | 
					
						
							|  |  |  |             case State::FULL_PACKET: | 
					
						
							|  |  |  |                 return decode_packet(buffer, viterbi_cost, FrameType::FULL_PACKET); | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 state_ = State::LSF; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case SyncWordType::BERT: | 
					
						
							|  |  |  |             state_ = State::BERT; | 
					
						
							|  |  |  |             return decode_bert(buffer, viterbi_cost); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return DecodeResult::FAIL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     State state() const { return state_; } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-06 17:10:25 -03:00
										 |  |  | } // modemm17
 |