Skip to content

Commit 79cfbb6

Browse files
authored
Python client/test app bug fixes (#75)
bypassed merge rules after email confirmation from Mike - Addressed bugs re: flag handling in test app - Removed bitstring from python client - refactored to use bitshift logic or struct bytearray extend in both the python client and test app - cleaned up default test app properties file - hit at least one of the python files with the formatter stick (sorry!)
2 parents d8cd3e0 + 439c177 commit 79cfbb6

6 files changed

Lines changed: 354 additions & 321 deletions

File tree

ammos-cryptolib/kmc_sdls/kmc_sdls_python/KmcSdlsClient/src/gov/nasa/jpl/ammos/kmc/sdlsclient/KmcSdlsClient.py

Lines changed: 146 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import distutils.util
1717
import os.path
1818
import re
19+
import struct
1920
from typing import NamedTuple
2021

2122
import kmc_python_c_sdls_interface
@@ -823,6 +824,38 @@ class TC_FramePrimaryHeader(NamedTuple):
823824
fl: int # Frame Length
824825
fsn: int # Frame Sequence Number
825826

827+
def hex(self):
828+
"""Convert TC frame primary header to hex string.
829+
830+
Header structure (40 bits / 5 bytes):
831+
tfvn(2) | bypass(1) | cc(1) | spare(2) | scid(10) |
832+
vcid(6) | fl(10) | fsn(8)
833+
834+
Returns:
835+
Hex string representation of the header.
836+
"""
837+
# Validation
838+
assert 0 <= self.tfvn <= 3, f"tfvn must be 2 bits (0-3), got {self.tfvn}"
839+
assert 0 <= self.bypass <= 1, f"bypass must be 1 bit (0-1), got {self.bypass}"
840+
assert 0 <= self.cc <= 1, f"cc must be 1 bit (0-1), got {self.cc}"
841+
assert 0 <= self.spare <= 3, f"spare must be 2 bits (0-3), got {self.spare}"
842+
assert 0 <= self.scid <= 1023, f"scid must be 10 bits (0-1023), got {self.scid}"
843+
assert 0 <= self.vcid <= 63, f"vcid must be 6 bits (0-63), got {self.vcid}"
844+
assert 0 <= self.fl <= 1023, f"fl must be 10 bits (0-1023), got {self.fl}"
845+
assert 0 <= self.fsn <= 255, f"fsn must be 8 bits (0-255), got {self.fsn}"
846+
847+
# Build 40-bit header using bit accumulation
848+
val = ((self.tfvn & 0x3) << 38 |
849+
(self.bypass & 0x1) << 37 |
850+
(self.cc & 0x1) << 36 |
851+
(self.spare & 0x3) << 34 |
852+
(self.scid & 0x3FF) << 24 |
853+
(self.vcid & 0x3F) << 18 |
854+
(self.fl & 0x3FF) << 8 |
855+
(self.fsn & 0xFF))
856+
857+
return val.to_bytes(5, 'big').hex()
858+
826859

827860
class AOS_FramePrimaryHeader(NamedTuple):
828861
tfvn: int # Transfer Frame Version Number
@@ -836,61 +869,60 @@ class AOS_FramePrimaryHeader(NamedTuple):
836869
fhec: int # Frame Header Error Control
837870
iz: bytearray
838871

839-
def hex(self):
840-
has_fhec = frame_global_config[f"aos.{self.scid}.{self.vcid}.{self.tfvn}"]["has_fhec"]
841-
has_iz = frame_global_config[f"aos.{self.scid}.{self.vcid}.{self.tfvn}"]["has_iz"]
842-
843-
from bitstring import Bits, BitArray
844-
tfvn_b = Bits(uint=self.tfvn, length=2)
845-
l = 2
846-
scid_b = Bits(uint=self.scid, length=8)
847-
l += 8
848-
vcid_b = Bits(uint=self.vcid, length=6)
849-
l += 6
850-
vcfc_b = Bits(uint=self.vcfc, length=24)
851-
l += 24
852-
replay_b = Bits(uint=self.replay, length=1)
853-
l += 1
854-
vcflag_b = Bits(uint=self.vcflag, length=1)
855-
l += 1
856-
spare_b = Bits(uint=self.spare, length=2)
857-
l += 2
858-
vcfcc_b = Bits(uint=self.vcfcc, length=4)
859-
l += 4
860-
if has_fhec:
861-
l += 16
862-
863-
if has_iz:
864-
l += len(self.iz)
865-
866-
header = BitArray(length=l)
867-
pos = 0
868-
header.overwrite(tfvn_b, pos)
869-
pos += 2
870-
header.overwrite(scid_b, pos)
871-
pos += 8
872-
header.overwrite(vcid_b, pos)
873-
pos += 6
874-
header.overwrite(vcfc_b, pos)
875-
pos += 24
876-
header.overwrite(replay_b, pos)
877-
pos += 1
878-
header.overwrite(vcflag_b, pos)
879-
pos += 1
880-
header.overwrite(spare_b, pos)
881-
pos += 2
882-
header.overwrite(vcfcc_b, pos)
883-
pos += 4
872+
def hex(self, config=None):
873+
"""Convert AOS frame primary header to hex string.
874+
875+
Header structure: tfvn(2) | scid(8) | vcid(6) | vcfc(24) |
876+
replay(1) | vcflag(1) | spare(2) | vcfcc(4)
877+
Optional: fhec(16), insert_zone(variable)
878+
879+
Args:
880+
config: Optional dict with 'has_fhec' and 'has_iz' keys.
881+
If not provided, looks up from frame_global_config.
882+
883+
Returns:
884+
Hex string representation of the header.
885+
"""
886+
# Validation
887+
assert 0 <= self.tfvn <= 3, f"tfvn must be 2 bits (0-3), got {self.tfvn}"
888+
assert 0 <= self.scid <= 255, f"scid must be 8 bits (0-255), got {self.scid}"
889+
assert 0 <= self.vcid <= 63, f"vcid must be 6 bits (0-63), got {self.vcid}"
890+
assert 0 <= self.vcfc <= 16777215, f"vcfc must be 24 bits (0-16777215), got {self.vcfc}"
891+
assert 0 <= self.replay <= 1, f"replay must be 1 bit (0-1), got {self.replay}"
892+
assert 0 <= self.vcflag <= 1, f"vcflag must be 1 bit (0-1), got {self.vcflag}"
893+
assert 0 <= self.spare <= 3, f"spare must be 2 bits (0-3), got {self.spare}"
894+
assert 0 <= self.vcfcc <= 15, f"vcfcc must be 4 bits (0-15), got {self.vcfcc}"
895+
assert 0 <= self.fhec <= 65535, f"fhec must be 16 bits (0-65535), got {self.fhec}"
896+
897+
# Single config lookup with defaults
898+
if config is None:
899+
key = f"aos.{self.scid}.{self.vcid}.{self.tfvn}"
900+
config = frame_global_config.get(key, {"has_fhec": False, "has_iz": False})
901+
902+
has_fhec = config.get("has_fhec", False)
903+
has_iz = config.get("has_iz", False)
904+
905+
# Build 48-bit base header using bit accumulation
906+
val = ((self.tfvn & 0x3) << 46 |
907+
(self.scid & 0xFF) << 38 |
908+
(self.vcid & 0x3F) << 32 |
909+
(self.vcfc & 0xFFFFFF) << 8 |
910+
(self.replay & 0x1) << 7 |
911+
(self.vcflag & 0x1) << 6 |
912+
(self.spare & 0x3) << 4 |
913+
(self.vcfcc & 0xF))
914+
915+
res = bytearray(val.to_bytes(6, 'big'))
916+
917+
# Optional: fhec(16 bits)
884918
if has_fhec:
885-
fhec_b = Bits(uint=self.fhec, length=16)
886-
header.overwrite(fhec_b, pos)
887-
pos += 16
919+
res.extend(struct.pack('>H', self.fhec))
888920

921+
# Optional: insert zone
889922
if has_iz:
890-
iz_b = Bits(self.iz)
891-
header.overwrite(iz_b, pos)
923+
res.extend(self.iz)
892924

893-
return header.h
925+
return res.hex()
894926

895927

896928
class TM_FramePrimaryHeader(NamedTuple):
@@ -907,31 +939,42 @@ class TM_FramePrimaryHeader(NamedTuple):
907939
fhp: int # First Header Pointer
908940

909941
def hex(self):
910-
from bitstring import Bits, BitArray
911-
tfvn_b = Bits(uint=self.tfvn, length=2)
912-
scid_b = Bits(uint=self.scid, length=10)
913-
vcid_b = Bits(uint=self.vcid, length=3)
914-
ocf_f_b = Bits(uint=self.ocf, length=1)
915-
mcfc_b = Bits(uint=self.mcfc, length=8)
916-
vcfc_b = Bits(uint=self.vcfc, length=8)
917-
shf_f_b = Bits(uint=self.shf, length=1)
918-
sync_f_b = Bits(uint=self.sf, length=1)
919-
po_f_b = Bits(uint=self.pof, length=1)
920-
slid_b = Bits(uint=self.slid, length=2)
921-
fhp_b = Bits(uint=self.fhp, length=11)
922-
header = BitArray(length=48)
923-
header.overwrite(tfvn_b, 0)
924-
header.overwrite(scid_b, 2) # 0 + 2
925-
header.overwrite(vcid_b, 12) # 2 + 10
926-
header.overwrite(ocf_f_b, 15) # 12 + 3
927-
header.overwrite(mcfc_b, 16) # 15 + 1
928-
header.overwrite(vcfc_b, 24) # 16 + 8
929-
header.overwrite(shf_f_b, 32) # 24 + 8
930-
header.overwrite(sync_f_b, 33) # 32 + 1
931-
header.overwrite(po_f_b, 34) # 33 + 1
932-
header.overwrite(slid_b, 35) # 34 + 1
933-
header.overwrite(fhp_b, 37) # 35 + 2
934-
return header.h
942+
"""Convert TM frame primary header to hex string.
943+
944+
Header structure (48 bits / 6 bytes):
945+
tfvn(2) | scid(10) | vcid(3) | ocf(1) | mcfc(8) | vcfc(8) |
946+
shf(1) | sf(1) | pof(1) | slid(2) | fhp(11)
947+
948+
Returns:
949+
Hex string representation of the header.
950+
"""
951+
# Validation
952+
assert 0 <= self.tfvn <= 3, f"tfvn must be 2 bits (0-3), got {self.tfvn}"
953+
assert 0 <= self.scid <= 1023, f"scid must be 10 bits (0-1023), got {self.scid}"
954+
assert 0 <= self.vcid <= 7, f"vcid must be 3 bits (0-7), got {self.vcid}"
955+
assert 0 <= self.ocf <= 1, f"ocf must be 1 bit (0-1), got {self.ocf}"
956+
assert 0 <= self.mcfc <= 255, f"mcfc must be 8 bits (0-255), got {self.mcfc}"
957+
assert 0 <= self.vcfc <= 255, f"vcfc must be 8 bits (0-255), got {self.vcfc}"
958+
assert 0 <= self.shf <= 1, f"shf must be 1 bit (0-1), got {self.shf}"
959+
assert 0 <= self.sf <= 1, f"sf must be 1 bit (0-1), got {self.sf}"
960+
assert 0 <= self.pof <= 1, f"pof must be 1 bit (0-1), got {self.pof}"
961+
assert 0 <= self.slid <= 3, f"slid must be 2 bits (0-3), got {self.slid}"
962+
assert 0 <= self.fhp <= 2047, f"fhp must be 11 bits (0-2047), got {self.fhp}"
963+
964+
# Build 48-bit header using bit accumulation
965+
val = ((self.tfvn & 0x3) << 46 |
966+
(self.scid & 0x3FF) << 36 |
967+
(self.vcid & 0x7) << 33 |
968+
(self.ocf & 0x1) << 32 |
969+
(self.mcfc & 0xFF) << 24 |
970+
(self.vcfc & 0xFF) << 16 |
971+
(self.shf & 0x1) << 15 |
972+
(self.sf & 0x1) << 14 |
973+
(self.pof & 0x1) << 13 |
974+
(self.slid & 0x3) << 11 |
975+
(self.fhp & 0x7FF))
976+
977+
return val.to_bytes(6, 'big').hex()
935978

936979

937980
class FrameSecurityHeader(NamedTuple):
@@ -945,29 +988,23 @@ class FrameSecurityHeader(NamedTuple):
945988
pad_field_len: int
946989

947990
def hex(self):
948-
from bitstring import Bits, BitArray
949-
length = 16 + (self.iv_field_len * 8) + (self.sn_field_len * 8) + (self.pad_field_len * 8)
950-
spi_b = Bits(uint=self.spi, length=16)
951-
iv_b = Bits(self.iv)
952-
sn_b = Bits(self.sn)
953-
pad_b = Bits(self.pad)
954-
idx = 0
955-
header = BitArray(length=length)
956-
header.overwrite(spi_b, idx)
957-
idx += 16
958-
if self.iv_field_len > 0:
959-
header.overwrite(iv_b, idx)
960-
idx += (self.iv_field_len * 8)
991+
"""Convert frame security header to hex string.
961992
962-
if self.sn_field_len > 0:
963-
header.overwrite(sn_b, idx)
964-
idx += (self.sn_field_len * 8)
993+
Returns:
994+
Hex string representation of the security header.
995+
"""
996+
# Validation
997+
assert 0 <= self.spi <= 65535, f"spi must be 16 bits (0-65535), got {self.spi}"
965998

999+
res = bytearray()
1000+
res.extend(struct.pack('>H', self.spi))
1001+
if self.iv_field_len > 0:
1002+
res.extend(self.iv)
1003+
if self.sn_field_len > 0:
1004+
res.extend(self.sn)
9661005
if self.pad_field_len > 0:
967-
header.overwrite(pad_b, idx)
968-
idx += (self.pad_field_len * 8)
969-
970-
return header.h
1006+
res.extend(self.pad)
1007+
return res.hex()
9711008

9721009

9731010
class FrameSecurityTrailer(NamedTuple):
@@ -978,24 +1015,21 @@ class FrameSecurityTrailer(NamedTuple):
9781015
fecf: int # Frame Error Control Field
9791016

9801017
def hex(self):
981-
from bitstring import Bits, BitArray
982-
mac_b = Bits(self.mac)
983-
ocf_b = Bits(self.ocf)
984-
fecf_b = Bits(uint=self.fecf, length=16)
985-
986-
length = 16 + (self.mac_field_len * 8) + (self.ocf_field_len * 8)
987-
idx = 0
988-
header = BitArray(length=length)
989-
if self.mac_field_len > 0:
990-
header.overwrite(mac_b, idx)
991-
idx += (self.mac_field_len * 8)
1018+
"""Convert frame security trailer to hex string.
9921019
993-
if self.ocf_field_len > 0:
994-
header.overwrite(ocf_b, idx)
995-
idx += (self.ocf_field_len * 8)
1020+
Returns:
1021+
Hex string representation of the security trailer.
1022+
"""
1023+
# Validation
1024+
assert 0 <= self.fecf <= 65535, f"fecf must be 16 bits (0-65535), got {self.fecf}"
9961025

997-
header.overwrite(fecf_b, idx)
998-
return header.h
1026+
res = bytearray()
1027+
if self.mac_field_len > 0:
1028+
res.extend(self.mac)
1029+
if self.ocf_field_len > 0:
1030+
res.extend(self.ocf)
1031+
res.extend(struct.pack('>H', self.fecf))
1032+
return res.hex()
9991033

10001034

10011035
class TC(NamedTuple):

0 commit comments

Comments
 (0)