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(&ltime);
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