AcraNetwork 1.2.1__tar.gz → 1.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter7/__init__.py +85 -23
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/__version__.py +4 -1
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork.egg-info/PKG-INFO +1 -1
- {acranetwork-1.2.1 → acranetwork-1.2.4}/PKG-INFO +1 -1
- {acranetwork-1.2.1 → acranetwork-1.2.4}/examples/validate_pcap.py +88 -63
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_ch7.py +132 -5
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IENA.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter10/Chapter10UDP.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter10/FileParser.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter10/__init__.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter11/ARINC429.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter11/Analog.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter11/CAN.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter11/ComputerData.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter11/MILSTD1553.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter11/PCM.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter11/TimeDataFormat.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter11/UART.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter11/Video.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter11/__init__.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/Chapter7/Golay.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/IRIG106/__init__.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/MPEG/ADTS.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/MPEG/H264.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/MPEG/PES.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/MPEG/PMT.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/MPEG/STANAG4609.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/MPEG/__init__.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/MPEGTS.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/McastSocket.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/NPD.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/ParserAligned.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/Pcap.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/SamDec008.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/SimpleEthernet.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/__init__.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/iNET.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/iNetX.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/nanotime.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork/ptptime.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork.egg-info/SOURCES.txt +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork.egg-info/dependency_links.txt +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/AcraNetwork.egg-info/top_level.txt +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/LICENSE +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/MANIFEST.in +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/README.md +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/examples/adau_to_ch10.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/examples/ch10_recorder.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/examples/ch10_to_pcap.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/examples/pkg_gen.ini +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/examples/tx_iena_udp.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/examples/tx_inetx_udp.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/examples/validate_ch10.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/setup.cfg +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/setup.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/__init__.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_afdx.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_ch10.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_golay.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_iena.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_inet.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_inetx.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_misc.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_mpegts.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_npd.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_paligned.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_pcap.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_ptptime.py +0 -0
- {acranetwork-1.2.1 → acranetwork-1.2.4}/test/test_simpleethernet.py +0 -0
|
@@ -23,6 +23,7 @@ import logging
|
|
|
23
23
|
import typing
|
|
24
24
|
from enum import IntEnum
|
|
25
25
|
|
|
26
|
+
|
|
26
27
|
ch7_logger = logging.getLogger(__name__)
|
|
27
28
|
|
|
28
29
|
|
|
@@ -34,6 +35,11 @@ class PTDPContent(IntEnum):
|
|
|
34
35
|
ETHERNET_MAC = 0x4
|
|
35
36
|
IP = 0x5
|
|
36
37
|
CHAPTER_24 = 0x6
|
|
38
|
+
ILLEGAL = 0xF
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def _missing_(cls, value):
|
|
42
|
+
return PTDPContent.ILLEGAL
|
|
37
43
|
|
|
38
44
|
|
|
39
45
|
class PTDPFragment(IntEnum):
|
|
@@ -41,12 +47,17 @@ class PTDPFragment(IntEnum):
|
|
|
41
47
|
FIRST = 0x1
|
|
42
48
|
MIDDLE = 0x2
|
|
43
49
|
LAST = 0x3
|
|
50
|
+
ILLEGAL = 0x4
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def _missing_(cls, value):
|
|
54
|
+
return PTDPFragment.ILLEGAL
|
|
44
55
|
|
|
45
56
|
|
|
46
57
|
PTDP_HDR_LEN = 0x6 # 24bits x2
|
|
47
58
|
PTFR_HDR_LEN = 0x4 # 1 byte unprotected and 3 bytes protected
|
|
48
59
|
|
|
49
|
-
|
|
60
|
+
PTDT_LLP_TRAILER_LEN = 1
|
|
50
61
|
PTDP_MAX_LEN = 0x800
|
|
51
62
|
|
|
52
63
|
|
|
@@ -77,10 +88,25 @@ def datapkts_to_ptfr(
|
|
|
77
88
|
# Create a new frame
|
|
78
89
|
ptfr = _new_ptfr(ptfr_len, streamid, golay)
|
|
79
90
|
for ptdp in datapkts_to_ptdp(eth_ch10_packets):
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
|
|
92
|
+
remaining_space = ptfr.remaining_space()
|
|
93
|
+
# logging.debug(f"Adding ptdp {ptdp} with remaining space {remaining_space}")
|
|
94
|
+
# If we have a low latency packet but not enough space to insert it full then
|
|
95
|
+
# insert a fill packet
|
|
96
|
+
if ptdp.low_latency and remaining_space <= (len(ptdp) + PTDT_LLP_TRAILER_LEN):
|
|
97
|
+
# logging.warning(f"Need to add fill packet to fill remaining space={remaining_space}")
|
|
98
|
+
fill = ptdp_fill(remaining_space)
|
|
99
|
+
remainder = ptfr.add_payload(fill.pack(), False)
|
|
100
|
+
yield ptfr
|
|
101
|
+
ptfr = _new_ptfr(ptfr_len, streamid, golay)
|
|
102
|
+
if len(remainder) > 0:
|
|
103
|
+
ptfr.add_payload(remainder)
|
|
104
|
+
# logging.debug(f"Added remainder of len {len(remainder)}. Remainder={ptfr.remaining_space()}")
|
|
105
|
+
|
|
106
|
+
# Add the packet and if there is remainder push out the ptfr packet and start a new one
|
|
82
107
|
remainder = ptfr.add_payload(ptdp.pack(), ptdp.low_latency)
|
|
83
|
-
|
|
108
|
+
ch7_logger.debug(f"PTDP ({ptdp}) to be added to PTRF leaving remainder of len={len(remainder)}")
|
|
109
|
+
while not ptfr.has_space():
|
|
84
110
|
# Spit out the full frame
|
|
85
111
|
yield ptfr
|
|
86
112
|
# Create anew frame
|
|
@@ -93,10 +119,11 @@ def datapkts_to_ptfr(
|
|
|
93
119
|
remainder = remainder[ptfr_len:] # If we have more data then save it for the next frame
|
|
94
120
|
ptfr = _new_ptfr(ptfr_len, streamid, golay)
|
|
95
121
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
122
|
+
if len(remainder) > 0:
|
|
123
|
+
# Point to the first offset of the frame.
|
|
124
|
+
ptfr.ptdp_offset = len(remainder)
|
|
125
|
+
# Add the PTDS to the frame
|
|
126
|
+
remainder = ptfr.add_payload(remainder)
|
|
100
127
|
|
|
101
128
|
|
|
102
129
|
def datapkts_to_ptdp(eth_ch10_packets: typing.Iterable[bytes, bool]) -> typing.Generator[PTDP, None, None]:
|
|
@@ -164,6 +191,7 @@ class PTDP(object):
|
|
|
164
191
|
)
|
|
165
192
|
|
|
166
193
|
self._payload = val
|
|
194
|
+
self.length = len(val)
|
|
167
195
|
|
|
168
196
|
def pack(self) -> bytes:
|
|
169
197
|
"""
|
|
@@ -198,7 +226,7 @@ class PTDP(object):
|
|
|
198
226
|
raise PTDPLengthError("GolayHdr=len={}. Must be corrupted".format(self.length))
|
|
199
227
|
elif len(buffer[6:]) < self.length:
|
|
200
228
|
raise PTDPRemainingData(
|
|
201
|
-
"Buffer length={} GolayHdr=len={} fragment={} content={}".format(
|
|
229
|
+
"Not a full PTDP packet. Rest likely in next packet . Buffer length={} GolayHdr=len={} fragment={} content={}".format(
|
|
202
230
|
len(buffer[6:]), self.length, self.fragment, self.content
|
|
203
231
|
)
|
|
204
232
|
)
|
|
@@ -222,9 +250,18 @@ class PTDP(object):
|
|
|
222
250
|
return not self.__eq__(other)
|
|
223
251
|
|
|
224
252
|
def __repr__(self):
|
|
225
|
-
return "PTDP: Len={} Content={} Fragment={} LowLatency={}"
|
|
226
|
-
|
|
227
|
-
|
|
253
|
+
return f"PTDP: Len={self.length} Content={repr(self.content)} Fragment={repr(self.fragment)} LowLatency={self.low_latency}"
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def ptdp_fill(total_len_min: int) -> PTDP:
|
|
257
|
+
_p = PTDP()
|
|
258
|
+
_p.content = PTDPContent.FILL
|
|
259
|
+
if total_len_min < (PTDP_HDR_LEN + 1):
|
|
260
|
+
payload_len = 1
|
|
261
|
+
else:
|
|
262
|
+
payload_len = total_len_min - PTDP_HDR_LEN
|
|
263
|
+
_p.payload = struct.pack(f">{payload_len}B", *([0xFF] * payload_len))
|
|
264
|
+
return _p
|
|
228
265
|
|
|
229
266
|
|
|
230
267
|
class PTFR(object):
|
|
@@ -255,11 +292,17 @@ class PTFR(object):
|
|
|
255
292
|
def add_payload(self, buffer: bytes, is_llp: bool = False) -> bytes:
|
|
256
293
|
"""
|
|
257
294
|
Add the buffer to the payload ensuring not to go over the length field
|
|
258
|
-
Return the
|
|
295
|
+
Return the remainder
|
|
259
296
|
"""
|
|
297
|
+
if len(buffer) == 0:
|
|
298
|
+
raise Exception("Can't add payload of len = 0")
|
|
299
|
+
if is_llp and len(buffer) + len(self._payload) > self.length:
|
|
300
|
+
raise Exception(
|
|
301
|
+
f"LLP packet ({len(buffer)}) cannot be added (ptfrlen={self.length}) as it will push the payload ({len(self.payload)}) into the next frame. Add a fill word"
|
|
302
|
+
)
|
|
260
303
|
if is_llp and len(self._payload) > 0 and self.llp:
|
|
261
304
|
ch7_logger.debug(
|
|
262
|
-
"Adding an LLP buffer to some existing llp payload. Shifting original data and adding llp at "
|
|
305
|
+
f"Adding an LLP buffer({len(buffer)}) to some existing llp payload ({len(self._payload)}). Shifting original data and adding llp at "
|
|
263
306
|
"start. len={}".format(len(buffer) + 1)
|
|
264
307
|
)
|
|
265
308
|
self.ptdp_offset += len(buffer) + 1
|
|
@@ -276,10 +319,11 @@ class PTFR(object):
|
|
|
276
319
|
elif is_llp and len(self.payload) == 0:
|
|
277
320
|
ch7_logger.debug("Adding first LLP buffer len={}".format(len(buffer) + 1))
|
|
278
321
|
self.llp = True
|
|
279
|
-
self._payload = buffer + struct.pack(">B",
|
|
322
|
+
self._payload = buffer + struct.pack(">B", 0x00) # Further LLPs will be added in front of this one
|
|
323
|
+
self.ptdp_offset += len(buffer) + 1
|
|
280
324
|
else:
|
|
281
|
-
ch7_logger.debug("Adding a normal PTDP buffer len={}".format(len(buffer)))
|
|
282
325
|
self._payload += buffer
|
|
326
|
+
ch7_logger.debug(f"Adding a normal PTDP buffer of len={len(buffer)} to a total len={len(self._payload)}")
|
|
283
327
|
|
|
284
328
|
if len(self._payload) > self.length:
|
|
285
329
|
len_to_take = self.length - len(self._payload)
|
|
@@ -289,6 +333,12 @@ class PTFR(object):
|
|
|
289
333
|
else:
|
|
290
334
|
return bytes()
|
|
291
335
|
|
|
336
|
+
def has_space(self, expected_addition: int = 0) -> bool:
|
|
337
|
+
return (len(self.payload) + expected_addition) < self.length
|
|
338
|
+
|
|
339
|
+
def remaining_space(self) -> int:
|
|
340
|
+
return self.length - len(self.payload)
|
|
341
|
+
|
|
292
342
|
def pack(self) -> bytes:
|
|
293
343
|
"""
|
|
294
344
|
Convert a PTFR object into a string for transmission. This will return the packed string and the remainder string
|
|
@@ -325,10 +375,8 @@ class PTFR(object):
|
|
|
325
375
|
|
|
326
376
|
def check_offsets(self, act_offset: int) -> bool:
|
|
327
377
|
if (act_offset != self.ptdp_offset) and (self.ptdp_offset != 2047):
|
|
328
|
-
ch7_logger.
|
|
329
|
-
"Offset of unpacked PTDP packet ({}) does not match the declared offset ({})"
|
|
330
|
-
act_offset, self.ptdp_offset
|
|
331
|
-
)
|
|
378
|
+
ch7_logger.debug(
|
|
379
|
+
f"Offset of unpacked PTDP packet ({act_offset}) does not match the declared offset ({self.ptdp_offset})"
|
|
332
380
|
)
|
|
333
381
|
return False
|
|
334
382
|
elif self.ptdp_offset != 2047:
|
|
@@ -383,15 +431,20 @@ class PTFR(object):
|
|
|
383
431
|
)
|
|
384
432
|
)
|
|
385
433
|
|
|
434
|
+
do_offset_check = True
|
|
386
435
|
if is_llp:
|
|
387
436
|
byte_offset = 0
|
|
388
437
|
elif remainder is None: # Fake the offset if we have jumped into the middle of a data stream
|
|
389
438
|
byte_offset = self.ptdp_offset
|
|
390
439
|
else:
|
|
391
440
|
byte_offset = -1 * len(remainder)
|
|
392
|
-
|
|
441
|
+
if len(remainder) == 0:
|
|
442
|
+
do_offset_check = False
|
|
443
|
+
|
|
393
444
|
offset_check_count = 0
|
|
445
|
+
|
|
394
446
|
while aligned:
|
|
447
|
+
ch7_logger.debug(f"Starting to check buf of lenght={len(buf)}")
|
|
395
448
|
p = PTDP(self._golay)
|
|
396
449
|
try:
|
|
397
450
|
buf = p.unpack(buf)
|
|
@@ -402,6 +455,7 @@ class PTFR(object):
|
|
|
402
455
|
len(buf), e, self.ptdp_offset
|
|
403
456
|
)
|
|
404
457
|
)
|
|
458
|
+
|
|
405
459
|
yield (None, None, e)
|
|
406
460
|
except PTDPRemainingData as e:
|
|
407
461
|
aligned = False
|
|
@@ -416,12 +470,16 @@ class PTFR(object):
|
|
|
416
470
|
yield (None, buf, e)
|
|
417
471
|
else:
|
|
418
472
|
if not is_llp and do_offset_check and byte_offset >= 0:
|
|
473
|
+
# ch7_logger.debug(f"do_offset_check={do_offset_check} byte_offset={byte_offset}")
|
|
419
474
|
self.check_offsets(byte_offset)
|
|
420
475
|
do_offset_check = False
|
|
421
476
|
offset_check_count += 1
|
|
422
477
|
elif not is_llp and not do_offset_check and offset_check_count < 1:
|
|
423
478
|
do_offset_check = True
|
|
424
479
|
byte_offset += len(p)
|
|
480
|
+
# ch7_logger.debug(
|
|
481
|
+
# f"Enable do_offset_check because {offset_check_count} < 1 byte_offset={byte_offset} len_p={len(p)}"
|
|
482
|
+
# )
|
|
425
483
|
elif not is_llp:
|
|
426
484
|
byte_offset += len(p)
|
|
427
485
|
|
|
@@ -433,6 +491,7 @@ class PTFR(object):
|
|
|
433
491
|
(next_llp,) = struct.unpack_from(">B", buf)
|
|
434
492
|
# Check if the next PTDP is low latency before yielding
|
|
435
493
|
if next_llp == 0xFF:
|
|
494
|
+
ch7_logger.debug("Next packet is LLP")
|
|
436
495
|
is_llp = True
|
|
437
496
|
buf = buf[1:]
|
|
438
497
|
byte_offset += len(p) + 1
|
|
@@ -456,8 +515,11 @@ class PTFR(object):
|
|
|
456
515
|
if len(remainder) > 0:
|
|
457
516
|
do_offset_check = False
|
|
458
517
|
|
|
518
|
+
# ch7_logger.debug(f"Returning p={repr(p)} and no remainder")
|
|
459
519
|
yield (p, bytes(), "")
|
|
460
520
|
|
|
521
|
+
# ch7_logger.debug("------PTFR expired-----")
|
|
522
|
+
|
|
461
523
|
def __eq__(self, other: PTFR):
|
|
462
524
|
if not isinstance(other, PTFR):
|
|
463
525
|
return False
|
|
@@ -472,6 +534,6 @@ class PTFR(object):
|
|
|
472
534
|
return not self.__eq__(other)
|
|
473
535
|
|
|
474
536
|
def __repr__(self):
|
|
475
|
-
return
|
|
476
|
-
self.length
|
|
537
|
+
return (
|
|
538
|
+
f"PTFR: Length={self.length} StreamID={self.streamid:#0X} Offset={self.ptdp_offset} LowLatency={self.llp}\n"
|
|
477
539
|
)
|
|
@@ -106,4 +106,7 @@
|
|
|
106
106
|
# 1.1.9 - Fixed ARINC ch10 intra packet header
|
|
107
107
|
# 1.2.0 - Moved Chapter 7 into the IRIG106 folder. Removed old Chapter10 directory
|
|
108
108
|
# 1.2.1 - Fixed logging in IP error message
|
|
109
|
-
|
|
109
|
+
# 1.2.2 - Fixed chapter 7 packet generation
|
|
110
|
+
# 1.2.3 - Last release was nto successful
|
|
111
|
+
# 1.2.4 - Removed exit in the ch7
|
|
112
|
+
__version__ = "1.2.4"
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
"""
|
|
4
4
|
# Very rudimentary (but fast) validation of recorded data
|
|
5
5
|
# Finds all inetx packets and validate no missing sequence numbers
|
|
6
6
|
# It will also take the url to an axn mem and verify data after downloading
|
|
7
|
+
"""
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
import sys
|
|
10
|
-
|
|
11
|
-
sys.path.append("..")
|
|
12
|
-
sys.path.append(".")
|
|
13
10
|
import AcraNetwork.Pcap as pcap
|
|
14
11
|
import glob
|
|
15
12
|
import os.path
|
|
@@ -24,13 +21,12 @@ from os import mkdir, remove
|
|
|
24
21
|
import datetime
|
|
25
22
|
from dataclasses import dataclass, field
|
|
26
23
|
import typing
|
|
24
|
+
import zstandard as zstd
|
|
25
|
+
import sys
|
|
27
26
|
|
|
27
|
+
VERSION = "0.5.0"
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
logging.basicConfig(
|
|
32
|
-
level=logging.INFO, format="%(levelname)-6s %(asctime)-15s %(message)s"
|
|
33
|
-
)
|
|
29
|
+
logging.basicConfig(level=logging.INFO, format="%(levelname)-6s %(asctime)-15s %(message)s")
|
|
34
30
|
|
|
35
31
|
|
|
36
32
|
@dataclass
|
|
@@ -56,7 +52,7 @@ class Streams:
|
|
|
56
52
|
return 0
|
|
57
53
|
return int(self.length * 8 * self.pkt_count / (self.end_ts - self.start_ts))
|
|
58
54
|
|
|
59
|
-
def timelen(self) ->float:
|
|
55
|
+
def timelen(self) -> float:
|
|
60
56
|
return self.end_ts - self.start_ts
|
|
61
57
|
|
|
62
58
|
def drops_to_hist(self):
|
|
@@ -66,7 +62,7 @@ class Streams:
|
|
|
66
62
|
bin_cnt = [0] * bins
|
|
67
63
|
for i in range(bins):
|
|
68
64
|
for s in self.sequence_list:
|
|
69
|
-
#print(f"{i}:{start_seq}:{s}:{bin_wdth}")
|
|
65
|
+
# print(f"{i}:{start_seq}:{s}:{bin_wdth}")
|
|
70
66
|
if (start_seq + bin_wdth * i) <= s < (start_seq + bin_wdth * (i + 1)):
|
|
71
67
|
bin_cnt[i] += 1
|
|
72
68
|
rstring = "|"
|
|
@@ -83,9 +79,7 @@ class Streams:
|
|
|
83
79
|
|
|
84
80
|
def create_parser():
|
|
85
81
|
# Argument parser
|
|
86
|
-
parser = argparse.ArgumentParser(
|
|
87
|
-
description="Validate inetx sequence numbers quickly in a pcap file"
|
|
88
|
-
)
|
|
82
|
+
parser = argparse.ArgumentParser(description="Validate inetx sequence numbers quickly in a pcap file")
|
|
89
83
|
# Common
|
|
90
84
|
parser.add_argument(
|
|
91
85
|
"--folder",
|
|
@@ -122,9 +116,7 @@ def create_parser():
|
|
|
122
116
|
default=False,
|
|
123
117
|
help="print a rough histogram of where the drops happened",
|
|
124
118
|
)
|
|
125
|
-
parser.add_argument(
|
|
126
|
-
"--version", action="version", version="%(prog)s {}".format(VERSION)
|
|
127
|
-
)
|
|
119
|
+
parser.add_argument("--version", action="version", version="%(prog)s {}".format(VERSION))
|
|
128
120
|
|
|
129
121
|
return parser
|
|
130
122
|
|
|
@@ -141,6 +133,11 @@ def uri_validator(x):
|
|
|
141
133
|
return False
|
|
142
134
|
|
|
143
135
|
|
|
136
|
+
def is_compressed(x: str) -> bool:
|
|
137
|
+
(_root, _ext) = os.path.splitext(x)
|
|
138
|
+
return _ext == ".zst"
|
|
139
|
+
|
|
140
|
+
|
|
144
141
|
def main(args):
|
|
145
142
|
roll_over = pow(2, 32)
|
|
146
143
|
fnames = {}
|
|
@@ -174,7 +171,7 @@ def main(args):
|
|
|
174
171
|
first_pcap_time = None
|
|
175
172
|
last_pcap_time = None
|
|
176
173
|
packet_data_vol = 0
|
|
177
|
-
tmp_folder = "
|
|
174
|
+
tmp_folder = ".tmp"
|
|
178
175
|
loss = 0
|
|
179
176
|
floss = 0
|
|
180
177
|
outf = ""
|
|
@@ -195,12 +192,27 @@ def main(args):
|
|
|
195
192
|
out_file.write(chunk)
|
|
196
193
|
|
|
197
194
|
dlspeed = data_len * 8 / (time.time() - sd) / 1e6
|
|
198
|
-
logging.info(
|
|
199
|
-
"Downloaded {} at {:.1f}Mbps and wrote to {}".format(
|
|
200
|
-
pfile, dlspeed, outf
|
|
201
|
-
)
|
|
202
|
-
)
|
|
195
|
+
logging.info("Downloaded {} at {:.1f}Mbps and wrote to {}".format(pfile, dlspeed, outf))
|
|
203
196
|
p = pcap.Pcap(outf)
|
|
197
|
+
elif is_compressed(pfile):
|
|
198
|
+
|
|
199
|
+
if not os.path.exists(tmp_folder):
|
|
200
|
+
mkdir(tmp_folder, 0o755)
|
|
201
|
+
fname_pcap, _ext = os.path.splitext(os.path.basename(pfile))
|
|
202
|
+
decompressed_f = os.path.join(tmp_folder, fname_pcap)
|
|
203
|
+
with open(pfile, "rb") as compressed:
|
|
204
|
+
with open(decompressed_f, "wb") as decompressed:
|
|
205
|
+
dctx = zstd.ZstdDecompressor()
|
|
206
|
+
dctx.copy_stream(compressed, decompressed)
|
|
207
|
+
|
|
208
|
+
# Get sizes
|
|
209
|
+
compressed_size = os.path.getsize(pfile)
|
|
210
|
+
decompressed_size = os.path.getsize(decompressed_f)
|
|
211
|
+
|
|
212
|
+
# Compute compression ratio
|
|
213
|
+
compression_ratio = decompressed_size / compressed_size
|
|
214
|
+
logging.info(f"Compression ratio: {compression_ratio:.2f}x")
|
|
215
|
+
p = pcap.Pcap(decompressed_f)
|
|
204
216
|
else:
|
|
205
217
|
p = pcap.Pcap(pfile)
|
|
206
218
|
prev_rec_ts = None
|
|
@@ -215,34 +227,23 @@ def main(args):
|
|
|
215
227
|
if prev_rec_ts is not None:
|
|
216
228
|
if prev_rec_ts > last_pcap_time:
|
|
217
229
|
delta = prev_rec_ts - last_pcap_time
|
|
218
|
-
logging.warning(
|
|
219
|
-
f"Record={i + 1} Record timestamp negative jump {delta}s")
|
|
230
|
+
logging.warning(f"Record={i + 1} Record timestamp negative jump {delta}s")
|
|
220
231
|
prev_rec_ts = last_pcap_time
|
|
221
232
|
|
|
222
233
|
packet_data_vol += len(r.payload)
|
|
223
234
|
total_pkt_count += 1
|
|
224
|
-
if len(r.payload) >= (
|
|
225
|
-
26 + 0x28
|
|
226
|
-
): # For short packets don't try to decode them as inetx
|
|
235
|
+
if len(r.payload) >= (26 + 0x28): # For short packets don't try to decode them as inetx
|
|
227
236
|
# pull out the key fields
|
|
228
|
-
(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
checksum,
|
|
232
|
-
control,
|
|
233
|
-
stream_id,
|
|
234
|
-
seq,
|
|
235
|
-
_len,
|
|
236
|
-
ptpsec,
|
|
237
|
-
ptpnsec
|
|
238
|
-
) = struct.unpack_from(">HHHIIIIII", r.payload, 0x24)
|
|
237
|
+
(dst_port, udp_len, checksum, control, stream_id, seq, _len, ptpsec, ptpnsec) = struct.unpack_from(
|
|
238
|
+
">HHHIIIIII", r.payload, 0x24
|
|
239
|
+
)
|
|
239
240
|
if control == args.control:
|
|
240
241
|
if stream_id in streams:
|
|
241
242
|
stream = streams[stream_id]
|
|
242
243
|
if seq != (stream.sequence + 1) % roll_over:
|
|
243
|
-
pkt_ts = datetime.datetime.fromtimestamp(
|
|
244
|
-
|
|
245
|
-
)
|
|
244
|
+
pkt_ts = datetime.datetime.fromtimestamp(r.sec + r.usec * 1e-6).strftime(
|
|
245
|
+
"%H:%M:%S.%f %d %b"
|
|
246
|
+
)
|
|
246
247
|
if seq < stream.sequence:
|
|
247
248
|
logging.warning(
|
|
248
249
|
"Source Restarted. File={} PktNum={} StreamID={:#0X} PrevSeq={} "
|
|
@@ -267,22 +268,31 @@ def main(args):
|
|
|
267
268
|
stream.sequence,
|
|
268
269
|
seq,
|
|
269
270
|
loss,
|
|
270
|
-
loss * stream.length
|
|
271
|
+
loss * stream.length,
|
|
271
272
|
)
|
|
272
273
|
)
|
|
273
274
|
loss_count += loss
|
|
274
|
-
loss_data +=
|
|
275
|
+
loss_data += loss * stream.length
|
|
275
276
|
stream.dropcnt += loss
|
|
276
277
|
stream.sequence_list.append(stream.sequence + 1)
|
|
277
278
|
floss += loss
|
|
278
279
|
stream.sequence = seq
|
|
279
280
|
stream.pkt_count += 1
|
|
280
|
-
stream.end_ts = ptpsec + ptpnsec/1e9
|
|
281
|
+
stream.end_ts = ptpsec + ptpnsec / 1e9
|
|
281
282
|
stream.datavol += len(r.payload)
|
|
282
283
|
else:
|
|
283
|
-
stream = Streams(
|
|
284
|
-
|
|
285
|
-
|
|
284
|
+
stream = Streams(
|
|
285
|
+
stream_id,
|
|
286
|
+
seq,
|
|
287
|
+
1,
|
|
288
|
+
ptpsec + ptpnsec / 1e9,
|
|
289
|
+
ptpsec + ptpnsec / 1e6,
|
|
290
|
+
0,
|
|
291
|
+
0,
|
|
292
|
+
len(r.payload),
|
|
293
|
+
len(r.payload),
|
|
294
|
+
[],
|
|
295
|
+
)
|
|
286
296
|
streams[stream_id] = stream
|
|
287
297
|
inetx_pkts_validate += 1
|
|
288
298
|
data_count_bytes += len(r.payload)
|
|
@@ -295,16 +305,12 @@ def main(args):
|
|
|
295
305
|
dr = 100
|
|
296
306
|
|
|
297
307
|
try:
|
|
298
|
-
ave_rec_rate_mbps = (
|
|
299
|
-
(packet_data_vol * 8) / (last_pcap_time - first_pcap_time) / 1e6
|
|
300
|
-
)
|
|
308
|
+
ave_rec_rate_mbps = (packet_data_vol * 8) / (last_pcap_time - first_pcap_time) / 1e6
|
|
301
309
|
except:
|
|
302
310
|
ave_rec_rate_mbps = 0
|
|
303
311
|
sids_found = len(streams)
|
|
304
312
|
if first_pcap_time is not None:
|
|
305
|
-
file_stamp = datetime.datetime.fromtimestamp(first_pcap_time).strftime(
|
|
306
|
-
"%H:%M:%S %d %b"
|
|
307
|
-
)
|
|
313
|
+
file_stamp = datetime.datetime.fromtimestamp(first_pcap_time).strftime("%H:%M:%S %d %b")
|
|
308
314
|
else:
|
|
309
315
|
file_stamp = "unknown"
|
|
310
316
|
info_str = (
|
|
@@ -319,9 +325,7 @@ def main(args):
|
|
|
319
325
|
if args.verbose:
|
|
320
326
|
if len(streams) > 0:
|
|
321
327
|
logging.info(
|
|
322
|
-
"{:>7s} {:>9s} {:>9s} {:>9s} {:>9s}".format(
|
|
323
|
-
"SID", "Seq", "LostCount", "ResetCnt", "Length"
|
|
324
|
-
)
|
|
328
|
+
"{:>7s} {:>9s} {:>9s} {:>9s} {:>9s}".format("SID", "Seq", "LostCount", "ResetCnt", "Length")
|
|
325
329
|
)
|
|
326
330
|
for sid, stream in streams.items():
|
|
327
331
|
logging.info(
|
|
@@ -337,12 +341,24 @@ def main(args):
|
|
|
337
341
|
remove(outf)
|
|
338
342
|
elif is_url and not args.verbose:
|
|
339
343
|
remove(outf)
|
|
344
|
+
if is_compressed(pfile):
|
|
345
|
+
remove(decompressed_f)
|
|
346
|
+
|
|
340
347
|
print("\n")
|
|
341
348
|
if len(streams) > 0:
|
|
342
349
|
logging.info(
|
|
343
350
|
"{:>7s} {:>15s} {:>9s} {:>9s} {:>9s} {:>9s} {:>9s} {:>18s} {:>12s} {:>12s} {:>12s}".format(
|
|
344
|
-
"SID",
|
|
345
|
-
"
|
|
351
|
+
"SID",
|
|
352
|
+
"Cnt",
|
|
353
|
+
"LostCount",
|
|
354
|
+
"ResetCnt",
|
|
355
|
+
"Length",
|
|
356
|
+
"PPS",
|
|
357
|
+
"Mbps",
|
|
358
|
+
"Elapsed Time(s)",
|
|
359
|
+
"DataVol(MB)",
|
|
360
|
+
"DropVol(Bytes)",
|
|
361
|
+
"BitRate(Mbps)",
|
|
346
362
|
)
|
|
347
363
|
)
|
|
348
364
|
for sid, stream in sorted(streams.items()):
|
|
@@ -352,9 +368,18 @@ def main(args):
|
|
|
352
368
|
_hist = ""
|
|
353
369
|
logging.info(
|
|
354
370
|
"{:#07X} {:15,d} {:9d} {:9d} {:9d} {:9d} {:9.1f} {:18.1f} {:12,.1f} {:12,d} {:12,.1f} {}".format(
|
|
355
|
-
sid,
|
|
356
|
-
stream.
|
|
357
|
-
stream.dropcnt
|
|
371
|
+
sid,
|
|
372
|
+
stream.pkt_count,
|
|
373
|
+
stream.dropcnt,
|
|
374
|
+
stream.rstcnt,
|
|
375
|
+
stream.length,
|
|
376
|
+
stream.pps(),
|
|
377
|
+
stream.bitrate() / 1e6,
|
|
378
|
+
stream.timelen(),
|
|
379
|
+
stream.datavol / 1e6,
|
|
380
|
+
stream.dropcnt * stream.length,
|
|
381
|
+
stream.datavol * 8 / (stream.timelen() * 1e6),
|
|
382
|
+
_hist,
|
|
358
383
|
)
|
|
359
384
|
)
|
|
360
385
|
|
|
@@ -8,10 +8,14 @@ import struct
|
|
|
8
8
|
import logging
|
|
9
9
|
from pstats import Stats
|
|
10
10
|
import cProfile
|
|
11
|
+
import typing
|
|
12
|
+
import random
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
14
16
|
|
|
17
|
+
logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(funcName)s:%(lineno)s:%(message)s")
|
|
18
|
+
|
|
15
19
|
|
|
16
20
|
def buf_generator(count, llp_count=0):
|
|
17
21
|
running_count = 0
|
|
@@ -25,6 +29,23 @@ def buf_generator(count, llp_count=0):
|
|
|
25
29
|
yield buf_len, low_latency
|
|
26
30
|
|
|
27
31
|
|
|
32
|
+
def ptfr_to_pcm_frame(
|
|
33
|
+
count: int,
|
|
34
|
+
):
|
|
35
|
+
remainder = bytes()
|
|
36
|
+
pcm_frame_len = 1024
|
|
37
|
+
offset_ptfr = 30
|
|
38
|
+
zero_buf = struct.pack(">B", 0) * offset_ptfr
|
|
39
|
+
pcm_frame = zero_buf
|
|
40
|
+
for ptfr in ch7.datapkts_to_ptfr(buf_generator(count)):
|
|
41
|
+
pcm_frame += ptfr.pack()
|
|
42
|
+
if len(pcm_frame) >= pcm_frame_len:
|
|
43
|
+
remainder = pcm_frame[pcm_frame_len:]
|
|
44
|
+
pcm_frame = pcm_frame[:pcm_frame_len]
|
|
45
|
+
yield pcm_frame
|
|
46
|
+
pcm_frame = zero_buf + remainder
|
|
47
|
+
|
|
48
|
+
|
|
28
49
|
class TestCaseCh7(unittest.TestCase):
|
|
29
50
|
def test_basic(self):
|
|
30
51
|
ch7_pkt = ch7.PTFR()
|
|
@@ -85,7 +106,7 @@ class TestGenerators(unittest.TestCase):
|
|
|
85
106
|
# print(repr(ptdp_pkt))
|
|
86
107
|
self.assertIsInstance(ptdp_pkt, ch7.PTDP)
|
|
87
108
|
|
|
88
|
-
def
|
|
109
|
+
def test_ptfr_generator(self):
|
|
89
110
|
remainder = bytes()
|
|
90
111
|
for ptfr in ch7.datapkts_to_ptfr(buf_generator(5), ptfr_len=200):
|
|
91
112
|
# print(repr(ptfr))
|
|
@@ -223,9 +244,10 @@ class TestRealEthernet(unittest.TestCase):
|
|
|
223
244
|
r.payload = eth_p
|
|
224
245
|
# Verify the size of the packets and it's probably good. I could unpack them here too
|
|
225
246
|
# self.assertEqual(2*64+eth.UDP.UDP_HEADER_SIZE+eth.IP.IP_HEADER_SIZE+eth.Ethernet.HEADERLEN, len(eth_p))
|
|
226
|
-
if
|
|
227
|
-
|
|
228
|
-
|
|
247
|
+
if p.content != ch7.PTDPContent.FILL:
|
|
248
|
+
if eth_p not in TestRealEthernet.pkts_sent:
|
|
249
|
+
self.assertTrue(False)
|
|
250
|
+
pkt_count += 1
|
|
229
251
|
pf.write(r)
|
|
230
252
|
eth_p = bytes()
|
|
231
253
|
ptdp_idx += 1
|
|
@@ -239,7 +261,6 @@ class TestRealEthernet(unittest.TestCase):
|
|
|
239
261
|
llc_count = 0
|
|
240
262
|
fill_count = 0
|
|
241
263
|
mac_count = 0
|
|
242
|
-
logging.basicConfig(level=logging.WARN)
|
|
243
264
|
remainder = b""
|
|
244
265
|
for i in range(3, 6):
|
|
245
266
|
f = open(THIS_DIR + "/ptfr_{}.bin".format(i), "rb")
|
|
@@ -267,5 +288,111 @@ class TestRealEthernet(unittest.TestCase):
|
|
|
267
288
|
self.assertEqual(4, mac_count)
|
|
268
289
|
|
|
269
290
|
|
|
291
|
+
def get_pkts(some_low_latency: bool = False, max_len: int = 178) -> typing.Generator[tuple[bytes, bool], None, None]:
|
|
292
|
+
|
|
293
|
+
count = 0
|
|
294
|
+
while True:
|
|
295
|
+
# pkt_len = random.randint(2, 180)
|
|
296
|
+
pkt_len = (count % max_len) + 2
|
|
297
|
+
paylaod_int = [pkt_len] + [count] * (pkt_len - 1)
|
|
298
|
+
payload = struct.pack(f">{pkt_len}Q", *paylaod_int)
|
|
299
|
+
count += 1
|
|
300
|
+
llc_pkts = [True, False, False, False, False, False, False]
|
|
301
|
+
# llc_pkts = [True, True, True, True, True, True, True]
|
|
302
|
+
if some_low_latency:
|
|
303
|
+
low_latency = llc_pkts[count % 7]
|
|
304
|
+
else:
|
|
305
|
+
low_latency = False
|
|
306
|
+
logging.debug(f"TX: Generated payload of length {pkt_len*8} count={count}")
|
|
307
|
+
yield payload, low_latency
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def get_pcm_frame(offset_ptfr: int = 0, some_low_latency: bool = False, max_len: int = 178):
|
|
311
|
+
pcm_frame_len = 1024
|
|
312
|
+
ptfr_len = pcm_frame_len - offset_ptfr - 4
|
|
313
|
+
zero_buf = struct.pack(">B", 0) * offset_ptfr
|
|
314
|
+
for ptfr in ch7.datapkts_to_ptfr(get_pkts(some_low_latency, max_len), ptfr_len=ptfr_len):
|
|
315
|
+
pcm_frame = zero_buf + ptfr.pack()
|
|
316
|
+
logging.debug(f"TX pcm_frame_len={len(pcm_frame)} ptfr_len={ptfr_len}")
|
|
317
|
+
yield pcm_frame
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def missing_elements(L):
|
|
321
|
+
start, end = L[0], L[-1]
|
|
322
|
+
return sorted(set(range(start, end + 1)).difference(L))
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class TestRandomSizedDecom(unittest.TestCase):
|
|
326
|
+
def test_no_llc(self):
|
|
327
|
+
offset = 0
|
|
328
|
+
first_PTFR = True
|
|
329
|
+
eth_p = bytes()
|
|
330
|
+
prev_eth_count = None
|
|
331
|
+
remainder = None
|
|
332
|
+
count = 0
|
|
333
|
+
for frame in get_pcm_frame(offset, some_low_latency=False):
|
|
334
|
+
ch7_pkt = ch7.PTFR()
|
|
335
|
+
ch7_buffer = frame[offset:]
|
|
336
|
+
ch7_pkt.length = len(ch7_buffer)
|
|
337
|
+
ch7_pkt.unpack(ch7_buffer)
|
|
338
|
+
count += 1
|
|
339
|
+
if count > 10000:
|
|
340
|
+
return
|
|
341
|
+
|
|
342
|
+
for p, remainder, e in ch7_pkt.get_aligned_payload(first_PTFR, remainder):
|
|
343
|
+
first_PTFR = False
|
|
344
|
+
if p is not None:
|
|
345
|
+
if p.length != 0:
|
|
346
|
+
if p.fragment == ch7.PTDPFragment.COMPLETE or p.fragment == ch7.PTDPFragment.LAST:
|
|
347
|
+
eth_p += p.payload
|
|
348
|
+
logging.debug(repr(p))
|
|
349
|
+
self.assertGreaterEqual(len(eth_p), 16)
|
|
350
|
+
(expected_len, count) = struct.unpack_from(">QQ", eth_p, 0x0)
|
|
351
|
+
logging.debug(f"RX payload count={count} len={len(eth_p)}")
|
|
352
|
+
if prev_eth_count is not None:
|
|
353
|
+
if prev_eth_count + 1 != count:
|
|
354
|
+
self.assertEqual(prev_eth_count + 1, count)
|
|
355
|
+
self.assertEqual(expected_len * 8, len(eth_p))
|
|
356
|
+
|
|
357
|
+
prev_eth_count = count
|
|
358
|
+
eth_p = bytes()
|
|
359
|
+
|
|
360
|
+
def test_some_llc(self):
|
|
361
|
+
offset = 0
|
|
362
|
+
first_PTFR = True
|
|
363
|
+
eth_p = bytes()
|
|
364
|
+
remainder = None
|
|
365
|
+
golay = ch7.Golay.Golay()
|
|
366
|
+
count = 0
|
|
367
|
+
numbers_found = []
|
|
368
|
+
for frame in get_pcm_frame(offset, some_low_latency=True, max_len=50):
|
|
369
|
+
ch7_pkt = ch7.PTFR(golay)
|
|
370
|
+
ch7_buffer = frame[offset:]
|
|
371
|
+
ch7_pkt.length = len(ch7_buffer)
|
|
372
|
+
ch7_pkt.unpack(ch7_buffer)
|
|
373
|
+
count += 1
|
|
374
|
+
if count > 10000:
|
|
375
|
+
return
|
|
376
|
+
|
|
377
|
+
for p, remainder, e in ch7_pkt.get_aligned_payload(first_PTFR, remainder):
|
|
378
|
+
first_PTFR = False
|
|
379
|
+
if p is not None:
|
|
380
|
+
if p.length != 0:
|
|
381
|
+
if p.fragment == ch7.PTDPFragment.COMPLETE or p.fragment == ch7.PTDPFragment.LAST:
|
|
382
|
+
eth_p += p.payload
|
|
383
|
+
logging.debug(repr(p))
|
|
384
|
+
if p.content != ch7.PTDPContent.FILL:
|
|
385
|
+
self.assertGreaterEqual(len(eth_p), 16)
|
|
386
|
+
(expected_len, count) = struct.unpack_from(">QQ", eth_p, 0x0)
|
|
387
|
+
logging.debug(f"RX payload count={count} len={len(eth_p)}")
|
|
388
|
+
numbers_found.append(count)
|
|
389
|
+
self.assertEqual(expected_len * 8, len(eth_p))
|
|
390
|
+
|
|
391
|
+
eth_p = bytes()
|
|
392
|
+
|
|
393
|
+
numbers_found.sort()
|
|
394
|
+
self.assertEqual(missing_elements(numbers_found), [])
|
|
395
|
+
|
|
396
|
+
|
|
270
397
|
if __name__ == "__main__":
|
|
271
398
|
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|