fprime-gds 4.0.0a9__py3-none-any.whl → 4.0.1__py3-none-any.whl
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.
- fprime_gds/common/distributor/distributor.py +12 -6
- fprime_gds/executables/data_product_writer.py +66 -30
- {fprime_gds-4.0.0a9.dist-info → fprime_gds-4.0.1.dist-info}/METADATA +1 -1
- {fprime_gds-4.0.0a9.dist-info → fprime_gds-4.0.1.dist-info}/RECORD +9 -9
- {fprime_gds-4.0.0a9.dist-info → fprime_gds-4.0.1.dist-info}/WHEEL +0 -0
- {fprime_gds-4.0.0a9.dist-info → fprime_gds-4.0.1.dist-info}/entry_points.txt +0 -0
- {fprime_gds-4.0.0a9.dist-info → fprime_gds-4.0.1.dist-info}/licenses/LICENSE.txt +0 -0
- {fprime_gds-4.0.0a9.dist-info → fprime_gds-4.0.1.dist-info}/licenses/NOTICE.txt +0 -0
- {fprime_gds-4.0.0a9.dist-info → fprime_gds-4.0.1.dist-info}/top_level.txt +0 -0
@@ -13,6 +13,7 @@ descriptor header will be passed on to the registered objects.
|
|
13
13
|
|
14
14
|
@bug No known bugs
|
15
15
|
"""
|
16
|
+
|
16
17
|
import logging
|
17
18
|
|
18
19
|
from fprime_gds.common.decoders.decoder import DecodingException
|
@@ -193,18 +194,23 @@ class Distributor(DataHandler):
|
|
193
194
|
self.__buf.extend(data)
|
194
195
|
|
195
196
|
(leftover_data, raw_msgs) = self.parse_into_raw_msgs_api(self.__buf)
|
196
|
-
assert
|
197
|
+
assert (
|
198
|
+
leftover_data == self.__buf
|
199
|
+
), "Leftover data is not equivalent to the remaining data in buffer"
|
197
200
|
|
198
201
|
for raw_msg in raw_msgs:
|
199
202
|
(length, data_desc, msg) = self.parse_raw_msg_api(raw_msg)
|
200
203
|
|
201
204
|
data_desc_key = data_desc_type.DataDescType(data_desc).name
|
202
|
-
|
205
|
+
decoders = self.__decoders[data_desc_key]
|
206
|
+
|
207
|
+
if not decoders:
|
208
|
+
LOGGER.warning(f"No decoder registered for: {data_desc_key}")
|
209
|
+
|
210
|
+
for d in decoders:
|
203
211
|
try:
|
204
212
|
d.data_callback(msg)
|
205
213
|
except DecodingException as dexc:
|
206
|
-
LOGGER.warning("Decoding error:
|
214
|
+
LOGGER.warning(f"Decoding error: {dexc}")
|
207
215
|
except Exception as exc:
|
208
|
-
LOGGER.warning("Parsing error:
|
209
|
-
else:
|
210
|
-
LOGGER.warning("No decoder registered for: %s", data_desc_type.DataDescType(data_desc).name)
|
216
|
+
LOGGER.warning(f"Parsing error: {exc}")
|
@@ -194,6 +194,7 @@ class QualifiedType(BaseModel):
|
|
194
194
|
class StructMember(BaseModel):
|
195
195
|
type: Union[IntegerType, FloatType, BoolType, StringType, QualifiedType]
|
196
196
|
size: int = 1
|
197
|
+
index: int
|
197
198
|
|
198
199
|
class StructType(BaseModel):
|
199
200
|
kind: str
|
@@ -209,7 +210,7 @@ class StructType(BaseModel):
|
|
209
210
|
class AliasType(BaseModel):
|
210
211
|
kind: str
|
211
212
|
qualifiedName: str
|
212
|
-
type: Union[AliasType, StructType, ArrayType, IntegerType, FloatType,
|
213
|
+
type: Union[AliasType, StructType, ArrayType, IntegerType, BoolType, FloatType, StringType, QualifiedType]
|
213
214
|
underlyingType: Union[StructType, ArrayType, IntegerType, BoolType, FloatType, StringType, QualifiedType]
|
214
215
|
|
215
216
|
@field_validator('kind')
|
@@ -222,7 +223,7 @@ class ArrayType(BaseModel):
|
|
222
223
|
kind: str
|
223
224
|
qualifiedName: str
|
224
225
|
size: int
|
225
|
-
elementType: Union[AliasType, StructType, ArrayType, IntegerType, FloatType,
|
226
|
+
elementType: Union[AliasType, StructType, ArrayType, IntegerType, BoolType, FloatType, StringType, QualifiedType]
|
226
227
|
|
227
228
|
@field_validator('kind')
|
228
229
|
def kind_qualifiedIdentifier(cls, v):
|
@@ -297,29 +298,33 @@ class DPHeader(BaseModel):
|
|
297
298
|
@computed_field
|
298
299
|
@property
|
299
300
|
def header(self) -> Dict[str, Union[Type, ArrayType, EnumType]]:
|
300
|
-
#
|
301
|
-
|
302
|
-
"FwPacketDescriptorType":
|
303
|
-
"FwDpIdType":
|
304
|
-
"FwDpPriorityType" :
|
305
|
-
"Seconds":
|
306
|
-
"USeconds":
|
307
|
-
"FwTimeBaseStoreType":
|
308
|
-
"FwTimeContextStoreType":
|
309
|
-
"Fw.DpCfg.ProcType":
|
310
|
-
"Fw.DpCfg.CONTAINER_USER_DATA_SIZE":
|
311
|
-
"Fw.DpState":
|
312
|
-
"FwSizeStoreType":
|
301
|
+
# Mapping from type/constant names to header field names
|
302
|
+
header_field_names = {
|
303
|
+
"FwPacketDescriptorType": "PacketDescriptor",
|
304
|
+
"FwDpIdType": "Id",
|
305
|
+
"FwDpPriorityType" : "Priority",
|
306
|
+
"Seconds": "Seconds",
|
307
|
+
"USeconds": "USeconds",
|
308
|
+
"FwTimeBaseStoreType": "TimeBase",
|
309
|
+
"FwTimeContextStoreType": "Context",
|
310
|
+
"Fw.DpCfg.ProcType": "ProcTypes",
|
311
|
+
"Fw.DpCfg.CONTAINER_USER_DATA_SIZE": "UserData",
|
312
|
+
"Fw.DpState": "DpState",
|
313
|
+
"FwSizeStoreType": "DataSize"
|
313
314
|
}
|
314
|
-
|
315
|
+
# All types/constants that make up the DP header
|
316
|
+
# Key: Values of above header_field_names
|
317
|
+
# Values: Initialized to None, populated below based on type names/constants in the JSON dictionary
|
318
|
+
header_dict = {v: None for v in header_field_names.values()}
|
319
|
+
for k, v in header_field_names.items():
|
315
320
|
# Seconds and USeconds are not in the dictionary, but are both always U32
|
316
321
|
if k == "Seconds" or k == "USeconds":
|
317
|
-
header_dict[
|
322
|
+
header_dict[v] = Type(type=IntegerType(name="U32", kind="integer", size=32, signed=False))
|
318
323
|
# According to Fw.Dp SDD, Header::UserData is an array of U8 of size Fw::DpCfg::CONTAINER_USER_DATA_SIZE.
|
319
324
|
elif k == "Fw.DpCfg.CONTAINER_USER_DATA_SIZE":
|
320
325
|
for t in self.constants:
|
321
326
|
if t.qualifiedName == k:
|
322
|
-
header_dict[
|
327
|
+
header_dict[v] = ArrayType(
|
323
328
|
kind="array",
|
324
329
|
qualifiedName="UserData",
|
325
330
|
size=t.value,
|
@@ -329,7 +334,7 @@ class DPHeader(BaseModel):
|
|
329
334
|
else:
|
330
335
|
for t in self.typeDefinitions:
|
331
336
|
if t.qualifiedName == k:
|
332
|
-
header_dict[
|
337
|
+
header_dict[v] = t
|
333
338
|
break
|
334
339
|
|
335
340
|
return header_dict
|
@@ -337,12 +342,15 @@ class DPHeader(BaseModel):
|
|
337
342
|
@computed_field
|
338
343
|
@property
|
339
344
|
def dataId(self) -> AliasType:
|
340
|
-
return self.header.get("
|
345
|
+
return self.header.get("Id")
|
341
346
|
|
342
347
|
@computed_field
|
343
348
|
@property
|
344
349
|
def dataSize(self) -> AliasType:
|
345
|
-
return self.header.get("
|
350
|
+
return self.header.get("DataSize")
|
351
|
+
|
352
|
+
def get_size_store_bytes(self) -> int:
|
353
|
+
return self.header.get("DataSize").underlyingType.size // 8
|
346
354
|
|
347
355
|
@model_validator(mode='after')
|
348
356
|
def validate_header(self) -> 'DPHeader':
|
@@ -371,7 +379,8 @@ type_mapping = {
|
|
371
379
|
'U64': 'Q', # Unsigned 64-bit integer
|
372
380
|
'F32': 'f', # 32-bit float
|
373
381
|
'F64': 'd', # 64-bit float
|
374
|
-
'bool': '?' # An 8 bit boolean
|
382
|
+
'bool': '?', # An 8 bit boolean
|
383
|
+
'string': 's'
|
375
384
|
# Add more mappings as needed
|
376
385
|
}
|
377
386
|
|
@@ -485,6 +494,7 @@ class DataProductWriter:
|
|
485
494
|
self.binaryFileName = binaryFileName
|
486
495
|
self.totalBytesRead = 0
|
487
496
|
self.calculatedCRC = 0
|
497
|
+
self.headerJSON = None
|
488
498
|
|
489
499
|
|
490
500
|
# ----------------------------------------------------------------------------------------------
|
@@ -520,8 +530,29 @@ class DataProductWriter:
|
|
520
530
|
except KeyError:
|
521
531
|
raise KeyError(f"Unrecognized JSON Dictionary Type: {intType}")
|
522
532
|
data = struct.unpack(format_str, bytes_read)[0]
|
533
|
+
return data
|
534
|
+
|
535
|
+
def read_and_deserialize_string(self) -> str:
|
536
|
+
size_store_type_bytes = self.headerJSON.get_size_store_bytes()
|
537
|
+
bytes_read_store = self.binaryFile.read(size_store_type_bytes)
|
538
|
+
if len(bytes_read_store) != size_store_type_bytes:
|
539
|
+
raise IOError(f"Tried to read {size_store_type_bytes} bytes from the binary file, but failed.")
|
540
|
+
|
541
|
+
self.totalBytesRead += size_store_type_bytes
|
542
|
+
|
543
|
+
format_str = f'{BIG_ENDIAN}H'
|
544
|
+
string_size_data = struct.unpack(format_str, bytes_read_store)[0]
|
545
|
+
|
546
|
+
bytes_read = self.binaryFile.read(string_size_data)
|
547
|
+
if len(bytes_read) != string_size_data:
|
548
|
+
raise IOError(f"Tried to read {string_size_data} bytes from the binary file, but failed.")
|
523
549
|
|
550
|
+
self.calculatedCRC = crc32(bytes_read_store + bytes_read, self.calculatedCRC) & 0xffffffff
|
551
|
+
self.totalBytesRead += string_size_data
|
524
552
|
|
553
|
+
format_str = f'{BIG_ENDIAN}{string_size_data}s'
|
554
|
+
data = struct.unpack(format_str, bytes_read)[0]
|
555
|
+
data = data.decode()
|
525
556
|
return data
|
526
557
|
|
527
558
|
# -----------------------------------------------------------------------------------------------------------------------
|
@@ -568,7 +599,7 @@ class DataProductWriter:
|
|
568
599
|
# AssertionError: If the field_config is not an IntegerType, FloatType, or BoolType.
|
569
600
|
# -----------------------------------------------------------------------------------------------------------------------
|
570
601
|
|
571
|
-
def read_field(self, field_config: Union[IntegerType, FloatType, BoolType]) -> Union[int, float, bool]:
|
602
|
+
def read_field(self, field_config: Union[IntegerType, FloatType, BoolType, StringType]) -> Union[int, float, bool]:
|
572
603
|
|
573
604
|
if type(field_config) is IntegerType:
|
574
605
|
sizeBytes = field_config.size // 8
|
@@ -579,6 +610,9 @@ class DataProductWriter:
|
|
579
610
|
elif type(field_config) is BoolType:
|
580
611
|
sizeBytes = field_config.size // 8
|
581
612
|
|
613
|
+
elif type(field_config) is StringType:
|
614
|
+
return self.read_and_deserialize_string()
|
615
|
+
|
582
616
|
else:
|
583
617
|
assert False, "Unsupported typeKind encountered"
|
584
618
|
|
@@ -626,6 +660,8 @@ class DataProductWriter:
|
|
626
660
|
elif isinstance(typeKind, BoolType):
|
627
661
|
parent_dict[field_name] = self.read_field(typeKind)
|
628
662
|
|
663
|
+
elif isinstance(typeKind, StringType):
|
664
|
+
parent_dict[field_name] = self.read_field(typeKind)
|
629
665
|
|
630
666
|
elif isinstance(typeKind, EnumType):
|
631
667
|
value = self.read_field(typeKind.representationType)
|
@@ -646,7 +682,8 @@ class DataProductWriter:
|
|
646
682
|
|
647
683
|
elif isinstance(typeKind, StructType):
|
648
684
|
array_list = []
|
649
|
-
|
685
|
+
sorted_members = dict(sorted(typeKind.members.items(), key=lambda member: member[1].index))
|
686
|
+
for key, member in sorted_members.items():
|
650
687
|
for i in range(member.size):
|
651
688
|
element_dict = {}
|
652
689
|
self.get_struct_item(key, member.type, typeList, element_dict)
|
@@ -830,7 +867,7 @@ class DataProductWriter:
|
|
830
867
|
header_json["typeDefinitions"] = dict_json["typeDefinitions"]
|
831
868
|
if "constants" in dict_json:
|
832
869
|
header_json["constants"] = dict_json["constants"]
|
833
|
-
headerJSON = DPHeader(**header_json)
|
870
|
+
self.headerJSON = DPHeader(**header_json)
|
834
871
|
|
835
872
|
except json.JSONDecodeError as e:
|
836
873
|
raise DictionaryError(self.jsonDict, e.lineno)
|
@@ -840,10 +877,10 @@ class DataProductWriter:
|
|
840
877
|
with open(self.binaryFileName, 'rb') as self.binaryFile:
|
841
878
|
|
842
879
|
# Read the header data up until the Records
|
843
|
-
headerData = self.get_header_info(headerJSON)
|
880
|
+
headerData = self.get_header_info(self.headerJSON)
|
844
881
|
|
845
882
|
# Read the total data size
|
846
|
-
dataSize = headerData['
|
883
|
+
dataSize = headerData['DataSize']
|
847
884
|
|
848
885
|
# Restart the count of bytes read
|
849
886
|
self.totalBytesRead = 0
|
@@ -851,13 +888,12 @@ class DataProductWriter:
|
|
851
888
|
recordList = [headerData]
|
852
889
|
|
853
890
|
while self.totalBytesRead < dataSize:
|
854
|
-
|
855
|
-
recordData = self.get_record_data(headerJSON, dictJSON)
|
891
|
+
recordData = self.get_record_data(self.headerJSON, dictJSON)
|
856
892
|
recordList.append(recordData)
|
857
893
|
|
858
894
|
computedCRC = self.calculatedCRC
|
859
895
|
# Read the data checksum
|
860
|
-
headerData['dataHash'] = self.read_field(headerJSON.dataHash.type)
|
896
|
+
headerData['dataHash'] = self.read_field(self.headerJSON.dataHash.type)
|
861
897
|
|
862
898
|
if computedCRC != headerData['dataHash']:
|
863
899
|
raise CRCError("Data", headerData['dataHash'], computedCRC)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: fprime-gds
|
3
|
-
Version: 4.0.
|
3
|
+
Version: 4.0.1
|
4
4
|
Summary: F Prime Flight Software Ground Data System layer
|
5
5
|
Author-email: Michael Starch <Michael.D.Starch@jpl.nasa.gov>, Thomas Boyer-Chammard <Thomas.Boyer.Chammard@jpl.nasa.gov>
|
6
6
|
License:
|
@@ -35,7 +35,7 @@ fprime_gds/common/decoders/event_decoder.py,sha256=ib-O18V5Z7bcnUUSDE9R0fU--bAZs
|
|
35
35
|
fprime_gds/common/decoders/file_decoder.py,sha256=Ky2U8bli3YL6GbT9jSSvI73ySOtf0cdZLK4FXTuWjfA,2542
|
36
36
|
fprime_gds/common/decoders/pkt_decoder.py,sha256=kW8k3OSbMy96w6MzsGWp656lAQvwxrIznWkD3Sbi8Ig,3329
|
37
37
|
fprime_gds/common/distributor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
|
-
fprime_gds/common/distributor/distributor.py,sha256=
|
38
|
+
fprime_gds/common/distributor/distributor.py,sha256=jged1utucsYkVBm5tSaFEXHDg8suiJ_Hn-9YLPCaVXA,8036
|
39
39
|
fprime_gds/common/encoders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
40
|
fprime_gds/common/encoders/ch_encoder.py,sha256=TBrTJ7TK4WwCh6KAspozh63WcPxrMImloB8tz7qeulw,2878
|
41
41
|
fprime_gds/common/encoders/cmd_encoder.py,sha256=5wG5854ozmxctnYou3q9MdQNkTQEmpCiT4oBVgNRZdE,3499
|
@@ -125,7 +125,7 @@ fprime_gds/executables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
125
125
|
fprime_gds/executables/apps.py,sha256=u79T_PlgMmNmA4YwWjs7LvPMCJnrjnURr05NMthOYP0,13350
|
126
126
|
fprime_gds/executables/cli.py,sha256=Qqq3JQOqTsfDRsbTALw25xnwN7fCEVlpcKDV4jvGopQ,50961
|
127
127
|
fprime_gds/executables/comm.py,sha256=08rO0o0MJgTRngB7Ygu2IL_gEAWKF7WFvFyro1CqReE,5214
|
128
|
-
fprime_gds/executables/data_product_writer.py,sha256=
|
128
|
+
fprime_gds/executables/data_product_writer.py,sha256=e1Rp2LT_Cpg08f0Ki8GhirC7Wn6LtYiAef7KLAkZHUY,37773
|
129
129
|
fprime_gds/executables/fprime_cli.py,sha256=CMoT7zWNwM8h2mSZW03AR96wl_XnZXoLNiOZN_sDi38,12431
|
130
130
|
fprime_gds/executables/run_deployment.py,sha256=Zl0Y9-6i6c8tZhcS7XkAeVQtzn0d9fV-3UJQZ0bnBrc,7237
|
131
131
|
fprime_gds/executables/tcpserver.py,sha256=KspVpu5YIuiWKOk5E6UDMKvqXYrRB1j9aX8CkMxysfw,17555
|
@@ -244,10 +244,10 @@ fprime_gds/flask/static/third-party/webfonts/fa-solid-900.woff2,sha256=mDS4KtJuK
|
|
244
244
|
fprime_gds/plugin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
245
245
|
fprime_gds/plugin/definitions.py,sha256=QlxW1gNvoiqGMslSJjh3dTFZuv0igFHawN__3XJ0Wns,5355
|
246
246
|
fprime_gds/plugin/system.py,sha256=M9xb-8jBhCUUx3X1z2uAP8Wx_v6NkL8JeaFgGcMnQqY,13432
|
247
|
-
fprime_gds-4.0.
|
248
|
-
fprime_gds-4.0.
|
249
|
-
fprime_gds-4.0.
|
250
|
-
fprime_gds-4.0.
|
251
|
-
fprime_gds-4.0.
|
252
|
-
fprime_gds-4.0.
|
253
|
-
fprime_gds-4.0.
|
247
|
+
fprime_gds-4.0.1.dist-info/licenses/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
248
|
+
fprime_gds-4.0.1.dist-info/licenses/NOTICE.txt,sha256=vXjA_xRcQhd83Vfk5D_vXg5kOjnnXvLuMi5vFKDEVmg,1612
|
249
|
+
fprime_gds-4.0.1.dist-info/METADATA,sha256=vl63LzQIM8HX9jfV3JtcjkmpxnhIpN8D46AEBuBJPoY,24574
|
250
|
+
fprime_gds-4.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
251
|
+
fprime_gds-4.0.1.dist-info/entry_points.txt,sha256=V2XMHMUJUGTVx5s3_kK1jLmoxSKE1vvj2XWHH9y49WQ,423
|
252
|
+
fprime_gds-4.0.1.dist-info/top_level.txt,sha256=6vzFLIX6ANfavKaXFHDMSLFtS94a6FaAsIWhjgYuSNE,27
|
253
|
+
fprime_gds-4.0.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|