NetSim Source Code Help v14.4
All 13 Components
 
Loading...
Searching...
No Matches
Medium.c
1/************************************************************************************
2* Copyright (C) 2023 *
3* TETCOS, Bangalore. India *
4* *
5* Tetcos owns the intellectual property rights in the Product and its content. *
6* The copying, redistribution, reselling or publication of any or all of the *
7* Product or its content without express prior written consent of Tetcos is *
8* prohibited. Ownership and / or any other right relating to the software and all *
9* intellectual property rights therein shall remain at all times with Tetcos. *
10* *
11* This source code is licensed per the NetSim license agreement. *
12* *
13* No portion of this source code may be used as the basis for a derivative work, *
14* or used, for any purpose other than its intended use per the NetSim license *
15* agreement. *
16* *
17* This source code and the algorithms contained within it are confidential trade *
18* secrets of TETCOS and may not be used as the basis for any other software, *
19* hardware, product or service. *
20* *
21* Author: Shashi Kant Suman *
22* *
23* ----------------------------------------------------------------------------------*/
24#define _NETSIM_MDEIUM_CODE_
25#include "main.h"
26#include "Medium.h"
27#include "ErrorModel.h"
28#include "PropagationModel.h"
29#pragma comment(lib,"NetworkStack.lib")
30#pragma comment(lib,"Metrics.lib")
31#pragma comment(lib,"PropagationModel.lib")
32//#define _MEDIUM_LOG_
33
34typedef struct stru_Packet_info
35{
36 NetSim_PACKET* packet;
37 NETSIM_ID txId;
38 NETSIM_ID txIf;
39 NETSIM_ID rxId;
40 NETSIM_ID rxIf;
41 double startTime_us;
42 double endTime_us;
43 PHY_MODULATION modulation;
44 double codeRate;
45 double dDataRate_mbps;
46 double dFrequency_MHz;
47 double dBandwidth_MHz;
48
49 double dMaxInterference_dbm;
50 double dRXPower_dbm;
51 struct stru_Packet_info* next;
52}PACKETINFO, *ptrPACKETINFO;
53
54typedef struct stru_Device
55{
56 NETSIM_ID deviceId;
57 NETSIM_ID interfaceId;
58 double frequency_MHz;
59 double bandwidth_MHz;
60 double dRxSensitivity_dBm;
61 double dEDThreshold_dBm;
62 PHY_MODULATION modulation;
63 double dCodeRate;
64 double dDataRate_mbps;
65
66 //SNR-PEP-Table Function
67 int MCS;
68 string StandardType;
69 string Ber_Model;
70
71 double dCummulativeReceivedPower_mw;
72 double dCummulativeReceivedPower_dbm;
73
74 void(*medium_change_callback)(NETSIM_ID, NETSIM_ID, bool, NetSim_PACKET*);
75 bool(*isRadioIdle)(NETSIM_ID, NETSIM_ID);
76 void* (*propagationinfo_find)(NETSIM_ID, NETSIM_ID, NETSIM_ID, NETSIM_ID);
77 bool(*isTranmitterBusy)(NETSIM_ID, NETSIM_ID);
78 void(*packetSentNotify)(NETSIM_ID, NETSIM_ID, NetSim_PACKET*);
79}DEVICE_IN_MEDIUM, *ptrDEVICE_IN_MEDIUM;
80
81typedef struct stru_medium
82{
83 ptrDEVICE_IN_MEDIUM** devices;
84 ptrPACKETINFO transmissionPacket;
85}MEDIUM,*ptrMEDIUM;
86static MEDIUM medium;
87static ptrDEVICE_IN_MEDIUM medium_find_device(NETSIM_ID devId,
88 NETSIM_ID devIf)
89{
90 if (!devId || !devIf)
91 fnNetSimError("Device id = %d, device interface = %d is not a valid input for %s,",
92 devId,
93 devIf,
94 __FUNCTION__);
95 if (medium.devices &&
96 medium.devices[devId - 1])
97 return medium.devices[devId - 1][devIf - 1];
98 return NULL;
99}
100
101
102static FILE* fplog = NULL;
103static void write_log(char* format,...)
104{
105#ifdef _MEDIUM_LOG_
106 if (fplog == NULL)
107 {
108 char str[BUFSIZ];
109 sprintf(str, "%s\\%s", pszIOLogPath, "medium.log");
110 fplog = fopen(str, "w");
111 }
112 va_list ls;
113 va_start(ls, format);
114 vfprintf(fplog, format, ls);
115 fflush(fplog);
116#else
117 format;
118#endif
119}
120
121static double GetRXPowerdBm(NETSIM_ID t, NETSIM_ID ti, NETSIM_ID r, NETSIM_ID ri, double time)
122{
123 ptrDEVICE_IN_MEDIUM dm = medium_find_device(t, ti);
124 if (!dm)
125 {
126 fnNetSimError("Device %d, interface %d is not added to medium before transmission.",
127 t, ti);
128 return NEGATIVE_DBM;
129 }
130
131 PPROPAGATION_INFO info = dm->propagationinfo_find(t, ti, r, ri);
132 if (info == NULL)
133 {
134 fnNetSimErrorandStop("Propagation info is NULL between %d:%d-%d:%d\n", t, ti, r, ri);
135 return NEGATIVE_DBM;
136 }
137 return _propagation_get_received_power_dbm(info, time);
138}
139
140_declspec(dllexport) void medium_add_device(NETSIM_ID d,
141 NETSIM_ID ifid,
142 double dFrequency_MHz,
143 double dBandwidth_MHz,
144 double dRxSensitivity_dBm,
145 double dEdThreshold_dBm,
146 void(*medium_change_callback)(NETSIM_ID, NETSIM_ID, bool,NetSim_PACKET*),
147 bool(*isRadioIdle)(NETSIM_ID, NETSIM_ID),
148 bool(*isTransmitterBusy)(NETSIM_ID, NETSIM_ID),
149 void*(*propagationinfo_find)(NETSIM_ID, NETSIM_ID, NETSIM_ID, NETSIM_ID),
150 void(*packetsentnotify)(NETSIM_ID,NETSIM_ID,NetSim_PACKET*))
151{
152 ptrDEVICE_IN_MEDIUM dm = calloc(1, sizeof * dm);
153 dm->deviceId = d;
154 dm->interfaceId = ifid;
155 dm->dEDThreshold_dBm = dEdThreshold_dBm;
156 dm->dRxSensitivity_dBm = dRxSensitivity_dBm;
157 dm->frequency_MHz = dFrequency_MHz;
158 dm->bandwidth_MHz = dBandwidth_MHz;
159 dm->dCummulativeReceivedPower_dbm = NEGATIVE_INFINITY;
160 dm->medium_change_callback = medium_change_callback;
161 dm->isRadioIdle = isRadioIdle;
162 dm->isTranmitterBusy = isTransmitterBusy;
163 dm->propagationinfo_find = propagationinfo_find;
164 dm->packetSentNotify = packetsentnotify;
165
166 if (!medium.devices)
167 medium.devices = calloc(NETWORK->nDeviceCount, sizeof * medium.devices);
168 if (!medium.devices[d - 1])
169 medium.devices[d - 1] = calloc(DEVICE(d)->nNumOfInterface, sizeof * medium.devices[d - 1]);
170 medium.devices[d - 1][ifid - 1] = dm;
171}
172
173_declspec(dllexport) void medium_update_frequency(NETSIM_ID d, NETSIM_ID in, double f_MHz)
174{
175 ptrDEVICE_IN_MEDIUM dm = medium_find_device(d, in);
176 if (!dm)
177 {
178 fnNetSimError("%s is called without adding device %d:%d to medium. use medium_add_device to add the device.\n",
179 __FUNCTION__, d, in);
180 return;
181 }
182 dm->frequency_MHz = f_MHz;
183}
184
185_declspec(dllexport) void medium_update_bandwidth(NETSIM_ID d, NETSIM_ID in, double bw_MHz)
186{
187 ptrDEVICE_IN_MEDIUM dm = medium_find_device(d, in);
188 if (!dm)
189 {
190 fnNetSimError("%s is called without adding device %d:%d to medium. use medium_add_device to add the device.\n",
191 __FUNCTION__, d, in);
192 return;
193 }
194 dm->bandwidth_MHz = bw_MHz;
195}
196
197_declspec(dllexport) void medium_update_rxsensitivity(NETSIM_ID d, NETSIM_ID in, double p_dbm)
198{
199 ptrDEVICE_IN_MEDIUM dm = medium_find_device(d, in);
200 if (!dm)
201 {
202 fnNetSimError("%s is called without adding device %d:%d to medium. use medium_add_device to add the device.\n",
203 __FUNCTION__, d, in);
204 return;
205 }
206 dm->dRxSensitivity_dBm = p_dbm;
207}
208
209_declspec(dllexport) void medium_update_edthershold(NETSIM_ID d, NETSIM_ID in, double p_dbm)
210{
211 ptrDEVICE_IN_MEDIUM dm = medium_find_device(d, in);
212 if (!dm)
213 {
214 fnNetSimError("%s is called without adding device %d:%d to medium. use medium_add_device to add the device.\n",
215 __FUNCTION__, d, in);
216 return;
217 }
218 dm->dEDThreshold_dBm = p_dbm;
219}
220
221_declspec(dllexport) void medium_update_modulation(NETSIM_ID d, NETSIM_ID in, PHY_MODULATION m, double coderate)
222{
223 ptrDEVICE_IN_MEDIUM dm = medium_find_device(d, in);
224 if (!dm)
225 {
226 fnNetSimError("%s is called without adding device %d:%d to medium. use medium_add_device to add the device.\n",
227 __FUNCTION__, d, in);
228 return;
229 }
230 dm->modulation = m;
231 dm->dCodeRate = coderate;
232}
233
234_declspec(dllexport) void medium_update_datarate(NETSIM_ID d, NETSIM_ID in, double r_mbps)
235{
236 ptrDEVICE_IN_MEDIUM dm = medium_find_device(d, in);
237 if (!dm)
238 {
239 fnNetSimError("%s is called without adding device %d:%d to medium. use medium_add_device to add the device.\n",
240 __FUNCTION__, d, in);
241 return;
242 }
243 dm->dDataRate_mbps = r_mbps;
244}
245
246_declspec(dllexport) void medium_update_MCS(NETSIM_ID d, NETSIM_ID in, int MCS, string Standard, string BER_Model)
247{
248 ptrDEVICE_IN_MEDIUM dm = medium_find_device(d, in);
249 if (!dm)
250 {
251 fnNetSimError("%s is called without adding device %d:%d to medium. use medium_add_device to add the device.\n",
252 __FUNCTION__, d, in);
253 return;
254 }
255 dm->MCS = MCS;
256 dm->StandardType = Standard;
257 dm->Ber_Model = BER_Model;
258}
259
260static void medium_remove_device(NETSIM_ID d,
261 NETSIM_ID ifId)
262{
263 ptrDEVICE_IN_MEDIUM dm = medium_find_device(d, ifId);
264 if (dm)
265 {
266 free(dm);
267 medium.devices[d - 1][ifId - 1] = NULL;
268 }
269}
270
271static ptrPACKETINFO packetInfo_add(NetSim_PACKET* packet,
272 NETSIM_ID txId,
273 NETSIM_ID txIf,
274 NETSIM_ID rxId,
275 NETSIM_ID rxIf)
276{
277 ptrDEVICE_IN_MEDIUM dm = medium_find_device(txId, txIf);
278
279 ptrPACKETINFO p = calloc(1, sizeof* p);
280 p->packet = packet;
281 p->rxId = rxId;
282 p->rxIf = rxIf;
283 p->startTime_us = packet->pstruPhyData->dArrivalTime;
284 p->endTime_us = packet->pstruPhyData->dEndTime;
285 p->txId = txId;
286 p->txIf = txIf;
287
288 p->codeRate = dm->dCodeRate;
289 p->dBandwidth_MHz = dm->bandwidth_MHz;
290 p->dDataRate_mbps = dm->dDataRate_mbps;
291 p->dFrequency_MHz = dm->frequency_MHz;
292 p->modulation = dm->modulation;
293 p->dRXPower_dbm = GetRXPowerdBm(txId, txIf, rxId, rxIf, p->startTime_us);
294 p->dMaxInterference_dbm = NEGATIVE_DBM;
295
296 if (medium.transmissionPacket)
297 {
298 ptrPACKETINFO t = medium.transmissionPacket;
299 while (t->next)
300 t = t->next;
301 t->next = p;
302 }
303 else
304 {
305 medium.transmissionPacket = p;
306 }
307 write_log("New Packet %d,TX=%d-%d,RX=%d-%d,RxPower=%lf,\n",
308 p->packet->nPacketId == 0 ? p->packet->nControlDataType * -1 : p->packet->nPacketId,
309 txId, txIf, rxId, rxIf,
310 p->dRXPower_dbm);
311 return p;
312}
313
314static ptrPACKETINFO packetInfo_find(NetSim_PACKET* packet,
315 NETSIM_ID txId,
316 NETSIM_ID txIf,
317 NETSIM_ID rxId,
318 NETSIM_ID rxIf)
319
320{
321 ptrPACKETINFO i = medium.transmissionPacket;
322 while (i)
323 {
324 if (txId == i->txId && txIf == i->txIf && rxId == i->rxId && rxIf == i->rxIf && packet == i->packet)
325 return i;
326 i = i->next;
327 }
328 return NULL;
329}
330
331
332static ptrPACKETINFO packetInfo_remove(NetSim_PACKET* packet)
333{
334 ptrPACKETINFO p = medium.transmissionPacket;
335 ptrPACKETINFO pr = NULL;
336 while (p)
337 {
338 if (p->packet == packet)
339 {
340 if (pr)
341 {
342 pr->next = p->next;
343 break;
344 }
345 else
346 {
347 medium.transmissionPacket = p->next;
348 break;
349 }
350 }
351 pr = p;
352 p = p->next;
353 }
354 p->next = NULL;
355 write_log("remove Packet %d,TX=%d-%d,RX=%d-%d,RxPower=%lf,\n",
356 p->packet->nPacketId == 0 ? p->packet->nControlDataType * -1 : p->packet->nPacketId,
357 p->txId, p->txIf, p->rxId, p->rxIf,
358 p->dRXPower_dbm);
359 return p;
360}
361
362static void packetInfo_free(ptrPACKETINFO info)
363{
364 free(info);
365}
366
367#define BOLTZMANN 1.38064852e-23 //m2kgs-2K-1
368#define TEMPERATURE 300 //kelvin
369static double compute_sinr(double p, double i, double bw)
370{
371 double noise = BOLTZMANN * TEMPERATURE * bw * 1000000; //in W
372 double Pmw = DBM_TO_MW(p);
373 double imw = DBM_TO_MW(i);
374 noise *= 1000; // in mW
375 return MW_TO_DBM(Pmw / (noise + imw));
376}
377
378static double GetRXPowerMW(NETSIM_ID t, NETSIM_ID ti, NETSIM_ID r, NETSIM_ID ri, double time)
379{
380 return DBM_TO_MW(GetRXPowerdBm(t, ti, r, ri, time));
381}
382
383static void medium_update_interference(ptrPACKETINFO info)
384{
385 info;
386 ptrPACKETINFO i = medium.transmissionPacket;
387 while (i)
388 {
389 /*if (i->txId == info->txId &&
390 i->txIf == info->txIf &&
391 i != info)
392 {
393 i = i->next;
394 continue;
395 }*/
396 ptrDEVICE_IN_MEDIUM dm = medium_find_device(i->rxId, i->rxIf);
397
398 double pdbm = GetRXPowerdBm(i->txId, i->txIf,
399 i->rxId, i->rxIf,
400 i->startTime_us);
401 double p = DBM_TO_MW(pdbm);
402
403 double interference = dm->dCummulativeReceivedPower_mw - p;
404 double interferencedbm = MW_TO_DBM(interference);
405
406 i->dMaxInterference_dbm = max(i->dMaxInterference_dbm, interferencedbm);
407
408 //if (dm->isTranmitterBusy(dm->deviceId, dm->interfaceId)) // Transmitter refers to transceiver.
409 //{
410 // i->packet->nPacketStatus = PacketStatus_Collided; // Also receiving when transmitting
411 // write_log("Packet %d collided due to %d-%d busy,\n",
412 // i->packet->nPacketId == 0 ? i->packet->nControlDataType * -1 : i->packet->nPacketId,
413 // dm->deviceId, dm->interfaceId);
414 //}
415
416 i = i->next;
417 }
418}
419
420static bool isAnypacketIsThereForThisTransmitter(ptrPACKETINFO info)
421{
422 ptrPACKETINFO i = medium.transmissionPacket;
423 while (i)
424 {
425 if (i != info)
426 {
427 if (i->txId == info->txId &&
428 i->txIf == info->txIf)
429 return true;
430 }
431 i = i->next;
432 }
433 return false;
434}
435
436static bool CheckFrequencyInterfrence(double dFrequency1, double dFrequency2, double bandwidth)
437{
438 if (dFrequency1 > dFrequency2)
439 {
440 if ((dFrequency1 - dFrequency2) >= bandwidth)
441 return false; // no interference
442 else
443 return true; // interference
444 }
445 else
446 {
447 if ((dFrequency2 - dFrequency1) >= bandwidth)
448 return false; // no interference
449 else
450 return true; // interference
451 }
452}
453
454static void update_power_due_to_transmission(ptrPACKETINFO info)
455{
456 ptrDEVICE_IN_MEDIUM txdm = medium_find_device(info->txId, info->txIf);
457 if (!txdm)
458 {
459 fnNetSimError("Device %d, interface %d is not added to medium before transmission.",
460 info->txId, info->txIf);
461 return;
462 }
463
464 NETSIM_ID nLoop, nLoopInterface;
465 for (nLoop = 1; nLoop <= NETWORK->nDeviceCount; nLoop++)
466 {
467 for (nLoopInterface = 1; nLoopInterface <= DEVICE(nLoop)->nNumOfInterface; nLoopInterface++)
468 {
469 ptrDEVICE_IN_MEDIUM dm = medium_find_device(nLoop, nLoopInterface);
470 if (!dm)
471 continue;
472
473 if (!CheckFrequencyInterfrence(txdm->frequency_MHz, dm->frequency_MHz, txdm->bandwidth_MHz))
474 continue; //Different band
475
476
477 double p = GetRXPowerMW(txdm->deviceId, txdm->interfaceId,
478 dm->deviceId, dm->interfaceId,
479 info->startTime_us);
480
481 dm->dCummulativeReceivedPower_mw += p;
482
483 dm->dCummulativeReceivedPower_dbm = MW_TO_DBM(dm->dCummulativeReceivedPower_mw);
484
485 write_log("\tTotal recv power of %d-%d = %lf\n", dm->deviceId, dm->interfaceId,
486 dm->dCummulativeReceivedPower_dbm);
487
488 if (nLoop == info->rxId &&
489 nLoopInterface == info->rxIf) continue; // Ignore receiver
490 if (nLoop == info->txId &&
491 nLoopInterface == info->txIf) continue; // Ignore transmitter
492
493 if (dm->dCummulativeReceivedPower_dbm > dm->dEDThreshold_dBm &&
494 dm->medium_change_callback)
495 dm->medium_change_callback(dm->deviceId, dm->interfaceId, true, info->packet);
496 double pdbm = GetRXPowerdBm(info->txId, info->txIf, dm->deviceId, dm->interfaceId, info->startTime_us);
497 if (pdbm > dm->dEDThreshold_dBm && dm->packetSentNotify)
498 dm->packetSentNotify(dm->deviceId, dm->interfaceId, info->packet);
499 }
500 }
501}
502
503static void update_power_due_to_transmission_stop(ptrPACKETINFO info)
504{
505 ptrDEVICE_IN_MEDIUM txdm = medium_find_device(info->txId, info->txIf);
506 if (!txdm)
507 {
508 fnNetSimError("Device %d, interface %d is not added to medium before transmission.",
509 info->txId, info->txIf);
510 return;
511 }
512
513 NETSIM_ID nLoop, nLoopInterface;
514 for (nLoop = 1; nLoop <= NETWORK->nDeviceCount; nLoop++)
515 {
516 for (nLoopInterface = 1; nLoopInterface <= DEVICE(nLoop)->nNumOfInterface; nLoopInterface++)
517 {
518 if (nLoop == info->txId &&
519 nLoopInterface == info->txIf)
520 {
521 if(txdm->isRadioIdle(txdm->deviceId, txdm->interfaceId) &&
522 txdm->medium_change_callback)
523 txdm->medium_change_callback(txdm->deviceId, txdm->interfaceId, false, NULL);
524 //continue;
525 }
526
527 ptrDEVICE_IN_MEDIUM dm = medium_find_device(nLoop, nLoopInterface);
528 if (!dm)
529 continue;
530
531 if (!CheckFrequencyInterfrence(txdm->frequency_MHz, dm->frequency_MHz, txdm->bandwidth_MHz))
532 continue; //Different band
533
534
535 dm->dCummulativeReceivedPower_mw -= GetRXPowerMW(txdm->deviceId, txdm->interfaceId,
536 dm->deviceId, dm->interfaceId,
537 info->startTime_us);
538
539 dm->dCummulativeReceivedPower_dbm = MW_TO_DBM(dm->dCummulativeReceivedPower_mw);
540
541 if (nLoop == info->rxId &&
542 nLoopInterface == info->rxIf) continue; // Ignore receiver
543 if (nLoop == info->txId &&
544 nLoopInterface == info->txIf) continue; // Ignore transmitter
545
546 if (dm->dCummulativeReceivedPower_dbm < dm->dEDThreshold_dBm &&
547 dm->medium_change_callback)
548 dm->medium_change_callback(dm->deviceId, dm->interfaceId, false, NULL);
549 }
550 }
551}
552
553static void medium_mark_packet_error(ptrPACKETINFO info)
554{
555 ptrDEVICE_IN_MEDIUM dm = medium_find_device(info->txId, info->txIf);
556 double i = info->dMaxInterference_dbm;
557 double p = info->dRXPower_dbm;
558 double w = info->dBandwidth_MHz;
559 double ber;
560 double f = _propagation_calculate_fadingloss(dm->propagationinfo_find(
561 info->txId, info->txIf,
562 info->rxId, info->rxIf));
563 p -= f;
564
565 //BER Model Selection
566 if (strcmp(dm->Ber_Model, "SINR_BER_PER_TABLE") == 0)
567 ber = calculate_BER_Using_Table(info->modulation, p, i, w, dm->MCS, dm->StandardType);
568 else
569 ber = calculate_FEC_BER(info->modulation, info->codeRate, p, i, w, info->dDataRate_mbps);
570
571 PACKET_STATUS status = fn_NetSim_Packet_DecideError(ber, info->packet->pstruPhyData->dPacketSize);
572 if (status == PacketStatus_Error && info->packet->nPacketStatus == PacketStatus_NoError)
573 {
574 if (i >= dm->dRxSensitivity_dBm) info->packet->nPacketStatus = PacketStatus_Collided;
575 else info->packet->nPacketStatus = PacketStatus_Error;
576 write_log("Packet %d errored, BER=%lf, Interference=%lf, RXPower=%lf,\n",
577 info->packet->nPacketId == 0 ? info->packet->nControlDataType * -1 : info->packet->nPacketId,
578 ber, i, p);
579 }
580}
581
582_declspec(dllexport) void medium_notify_packet_send(NetSim_PACKET* packet,
583 NETSIM_ID txId,
584 NETSIM_ID txIf,
585 NETSIM_ID rxId,
586 NETSIM_ID rxIf)
587{
588 ptrPACKETINFO info = packetInfo_add(packet, txId, txIf, rxId, rxIf);
589 if (isAnypacketIsThereForThisTransmitter(info))
590 return;
591 update_power_due_to_transmission(info);
592 medium_update_interference(info);
593}
594
595_declspec(dllexport) void medium_notify_packet_received(NetSim_PACKET* packet)
596{
597 ptrPACKETINFO info = packetInfo_remove(packet);
598 medium_mark_packet_error(info);
599 if (!isAnypacketIsThereForThisTransmitter(info))
600 update_power_due_to_transmission_stop(info);
601 packetInfo_free(info);
602}
603
604_declspec(dllexport) bool medium_isIdle(NETSIM_ID d,
605 NETSIM_ID in)
606{
607 ptrDEVICE_IN_MEDIUM dm = medium_find_device(d, in);
608 return (dm->dCummulativeReceivedPower_dbm < dm->dEDThreshold_dBm);
609}
610
611_declspec(dllexport) double medium_get_interference(NetSim_PACKET* packet,
612 NETSIM_ID txId,
613 NETSIM_ID txIf,
614 NETSIM_ID rxId,
615 NETSIM_ID rxIf)
616{
617 ptrPACKETINFO info = packetInfo_find(packet, txId, txIf, rxId, rxIf);
618 if (info)
619 return (info->dMaxInterference_dbm);
620 else
621 return NEGATIVE_DBM;
622}
623