183 lines
6.6 KiB
Python
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
|
|
|
|
|