EMANE  1.2.1
build/lib/emane/events/tdmascheduleevent.py
Go to the documentation of this file.
1 #
2 # Copyright (c) 2015,2017 - Adjacent Link LLC, Bridgewater, New Jersey
3 # All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 #
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in
13 # the documentation and/or other materials provided with the
14 # distribution.
15 # * Neither the name of Adjacent Link LLC nor the names of its
16 # contributors may be used to endorse or promote products derived
17 # from this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 # POSSIBILITY OF SUCH DAMAGE.
31 #
32 
33 from . import Event
34 from . import tdmascheduleevent_pb2
35 from collections import namedtuple
36 import os
37 
39  IDENTIFIER = 105
40  TX=1
41  RX=2
42  IDLE=3
43 
44  _FrameEntry = namedtuple('FrameEntry', ['frame', 'slots'])
45 
46  def __init__(self,**kwargs):
47  self._event = tdmascheduleevent_pb2.TDMAScheduleEvent()
48  self._frames = {}
49 
50  for (name,value) in list(kwargs.items()):
51  if name == 'frequency':
52  if (isinstance(value,int) or \
53  isinstance(value,int)) and \
54  value >= 0:
55  self._event.frequencyHz = value
56  else:
57  raise ValueError("frequency must be a positive numeric")
58 
59  elif name == 'datarate':
60  if (isinstance(value,int) or \
61  isinstance(value,int)) and \
62  value >= 0:
63  self._event.dataRatebps = value
64  else:
65  raise ValueError("datarate must be a positive numeric")
66 
67  elif name == 'service':
68  if (isinstance(value,int) or \
69  isinstance(value,int)) and \
70  value >= 0:
71  self._event.serviceClass = value
72  else:
73  raise ValueError("service must be a positive numeric")
74 
75  elif name == 'power':
76  if (isinstance(value,int) or \
77  isinstance(value,int) or \
78  isinstance(value,float)):
79  self._event.powerdBm = value
80  else:
81  raise ValueError("power must be a numeric")
82 
83  else:
84  raise KeyError("unknown parameter: %s" % name)
85 
86  def structure(self,**kwargs):
87  slotsPerFrame = None
88  framesPerMultiFrame = None
89  slotOverheadMicroseconds = None
90  slotDurationMicroseconds = None
91  bandwidthHz = None
92 
93  if not kwargs:
94 
95  if self._event.HasField('structure'):
96  return {'slots': self._event.structure.slotsPerFrame,
97  'frames': self._event.structure.framesPerMultiFrame,
98  'slotduration':self._event.structure.slotDurationMicroseconds,
99  'slotoverhead':self._event.structure.slotOverheadMicroseconds,
100  'bandwidth': self._event.structure.bandwidthHz}
101  else:
102  return None
103 
104  for (name,value) in list(kwargs.items()):
105  if name == 'slots':
106  if (isinstance(value,int) or \
107  isinstance(value,int)) and \
108  value > 0:
109  slotsPerFrame = value
110  else:
111  raise ValueError("'slots' must be a positive integer greater than 0")
112 
113  elif name == 'frames':
114  if (isinstance(value,int) or \
115  isinstance(value,int)) and \
116  value > 0:
117  framesPerMultiFrame = value
118  else:
119  raise ValueError("'frames' must be a positive integer greater than 0")
120 
121  elif name == 'slotduration':
122  if (isinstance(value,int) or \
123  isinstance(value,int)) and \
124  value > 0:
125  slotDurationMicroseconds = value
126  else:
127  raise ValueError("'slotduration' must be a positive integer greater than 0")
128 
129  elif name == 'slotoverhead':
130  if (isinstance(value,int) or \
131  isinstance(value,int)) and \
132  value >= 0:
133  slotOverheadMicroseconds = value
134  else:
135  raise ValueError("'slotoverhead' must be a positive integer (usecs)")
136 
137  elif name == 'bandwidth':
138  if (isinstance(value,int) or \
139  isinstance(value,int)) and \
140  value > 0:
141  bandwidthHz = value
142  else:
143  raise ValueError("'bandwidth' must be a positive integer greater than 0 (Hz)")
144 
145  else:
146  raise KeyError("unknown parameter: %s" % name)
147 
148 
149  if slotsPerFrame == None or \
150  framesPerMultiFrame == None or \
151  slotOverheadMicroseconds == None or \
152  slotDurationMicroseconds == None or \
153  bandwidthHz == None:
154  raise KeyError("Missing one ore more keys: 'slots', 'frames', 'slotduration', 'slotoverhead', 'bandwidth'")
155 
156  self._event.structure.slotsPerFrame = slotsPerFrame
157  self._event.structure.framesPerMultiFrame = framesPerMultiFrame
158  self._event.structure.slotDurationMicroseconds = slotDurationMicroseconds
159  self._event.structure.slotOverheadMicroseconds = slotOverheadMicroseconds
160  self._event.structure.bandwidthHz = bandwidthHz
161 
162 
163  def append(self,frameIndex,slotIndex,**kwargs):
164  frameFrequencyHz = None
165  frameDataRatebps = None
166  frameClass = None
167  framePowerdBm = None
168  slotFrequencyHz = None
169  slotDataRatebps = None
170  slotClass = None
171  slotPowerdBm = None
172  slotType = None
173  slotDestination = None
174 
175  if frameIndex in self._frames and \
176  slotIndex in self._frames[frameIndex].slots:
177  raise ValueError("slot index already defined for frame")
178 
179  for (name,value) in list(kwargs.items()):
180  if name == 'frame.frequency':
181  if (isinstance(value,int) or \
182  isinstance(value,int)) and \
183  value > 0:
184  frameFrequencyHz = value
185  else:
186  raise ValueError("'frame.frequency' must be a integer greater that 0 (Hz)")
187 
188  elif name == 'frame.datarate':
189  if (isinstance(value,int) or \
190  isinstance(value,int)) and \
191  value > 0:
192  frameDataRatebps = value
193  else:
194  raise ValueError("'frame.datarate' must be a positive integer greater than 0 (bps)")
195 
196  elif name == 'frame.service':
197  if (isinstance(value,int) or \
198  isinstance(value,int)) and \
199  value >= 0 and value <= 3:
200  frameClass = value
201  else:
202  raise ValueError("'frame.service' must be a positive integer in the set [0,3]")
203 
204  elif name == 'frame.power':
205  if (isinstance(value,int) or \
206  isinstance(value,int) or \
207  isinstance(value,float)):
208 
209  framePowerdBm = value
210  else:
211  raise ValueError("'frame.power' must be a numeric (dBm)")
212 
213  elif name == 'frequency':
214  if (isinstance(value,int) or \
215  isinstance(value,int)) and \
216  value > 0:
217  slotFrequencyHz = value
218  else:
219  raise ValueError("'frequency' must be a integer greater that 0 (Hz)")
220 
221  elif name == 'datarate':
222  if (isinstance(value,int) or \
223  isinstance(value,int)) and \
224  value > 0:
225  slotDataRatebps = value
226  else:
227  raise ValueError("'datarate' must be a positive integer greater than 0 (bps)")
228 
229  elif name == 'service':
230  if (isinstance(value,int) or \
231  isinstance(value,int)) and \
232  value >= 0 and value <= 3:
233  slotClass = value
234  else:
235  raise ValueError("'service' must be a positive integer in the set [0,3]")
236 
237  elif name == 'power':
238  if (isinstance(value,int) or \
239  isinstance(value,int) or \
240  isinstance(value,float)):
241  slotPowerdBm = value
242  else:
243  raise ValueError("'power' must be a numeric (dBm)")
244 
245 
246  elif name == 'destination':
247  if (isinstance(value,int) or \
248  isinstance(value,int)) and \
249  value > 0:
250  slotDestination = value
251  else:
252  raise ValueError("'destination' must be a positive integer (NEM Id)")
253 
254  elif name == 'type':
255  if value == "tx" or value == TDMAScheduleEvent.TX:
256  slotType = "tx"
257 
258  elif value == "rx" or value == TDMAScheduleEvent.RX:
259  slotType = "rx"
260 
261  elif value =="idle" or value == TDMAScheduleEvent.IDLE:
262  slotType = "idle"
263 
264  else:
265  raise ValueError("'type' must be one of: tx, rx or idle")
266 
267  else:
268  raise KeyError("unknown parameter: %s" % name)
269 
270  if slotType == "tx":
271  if slotFrequencyHz == None and \
272  frameFrequencyHz == None and \
273  self._event.frequencyHz == None:
274  raise KeyError("tx slot 'frequency' must be specified when 'frame.frequency' missing and default not set")
275 
276  if slotDataRatebps == None and \
277  frameDataRatebps == None and \
278  self._event.dataRatebps == None:
279  raise KeyError("tx slot 'datarate' must be specified when 'frame.datarate' missing and default not set")
280 
281  if slotClass == None and \
282  frameClass == None and \
283  self._event.serviceClass == None:
284  raise KeyError("tx slot 'service' must be specified when 'frame.service' missing and default not set")
285 
286  if slotPowerdBm != None and \
287  framePowerdBm == None and \
288  self._event.powerdBm == None:
289  raise KeyError("tx slot 'power' must be specified when 'frame.power' missing and default not set")
290 
291  elif slotType == "rx":
292  if slotDataRatebps != None or \
293  slotClass != None or \
294  slotPowerdBm != None or \
295  slotDestination != None:
296  raise KeyError("rx slot cannot have 'datarate', 'service', 'power' and/or 'destination'")
297 
298  if slotFrequencyHz == None and \
299  frameFrequencyHz == None and \
300  self._event.frequencyHz == None:
301  raise KeyError("rx slot 'frequency' must be specified when 'frame.frequency' missing and default not set")
302 
303  elif slotType == "idle":
304  if slotFrequencyHz != None or \
305  slotDataRatebps != None or \
306  slotClass != None or \
307  slotPowerdBm != None:
308  raise ValueError("idle slot cannot have 'frequency', 'datarate', 'service', 'power', and/or 'destination'")
309 
310  else:
311  raise KeyError("missing 'type'")
312 
313  if frameIndex in self._frames:
314  frame = self._frames[frameIndex].frame
315  else:
316  frame = self._event.frames.add()
317  self._frames[frameIndex] = TDMAScheduleEvent._FrameEntry(frame,set())
318  frame.index = frameIndex
319 
320  if frameFrequencyHz != None:
321  frame.frequencyHz = frameFrequencyHz
322 
323  if frameDataRatebps != None:
324  frame.dataRatebps = frameDataRatebps
325 
326  if frameClass != None:
327  frame.serviceClass = frameClass
328 
329  if framePowerdBm != None:
330  frame.powerdBm = framePowerdBm
331 
332  slot = frame.slots.add()
333 
334  slot.index = slotIndex
335 
336  if slotType == "tx":
337  slot.type = tdmascheduleevent_pb2.TDMAScheduleEvent.Frame.Slot.SLOT_TX
338 
339  if slotFrequencyHz != None:
340  slot.tx.frequencyHz = slotFrequencyHz
341 
342  if slotDataRatebps != None:
343  slot.tx.dataRatebps = slotDataRatebps
344 
345  if slotClass != None:
346  slot.tx.serviceClass = slotClass
347 
348  if slotPowerdBm != None:
349  slot.tx.powerdBm = slotPowerdBm
350 
351  if slotDestination != None:
352  slot.tx.destination = slotDestination
353 
354  elif slotType == "rx":
355  slot.type = tdmascheduleevent_pb2.TDMAScheduleEvent.Frame.Slot.SLOT_RX
356 
357  if slotFrequencyHz != None:
358  slot.rx.frequencyHz = slotFrequencyHz
359 
360  else:
361  slot.type = tdmascheduleevent_pb2.TDMAScheduleEvent.Frame.Slot.SLOT_IDLE
362 
363  self._frames[frameIndex].slots.add(slotIndex)
364 
365  def serialize(self):
366  return self._event.SerializeToString()
367 
368  def restore(self,data):
369  self._event.ParseFromString(data)
370 
371  def __iter__(self):
372  for frame in self._event.frames:
373  kwargs = {'index' : frame.index}
374 
375  if frame.HasField('frequencyHz'):
376  kwargs['frame.frequency'] = frame.frequencyHz
377 
378  if frame.HasField('dataRatebps'):
379  kwargs['frame.datarate'] = frame.dataRatebps
380 
381  if frame.HasField('serviceClass'):
382  kwargs['frame.service'] = frame.serviceClass
383 
384  if frame.HasField('powerdBm'):
385  kwargs['frame.power'] = frame.powerdBm
386 
387  slots = {}
388 
389  for slot in frame.slots:
390  s = {}
391 
392  if slot.type == tdmascheduleevent_pb2.TDMAScheduleEvent.Frame.Slot.SLOT_TX:
393  s['type'] = 'tx'
394 
395  if slot.HasField('tx'):
396  if slot.tx.HasField('frequencyHz'):
397  s['frequency'] = slot.tx.frequencyHz
398 
399  if slot.tx.HasField('dataRatebps'):
400  s['datarate'] = slot.tx.dataRatebps
401 
402  if slot.tx.HasField('serviceClass'):
403  s['service'] = slot.tx.serviceClass
404 
405  if slot.tx.HasField('powerdBm'):
406  s['power'] = slot.tx.powerdBm
407 
408  if slot.tx.HasField('destination'):
409  s['destination'] = slot.tx.destination
410 
411  elif slot.type == tdmascheduleevent_pb2.TDMAScheduleEvent.Frame.Slot.SLOT_RX:
412  s['type'] = 'rx'
413 
414  if slot.HasField('rx') and slot.rx.HasField('frequencyHz'):
415  s['frequency'] = slot.rx.frequencyHz
416 
417  else:
418  s['type'] = 'idle'
419 
420  slots[slot.index] = s
421 
422  kwargs['slots'] = slots
423 
424  yield kwargs