flexPTP-test/FlexPtpController.py
2026-05-07 10:42:36 +02:00

183 lines
6.6 KiB
Python

import os
import queue
import re
import time
from typing import Callable
from DeviceInterface import DeviceInterface
class FlexPtpEvent:
def __init__(self, name: str, args: dict) -> None:
self.__name = name
self.__args = args
def get_name(self) -> str:
return self.__name
def get_args(self) -> dict:
return self.__args
class FlexPtpController:
def __log_processor(self, data: str, spec_event: str) -> None:
if spec_event == "exit":
event = FlexPtpEvent("exit", {})
self.__event_queue.put(event)
return
# -------
stripped_data = data.strip()
line = stripped_data # strip accidental whitespaces from the start and the end of the line
match = re.search(r"^\[LOG-([A-Z:]+)\]", line) # serach for the LOGID
if match is not None and len(match.groups()) == 1: # check if LOGID was present
log_id = match.group(1) # extract LOGID
rest = line[len(match.group(0)):].strip()
if log_id == "BMCA": # BMCA event has occurred
match = re.match(r"([A-Z_]+) -> ([A-Z_]+)", rest)
if match is not None and len(match.groups()) == 2:
event = FlexPtpEvent("bmca-statechange", { "from": match.group(1), "to": match.group(2) })
self.__event_queue.put(event)
elif log_id == "DEF:S:A" or log_id == "DEF:S:H": # DEFAULT SLAVE log event has occurred
if_type = log_id[-1]
if if_type == "H": # HLT interface columns
cn = 10
else: # Addend interface columns
cn = 11
match = re.match(r"^" + r"([-.0-9]+)[ ]+" * (cn - 1) + r"([-.0-9]+)", rest)
if match is not None and len(match.groups()) == cn:
args = {
"T1": float(match.group(1) + "." + match.group(2)),
"T4": float(match.group(3) + "." + match.group(4)),
"Dt": int(match.group(5)) * 1000000000 + int(match.group(6)),
"corr_ppb": float(match.group(cn - 2)),
"mpd_ns": int(match.group(cn - 1)),
"sync_period_ns": int(match.group(cn))
}
self.__event_queue.put(FlexPtpEvent("synclog-slave", args=args))
elif log_id == "DEF:M:M": # DEFAULT master : mean path delay log event has occurred
self.__event_queue.put(FlexPtpEvent("mpd-master", { "mpd_ns": int(rest) }))
elif log_id == "DEF:M:S": # DEFAULT master : P2P slave state change log event has occurred
match = re.match(r"([A-Z_]+) -> ([A-Z_]+)", rest)
if match is not None and len(match.groups()) == 2:
event = FlexPtpEvent("p2p-slave-statechange", { "from": match.group(1), "to": match.group(2) })
self.__event_queue.put(event)
else:
# unhandled event
pass
if self.__log_cb is not None:
self.__log_cb(stripped_data + "\n")
def __init__(self, di: DeviceInterface) -> None:
self.__di = di
self.__di.register_out_callback(self.__log_processor)
self.__log_cb: Callable | None = None
self.__event_queue = queue.Queue()
pass
def reset_flexptp(self) -> None:
self.__di.execute_command("ptp reset")
def start_e2e_udp(self) -> None:
self.__di.execute_command("ptp profile preset default")
def start_p2p_udp(self) -> None:
self.__di.execute_command("ptp profile preset defp2p")
def start_e2e_l2(self) -> None:
self.__di.execute_command("ptp profile preset default")
self.__di.execute_command("ptp transport 802.3")
self.reset_flexptp()
def start_p2p_l2(self) -> None:
self.__di.execute_command("ptp profile preset defp2p")
self.__di.execute_command("ptp transport 802.3")
self.reset_flexptp()
def start_gPTP(self) -> None:
self.__di.execute_command("ptp profile preset gPTP")
def start_by_id(self, id: str) -> None:
id = id.replace("_", "").upper()
if id == "E2EL4":
self.start_e2e_udp()
elif id == "E2EL2":
self.start_e2e_l2()
elif id == "P2PL4":
self.start_p2p_udp()
elif id == "P2PL2":
self.start_p2p_l2()
elif id == "GPTP":
self.start_gPTP()
def set_priority(self, priority1: int, priority2: int) -> None:
self.__di.execute_command("ptp priority {:d} {:d}".format(priority1, priority2))
def set_domain(self, domain: int) -> None:
self.__di.execute_command("ptp domain {:d}".format(domain))
def disable_all_logging(self) -> None:
logging_types = [ "def", "corr", "ts", "info", "locked", "bmca", "logid" ]
for lt in logging_types:
self.__di.execute_command("ptp log " + lt + " off", expect_results=False)
def enable_log(self, id: str, en: bool) -> None:
if en:
onoff = "on"
else:
onoff = "off"
self.__di.execute_command("ptp log {:s} {:s}".format(id, onoff), expect_results=False)
def set_servo_offset(self, offset: int) -> None:
self.__di.execute_command("ptp servo offset {:d}".format(offset))
def register_log_callback(self, cb: Callable | None) -> None:
self.__log_cb = cb
def get_event(self, timeout: float) -> FlexPtpEvent:
try:
return self.__event_queue.get(timeout=timeout)
except:
return FlexPtpEvent("none", {})
def wait_for_event(self, expected_name: str, timeout: float, argcrits = {}) -> FlexPtpEvent:
timeout_left = timeout
start = time.time_ns()
event = FlexPtpEvent("none", {})
critera_met = False
while (event.get_name() != expected_name or not critera_met) and timeout_left > 0:
try:
event = self.__event_queue.get(timeout=timeout_left) # type: FlexPtpEvent
# propagate exit event
if event.get_name() == "exit":
return event
critera_met = True
for c_name, c_value in argcrits.items():
args = event.get_args()
if c_name in args:
if args[c_name] != c_value:
critera_met = False
break
except:
pass
now = time.time_ns()
timeout_left = timeout - ((now - start) / 1E+09)
return event