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