AcraNetwork 1.2.7__tar.gz → 1.2.8__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.
Files changed (71) hide show
  1. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter7/Golay.py +62 -65
  2. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/Pcap.py +67 -3
  3. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/__version__.py +6 -2
  4. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork.egg-info/PKG-INFO +1 -1
  5. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork.egg-info/SOURCES.txt +0 -1
  6. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork.egg-info/top_level.txt +0 -1
  7. {acranetwork-1.2.7 → acranetwork-1.2.8}/PKG-INFO +1 -1
  8. acranetwork-1.2.8/test/test_golay.py +623 -0
  9. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_pcap.py +50 -0
  10. acranetwork-1.2.7/test/__init__.py +0 -0
  11. acranetwork-1.2.7/test/test_golay.py +0 -321
  12. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IENA.py +0 -0
  13. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter10/Chapter10UDP.py +0 -0
  14. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter10/FileParser.py +0 -0
  15. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter10/__init__.py +0 -0
  16. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/ARINC429.py +0 -0
  17. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/Analog.py +0 -0
  18. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/CAN.py +0 -0
  19. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/ComputerData.py +0 -0
  20. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/MILSTD1553.py +0 -0
  21. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/PCM.py +0 -0
  22. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/TimeDataFormat.py +0 -0
  23. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/UART.py +0 -0
  24. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/Video.py +0 -0
  25. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter11/__init__.py +0 -0
  26. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter7/__init__.py +0 -0
  27. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/Chapter7/golay_c.c +0 -0
  28. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/IRIG106/__init__.py +0 -0
  29. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/ADTS.py +0 -0
  30. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/H264.py +0 -0
  31. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/PES.py +0 -0
  32. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/PMT.py +0 -0
  33. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/STANAG4609.py +0 -0
  34. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEG/__init__.py +0 -0
  35. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/MPEGTS.py +0 -0
  36. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/McastSocket.py +0 -0
  37. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/NPD.py +0 -0
  38. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/ParserAligned.py +0 -0
  39. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/SamDec008.py +0 -0
  40. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/SimpleEthernet.py +0 -0
  41. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/__init__.py +0 -0
  42. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/iNET.py +0 -0
  43. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/iNetX.py +0 -0
  44. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/nanotime.py +0 -0
  45. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork/ptptime.py +0 -0
  46. {acranetwork-1.2.7 → acranetwork-1.2.8}/AcraNetwork.egg-info/dependency_links.txt +0 -0
  47. {acranetwork-1.2.7 → acranetwork-1.2.8}/LICENSE +0 -0
  48. {acranetwork-1.2.7 → acranetwork-1.2.8}/MANIFEST.in +0 -0
  49. {acranetwork-1.2.7 → acranetwork-1.2.8}/README.md +0 -0
  50. {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/adau_to_ch10.py +0 -0
  51. {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/ch10_recorder.py +0 -0
  52. {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/ch10_to_pcap.py +0 -0
  53. {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/pkg_gen.ini +0 -0
  54. {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/tx_iena_udp.py +0 -0
  55. {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/tx_inetx_udp.py +0 -0
  56. {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/validate_ch10.py +0 -0
  57. {acranetwork-1.2.7 → acranetwork-1.2.8}/examples/validate_pcap.py +0 -0
  58. {acranetwork-1.2.7 → acranetwork-1.2.8}/setup.cfg +0 -0
  59. {acranetwork-1.2.7 → acranetwork-1.2.8}/setup.py +0 -0
  60. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_afdx.py +0 -0
  61. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_ch10.py +0 -0
  62. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_ch7.py +0 -0
  63. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_iena.py +0 -0
  64. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_inet.py +0 -0
  65. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_inetx.py +0 -0
  66. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_misc.py +0 -0
  67. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_mpegts.py +0 -0
  68. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_npd.py +0 -0
  69. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_paligned.py +0 -0
  70. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_ptptime.py +0 -0
  71. {acranetwork-1.2.7 → acranetwork-1.2.8}/test/test_simpleethernet.py +0 -0
@@ -33,30 +33,37 @@ G_P = [0xC75, 0x63B, 0xF68, 0x7B4, 0x3DA, 0xD99, 0x6CD, 0x367, 0xDC6, 0xA97, 0x9
33
33
  H_P = [0xA4F, 0xF68, 0x7B4, 0x3DA, 0x1ED, 0xAB9, 0xF13, 0xDC6, 0x6E3, 0x93E, 0x49F, 0xC75]
34
34
 
35
35
 
36
- class Singleton(type):
37
- _instances = {}
38
-
39
- def __call__(cls, *args, **kwargs):
40
- if cls not in cls._instances:
41
- cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
42
- return cls._instances[cls]
43
-
44
-
45
- class Golay(object):
46
- __metaclass__ = Singleton
36
+ class Golay:
47
37
  """
48
38
  Encode and Decode Golay numbers
49
39
  """
50
40
 
41
+ # Look-up tables are class variables. They will be initialised by the
42
+ # constructor of the first instance of the Golay class to be created.
43
+ # Set them to None here so the constructor can tell that they must be
44
+ # set up.
45
+ EncodeTable = None
46
+ SyndromeTable = None
47
+ CorrectTable = None
48
+ ErrorTable = None
49
+
51
50
  def __init__(self):
52
51
  if _use_c_extension:
53
52
  _golay_native.golay_init_tables()
54
53
  else:
55
- self.SyndromeTable = [0] * GOLAY_SIZE
56
- self.CorrectTable = [0] * GOLAY_SIZE
57
- self.ErrorTable = [0] * GOLAY_SIZE
54
+ if Golay.EncodeTable is None:
55
+ self._init_encode_table()
58
56
  self._initgolaydecode()
59
57
 
58
+
59
+ def _init_encode_table(self):
60
+ Golay.EncodeTable = [0] * GOLAY_SIZE
61
+ for x in range(GOLAY_SIZE):
62
+ Golay.EncodeTable[x] = x << 12
63
+ for i in range(12):
64
+ if x >> (11 - i) & 1:
65
+ Golay.EncodeTable[x] ^= G_P[i]
66
+
60
67
  def encode(self, raw, as_string=False):
61
68
  if not (0 <= raw <= 0xFFF):
62
69
  raise ValueError("Only 12-bit unsigned values allowed")
@@ -67,84 +74,70 @@ class Golay(object):
67
74
  encoded = self._encode_python(raw)
68
75
 
69
76
  if as_string:
70
- return struct.pack(">BH", encoded >> 16, encoded & 0xFFFF)
77
+ return encoded.to_bytes(3, "big")
71
78
  return encoded
72
79
 
73
80
  def decode(self, encoded):
74
81
  if _use_c_extension:
75
82
  return _golay_native.golay_decode(encoded)
76
83
  else:
77
- if isinstance(encoded, bytes):
84
+ # encoded is either an integer <= 0xFFFFFF, or is a bytes-like type
85
+ if not isinstance(encoded, int):
78
86
  if len(encoded) != 3:
79
87
  raise ValueError("3-byte input required")
80
- (b, w) = struct.unpack(">BH", encoded)
81
- v = w + (b << 16)
88
+ v = int.from_bytes(encoded, "big")
82
89
  elif not (0 <= encoded <= 0xFFFFFF):
83
90
  raise ValueError("Only 24-bit unsigned values supported")
84
91
  else:
85
92
  v = encoded
86
93
  return self._decode_python(v)
87
94
 
88
- @staticmethod
89
- @lru_cache()
90
- def _init_Table():
91
- EncodeTable = [0] * GOLAY_SIZE
92
- for x in range(GOLAY_SIZE):
93
- EncodeTable[x] = x << 12
94
- for i in range(12):
95
- if x >> (11 - i) & 1:
96
- EncodeTable[x] ^= G_P[i]
97
-
98
- return EncodeTable
99
95
 
100
- def _encode_python(self, raw, as_string=False):
96
+ def _encode_python(self, raw):
101
97
  """
102
98
  Encode the value as a 24b code
103
99
 
100
+ The leading '_' indicates this is a private method; do not call this
101
+ directly, call encode() instead.
102
+
104
103
  :type raw: int
105
- :return: int
104
+ :param raw: value to be encoded that is already validated to be 0..FFF
105
+ :return: encoded value as a 24-bit integer
106
106
  """
107
- if 0xFFF < raw < 0:
108
- raise Exception("Converestion of 12b value only")
107
+ # self.encode() has already checked that 0 <= raw <= 0xFFF so do not
108
+ # check again
109
+ # Also, there is no to_string argument because that is handled by
110
+ # encode()
109
111
 
110
- EncodeTable = Golay._init_Table()
111
- encoded = EncodeTable[raw & 0xFFF]
112
- if as_string:
113
- return struct.pack(">BH", encoded >> 16, encoded & 0xFFFF)
114
- else:
115
- return encoded
112
+ return Golay.EncodeTable[raw & 0xFFF]
116
113
 
117
- def _decode_python(self, encoded):
114
+ def _decode_python(self, v):
118
115
  """
119
116
  Decode a 24b number as a golay
120
117
 
121
- :type encoded: int|bytes
122
- :param encoded:
123
- :return:
124
- """
125
- if type(encoded) is bytes:
126
- if len(encoded) != 3:
127
- raise Exception("String to decode should be 3 bytes")
128
- (b, w) = struct.unpack(">BH", encoded)
129
- v = w + (b << 16)
130
- elif 0xFFFFF < encoded < 0:
131
- raise Exception("Only supports 24b unsigned numbers")
132
- else:
133
- v = encoded
118
+ The leading '_' indicates this is a private method; do not call this
119
+ directly, call decode() instead.
134
120
 
121
+ :type v: int
122
+ :param v: integer that has already been validated to be 24bit
123
+ :return: decoded 12-bit value
124
+ """
125
+ # self.decode() has converted the value to an integer and verified
126
+ # that it is valid. So do not repeat the check.
127
+
135
128
  return self._decode2(((v) >> 12) & 0xFFF, (v) & 0xFFF)
136
129
 
137
130
  def _syndrome2(self, v1, v2):
138
- return self.SyndromeTable[v2] ^ (v1)
131
+ return Golay.SyndromeTable[v2] ^ (v1)
139
132
 
140
133
  def _syndrome(self, v):
141
134
  return self._syndrome2(((v) >> 12) & 0xFFF, (v) & 0xFFF)
142
135
 
143
136
  def _errors2(self, v1, v2):
144
- return self.ErrorTable[self._syndrome2(v1, v2)]
137
+ return Golay.ErrorTable[self._syndrome2(v1, v2)]
145
138
 
146
139
  def _decode2(self, v1, v2):
147
- return (v1) ^ self.CorrectTable[self._syndrome2(v1, v2)]
140
+ return (v1) ^ Golay.CorrectTable[self._syndrome2(v1, v2)]
148
141
 
149
142
  def _errors(self, v):
150
143
  return self._errors2(((v) >> 12) & 0xFFF, (v) & 0xFFF)
@@ -171,22 +164,26 @@ class Golay(object):
171
164
  return ret
172
165
 
173
166
  def _initgolaydecode(self):
167
+ Golay.SyndromeTable = [0] * GOLAY_SIZE
168
+ Golay.CorrectTable = [0] * GOLAY_SIZE
169
+ Golay.ErrorTable = [0] * GOLAY_SIZE
170
+
174
171
  for x in range(GOLAY_SIZE):
175
- self.SyndromeTable[x] = 0
172
+ Golay.SyndromeTable[x] = 0
176
173
  for i in range(12):
177
174
  if (x >> (11 - i)) & 1:
178
- self.SyndromeTable[x] ^= H_P[i]
179
- self.ErrorTable[x] = 4
180
- self.CorrectTable[x] = 0xFFF
175
+ Golay.SyndromeTable[x] ^= H_P[i]
176
+ Golay.ErrorTable[x] = 4
177
+ Golay.CorrectTable[x] = 0xFFF
181
178
 
182
- self.ErrorTable[0] = 0
183
- self.CorrectTable[0] = 0
179
+ Golay.ErrorTable[0] = 0
180
+ Golay.CorrectTable[0] = 0
184
181
  for i in range(24):
185
182
  for j in range(24):
186
183
  for k in range(24):
187
184
  error = (1 << i) | (1 << j) | (1 << k)
188
- syndrom = self._syndrome(error)
189
- self.CorrectTable[syndrom] = (error >> 12) & 0xFFF
190
- self.ErrorTable[syndrom] = Golay._onesincode(error, 24)
185
+ syndrome = self._syndrome(error)
186
+ Golay.CorrectTable[syndrome] = (error >> 12) & 0xFFF
187
+ Golay.ErrorTable[syndrome] = Golay._onesincode(error, 24)
191
188
 
192
189
  return True
@@ -31,12 +31,18 @@ class PcapRecord(object):
31
31
  :type _packet: str
32
32
  """
33
33
 
34
- def __init__(self):
34
+ def __init__(self, now=False):
35
+ """
36
+ :param now: if True, record time is set to the current time.
37
+ :type now: bool
38
+ """
35
39
  self.sec: int = 0 #: Second timestamp of the record. Epoch time
36
40
  self.usec: int = 0 #: Microsecond timestamp of the record
37
41
  self.incl_len: int = 0 #: The number of bytes captured and saved in the file
38
- self.orig_len: int = 0 #: The number of bytesas appearded on the network when captured
42
+ self.orig_len: int = 0 #: The number of bytes as appeared on the network when captured
39
43
  self._payload: bytes = bytes()
44
+ if now:
45
+ self.set_current_time()
40
46
 
41
47
  # Use a property on packet so that the length is triggered on it changing
42
48
  @property
@@ -140,8 +146,47 @@ class Pcap(object):
140
146
 
141
147
  So after opening the file, iterate through the object to read the records
142
148
 
149
+ A PCAP file can be opened for reading or writing by specifying mode "r"
150
+ or "w", or for append by specifying "a".
151
+
152
+ When a PCAP file is open for writing or appending, PcapRecord objects can
153
+ be written to it.
154
+
155
+ # Write 10 UDP records to a file
156
+ # For simplicity use the same MAC, IP and UDP headers in all records
157
+ >>> headers = (bytes((0x77,0x88,0x99,0xAA,0xBB,0xCC,0x66,0x55,0x44,0x33,0x22,0x11,
158
+ ... 0x08,0x00))
159
+ ... +bytes((0x45,0x00,0x00,0x36,0x77,0x77,0x40,0x00,0xff,0x11,0x8a,0xa4,
160
+ ... 0x12,0x34,0x56,0x78,0x99,0x88,0x77,0x66))
161
+ ... +bytes((0x12,0x34,0x56,0x78,0x00,0x22,0x00,0x00))
162
+ ... )
163
+ >>> with Pcap("_dummy.pcap", mode='w') as p:
164
+ ... r = PcapRecord()
165
+ ... for i in range(10):
166
+ ... start_ch = ord('A') + i
167
+ ... r.payload = headers + bytes((x for x in range(start_ch,start_ch+26)))
168
+ ... p.write(r)
169
+
170
+ When a PCAP file is open for reading, iterate through the records.
171
+ >>> with Pcap("_dummy.pcap", mode='r') as p2:
172
+ ... print(f"{p2.filename} contains {p2.filesize} bytes and is open with mode '{p2.mode}'")
173
+ ... print(f"Network type ID {p2.network}{' (Ethernet)' if p2.network==1 else ''}")
174
+ ... for ix, record in enumerate(p2):
175
+ ... print(f"{ix} {record.orig_len} bytes: {record.payload}")
176
+ ...
177
+ _dummy.pcap contains 864 bytes and is open with mode 'r'
178
+ Network type ID 1 (Ethernet)
179
+ 0 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00ABCDEFGHIJKLMNOPQRSTUVWXYZ'
180
+ 1 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00BCDEFGHIJKLMNOPQRSTUVWXYZ['
181
+ 2 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00CDEFGHIJKLMNOPQRSTUVWXYZ[\\'
182
+ 3 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00DEFGHIJKLMNOPQRSTUVWXYZ[\\]'
183
+ 4 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00EFGHIJKLMNOPQRSTUVWXYZ[\\]^'
184
+ 5 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00FGHIJKLMNOPQRSTUVWXYZ[\\]^_'
185
+ 6 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00GHIJKLMNOPQRSTUVWXYZ[\\]^_`'
186
+ 7 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00HIJKLMNOPQRSTUVWXYZ[\\]^_`a'
187
+ 8 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00IJKLMNOPQRSTUVWXYZ[\\]^_`ab'
188
+ 9 68 bytes: b'w\x88\x99\xaa\xbb\xccfUD3"\x11\x08\x00E\x00\x006ww@\x00\xff\x11\x8a\xa4\x124Vx\x99\x88wf\x124Vx\x00"\x00\x00JKLMNOPQRSTUVWXYZ[\\]^_`abc'
143
189
 
144
- Open a PCAP file for reading. Iterate through the records.
145
190
 
146
191
  The pcap can also be treated a list to select the relevant object.
147
192
 
@@ -185,11 +230,21 @@ class Pcap(object):
185
230
  self.network: int = 1 #: Link-layer header type. http://www.tcpdump.org/linktypes.html
186
231
  self.filesize = 0
187
232
 
233
+ # rec_no is convenient if the file is not being read in a simple loop,
234
+ # so "for ix, record in enumerate(p)" cannot easily be used. It is the
235
+ # number of the last record read or written. Wireshark numbers records
236
+ # starting at 1, so after the first record is read or written, rec_no
237
+ # will be 1
238
+ self.rec_no = 0
239
+
240
+ self.fopen = None # make deterministic if the file open fails
188
241
  try:
189
242
  self.fopen = open(filename, f"{self.mode}b", self._bufferring)
190
243
  except Exception as e:
191
244
  raise IOError(f"Failed to open {self.filename}. err={e}")
192
245
 
246
+ # mode can be anything that open() will accept with 'b' added. So it
247
+ # could be "a". But for "r" or "w", then the header must be handled.
193
248
  if self.mode == "r":
194
249
  self._read_global_header()
195
250
  elif self.mode == "w":
@@ -200,6 +255,13 @@ class Pcap(object):
200
255
  except Exception as e:
201
256
  self.filesize = 0
202
257
 
258
+ # Define __enter__() and __exit__() so "with Pcap(...) as x" can be used
259
+ def __enter__(self):
260
+ return self
261
+
262
+ def __exit__(self, exc_type, exc_value, traceback):
263
+ self.close()
264
+
203
265
  def flush(self):
204
266
  return self.fopen.flush()
205
267
 
@@ -254,6 +316,7 @@ class Pcap(object):
254
316
 
255
317
  _pkt = pcaprecord.pack()
256
318
  self.fopen.write(_pkt)
319
+ self.rec_no += 1
257
320
  self.filesize += len(_pkt)
258
321
 
259
322
  def close(self):
@@ -280,6 +343,7 @@ class Pcap(object):
280
343
  except:
281
344
  raise StopIteration
282
345
  else:
346
+ self.rec_no += 1
283
347
  return pcaprecord
284
348
 
285
349
  __next__ = next
@@ -111,5 +111,9 @@
111
111
  # 1.2.4 - Removed exit in the ch7
112
112
  # 1.2.5 - Added C implementation of Golay. Also improved the existing python impl
113
113
  # 1.2.6 - Further optimisation of the C Golay implementation
114
- # 1.2.7 - Chagned setup so as not to break if extension cannot be compiled
115
- __version__ = "1.2.7"
114
+ # 1.2.7 - Changed setup so as not to break if extension cannot be compiled
115
+ # 1.2.8 (FJP 2025-07-01)
116
+ # - Added Context Manager support to Pcap.py
117
+ # - Allow Golay.decode() to accept bytearray or other bytes-like object instead of only bytes (if not int)
118
+ # - simplified Golay.py; removed some redundant checks
119
+ __version__ = "1.2.8"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AcraNetwork
3
- Version: 1.2.7
3
+ Version: 1.2.8
4
4
  Summary: Classes and utilities to support Flight Test Instrumentation Ethernet networks
5
5
  Home-page: https://github.com/diarmuidcwc/AcraNetwork
6
6
  Author: Diarmuid Collins
@@ -52,7 +52,6 @@ examples/tx_iena_udp.py
52
52
  examples/tx_inetx_udp.py
53
53
  examples/validate_ch10.py
54
54
  examples/validate_pcap.py
55
- test/__init__.py
56
55
  test/test_afdx.py
57
56
  test/test_ch10.py
58
57
  test/test_ch7.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AcraNetwork
3
- Version: 1.2.7
3
+ Version: 1.2.8
4
4
  Summary: Classes and utilities to support Flight Test Instrumentation Ethernet networks
5
5
  Home-page: https://github.com/diarmuidcwc/AcraNetwork
6
6
  Author: Diarmuid Collins