hitl_tester.modules.cyber_6t.gpio
Controls the USB GPIO
(c) 2020-2024 TurnAround Factor, Inc.
#
CUI DISTRIBUTION CONTROL
Controlled by: DLA J68 R&D SBIP
CUI Category: Small Business Research and Technology
Distribution/Dissemination Controls: PROTECTED BY SBIR DATA RIGHTS
POC: GOV SBIP Program Manager Denise Price, 571-767-0111
Distribution authorized to U.S. Government Agencies only, to protect information not owned by the
U.S. Government and protected by a contractor’s ‘limited rights’ statement, or received with the understanding that
it is not routinely transmitted outside the U.S. Government (determination made September 14, 2024). Other requests
for this document shall be referred to ACOR DLA Logistics Operations (J-68), 8725 John J. Kingman Rd., Suite 4317,
Fort Belvoir, VA 22060-6221
#
SBIR DATA RIGHTS
Contract No.:SP4701-23-C-0083
Contractor Name: TurnAround Factor, Inc.
Contractor Address: 10365 Wood Park Ct. Suite 313 / Ashland, VA 23005
Expiration of SBIR Data Rights Period: September 24, 2029
The Government's rights to use, modify, reproduce, release, perform, display, or disclose technical data or computer
software marked with this legend are restricted during the period shown as provided in paragraph (b)(4) of the Rights
in Noncommercial Technical Data and Computer Software--Small Business Innovative Research (SBIR) Program clause
contained in the above identified contract. No restrictions apply after the expiration date shown above. Any
reproduction of technical data, computer software, or portions thereof marked with this legend must also reproduce
the markings.
1""" 2Controls the USB GPIO 3 4# (c) 2020-2024 TurnAround Factor, Inc. 5# 6# CUI DISTRIBUTION CONTROL 7# Controlled by: DLA J68 R&D SBIP 8# CUI Category: Small Business Research and Technology 9# Distribution/Dissemination Controls: PROTECTED BY SBIR DATA RIGHTS 10# POC: GOV SBIP Program Manager Denise Price, 571-767-0111 11# Distribution authorized to U.S. Government Agencies only, to protect information not owned by the 12# U.S. Government and protected by a contractor’s ‘limited rights’ statement, or received with the understanding that 13# it is not routinely transmitted outside the U.S. Government (determination made September 14, 2024). Other requests 14# for this document shall be referred to ACOR DLA Logistics Operations (J-68), 8725 John J. Kingman Rd., Suite 4317, 15# Fort Belvoir, VA 22060-6221 16# 17# SBIR DATA RIGHTS 18# Contract No.:SP4701-23-C-0083 19# Contractor Name: TurnAround Factor, Inc. 20# Contractor Address: 10365 Wood Park Ct. Suite 313 / Ashland, VA 23005 21# Expiration of SBIR Data Rights Period: September 24, 2029 22# The Government's rights to use, modify, reproduce, release, perform, display, or disclose technical data or computer 23# software marked with this legend are restricted during the period shown as provided in paragraph (b)(4) of the Rights 24# in Noncommercial Technical Data and Computer Software--Small Business Innovative Research (SBIR) Program clause 25# contained in the above identified contract. No restrictions apply after the expiration date shown above. Any 26# reproduction of technical data, computer software, or portions thereof marked with this legend must also reproduce 27# the markings. 28""" 29 30import atexit 31from dataclasses import dataclass 32from enum import IntEnum 33 34import serial 35from serial import SerialException 36 37from hitl_tester.modules.logger import logger 38 39 40class NoDataException(Exception): 41 """Exception raised when no data is received""" 42 43 def __init__(self): 44 super().__init__("No data received") 45 46 47class Baud(IntEnum): 48 """The 6T baud rate in kb/s.""" 49 50 RATE_1000 = 0 51 RATE_500 = 1 52 RATE_250 = 2 53 RATE_250_LIMITED = 3 54 55 56@dataclass 57class Pinout6T: 58 """Represents teh 6T pinout.""" 59 60 dormant_1: bool = True 61 dormant_2: bool = True 62 reset: bool = True 63 baud_rate: Baud = Baud.RATE_250_LIMITED 64 position_id: int = 0xF # ID 254 (NULL address) 65 66 def __int__(self) -> int: 67 return ( 68 (self.position_id & 0xF) << 5 69 | (self.baud_rate & 0x3) << 3 70 | self.reset << 2 71 | self.dormant_2 << 1 72 | self.dormant_1 73 ) 74 75 76class GPIOController: 77 """GPIO controller""" 78 79 battery_1 = Pinout6T() 80 battery_2 = Pinout6T() 81 battery_3 = Pinout6T() 82 83 @staticmethod 84 def get_index(num: int) -> str: 85 """Gets correct index""" 86 if num < 10: 87 return str(num) 88 return chr(55 + num) 89 90 @staticmethod 91 def on(num: int): 92 """Turn GPIO on""" 93 GPIOController.call(f"gpio set {GPIOController.get_index(num)}") 94 95 @staticmethod 96 def off(num: int): 97 """Turn GPIO off""" 98 GPIOController.call(f"gpio clear {GPIOController.get_index(num)}") 99 100 @staticmethod 101 def status() -> str: 102 """Shows GPIO status""" 103 return GPIOController.call("gpio readall") 104 105 @staticmethod 106 def call(cmd: str) -> str: 107 """Talk to GPIO""" 108 response = None 109 try: 110 # 9600,8,N,1 111 with serial.Serial("/dev/taf-gpio", timeout=1) as ser: 112 ser.write(bytes(cmd + "\r", "utf-8")) 113 response = ser.read(25) 114 if not response: 115 raise NoDataException 116 response = response[len(cmd) : -1] 117 if not response: 118 raise NoDataException 119 response = response.decode().strip("\n\r") 120 except (TimeoutError, NoDataException) as ex: 121 logger.write_debug_to_report(ex) 122 except (FileNotFoundError, SerialException): 123 pass 124 return response or "" 125 126 @classmethod 127 def reset(cls): 128 """Reset GPIO to floating.""" 129 cls.call("gpio writeall 00000000") 130 cls.call("gpio iodir ffffffff") 131 132 @classmethod 133 def set_battery_state(cls): 134 """Set the battery pins according to the pinouts for battery 1, 2, 3.""" 135 cls.call("gpio writeall 00000000") 136 cls.call(f"gpio iodir {int(cls.battery_3) << 18 | int(cls.battery_2) << 9 | int(cls.battery_1):08x}") 137 138 139@atexit.register 140def __atexit__(): 141 """Float all pins when shutting down.""" 142 logger.write_debug_to_report("Shutting down GPIO.") 143 GPIOController.battery_1 = Pinout6T() 144 GPIOController.battery_2 = Pinout6T() 145 GPIOController.battery_3 = Pinout6T() 146 GPIOController.set_battery_state() 147 148 149if __name__ == "__main__": 150 logger.write_debug_to_report("Power cycling...") 151 GPIOController.reset() 152 logger.write_debug_to_report(f"Status: {GPIOController.status()}")
class
NoDataException(builtins.Exception):
41class NoDataException(Exception): 42 """Exception raised when no data is received""" 43 44 def __init__(self): 45 super().__init__("No data received")
Exception raised when no data is received
Inherited Members
- builtins.BaseException
- with_traceback
- add_note
- args
class
Baud(enum.IntEnum):
48class Baud(IntEnum): 49 """The 6T baud rate in kb/s.""" 50 51 RATE_1000 = 0 52 RATE_500 = 1 53 RATE_250 = 2 54 RATE_250_LIMITED = 3
The 6T baud rate in kb/s.
RATE_1000 =
<Baud.RATE_1000: 0>
RATE_500 =
<Baud.RATE_500: 1>
RATE_250 =
<Baud.RATE_250: 2>
RATE_250_LIMITED =
<Baud.RATE_250_LIMITED: 3>
Inherited Members
- enum.Enum
- name
- value
- builtins.int
- conjugate
- bit_length
- bit_count
- to_bytes
- from_bytes
- as_integer_ratio
- is_integer
- real
- imag
- numerator
- denominator
@dataclass
class
Pinout6T:
57@dataclass 58class Pinout6T: 59 """Represents teh 6T pinout.""" 60 61 dormant_1: bool = True 62 dormant_2: bool = True 63 reset: bool = True 64 baud_rate: Baud = Baud.RATE_250_LIMITED 65 position_id: int = 0xF # ID 254 (NULL address) 66 67 def __int__(self) -> int: 68 return ( 69 (self.position_id & 0xF) << 5 70 | (self.baud_rate & 0x3) << 3 71 | self.reset << 2 72 | self.dormant_2 << 1 73 | self.dormant_1 74 )
Represents teh 6T pinout.
Pinout6T( dormant_1: bool = True, dormant_2: bool = True, reset: bool = True, baud_rate: Baud = <Baud.RATE_250_LIMITED: 3>, position_id: int = 15)
class
GPIOController:
77class GPIOController: 78 """GPIO controller""" 79 80 battery_1 = Pinout6T() 81 battery_2 = Pinout6T() 82 battery_3 = Pinout6T() 83 84 @staticmethod 85 def get_index(num: int) -> str: 86 """Gets correct index""" 87 if num < 10: 88 return str(num) 89 return chr(55 + num) 90 91 @staticmethod 92 def on(num: int): 93 """Turn GPIO on""" 94 GPIOController.call(f"gpio set {GPIOController.get_index(num)}") 95 96 @staticmethod 97 def off(num: int): 98 """Turn GPIO off""" 99 GPIOController.call(f"gpio clear {GPIOController.get_index(num)}") 100 101 @staticmethod 102 def status() -> str: 103 """Shows GPIO status""" 104 return GPIOController.call("gpio readall") 105 106 @staticmethod 107 def call(cmd: str) -> str: 108 """Talk to GPIO""" 109 response = None 110 try: 111 # 9600,8,N,1 112 with serial.Serial("/dev/taf-gpio", timeout=1) as ser: 113 ser.write(bytes(cmd + "\r", "utf-8")) 114 response = ser.read(25) 115 if not response: 116 raise NoDataException 117 response = response[len(cmd) : -1] 118 if not response: 119 raise NoDataException 120 response = response.decode().strip("\n\r") 121 except (TimeoutError, NoDataException) as ex: 122 logger.write_debug_to_report(ex) 123 except (FileNotFoundError, SerialException): 124 pass 125 return response or "" 126 127 @classmethod 128 def reset(cls): 129 """Reset GPIO to floating.""" 130 cls.call("gpio writeall 00000000") 131 cls.call("gpio iodir ffffffff") 132 133 @classmethod 134 def set_battery_state(cls): 135 """Set the battery pins according to the pinouts for battery 1, 2, 3.""" 136 cls.call("gpio writeall 00000000") 137 cls.call(f"gpio iodir {int(cls.battery_3) << 18 | int(cls.battery_2) << 9 | int(cls.battery_1):08x}")
GPIO controller
battery_1 =
Pinout6T(dormant_1=True, dormant_2=True, reset=True, baud_rate=<Baud.RATE_250_LIMITED: 3>, position_id=15)
battery_2 =
Pinout6T(dormant_1=True, dormant_2=True, reset=True, baud_rate=<Baud.RATE_250_LIMITED: 3>, position_id=15)
battery_3 =
Pinout6T(dormant_1=True, dormant_2=True, reset=True, baud_rate=<Baud.RATE_250_LIMITED: 3>, position_id=15)
@staticmethod
def
get_index(num: int) -> str:
84 @staticmethod 85 def get_index(num: int) -> str: 86 """Gets correct index""" 87 if num < 10: 88 return str(num) 89 return chr(55 + num)
Gets correct index
@staticmethod
def
on(num: int):
91 @staticmethod 92 def on(num: int): 93 """Turn GPIO on""" 94 GPIOController.call(f"gpio set {GPIOController.get_index(num)}")
Turn GPIO on
@staticmethod
def
off(num: int):
96 @staticmethod 97 def off(num: int): 98 """Turn GPIO off""" 99 GPIOController.call(f"gpio clear {GPIOController.get_index(num)}")
Turn GPIO off
@staticmethod
def
status() -> str:
101 @staticmethod 102 def status() -> str: 103 """Shows GPIO status""" 104 return GPIOController.call("gpio readall")
Shows GPIO status
@staticmethod
def
call(cmd: str) -> str:
106 @staticmethod 107 def call(cmd: str) -> str: 108 """Talk to GPIO""" 109 response = None 110 try: 111 # 9600,8,N,1 112 with serial.Serial("/dev/taf-gpio", timeout=1) as ser: 113 ser.write(bytes(cmd + "\r", "utf-8")) 114 response = ser.read(25) 115 if not response: 116 raise NoDataException 117 response = response[len(cmd) : -1] 118 if not response: 119 raise NoDataException 120 response = response.decode().strip("\n\r") 121 except (TimeoutError, NoDataException) as ex: 122 logger.write_debug_to_report(ex) 123 except (FileNotFoundError, SerialException): 124 pass 125 return response or ""
Talk to GPIO
@classmethod
def
reset(cls):
127 @classmethod 128 def reset(cls): 129 """Reset GPIO to floating.""" 130 cls.call("gpio writeall 00000000") 131 cls.call("gpio iodir ffffffff")
Reset GPIO to floating.
@classmethod
def
set_battery_state(cls):
133 @classmethod 134 def set_battery_state(cls): 135 """Set the battery pins according to the pinouts for battery 1, 2, 3.""" 136 cls.call("gpio writeall 00000000") 137 cls.call(f"gpio iodir {int(cls.battery_3) << 18 | int(cls.battery_2) << 9 | int(cls.battery_1):08x}")
Set the battery pins according to the pinouts for battery 1, 2, 3.