From 71ab73a3f8ccf64bf9d0cb0039899e83a19dfe0a Mon Sep 17 00:00:00 2001 From: Ben Nicholson Date: Wed, 17 Jun 2026 18:33:02 +1000 Subject: [PATCH] revert 3e88e25a879e4904f15a9ca04c90ea9a09368150 revert Update PTPLogger/PTPLogger.sh --- PTPLogger/PTPLogger.sh | 212 +++++++++++------------------------------ 1 file changed, 55 insertions(+), 157 deletions(-) diff --git a/PTPLogger/PTPLogger.sh b/PTPLogger/PTPLogger.sh index d1e9636..000e8f9 100644 --- a/PTPLogger/PTPLogger.sh +++ b/PTPLogger/PTPLogger.sh @@ -1,175 +1,73 @@ -import re -import datetime as dt -import matplotlib.pyplot as plt -import matplotlib.dates as mdates -from matplotlib.lines import Line2D +#!/bin/bash -import tkinter as tk -from tkinter import filedialog, messagebox, scrolledtext +#### Tested running on a 1232 +SOCK="/var/run/ptp4l_media1" +HOST=$(hostname) +LOGFILE="ptp_media1.log" +WINDOW=60 -def parse_log(file_path): - t, rms, freq = [], [], [] - state_events = [] - master_events = [] +offsets=() +delays=() +freqs=() - last_timestamp = None +prev_offset="" +prev_time="" - with open(file_path, encoding='utf-8', errors='ignore') as f: - for line in f: +while true; do + now_fmt=$(date +"%b %d %T") + uptime=$(awk '{print $1}' /proc/uptime) + now_ns=$(date +%s%N) - ts_match = re.match(r'^(\w+ \d+ \d+:\d+:\d+)', line) - if ts_match: - try: - timestr = ts_match.group(1) + " 2026" - last_timestamp = dt.datetime.strptime(timestr, "%b %d %H:%M:%S %Y") - except: - pass + # --- get offset --- + ts_np=$(pmc -u -s $SOCK "GET TIME_STATUS_NP") + offset=$(echo "$ts_np" | awk '/master_offset/ {print $2}') - timestamp = last_timestamp + # --- get delay --- + cds=$(pmc -u -s $SOCK "GET CURRENT_DATA_SET") + delay=$(echo "$cds" | awk '/meanPathDelay/ {print $2}') - if not timestamp: - continue + # --- compute freq (ns/sec ≈ ppb-like behaviour) --- + if [[ -n "$prev_offset" ]]; then + dt=$((now_ns - prev_time)) + doffset=$((offset - prev_offset)) + freq=$(awk -v d="$doffset" -v t="$dt" 'BEGIN {printf "%.0f", (d / t) * 1e9}') + else + freq=0 + fi - m = re.search(r'rms\s+(\d+).*freq\s+([+-]?\d+)', line) - if m: - t.append(timestamp) - rms.append(int(m.group(1))) - freq.append(int(m.group(2))) + prev_offset=$offset + prev_time=$now_ns - m = re.search(r'port \d+: (\w+) to (\w+)', line) - if m: - state_events.append((timestamp, f"{m.group(1)}→{m.group(2)}")) + # store + offsets+=("$offset") + delays+=("$delay") + freqs+=("$freq") - m = re.search( - r'(selected best master clock|new foreign master)\s+([0-9a-fA-F\.:]+)', - line - ) - if m: - master_events.append((timestamp, m.group(2))) + # trim window + if [ ${#offsets[@]} -gt $WINDOW ]; then + offsets=("${offsets[@]:1}") + delays=("${delays[@]:1}") + freqs=("${freqs[@]:1}") + fi - return t, rms, freq, state_events, master_events + # --- stats --- + rms=$(printf "%s\n" "${offsets[@]}" | awk '{s+=$1*$1} END {printf "%.0f", sqrt(s/NR)}') + max=$(printf "%s\n" "${offsets[@]}" | \ + awk 'BEGIN{m=0}{if($1>m)m=$1;if(-$1>m)m=-$1}END{print m}') -def plot_data(t, rms, freq, state_events, master_events, detail): + freq_avg=$(printf "%s\n" "${freqs[@]}" | awk '{s+=$1} END {printf "%.0f", s/NR}') + freq_std=$(printf "%s\n" "${freqs[@]}" | \ + awk '{s+=$1; ss+=$1*$1} END {m=s/NR; printf "%.0f", sqrt(ss/NR - m*m)}') - if not t: - messagebox.showerror("Error", "No valid RMS/freq data found.") - return + delay_avg=$(printf "%s\n" "${delays[@]}" | awk '{s+=$1} END {printf "%.0f", s/NR}') + delay_std=$(printf "%s\n" "${delays[@]}" | \ + awk '{s+=$1; ss+=$1*$1} END {m=s/NR; printf "%.0f", sqrt(ss/NR - m*m)}') - fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True) + line="$now_fmt $HOST ptp4l@media1[$$]: [$uptime] rms $rms max $max freq $freq_avg +/- $freq_std delay $delay_avg +/- $delay_std" - ax1.plot(t, rms, color='black') - ax1.set_ylabel("RMS (ns)") - ax1.grid() + echo "$line" | tee -a "$LOGFILE" - ax2.plot(t, freq, color='black') - ax2.set_ylabel("Frequency deviation") - ax2.set_xlabel("Time") - ax2.grid() - - # event lines - for ts, _ in state_events: - ax1.axvline(ts, color='blue', linestyle='--', alpha=0.7) - ax2.axvline(ts, color='blue', linestyle='--', alpha=0.7) - - for ts, _ in master_events: - ax1.axvline(ts, color='red', linestyle='--', alpha=0.7) - ax2.axvline(ts, color='red', linestyle='--', alpha=0.7) - - legend = [ - Line2D([0], [0], color='black', label='RMS/Freq'), - Line2D([0], [0], color='blue', linestyle='--', label='State'), - Line2D([0], [0], color='red', linestyle='--', label='Master'), - ] - ax1.legend(handles=legend) - - multi_day = any(d.date() != t[0].date() for d in t) - - if multi_day: - formatter = mdates.DateFormatter('%d %H:%M') - else: - formatter = mdates.DateFormatter('%H:%M:%S') - - if detail == "Seconds": - locator = mdates.SecondLocator(interval=1) - elif detail == "5 sec": - locator = mdates.SecondLocator(interval=5) - elif detail == "10 sec": - locator = mdates.SecondLocator(interval=10) - elif detail == "30 sec": - locator = mdates.SecondLocator(interval=30) - elif detail == "1 min": - locator = mdates.MinuteLocator(interval=1) - else: - locator = mdates.AutoDateLocator(maxticks=20) - - ax2.xaxis.set_major_locator(locator) - ax2.xaxis.set_major_formatter(formatter) - - plt.xticks(rotation=45) - plt.tight_layout() - plt.show() - - -def open_file(): - file_path = filedialog.askopenfilename( - title="Select log", - filetypes=[("Log files", "*.log *.txt"), ("All files", "*.*")] - ) - - if not file_path: - return - - detail = detail_var.get() - - t, rms, freq, state_events, master_events = parse_log(file_path) - - plot_data(t, rms, freq, state_events, master_events, detail) - - event_box.delete(1.0, tk.END) - - events = [] - - for ts, label in state_events: - events.append((ts, f"{ts} | STATE {label}")) - - for ts, label in master_events: - events.append((ts, f"{ts} | MASTER {label}")) - - events.sort(key=lambda x: x[0]) - - if events: - for _, line in events: - event_box.insert(tk.END, line + "\n") - else: - event_box.insert(tk.END, "No events found.\n") - - -# GUI -root = tk.Tk() -root.title("PTP Log Viewer") -root.geometry("750x550") - -frame = tk.Frame(root) -frame.pack(pady=5) - -tk.Button(frame, text="Open Log", command=open_file).pack(side=tk.LEFT, padx=10) - -detail_var = tk.StringVar(value="Auto") - -tk.OptionMenu( - frame, - detail_var, - "Auto", - "Seconds", - "5 sec", - "10 sec", - "30 sec", - "1 min" -).pack(side=tk.LEFT) - -event_box = scrolledtext.ScrolledText(root) -event_box.pack(fill=tk.BOTH, expand=True) - -root.mainloop() \ No newline at end of file + sleep 1 +done \ No newline at end of file