Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import datetime
- import typing
- import sys
- # This table class is used to represent the CSV data
- # You can easily append/set fields in columns or rows with the data automatically being formatted
- class Table:
- def __init__(self):
- self.fields = {}
- pass
- @staticmethod
- def __set_capacity(_list: [], _elements: int):
- if (length := len(_list)) < _elements:
- _list.extend([""] * (_elements - length))
- def set_fields(self, _values: []):
- for value in _values:
- self.fields[value] = []
- def set(self, _index, _field, _value): # This could be changed to __setitem__
- self.__set_capacity(self.fields[_field], _index + 1)
- self.fields[_field][_index] = _value
- def insert(self, _index, _field, _value):
- for field in self.fields:
- if field == _field:
- self.fields[field].insert(_index, _value)
- else:
- self.fields[field].insert(_index, "")
- def get_rows(self):
- longestColumn = 0
- for field in self.fields:
- if (length := len(self.fields[field])) > longestColumn:
- longestColumn = length
- return longestColumn
- def append(self, _field, _value):
- self.fields[_field].append(_value)
- def to_csv(self):
- output = bytearray()
- toWrite = []
- def __append(_value):
- output.extend(_value.encode("ascii"))
- for field in self.fields:
- __append(field)
- toWrite.append(self.fields[field])
- __append(",")
- output.pop()
- __append("\n")
- longestColumn = 0
- for field in self.fields:
- length = len(self.fields[field])
- if length > longestColumn:
- longestColumn = length
- for index in range(longestColumn):
- for column in toWrite:
- self.__set_capacity(column, longestColumn)
- __append(column[index])
- __append(',')
- output.pop()
- __append('\n')
- return output
- # To prevent leading zeros from the bitmask being removed by Python
- class Bitmask:
- def __init__(self, _data: int, _bits: int):
- self.bits = _bits
- self.data = bin(_data)[2:]
- self.data = ('0' * (_bits - len(self.data))) + self.data
- def __getitem__(self, _index):
- return self.data[_index] == '1'
- # A dictionary with a set size of non-mutable keys to ensure telemetry frame parameter names can reliably be
- # referenced, i.e., a typo of a parameter name will throw an error rather than silently adding a new element
- class FixedDict:
- # Todo: Add typing.Literal type hinting to _v
- def __init__(self, _v):
- self.data = {}
- self._literals = _v
- self._literalValues = typing.get_args(self._literals)
- for literal in self._literalValues:
- self.data[literal] = None
- def __setitem__(self, _key, _value):
- if _key in self._literalValues:
- self.data[_key] = _value
- else:
- raise Exception(f"Key '{_key}' does not exist")
- def __getitem__(self, _key):
- if _key in self._literalValues:
- return self.data[_key]
- else:
- raise Exception(f"Key '{_key}' does not exist")
- def __len__(self):
- return len(self.data)
- def __iter__(self):
- values = []
- for index, value in enumerate(self.data):
- values += [(value, self.data[value])]
- return iter(values)
- # Check if a bit is set from the MSB given an index
- # E.g., is_set(0b0100, 1) == True
- # This is mostly redundant due to Python's variable width integers
- def is_set(_value=0x00, _bit=0):
- if _value == 0: # Zero has a bit length of 0 - This would cause a negative bit shift amount
- return False
- return (_value & (1 << (int.bit_length(_value) - 1)) >> _bit) != 0
- # I stole this from StackOverflow
- # https://stackoverflow.com/questions/32675679/convert-binary-string-to-bytearray-in-python-3
- def bitstring_to_bytes(s):
- if s != '':
- return int(s, 2).to_bytes((len(s) + 7) // 8, byteorder="big")
- else:
- return bytearray(0)
- def remove_bits_from_left_preserving_sign(number, n_bits):
- # Remember the original sign
- sign = -1 if number < 0 else 1
- # Work with the absolute value
- abs_number = abs(number)
- total_bits = abs_number.bit_length()
- bits_to_keep = total_bits - n_bits
- # Ensure that we are not trying to remove more bits than the number has
- if bits_to_keep <= 0:
- return 0
- # Create a mask to keep the rightmost bits_to_keep bits
- mask = (1 << bits_to_keep) - 1
- # Apply the mask and reapply the original sign
- return (abs_number & mask) * sign
- # Return byte array as an integer _width measured in bytes If _width = 0 then automatic width
- # Fixme: The method of discarding bits feels like bit of a hack... This works but there may be better methods
- def as_int(_bytes: bytearray, _width=0, _endian: typing.Literal["little", "big"] = "big", _l_discard=0, _r_discard=0, _signed=False):
- value: int
- if _width == 0:
- value = int.from_bytes(_bytes, _endian, signed=_signed)
- else:
- value = int.from_bytes(_bytes[:_width], _endian, signed=_signed)
- value = remove_bits_from_left_preserving_sign(value, _l_discard)
- value = value >> _r_discard
- return value
- def as_date_str(_t):
- if _t == 0: # When you intentionally want it blank (hopefully nobody refers to this specific date)
- return ""
- try:
- return datetime.datetime.utcfromtimestamp(_t).strftime("%Y-%m-%d@%H:%M.%S")
- except OSError:
- return "INVALID EPOCH"
- # Used for issues with the log file, issues which cannot be resolved by the user raise an exception
- def error_exit(_message: str):
- print(_message, file=sys.stderr)
- exit(1)
Advertisement
Add Comment
Please, Sign In to add comment