1 /******************************************************************************\
2 * Technische Universitaet Darmstadt, Institut fuer Nachrichtentechnik
3 * Copyright (c) 2007
4 *
5 * Author(s):
6 * Volker Fischer, Andrew Murphy
7 *
8 * Adapter for ham sstv use Ties Bos - PA0MBO
9 *
10 * Description:
11 * DRM Parameters
12 *
13 ******************************************************************************
14 *
15 * This program is free software(), you can redistribute it and/or modify it under
16 * the terms of the GNU General Public License as published by the Free Software
17 * Foundation(), either version 2 of the License, or (at your option) any later
18 * version.
19 *
20 * This program is distributed in the hope that it will be useful, but WITHOUT
21 * ANY WARRANTY(), without even the implied warranty of MERCHANTABILITY or FITNESS
22 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
23 * details.
24 *
25 * You should have received a copy of the GNU General Public License along with
26 * this program(), if not, write to the Free Software Foundation, Inc.,
27 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 *
29 \******************************************************************************/
30
31 #include "Parameter.h"
32 //#include "DrmReceiver.h"
33 #include <limits>
34 #include <sstream>
35 #include <iomanip>
36 //#include "util/LogPrint.h"
37
38 /* Implementation *************************************************************/
CParameter()39 CParameter::CParameter():
40 // pDRMRec(pRx),
41
42
43
44 Stream(MAX_NUM_STREAMS), Service(MAX_NUM_SERVICES),
45
46 iNumAudioFrames(0),
47 vecbiAudioFrameStatus(0),
48 bMeasurePSD(),
49 vecrPSD(0),
50 matcReceivedPilotValues(),
51 RawSimDa(),
52 eSimType(ST_NONE),
53 iDRMChannelNum(0),
54 iSpecChDoppler(0),
55 rBitErrRate(0.0),
56 rSyncTestParam(0.0),
57 rSINR(0.0),
58 iNumBitErrors(0),
59 iChanEstDelay(0),
60 iNumTaps(0),
61 iPathDelay(MAX_NUM_TAPS_DRM_CHAN),
62 rGainCorr(0.0),
63 iOffUsfExtr(0),
64 ReceiveStatus(),
65 FrontEndParameters(),
66 AltFreqSign(),
67 rMER(0.0),
68 rWMERMSC(0.0),
69 rWMERFAC(0.0),
70 rSigmaEstimate(0.0),
71 rMinDelay(0.0),
72 rMaxDelay(0.0),
73 bMeasureDelay(),
74 vecrRdel(0),
75 vecrRdelThresholds(0),
76 vecrRdelIntervals(0),
77 bMeasureDoppler(0),
78 rRdop(0.0),
79 bMeasureInterference(false),
80 rIntFreq(0.0),
81 rINR(0.0),
82 rICR(0.0),
83 rMaxPSDwrtSig(0.0),
84 rMaxPSDFreq(0.0),
85 rSigStrengthCorrection(0.0),
86 bRunThread(false),
87 bUsingMultimedia(false),
88 CellMappingTable(),
89 rSysSimSNRdB(0.0),
90 iFrequency(0),
91 bValidSignalStrength(false),
92 rSigStr(0.0),
93 rIFSigStr(0.0),
94 iCurSelAudioService(0),
95 iCurSelDataService(0),
96 eRobustnessMode(RM_ROBUSTNESS_MODE_B),
97 eSpectOccup(SO_3),
98 LastAudioService(),
99 LastDataService(),
100 Mutex()
101 {
102 init();
103 GenerateRandomSerialNumber();
104 CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup);
105 }
106
init()107 void CParameter::init()
108 {
109 eSymbolInterlMode=SI_LONG;
110 eMSCCodingScheme=CS_1_SM;
111 eSDCCodingScheme=CS_1_SM;
112 iNumAudioService=0;
113 iNumDataService=0;
114 iAMSSCarrierMode=0;
115 sReceiverID=" ";
116 sSerialNumber="";
117 sDataFilesDirectory=".";
118 MSCPrLe.init();
119 iNumBitsHierarchFrameTotal=0;
120 iNumDecodedBitsMSC=0;
121 iNumSDCBitsPerSFrame=0;
122 iNumAudioDecoderBits=0;
123 iNumDataDecoderBits=0;
124 iYear=0;
125 iMonth=0;
126 iDay=0;
127 iUTCHour=0;
128 iUTCMin=0;
129 iFrameIDTransm=0;
130 iFrameIDReceiv=0;
131 rFreqOffsetAcqui=0.0;
132 rFreqOffsetTrack=0.0;
133 rResampleOffset=0.0;
134 iTimingOffsTrack=0;
135 eReceiverMode=RM_NONE;
136 eAcquiState=AS_NO_SIGNAL;
137 }
138
139
~CParameter()140 CParameter::~CParameter()
141 {
142 }
143
CParameter(const CParameter & p)144 CParameter::CParameter(const CParameter& p):
145 // pDRMRec(p.pDRMRec),
146 eSymbolInterlMode(p.eSymbolInterlMode),
147 eMSCCodingScheme(p.eMSCCodingScheme),
148 eSDCCodingScheme(p.eSDCCodingScheme),
149 iNumAudioService(p.iNumAudioService),
150 iNumDataService(p.iNumDataService),
151 iAMSSCarrierMode(p.iAMSSCarrierMode),
152 sReceiverID(p.sReceiverID),
153 sSerialNumber(p.sSerialNumber),
154 sDataFilesDirectory(p.sDataFilesDirectory),
155 MSCPrLe(p.MSCPrLe),
156 Stream(p.Stream), Service(p.Service),
157 iNumBitsHierarchFrameTotal(p.iNumBitsHierarchFrameTotal),
158 iNumDecodedBitsMSC(p.iNumDecodedBitsMSC),
159 iNumSDCBitsPerSFrame(p.iNumSDCBitsPerSFrame),
160 iNumAudioDecoderBits(p.iNumAudioDecoderBits),
161 iNumDataDecoderBits(p.iNumDataDecoderBits),
162 iYear(p.iYear),
163 iMonth(p.iMonth),
164 iDay(p.iDay),
165 iUTCHour(p.iUTCHour),
166 iUTCMin(p.iUTCMin),
167 iFrameIDTransm(p.iFrameIDTransm),
168 iFrameIDReceiv(p.iFrameIDReceiv),
169 rFreqOffsetAcqui(p.rFreqOffsetAcqui),
170 rFreqOffsetTrack(p.rFreqOffsetTrack),
171 rResampleOffset(p.rResampleOffset),
172 iTimingOffsTrack(p.iTimingOffsTrack),
173 eReceiverMode(p.eReceiverMode),
174 eAcquiState(p.eAcquiState),
175 iNumAudioFrames(p.iNumAudioFrames),
176 vecbiAudioFrameStatus(p.vecbiAudioFrameStatus),
177 bMeasurePSD(p.bMeasurePSD),
178 vecrPSD(p.vecrPSD),
179 //matcReceivedPilotValues(p.matcReceivedPilotValues),
180 matcReceivedPilotValues(), // OPH says copy constructor for CMatrix not safe yet
181 RawSimDa(p.RawSimDa),
182 eSimType(p.eSimType),
183 iDRMChannelNum(p.iDRMChannelNum),
184 iSpecChDoppler(p.iSpecChDoppler),
185 rBitErrRate(p.rBitErrRate),
186 rSyncTestParam (p.rSyncTestParam),
187 rSINR(p.rSINR),
188 iNumBitErrors(p.iNumBitErrors),
189 iChanEstDelay(p.iChanEstDelay),
190 iNumTaps(p.iNumTaps),
191 iPathDelay(p.iPathDelay),
192 rGainCorr(p.rGainCorr),
193 iOffUsfExtr(p.iOffUsfExtr),
194 ReceiveStatus(p.ReceiveStatus),
195 FrontEndParameters(p.FrontEndParameters),
196 AltFreqSign(p.AltFreqSign),
197 rMER(p.rMER),
198 rWMERMSC(p.rWMERMSC),
199 rWMERFAC(p.rWMERFAC),
200 rSigmaEstimate(p.rSigmaEstimate),
201 rMinDelay(p.rMinDelay),
202 rMaxDelay(p.rMaxDelay),
203 bMeasureDelay(p.bMeasureDelay),
204 vecrRdel(p.vecrRdel),
205 vecrRdelThresholds(p.vecrRdelThresholds),
206 vecrRdelIntervals(p.vecrRdelIntervals),
207 bMeasureDoppler(p.bMeasureDoppler),
208 rRdop(p.rRdop),
209 bMeasureInterference(p.bMeasureInterference),
210 rIntFreq(p.rIntFreq),
211 rINR(p.rINR),
212 rICR(p.rICR),
213 rMaxPSDwrtSig(p.rMaxPSDwrtSig),
214 rMaxPSDFreq(p.rMaxPSDFreq),
215 rSigStrengthCorrection(p.rSigStrengthCorrection),
216 bRunThread(p.bRunThread),
217 bUsingMultimedia(p.bUsingMultimedia),
218 CellMappingTable(), // jfbc CCellMappingTable uses a CMatrix :(
219 // GPSData(p.GPSData),
220 rSysSimSNRdB(p.rSysSimSNRdB),
221 iFrequency(p.iFrequency),
222 bValidSignalStrength(p.bValidSignalStrength),
223 rSigStr(p.rSigStr),
224 rIFSigStr(p.rIFSigStr),
225 iCurSelAudioService(p.iCurSelAudioService),
226 iCurSelDataService(p.iCurSelDataService),
227 eRobustnessMode(p.eRobustnessMode),
228 eSpectOccup(p.eSpectOccup),
229 LastAudioService(p.LastAudioService),
230 LastDataService(p.LastDataService)
231 //, Mutex() // jfbc: I don't think this state should be copied
232 {
233 CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup);
234 matcReceivedPilotValues = p.matcReceivedPilotValues; // TODO
235 }
236
operator =(const CParameter & p)237 CParameter& CParameter::operator=(const CParameter& p)
238 {
239 // pDRMRec = p.pDRMRec;
240 eSymbolInterlMode = p.eSymbolInterlMode;
241 eMSCCodingScheme = p.eMSCCodingScheme;
242 eSDCCodingScheme = p.eSDCCodingScheme;
243 iNumAudioService = p.iNumAudioService;
244 iNumDataService = p.iNumDataService;
245 iAMSSCarrierMode = p.iAMSSCarrierMode;
246 sReceiverID = p.sReceiverID;
247 sSerialNumber = p.sSerialNumber;
248 sDataFilesDirectory = p.sDataFilesDirectory;
249 MSCPrLe = p.MSCPrLe;
250 Stream = p.Stream;
251 Service = p.Service;
252 iNumBitsHierarchFrameTotal = p.iNumBitsHierarchFrameTotal;
253 iNumDecodedBitsMSC = p.iNumDecodedBitsMSC;
254 iNumSDCBitsPerSFrame = p.iNumSDCBitsPerSFrame;
255 iNumAudioDecoderBits = p.iNumAudioDecoderBits;
256 iNumDataDecoderBits = p.iNumDataDecoderBits;
257 iYear = p.iYear;
258 iMonth = p.iMonth;
259 iDay = p.iDay;
260 iUTCHour = p.iUTCHour;
261 iUTCMin = p.iUTCMin;
262 iFrameIDTransm = p.iFrameIDTransm;
263 iFrameIDReceiv = p.iFrameIDReceiv;
264 rFreqOffsetAcqui = p.rFreqOffsetAcqui;
265 rFreqOffsetTrack = p.rFreqOffsetTrack;
266 rResampleOffset = p.rResampleOffset;
267 iTimingOffsTrack = p.iTimingOffsTrack;
268 eReceiverMode = p.eReceiverMode;
269 eAcquiState = p.eAcquiState;
270 iNumAudioFrames = p.iNumAudioFrames;
271 vecbiAudioFrameStatus = p.vecbiAudioFrameStatus;
272 bMeasurePSD = p.bMeasurePSD;
273 vecrPSD = p.vecrPSD;
274 matcReceivedPilotValues = p.matcReceivedPilotValues;
275 RawSimDa = p.RawSimDa;
276 eSimType = p.eSimType;
277 iDRMChannelNum = p.iDRMChannelNum;
278 iSpecChDoppler = p.iSpecChDoppler;
279 rBitErrRate = p.rBitErrRate;
280 rSyncTestParam = p.rSyncTestParam;
281 rSINR = p.rSINR;
282 iNumBitErrors = p.iNumBitErrors;
283 iChanEstDelay = p.iChanEstDelay;
284 iNumTaps = p.iNumTaps;
285 iPathDelay = p.iPathDelay;
286 rGainCorr = p.rGainCorr;
287 iOffUsfExtr = p.iOffUsfExtr;
288 ReceiveStatus = p.ReceiveStatus;
289 FrontEndParameters = p.FrontEndParameters;
290 AltFreqSign = p.AltFreqSign;
291 rMER = p.rMER;
292 rWMERMSC = p.rWMERMSC;
293 rWMERFAC = p.rWMERFAC;
294 rSigmaEstimate = p.rSigmaEstimate;
295 rMinDelay = p.rMinDelay;
296 rMaxDelay = p.rMaxDelay;
297 bMeasureDelay = p.bMeasureDelay;
298 vecrRdel = p.vecrRdel;
299 vecrRdelThresholds = p.vecrRdelThresholds;
300 vecrRdelIntervals = p.vecrRdelIntervals;
301 bMeasureDoppler = p.bMeasureDoppler;
302 rRdop = p.rRdop;
303 bMeasureInterference = p.bMeasureInterference;
304 rIntFreq = p.rIntFreq;
305 rINR = p.rINR;
306 rICR = p.rICR;
307 rMaxPSDwrtSig = p.rMaxPSDwrtSig;
308 rMaxPSDFreq = p.rMaxPSDFreq;
309 rSigStrengthCorrection = p.rSigStrengthCorrection;
310 bRunThread = p.bRunThread;
311 bUsingMultimedia = p.bUsingMultimedia;
312 CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup); // don't copy CMatrix
313 // GPSData = p.GPSData;
314 rSysSimSNRdB = p.rSysSimSNRdB;
315 iFrequency = p.iFrequency;
316 bValidSignalStrength = p.bValidSignalStrength;
317 rSigStr = p.rSigStr;
318 rIFSigStr = p.rIFSigStr;
319 iCurSelAudioService = p.iCurSelAudioService;
320 iCurSelDataService = p.iCurSelDataService;
321 eRobustnessMode = p.eRobustnessMode;
322 eSpectOccup = p.eSpectOccup;
323 LastAudioService = p.LastAudioService;
324 LastDataService = p.LastDataService;
325 return *this;
326 }
327
ResetServicesStreams()328 void CParameter::ResetServicesStreams()
329 {
330 int i;
331 if(GetReceiverMode() == RM_DRM)
332 {
333
334 /* Store informations about last services selected
335 * this for select current service automatically after a resync */
336
337 if (iCurSelAudioService > 0)
338 LastAudioService.Save(iCurSelAudioService, Service[iCurSelAudioService].iServiceID);
339
340 if (iCurSelDataService > 0)
341 LastDataService.Save(iCurSelDataService, Service[iCurSelDataService].iServiceID);
342
343 /* Reset everything to possible start values */
344 for (i = 0; i < MAX_NUM_SERVICES; i++)
345 {
346 Service[i].AudioParam.strTextMessage = "";
347 Service[i].AudioParam.iStreamID = STREAM_ID_NOT_USED;
348 Service[i].AudioParam.eAudioCoding = CAudioParam::AC_AAC;
349 Service[i].AudioParam.eSBRFlag = CAudioParam::SB_NOT_USED;
350 Service[i].AudioParam.eAudioSamplRate = CAudioParam::AS_24KHZ;
351 Service[i].AudioParam.bTextflag = false;
352 Service[i].AudioParam.bEnhanceFlag = false;
353 Service[i].AudioParam.eAudioMode = CAudioParam::AM_MONO;
354 Service[i].AudioParam.iCELPIndex = 0;
355 Service[i].AudioParam.bCELPCRC = false;
356 Service[i].AudioParam.eHVXCRate = CAudioParam::HR_2_KBIT;
357 Service[i].AudioParam.bHVXCCRC = false;
358
359 Service[i].DataParam.iStreamID = STREAM_ID_NOT_USED;
360 Service[i].DataParam.ePacketModInd = CDataParam::PM_PACKET_MODE;
361 Service[i].DataParam.eDataUnitInd = CDataParam::DU_SINGLE_PACKETS;
362 Service[i].DataParam.iPacketID = 0;
363 Service[i].DataParam.iPacketLen = 0;
364 Service[i].DataParam.eAppDomain = CDataParam::AD_DRM_SPEC_APP;
365 Service[i].DataParam.iUserAppIdent = 0;
366
367 Service[i].iServiceID = SERV_ID_NOT_USED;
368 Service[i].eCAIndication = CService::CA_NOT_USED;
369 Service[i].iLanguage = 0;
370 Service[i].strCountryCode = "";
371 Service[i].strLanguageCode = "";
372 Service[i].eAudDataFlag = CService::SF_AUDIO;
373 Service[i].iServiceDescr = 0;
374 Service[i].strLabel = "";
375 }
376
377 for (i = 0; i < MAX_NUM_STREAMS; i++)
378 {
379 Stream[i].iLenPartA = 0;
380 Stream[i].iLenPartB = 0;
381 }
382 }
383 else
384 {
385
386 // Set up encoded AM audio parameters
387 Service[0].AudioParam.strTextMessage = "";
388 Service[0].AudioParam.iStreamID = 0;
389 Service[0].AudioParam.eAudioCoding = CAudioParam::AC_AAC;
390 Service[0].AudioParam.eSBRFlag = CAudioParam::SB_NOT_USED;
391 Service[0].AudioParam.eAudioSamplRate = CAudioParam::AS_24KHZ;
392 Service[0].AudioParam.bTextflag = false;
393 Service[0].AudioParam.bEnhanceFlag = false;
394 Service[0].AudioParam.eAudioMode = CAudioParam::AM_MONO;
395 Service[0].AudioParam.iCELPIndex = 0;
396 Service[0].AudioParam.bCELPCRC = false;
397 Service[0].AudioParam.eHVXCRate = CAudioParam::HR_2_KBIT;
398 Service[0].AudioParam.bHVXCCRC = false;
399
400 Service[0].iServiceID = SERV_ID_NOT_USED;
401 Service[0].eCAIndication = CService::CA_NOT_USED;
402 Service[0].iLanguage = 0;
403 Service[0].strCountryCode = "";
404 Service[0].strLanguageCode = "";
405 Service[0].eAudDataFlag = CService::SF_AUDIO;
406 Service[0].iServiceDescr = 0;
407 Service[0].strLabel = "";
408
409 Stream[0].iLenPartA = 0;
410 Stream[0].iLenPartB = 1044;
411 }
412
413 /* Reset alternative frequencies */
414 AltFreqSign.Reset();
415
416 /* Date, time */
417 iDay = 0;
418 iMonth = 0;
419 iYear = 0;
420 iUTCHour = 0;
421 iUTCMin = 0;
422 }
423
GetActiveServices(set<int> & actServ)424 void CParameter::GetActiveServices(set<int>& actServ)
425 {
426 /* Init return vector */
427 actServ.clear();
428
429 /* Get active services */
430 for (int i = 0; i < MAX_NUM_SERVICES; i++)
431 {
432 if (Service[i].IsActive())
433 /* A service is active, add ID to set */
434 actServ.insert(i);
435 }
436 }
437
438 /* using a set ensures each stream appears only once */
GetActiveStreams(set<int> & actStr)439 void CParameter::GetActiveStreams(set<int>& actStr)
440 {
441 actStr.clear();
442
443 /* Determine which streams are active */
444 for (int i = 0; i < MAX_NUM_SERVICES; i++)
445 {
446 if (Service[i].IsActive())
447 {
448 /* Audio stream */
449 if (Service[i].AudioParam.iStreamID != STREAM_ID_NOT_USED)
450 actStr.insert(Service[i].AudioParam.iStreamID);
451
452 /* Data stream */
453 if (Service[i].DataParam.iStreamID != STREAM_ID_NOT_USED)
454 actStr.insert(Service[i].DataParam.iStreamID);
455 }
456 }
457 }
458
GetBitRateKbps(const int iShortID,const _BOOLEAN bAudData)459 _REAL CParameter::GetBitRateKbps(const int iShortID, const _BOOLEAN bAudData)
460 {
461 /* Init lengths to zero in case the stream is not yet assigned */
462 int iLen = 0;
463
464 /* First, check if audio or data service and get lengths */
465 if (Service[iShortID].eAudDataFlag == CService::SF_AUDIO)
466 {
467 /* Check if we want to get the data stream connected to an audio
468 stream */
469 if (bAudData == true)
470 {
471 iLen = GetStreamLen( Service[iShortID].DataParam.iStreamID);
472 }
473 else
474 {
475 iLen = GetStreamLen( Service[iShortID].AudioParam.iStreamID);
476 }
477 }
478 else
479 {
480 iLen = GetStreamLen( Service[iShortID].DataParam.iStreamID);
481 }
482
483 /* We have 3 frames with time duration of 1.2 seconds. Bit rate should be
484 returned in kbps (/ 1000) */
485 return (_REAL) iLen * SIZEOF__BYTE * 3 / (_REAL) 1.2 / 1000;
486 }
487
PartABLenRatio(const int iShortID)488 _REAL CParameter::PartABLenRatio(const int iShortID)
489 {
490 int iLenA = 0;
491 int iLenB = 0;
492
493 /* Get the length of protection part A and B */
494 if (Service[iShortID].eAudDataFlag == CService::SF_AUDIO)
495 {
496 /* Audio service */
497 if (Service[iShortID].AudioParam.iStreamID != STREAM_ID_NOT_USED)
498 {
499 iLenA = Stream[Service[iShortID].AudioParam.iStreamID].iLenPartA;
500 iLenB = Stream[Service[iShortID].AudioParam.iStreamID].iLenPartB;
501 }
502 }
503 else
504 {
505 /* Data service */
506 if (Service[iShortID].DataParam.iStreamID != STREAM_ID_NOT_USED)
507 {
508 iLenA = Stream[Service[iShortID].DataParam.iStreamID].iLenPartA;
509 iLenB = Stream[Service[iShortID].DataParam.iStreamID].iLenPartB;
510 }
511 }
512
513 const int iTotLen = iLenA + iLenB;
514
515 if (iTotLen != 0)
516 return (_REAL) iLenA / iTotLen;
517 else
518 return (_REAL) 0.0;
519 }
520
InitCellMapTable(const ERobMode eNewWaveMode,const ESpecOcc eNewSpecOcc)521 void CParameter::InitCellMapTable(const ERobMode eNewWaveMode,
522 const ESpecOcc eNewSpecOcc)
523 {
524 /* Set new values and make table */
525 eRobustnessMode = eNewWaveMode;
526 eSpectOccup = eNewSpecOcc;
527 CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup);
528 }
529
SetWaveMode(const ERobMode eNewWaveMode)530 _BOOLEAN CParameter::SetWaveMode(const ERobMode eNewWaveMode)
531 {
532 /* First check if spectrum occupancy and robustness mode pair is defined */
533 if ((
534 (eNewWaveMode == RM_ROBUSTNESS_MODE_E) ||
535 (eNewWaveMode == RM_ROBUSTNESS_MODE_D)
536 ) && !(
537 (eSpectOccup == SO_3) ||
538 (eSpectOccup == SO_5)
539 ))
540 {
541 /* Set spectrum occupance to a valid parameter */
542 eSpectOccup = SO_3;
543 }
544
545 /* Apply changes only if new paramter differs from old one */
546 if (eRobustnessMode != eNewWaveMode)
547 {
548 /* Set new value */
549 eRobustnessMode = eNewWaveMode;
550
551 /* This parameter change provokes update of table */
552 CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup);
553
554 /* Set init flags */
555 // if(pDRMRec) pDRMRec->InitsForWaveMode();
556
557 /* Signal that parameter has changed */
558 return true;
559 }
560 else
561 return false;
562 }
563
SetSpectrumOccup(ESpecOcc eNewSpecOcc)564 void CParameter::SetSpectrumOccup(ESpecOcc eNewSpecOcc)
565 {
566 /* First check if spectrum occupancy and robustness mode pair is defined */
567 if ((
568 (eRobustnessMode == RM_ROBUSTNESS_MODE_E) ||
569 (eRobustnessMode == RM_ROBUSTNESS_MODE_D)
570 ) && !(
571 (eNewSpecOcc == SO_3) ||
572 (eNewSpecOcc == SO_5)
573 ))
574 {
575 /* Set spectrum occupance to a valid parameter */
576 eNewSpecOcc = SO_3;
577 }
578
579 /* Apply changes only if new paramter differs from old one */
580 if (eSpectOccup != eNewSpecOcc)
581 {
582 /* Set new value */
583 eSpectOccup = eNewSpecOcc;
584
585 /* This parameter change provokes update of table */
586 CellMappingTable.MakeTable(eRobustnessMode, eSpectOccup);
587
588 /* Set init flags */
589 // if(pDRMRec) pDRMRec->InitsForSpectrumOccup();
590 }
591 }
592
SetStreamLen(const int iStreamID,const int iNewLenPartA,const int iNewLenPartB)593 void CParameter::SetStreamLen(const int iStreamID, const int iNewLenPartA,
594 const int iNewLenPartB)
595 {
596 /* Apply changes only if parameters have changed */
597 if ((Stream[iStreamID].iLenPartA != iNewLenPartA) ||
598 (Stream[iStreamID].iLenPartB != iNewLenPartB))
599 {
600 /* Use new parameters */
601 Stream[iStreamID].iLenPartA = iNewLenPartA;
602 Stream[iStreamID].iLenPartB = iNewLenPartB;
603
604 /* Set init flags */
605 // if(pDRMRec) pDRMRec->InitsForMSC();
606 }
607 }
608
GetStreamLen(const int iStreamID)609 int CParameter::GetStreamLen(const int iStreamID)
610 {
611 if(iStreamID != STREAM_ID_NOT_USED)
612 return Stream[iStreamID].iLenPartA + Stream[iStreamID].iLenPartB;
613 else
614 return 0;
615 }
616
SetNumDecodedBitsMSC(const int iNewNumDecodedBitsMSC)617 void CParameter::SetNumDecodedBitsMSC(const int iNewNumDecodedBitsMSC)
618 {
619 /* Apply changes only if parameters have changed */
620 if (iNewNumDecodedBitsMSC != iNumDecodedBitsMSC)
621 {
622 iNumDecodedBitsMSC = iNewNumDecodedBitsMSC;
623
624 /* Set init flags */
625 // if(pDRMRec) pDRMRec->InitsForMSCDemux();
626 }
627 }
628
SetNumDecodedBitsSDC(const int iNewNumDecodedBitsSDC)629 void CParameter::SetNumDecodedBitsSDC(const int iNewNumDecodedBitsSDC)
630 {
631 /* Apply changes only if parameters have changed */
632 if (iNewNumDecodedBitsSDC != iNumSDCBitsPerSFrame)
633 {
634 iNumSDCBitsPerSFrame = iNewNumDecodedBitsSDC;
635
636 /* Set init flags */
637 // if(pDRMRec) pDRMRec->InitsForNoDecBitsSDC();
638 }
639 }
640
SetNumBitsHieraFrTot(const int iNewNumBitsHieraFrTot)641 void CParameter::SetNumBitsHieraFrTot(const int iNewNumBitsHieraFrTot)
642 {
643 /* Apply changes only if parameters have changed */
644 if (iNewNumBitsHieraFrTot != iNumBitsHierarchFrameTotal)
645 {
646 iNumBitsHierarchFrameTotal = iNewNumBitsHieraFrTot;
647
648 /* Set init flags */
649 // if(pDRMRec) pDRMRec->InitsForMSCDemux();
650 }
651 }
652
SetNumAudioDecoderBits(const int iNewNumAudioDecoderBits)653 void CParameter::SetNumAudioDecoderBits(const int iNewNumAudioDecoderBits)
654 {
655 /* Apply changes only if parameters have changed */
656 if (iNewNumAudioDecoderBits != iNumAudioDecoderBits)
657 {
658 iNumAudioDecoderBits = iNewNumAudioDecoderBits;
659 }
660 }
661
SetNumDataDecoderBits(const int iNewNumDataDecoderBits)662 void CParameter::SetNumDataDecoderBits(const int iNewNumDataDecoderBits)
663 {
664 /* Apply changes only if parameters have changed */
665 if (iNewNumDataDecoderBits != iNumDataDecoderBits)
666 {
667 iNumDataDecoderBits = iNewNumDataDecoderBits;
668 }
669 }
670
SetMSCProtLev(const CMSCProtLev NewMSCPrLe,const _BOOLEAN bWithHierarch)671 void CParameter::SetMSCProtLev(const CMSCProtLev NewMSCPrLe,
672 const _BOOLEAN bWithHierarch)
673 {
674 // _BOOLEAN bParamersHaveChanged = false;
675
676 if ((NewMSCPrLe.iPartA != MSCPrLe.iPartA) ||
677 (NewMSCPrLe.iPartB != MSCPrLe.iPartB))
678 {
679 MSCPrLe.iPartA = NewMSCPrLe.iPartA;
680 MSCPrLe.iPartB = NewMSCPrLe.iPartB;
681
682 // bParamersHaveChanged = true;
683 }
684
685 /* Apply changes only if parameters have changed */
686 if (bWithHierarch == true)
687 {
688 if (NewMSCPrLe.iHierarch != MSCPrLe.iHierarch)
689 {
690 MSCPrLe.iHierarch = NewMSCPrLe.iHierarch;
691
692 // bParamersHaveChanged = true;
693 }
694 }
695
696 /* In case parameters have changed, set init flags */
697 // if (bParamersHaveChanged == true)
698 // if(pDRMRec) pDRMRec->InitsForMSC();
699 }
700
SetServiceParameters(int iShortID,const CService & newService)701 void CParameter::SetServiceParameters(int iShortID, const CService& newService)
702 {
703 Service[iShortID] = newService;
704 }
705
SetAudioParam(const int iShortID,const CAudioParam & NewAudParam)706 void CParameter::SetAudioParam(const int iShortID, const CAudioParam& NewAudParam)
707 {
708 /* Apply changes only if parameters have changed */
709 if (Service[iShortID].AudioParam != NewAudParam)
710 {
711 Service[iShortID].AudioParam = NewAudParam;
712
713 /* Set init flags */
714 // if(pDRMRec) pDRMRec->InitsForAudParam();
715 }
716 }
717
GetAudioParam(const int iShortID)718 CAudioParam CParameter::GetAudioParam(const int iShortID)
719 {
720 return Service[iShortID].AudioParam;
721 }
722
SetDataParam(const int iShortID,const CDataParam & NewDataParam)723 void CParameter::SetDataParam(const int iShortID, const CDataParam& NewDataParam)
724 {
725 CDataParam& DataParam = Service[iShortID].DataParam;
726
727 /* Apply changes only if parameters have changed */
728 if (DataParam != NewDataParam)
729 {
730 DataParam = NewDataParam;
731
732 /* Set init flags */
733 // if(pDRMRec) pDRMRec->InitsForDataParam();
734 }
735 }
736
GetDataParam(const int iShortID)737 CDataParam CParameter::GetDataParam(const int iShortID)
738 {
739 return Service[iShortID].DataParam;
740 }
741
SetInterleaverDepth(const ESymIntMod eNewDepth)742 void CParameter::SetInterleaverDepth(const ESymIntMod eNewDepth)
743 {
744 if (eSymbolInterlMode != eNewDepth)
745 {
746 eSymbolInterlMode = eNewDepth;
747
748 /* Set init flags */
749 // if(pDRMRec) pDRMRec->InitsForInterlDepth();
750 }
751 }
752
SetMSCCodingScheme(const ECodScheme eNewScheme)753 void CParameter::SetMSCCodingScheme(const ECodScheme eNewScheme)
754 {
755 if (eMSCCodingScheme != eNewScheme)
756 {
757 eMSCCodingScheme = eNewScheme;
758
759 /* Set init flags */
760 // if(pDRMRec) pDRMRec->InitsForMSCCodSche();
761 }
762 }
763
SetSDCCodingScheme(const ECodScheme eNewScheme)764 void CParameter::SetSDCCodingScheme(const ECodScheme eNewScheme)
765 {
766 if (eSDCCodingScheme != eNewScheme)
767 {
768 eSDCCodingScheme = eNewScheme;
769
770 /* Set init flags */
771 // if(pDRMRec) pDRMRec->InitsForSDCCodSche();
772 }
773 }
774
SetCurSelAudioService(const int iNewService)775 void CParameter::SetCurSelAudioService(const int iNewService)
776 {
777 /* Change the current selected audio service ID only if the new ID does
778 contain an audio service. If not, keep the old ID. In that case it is
779 possible to select a "data-only" service and still listen to the audio of
780 the last selected service */
781 if ((iCurSelAudioService != iNewService) &&
782 (Service[iNewService].AudioParam.iStreamID != STREAM_ID_NOT_USED))
783 {
784 iCurSelAudioService = iNewService;
785
786 LastAudioService.Reset();
787
788 /* Set init flags */
789 // if(pDRMRec) pDRMRec->InitsForAudParam();
790 }
791 }
792
SetCurSelDataService(const int iNewService)793 void CParameter::SetCurSelDataService(const int iNewService)
794 {
795 /* Change the current selected data service ID only if the new ID does
796 contain a data service. If not, keep the old ID. In that case it is
797 possible to select a "data-only" service and click back to an audio
798 service to be able to decode data service and listen to audio at the
799 same time */
800 if ((iCurSelDataService != iNewService) &&
801 (Service[iNewService].DataParam.iStreamID != STREAM_ID_NOT_USED))
802 {
803 iCurSelDataService = iNewService;
804
805 LastDataService.Reset();
806
807 /* Set init flags */
808 // if(pDRMRec) pDRMRec->InitsForDataParam();
809 }
810 }
811
EnableMultimedia(const _BOOLEAN bFlag)812 void CParameter::EnableMultimedia(const _BOOLEAN bFlag)
813 {
814 if (bUsingMultimedia != bFlag)
815 {
816 bUsingMultimedia = bFlag;
817
818 /* Set init flags */
819 // if(pDRMRec) pDRMRec->InitsForMSCDemux();
820 }
821 }
822
SetNumOfServices(const size_t iNNumAuSe,const size_t iNNumDaSe)823 void CParameter::SetNumOfServices(const size_t iNNumAuSe, const size_t iNNumDaSe)
824 {
825 /* Check whether number of activated services is not greater than the
826 number of services signalled by the FAC because it can happen that
827 a false CRC check (it is only a 8 bit CRC) of the FAC block
828 initializes a wrong service */
829 set<int> actServ;
830
831 GetActiveServices(actServ);
832 if (actServ.size() > iNNumAuSe + iNNumDaSe)
833 {
834 /* Reset services and streams and set flag for init modules */
835 ResetServicesStreams();
836 // if(pDRMRec) pDRMRec->InitsForMSCDemux();
837 }
838
839 if ((iNumAudioService != iNNumAuSe) || (iNumDataService != iNNumDaSe))
840 {
841 iNumAudioService = iNNumAuSe;
842 iNumDataService = iNNumDaSe;
843
844 /* Set init flags */
845 // if(pDRMRec) pDRMRec->InitsForMSCDemux();
846 }
847 }
848
SetAudDataFlag(const int iShortID,const CService::ETyOServ iNewADaFl)849 void CParameter::SetAudDataFlag(const int iShortID, const CService::ETyOServ iNewADaFl)
850 {
851 if (Service[iShortID].eAudDataFlag != iNewADaFl)
852 {
853 Service[iShortID].eAudDataFlag = iNewADaFl;
854
855 /* Set init flags */
856 // if(pDRMRec) pDRMRec->InitsForMSC();
857 }
858 }
859
SetServiceID(const int iShortID,const uint32_t iNewServiceID)860 void CParameter::SetServiceID(const int iShortID, const uint32_t iNewServiceID)
861 {
862 if (Service[iShortID].iServiceID != iNewServiceID)
863 {
864 /* JFBC - what is this for? */
865 if ((iShortID == 0) && (Service[0].iServiceID > 0))
866 ResetServicesStreams();
867
868 Service[iShortID].iServiceID = iNewServiceID;
869
870 /* Set init flags */
871 // if(pDRMRec) pDRMRec->InitsForMSC();
872
873
874 /* If the receiver has lost the sync automatically restore
875 last current service selected */
876
877 if ((iShortID > 0) && (iNewServiceID > 0))
878 {
879 if(LastAudioService.iServiceID == iNewServiceID)
880 {
881 /* Restore last audio service selected */
882 iCurSelAudioService = LastAudioService.iService;
883
884 LastAudioService.Reset();
885
886 /* Set init flags */
887 // if(pDRMRec) pDRMRec->InitsForAudParam();
888 }
889
890 if (LastDataService.iServiceID == iNewServiceID)
891 {
892 /* Restore last data service selected */
893 iCurSelDataService = LastDataService.iService;
894
895 LastDataService.Reset();
896
897 /* Set init flags */
898 // if(pDRMRec) pDRMRec->InitsForDataParam();
899 }
900 }
901 }
902 }
903
904
905 /* Implementaions for simulation -------------------------------------------- */
Add(uint32_t iNewSRS)906 void CRawSimData::Add(uint32_t iNewSRS)
907 {
908 /* Attention, function does not take care of overruns, data will be
909 lost if added to a filled shift register! */
910 if (iCurWritePos < ciMaxDelBlocks)
911 veciShRegSt[iCurWritePos++] = iNewSRS;
912 }
913
Get()914 uint32_t CRawSimData::Get()
915 {
916 /* We always use the first value of the array for reading and do a
917 shift of the other data by adding a arbitrary value (0) at the
918 end of the whole shift register */
919 uint32_t iRet = veciShRegSt[0];
920 veciShRegSt.AddEnd(0);
921 iCurWritePos--;
922
923 return iRet;
924 }
925
GetSysSNRdBPilPos() const926 _REAL CParameter::GetSysSNRdBPilPos() const
927 {
928 /*
929 Get system SNR in dB for the pilot positions. Since the average power of
930 the pilots is higher than the data cells, the SNR is also higher at these
931 positions compared to the total SNR of the DRM signal.
932 */
933 return (_REAL) 10.0 * log10(pow((_REAL) 10.0, rSysSimSNRdB / 10) /
934 CellMappingTable.rAvPowPerSymbol * CellMappingTable.rAvScatPilPow * (_REAL) CellMappingTable.iNumCarrier);
935 }
936
937 void
SetSNR(const _REAL iNewSNR)938 CParameter::SetSNR(const _REAL iNewSNR)
939 {
940 SNRstat.addSample(iNewSNR);
941 }
942
943 _REAL
GetSNR()944 CParameter::GetSNR()
945 {
946 return SNRstat.getCurrent();
947 }
948
GetNominalSNRdB()949 _REAL CParameter::GetNominalSNRdB()
950 {
951 /* Convert SNR from system bandwidth to nominal bandwidth */
952 return (_REAL) 10.0 * log10(pow((_REAL) 10.0, rSysSimSNRdB / 10) *
953 GetSysToNomBWCorrFact());
954 }
955
SetNominalSNRdB(const _REAL rSNRdBNominal)956 void CParameter::SetNominalSNRdB(const _REAL rSNRdBNominal)
957 {
958 /* Convert SNR from nominal bandwidth to system bandwidth */
959 rSysSimSNRdB = (_REAL) 10.0 * log10(pow((_REAL) 10.0, rSNRdBNominal / 10) /
960 GetSysToNomBWCorrFact());
961 }
962
GetNominalBandwidth()963 _REAL CParameter::GetNominalBandwidth()
964 {
965 _REAL rNomBW;
966
967 /* Nominal bandwidth as defined in the DRM standard */
968 switch (eSpectOccup)
969 {
970 case SO_0:
971 rNomBW = (_REAL) 4500.0; /* Hz */
972 break;
973
974 case SO_1:
975 rNomBW = (_REAL) 5000.0; /* Hz */
976 break;
977
978 case SO_2:
979 rNomBW = (_REAL) 9000.0; /* Hz */
980 break;
981
982 case SO_3:
983 rNomBW = (_REAL) 10000.0; /* Hz */
984 break;
985
986 case SO_4:
987 rNomBW = (_REAL) 18000.0; /* Hz */
988 break;
989
990 case SO_5:
991 rNomBW = (_REAL) 20000.0; /* Hz */
992 break;
993
994 default:
995 rNomBW = (_REAL) 10000.0; /* Hz */
996 break;
997 }
998
999 return rNomBW;
1000 }
1001
GetSysToNomBWCorrFact()1002 _REAL CParameter::GetSysToNomBWCorrFact()
1003 {
1004 _REAL rNomBW = GetNominalBandwidth();
1005
1006 /* Calculate system bandwidth (N / T_u) */
1007 const _REAL rSysBW = (_REAL) CellMappingTable.iNumCarrier / CellMappingTable.iFFTSizeN * SOUNDCRD_SAMPLE_RATE;
1008
1009 return rSysBW / rNomBW;
1010 }
1011
1012
SetIFSignalLevel(_REAL rNewSigStr)1013 void CParameter::SetIFSignalLevel(_REAL rNewSigStr)
1014 {
1015 rIFSigStr = rNewSigStr;
1016 }
1017
GetIFSignalLevel()1018 _REAL CParameter::GetIFSignalLevel()
1019 {
1020 return rIFSigStr;
1021 }
1022
SetStatus(const ETypeRxStatus OK)1023 void CRxStatus::SetStatus(const ETypeRxStatus OK)
1024 {
1025 status = OK;
1026 iNum++;
1027 if(OK==RX_OK)
1028 iNumOK++;
1029 }
1030
1031 //void CParameter::GenerateReceiverID()
1032 //{
1033 // //Set receiver ID
1034 // string sVer;
1035 // unsigned int iImplementation = 0;;
1036 // unsigned int iMajor = 0;
1037 // unsigned int iMinor = 0;
1038
1039 // sReceiverID = "drea";
1040
1041 // sVer = dream_version;
1042
1043 // size_t pos;
1044
1045 // while((pos = sVer.find('.')) != string::npos)
1046 // sVer.replace(pos, 1, " ");
1047
1048 // if ((pos = sVer.find("cvs")) != string::npos)
1049 // sVer.replace(pos, 3, " ");
1050
1051 // stringstream ssVer(sVer);
1052 // ssVer >> iImplementation >> iMajor >> iMinor;
1053
1054 // stringstream ssInfoVer;
1055 // ssInfoVer << setw(2) << setfill('0') << iImplementation << setw(2) << setfill('0') << iMajor << setw(2) << setfill('0') << iMinor;
1056
1057 // sReceiverID += ssInfoVer.str();
1058
1059 // while (sSerialNumber.length() < 6)
1060 // sSerialNumber += "_";
1061
1062 // if (sSerialNumber.length() > 6)
1063 // sSerialNumber.erase(6, pDRMRec->GetParameters()->sSerialNumber.length()-6);
1064
1065 // sReceiverID += pDRMRec->GetParameters()->sSerialNumber;
1066 //}
1067
GenerateRandomSerialNumber()1068 void CParameter::GenerateRandomSerialNumber()
1069 {
1070 //seed random number generator
1071 srand((unsigned int)time(0));
1072
1073 char randomChars[36];
1074
1075 for (size_t q=0; q < 36; q++)
1076 {
1077 if (q < 26)
1078 randomChars[q] = char(q)+97;
1079 else
1080 randomChars[q] = (char(q)-26)+48;
1081 }
1082
1083 char serialNumTemp[7];
1084
1085 for (size_t i=0; i < 6; i++)
1086 serialNumTemp[i] = randomChars[(int) 35.0*rand()/RAND_MAX];
1087
1088 serialNumTemp[6] = '\0';
1089
1090 sSerialNumber = serialNumTemp;
1091 }
1092
CMinMaxMean()1093 CMinMaxMean::CMinMaxMean():rSum(0.0),rCur(0.0),
1094 rMin(numeric_limits<_REAL>::max()),rMax(numeric_limits<_REAL>::min()),iNum(0)
1095 {
1096 }
1097
1098 void
addSample(_REAL r)1099 CMinMaxMean::addSample(_REAL r)
1100 {
1101 rCur = r;
1102 rSum += r;
1103 iNum++;
1104 if(r>rMax)
1105 rMax = r;
1106 if(r<rMin)
1107 rMin = r;
1108 }
1109
1110 _REAL
getCurrent()1111 CMinMaxMean::getCurrent()
1112 {
1113 return rCur;
1114 }
1115
1116 _REAL
getMean()1117 CMinMaxMean::getMean()
1118 {
1119 _REAL rMean = 0.0;
1120 if(iNum>0)
1121 rMean = rSum / iNum;
1122 rSum = 0.0;
1123 iNum = 0;
1124 return rMean;
1125 }
1126
1127 void
getMinMax(_REAL & rMinOut,_REAL & rMaxOut)1128 CMinMaxMean::getMinMax(_REAL& rMinOut, _REAL& rMaxOut)
1129 {
1130 if(rMin <= rMax)
1131 {
1132 rMinOut = rMin;
1133 rMaxOut = rMax;
1134 }
1135 else
1136 {
1137 rMinOut = 0.0;
1138 rMaxOut = 0.0;
1139 }
1140 rMin = numeric_limits<_REAL>::max();
1141 rMax = numeric_limits<_REAL>::min();
1142 }
1143
Frequency(size_t n) const1144 string CServiceDefinition::Frequency(size_t n) const
1145 {
1146 if(n>=veciFrequencies.size())
1147 return ""; // not in the list
1148
1149 stringstream ss;
1150 int iFrequency = veciFrequencies[n];
1151
1152 switch (iSystemID)
1153 {
1154 case 0:
1155 case 1:
1156 case 2:
1157 /* AM or DRM */
1158 ss << iFrequency;
1159 break;
1160
1161 case 3:
1162 case 4:
1163 case 5:
1164 /* 'FM1 frequency' - 87.5 to 107.9 MHz (100 kHz steps) */
1165 ss << 87.5 + 0.1 * float(iFrequency);
1166 break;
1167
1168 case 6:
1169 case 7:
1170 case 8:
1171 /* 'FM2 frequency'- 76.0 to 90.0 MHz (100 kHz steps) */
1172 ss << 76.0 + 0.1 * float(iFrequency);
1173 break;
1174
1175 case 9:
1176 case 10:
1177 case 11:
1178 if(iFrequency<=11) {
1179 int chan = iFrequency / 4;
1180 char subchan = 'A' + iFrequency % 4;
1181 ss << "Band I channel " << (chan+2) << subchan;
1182 } else if(64<= iFrequency && iFrequency <=95) {
1183 int chan = iFrequency / 4;
1184 char subchan = 'A' + iFrequency % 4;
1185 ss << "Band III channel " << (chan-11) << subchan;
1186 } else if(96<= iFrequency && iFrequency <=101) {
1187 int chan = iFrequency / 6;
1188 char subchan = 'A' + iFrequency % 6;
1189 ss << "Band III+ channel " << (chan-3) << subchan;
1190 } else if(128<= iFrequency && iFrequency <=143) {
1191 char chan = iFrequency - 128;
1192 double m = 1452.96+1.712*double(chan);
1193 ss << "European L-Band channel L" << ('A'+chan) << ", " << m << " MHz";
1194 } else if(160<= iFrequency && iFrequency <=182) {
1195 int chan = iFrequency - 159;
1196 double m = 1451.072+1.744*double(chan);
1197 ss << "Canadian L-Band channel " << chan << ", " << m << " MHz";
1198 } else {
1199 ss << "unknown channel " << iFrequency;
1200 }
1201 break;
1202 default:
1203 break;
1204 }
1205 return ss.str();
1206 }
1207
FrequencyUnits() const1208 string CServiceDefinition::FrequencyUnits() const
1209 {
1210 switch (iSystemID)
1211 {
1212 case 0:
1213 case 1:
1214 case 2:
1215 return "kHz";
1216 break;
1217
1218 case 3:
1219 case 4:
1220 case 5:
1221 case 6:
1222 case 7:
1223 case 8:
1224 return "MHz";
1225 break;
1226
1227 default:
1228 return "";
1229 break;
1230 }
1231 }
1232
System() const1233 string CServiceDefinition::System() const
1234 {
1235 switch (iSystemID)
1236 {
1237 case 0:
1238 return "DRM";
1239 break;
1240
1241 case 1:
1242 case 2:
1243 return "AM";
1244 break;
1245
1246 case 3:
1247 case 4:
1248 case 5:
1249 case 6:
1250 case 7:
1251 case 8:
1252 return "FM";
1253 break;
1254 case 9:
1255 case 10:
1256 case 11:
1257 return "DAB";
1258 break;
1259
1260 default:
1261 return "";
1262 break;
1263 }
1264 }
1265
ServiceID() const1266 string COtherService::ServiceID() const
1267 {
1268 stringstream ss;
1269 /*
1270 switch (iSystemID)
1271 {
1272 case 0:
1273 case 1:
1274 ss << "ID:" << hex << setw(6) << iServiceID;
1275 break;
1276
1277 case 3:
1278 case 6:
1279 ss << "ECC+PI:" << hex << setw(6) << iServiceID;
1280 break;
1281 case 4:
1282 case 7:
1283 ss << "PI:" << hex << setw(4) << iServiceID;
1284 break;
1285 case 9:
1286 ss << "ECC+aud:" << hex << setw(6) << iServiceID;
1287 break;
1288 case 10:
1289 ss << "AUDIO:" << hex << setw(4) << iServiceID;
1290 break;
1291 case 11:
1292 ss << "DATA:" << hex << setw(8) << iServiceID;
1293 break;
1294 break;
1295
1296 default:
1297 break;
1298 }
1299 */
1300 return ss.str();
1301 }
1302
1303 /* See ETSI ES 201 980 v2.1.1 Annex O */
1304 _BOOLEAN
IsActive(const time_t ltime)1305 CAltFreqSched::IsActive(const time_t ltime)
1306 {
1307 int iScheduleStart;
1308 int iScheduleEnd;
1309 int iWeekDay;
1310
1311 /* Empty schedule is always active */
1312 if (iDuration == 0)
1313 return true;
1314
1315 /* Calculate time in UTC */
1316 struct tm *gmtCur = gmtime(<ime);
1317
1318 /* Check day
1319 tm_wday: day of week (0 - 6; Sunday = 0)
1320 I must normalize so Monday = 0 */
1321
1322 if (gmtCur->tm_wday == 0)
1323 iWeekDay = 6;
1324 else
1325 iWeekDay = gmtCur->tm_wday - 1;
1326
1327 /* iTimeWeek minutes since last Monday 00:00 in UTC */
1328 /* the value is in the range 0 <= iTimeWeek < 60 * 24 * 7) */
1329
1330 const int iTimeWeek =
1331 (iWeekDay * 24 * 60) + (gmtCur->tm_hour * 60) + gmtCur->tm_min;
1332
1333 /* Day Code: this field indicates which days the frequency schedule
1334 * (the following Start Time and Duration) applies to.
1335 * The msb indicates Monday, the lsb Sunday. Between one and seven bits may be set to 1.
1336 */
1337 for (int i = 0; i < 7; i++)
1338 {
1339 /* Check if day is active */
1340 if ((1 << (6 - i)) & iDayCode)
1341 {
1342 /* Tuesday -> 1 * 24 * 60 = 1440 */
1343 iScheduleStart = (i * 24 * 60) + iStartTime;
1344 iScheduleEnd = iScheduleStart + iDuration;
1345
1346 /* the normal check (are we inside start and end?) */
1347 if ((iTimeWeek >= iScheduleStart) && (iTimeWeek <= iScheduleEnd))
1348 return true;
1349
1350 /* the wrap-around check */
1351 const int iMinutesPerWeek = 7 * 24 * 60;
1352
1353 if (iScheduleEnd > iMinutesPerWeek)
1354 {
1355 /* our duration wraps into next Monday (or even later) */
1356 if (iTimeWeek < (iScheduleEnd - iMinutesPerWeek))
1357 return true;
1358 }
1359 }
1360 }
1361 return false;
1362 }
1363