1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
|
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB. //
// //
// 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 as version 3 of the License, or //
// //
// 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 V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef YSF_H_
#define YSF_H_
#include <string.h>
#include <iostream>
#include <string>
#include "viterbi5.h"
#include "fec.h"
#include "crc.h"
#include "pn.h"
#include "export.h"
namespace DSDcc
{
class DSDDecoder;
class DSDCC_API DSDYSF
{
public:
typedef enum
{
FIHeader,
FICommunication,
FITerminator,
FITest
} FrameInformation;
typedef enum
{
CMGroupCQ,
CMRadioID,
CMReserved,
CMIndividual
} CallMode;
typedef enum
{
MRDirectWave,
MRDownlinUplinkkNotBusy,
MRDownlinkUplinkBusy,
MRReserved
} MessageRouting;
typedef enum
{
DTVoiceData1,
DTDataFullRate,
DTVoiceData2,
DTVoiceFullRate
} DataType;
typedef enum
{
FICHNoError,
FICHErrorGolay,
FICHErrorCRC
} FICHError;
#pragma pack(push, 1)
struct FICH
{
FICH() :
m_reserved(0),
m_freqDeviation(0),
m_voipPath(0),
m_sqlType(0)
{
memset(&m_frameInfo[0], 0, 32);
}
uint8_t m_frameInfo[2]; //!< 31:30 FI
uint8_t m_callsignType[2]; //!< 29:28 CS
uint8_t m_callMode[2]; //!< 27:26 CM
uint8_t m_blockNumber[2]; //!< 25:24 BN
uint8_t m_blockTotal[2]; //!< 23:22 BT
uint8_t m_frameNumber[3]; //!< 21:19 FN
uint8_t m_frameTotal[3]; //!< 18:17 FT
uint8_t m_reserved; //!< 15
uint8_t m_freqDeviation; //!< 14 Dev
uint8_t m_messagePath[3]; //!< 13:11 MR
uint8_t m_voipPath; //!< 10 VoIP
uint8_t m_dataType[2]; //!< 9:8 DT
uint8_t m_sqlType; //!< 7 SQL
uint8_t m_sqlCode[7]; //!< 6:0 SC
void setBytes(const unsigned char *bytes) {
memcpy(&m_frameInfo[0], bytes, 32);
}
FrameInformation getFrameInformation() const {
return (FrameInformation) (((m_frameInfo[0]&1)<<1) + (m_frameInfo[1]&1));
}
CallMode getCallMode() const {
return (CallMode) (((m_callMode[0]&1)<<1) + (m_callMode[1]&1));
}
int getBlockNumber() const {
return ((m_blockNumber[0]&1)<<1) + (m_blockNumber[1]&1);
}
int getBlockTotal() const {
return ((m_blockTotal[0]&1)<<1) + (m_blockTotal[1]&1);
}
int getFrameNumber() const {
return ((m_frameNumber[0]&1)<<2) + ((m_frameNumber[1]&1)<<1) + (m_frameNumber[2]&1);
}
int getFrameTotal() const {
return ((m_frameTotal[0]&1)<<2) + ((m_frameTotal[1]&1)<<1) + (m_frameTotal[2]&1);
}
bool isNarrowMode() const {
return (m_freqDeviation & 1) == 1;
}
MessageRouting getMessageRouting() const {
int mrValue = ((m_messagePath[0]&1)<<2) + ((m_messagePath[1]&1)<<1) + (m_messagePath[2]&1);
if (mrValue < (int) MRReserved) {
return (MessageRouting) mrValue;
} else {
return MRReserved;
}
}
bool isInternetPath() const {
return (m_voipPath & 1) == 1;
}
DataType getDataType() const {
return (DataType) (((m_dataType[0]&1)<<1) + (m_dataType[1]&1));
}
bool isSquelchCodeEnabled() const {
return (m_sqlType & 1) == 0;
}
int getSquelchCode() const {
return ((m_sqlCode[0]&1)<<6)
+ ((m_sqlCode[1]&1)<<5)
+ ((m_sqlCode[2]&1)<<4)
+ ((m_sqlCode[3]&1)<<3)
+ ((m_sqlCode[4]&1)<<2)
+ ((m_sqlCode[5]&1)<<1)
+ (m_sqlCode[6]&1);
}
friend std::ostream &operator<<(std::ostream &output, const FICH& fich)
{
output << "FI: " << (int) fich.getFrameInformation()
<< " CM: " << (int) fich.getCallMode()
<< " Block#: " << fich.getBlockNumber() << "/" << fich.getBlockTotal()
<< " Frame#: " << fich.getFrameNumber() << "/" << fich.getFrameTotal()
<< " Dev: " << (fich.isNarrowMode() ? "narrow" : "wide")
<< " MR: " << (int) fich.getMessageRouting()
<< " VoIP: " << (fich.isInternetPath() ? "internet" : "local")
<< " DT: " << (int) fich.getDataType()
<< " SQL: " << (fich.isSquelchCodeEnabled() ? "on" : "off")
<< " SQL code: " << fich.getSquelchCode();
return output;
}
};
#pragma pack(pop)
explicit DSDYSF(DSDDecoder *dsdDecoder);
~DSDYSF();
void init();
void process();
const FICH& getFICH() const { return m_fich; }
FICHError getFICHError() const { return m_fichError; }
const char *getDest() const { return m_dest; }
const char *getSrc() const { return m_src; }
const char *getDownlink() const { return m_downlink; }
const char *getUplink() const { return m_uplink; }
const char *getRem4() const { return m_rem4; }
bool radioIdMode() const { return m_fich.getCallMode() == CMRadioID; }
const char *getDestId() const { return m_destId; }
const char *getSrcId() const { return m_srcId; }
static const char *ysfChannelTypeText[4];
static const char *ysfDataTypeText[4];
static const char *ysfCallModeText[4];
private:
void processFICH(int symbolIndex, unsigned char dibit);
void processHeader(int symbolIndex, unsigned char dibit);
void processVD1(int symbolIndex, unsigned char dibit);
void processVD2(int symbolIndex, unsigned char dibit);
void processVD2Voice(int mbeIndex, unsigned char dibit);
void processVFR(int symbolIndex, unsigned char dibit);
void processVFRSubHeader(int symbolIndex, unsigned char dibit);
void processVFRFullIMBE(int symbolIndex, unsigned char dibit);
void processCSD1(unsigned char *dchBytes);
void processCSD2(unsigned char *dchBytes);
void processCSD3_1(unsigned char *dchBytes);
void processCSD3_2(unsigned char *dchBytes);
void processAMBE(int mbeIndex, unsigned char dibit);
void procesVFRFrame(int mbeIndex, unsigned char dibit);
void storeSymbolDV(unsigned char *mbeFrame, int dibitindex, unsigned char dibit, bool invertDibit = false);
bool checkCRC16(unsigned char *bits, unsigned long nbBytes, unsigned char *xoredBytes = 0);
void scrambleVFR(uint8_t out[], uint8_t in[], uint16_t n, uint32_t seed, uint8_t shift);
DSDDecoder *m_dsdDecoder;
int m_symbolIndex; //!< Current symbol index
unsigned char m_fichRaw[100]; //!< FICH dibits after de-interleave + Viterbi stuff symbols
unsigned char m_fichGolay[100]; //!< FICH Golay encoded bits + 4 stuff bits + Viterbi stuff bits
unsigned char m_fichBits[48]; //!< Final FICH + CRC16
FICH m_fich; //!< Validated FICH
FICHError m_fichError; //!< FICH decoding error status
unsigned char m_dch1Raw[180]; //!< DCH1 dibits after de-interleave
unsigned char m_dch1Bits[180]; //!< DCH1 bits after de-convolution
unsigned char m_dch2Raw[180]; //!< DCH2 dibits after de-interleave
unsigned char m_dch2Bits[180]; //!< DCH2 bits after de-convolution
unsigned char m_vd2BitsRaw[104]; //!< V/D type 2 VCH+VeCH after de-interleave and de-whitening
unsigned char m_vd2MBEBits[72];
unsigned char m_vfrBitsRaw[144]; //!< VFR bits after de-interleave and de-scarambling
unsigned char m_vfrBits[88]; //!< VFR bits after FEC
bool m_vfrStart;
Viterbi5 m_viterbiFICH;
Golay_24_12 m_golay_24_12;
CRC m_crc;
PN_9_5 m_pn;
unsigned char m_bitWork[48];
char m_dest[10+1]; //!< Destination callsign from CSD1
char m_src[10+1]; //!< Source callsign from CSD1
char m_downlink[10+1]; //!< Downlink callsign from CSD2
char m_uplink[10+1]; //!< Uplink callsign from CSD2
char m_rem1[5+1]; //!< Callsign supplementary information #1 from CSD3
char m_rem2[5+1]; //!< Callsign supplementary information #2 from CSD3
char m_rem3[5+1]; //!< Callsign supplementary information #3 from CSD3
char m_rem4[5+1]; //!< Callsign supplementary information #4 from CSD3
char m_destId[5+1]; //!< Destination radio ID
char m_srcId[5+1]; //!< Source radio ID
// AMBE interleave
const int *w, *x, *y, *z;
static const int rW[36];
static const int rX[36];
static const int rY[36];
static const int rZ[36];
static const int m_fichInterleave[100]; //!< FICH symbols interleaving matrix
static const int m_dchInterleave[180]; //!< DCH symbols interleaving matrix
static const int m_vd2Interleave[104]; //!< V/D type 2 interleaving matrix
static const int m_vd2DVSIInterleave[49]; //!< V/D type 2 interleaving matrix for DVSI AMBE3000 chip use
static const int m_vfrInterleave[144]; //!< VFR interleaving matrix
};
} // namespace DSDcc
#endif /* YSF_H_ */
|