Step 6.3: PTP hybrid mode (unicast Delay_Req/Resp), step 6 done

- As TimeReceiver in ptp.mode hybrid: Delay_Req unicast to the GM (IP
  from its Announce, MAC recorded by the RX hook from its Sync frames),
  unicastFlag set.
- As TimeTransmitter: a Delay_Req with the unicastFlag gets a unicast
  Delay_Resp; multicast requests get multicast replies.
- EMAC timestamps every received frame (en_ts4all): its PTP filter left
  unicast Delay_Req unstamped ("no HW RX timestamp").
- A unicast Delay_Resp's logMessageInterval 0x7F is ignored (use
  ptp.log_delay_req); log_us() clamps to -7..6 (the shift was undefined).
- Verified vs ptp4l --hybrid_e2e 1: board hybrid TimeReceiver 18
  Delay_Req in 20 s, all answered, locked; board TimeTransmitter
  (p1 100): tcpdump shows Sync/Follow_Up/Announce to 224.0.1.129,
  Delay_Req 192.168.192.233 -> .244 [unicast] and Delay_Resp .244 ->
  .233 [unicast] within 0.4 ms; ptp4l s2.
- Docs: TimeTransmitter/hybrid notes; step 6 ticked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-25 08:21:09 +10:00
parent dcea39b216
commit 5bd1a20e43
5 changed files with 67 additions and 13 deletions
+14
View File
@@ -18,6 +18,7 @@ typedef struct {
uint8_t type;
uint16_t seq;
uint8_t port_id[10];
uint8_t mac[6]; // Ethernet source
eth_mac_time_t ts;
} rx_rec_t;
@@ -48,6 +49,7 @@ static esp_err_t rx_hook(esp_eth_handle_t eth, uint8_t *buf, uint32_t len, void
r->type = ptp[0] & 0x0f;
r->seq = (ptp[30] << 8) | ptp[31];
memcpy(r->port_id, ptp + 20, 10);
memcpy(r->mac, buf + 6, 6);
r->ts = *ts;
portEXIT_CRITICAL(&s_lock);
}
@@ -56,6 +58,12 @@ static esp_err_t rx_hook(esp_eth_handle_t eth, uint8_t *buf, uint32_t len, void
}
bool ptp_hw_rx_ts(uint8_t msg_type, uint16_t seq, const uint8_t *src_port_id, eth_mac_time_t *ts)
{
return ptp_hw_rx_ts_mac(msg_type, seq, src_port_id, ts, NULL);
}
bool ptp_hw_rx_ts_mac(uint8_t msg_type, uint16_t seq, const uint8_t *src_port_id, eth_mac_time_t *ts,
uint8_t src_mac[6])
{
bool found = false;
portENTER_CRITICAL(&s_lock);
@@ -63,6 +71,9 @@ bool ptp_hw_rx_ts(uint8_t msg_type, uint16_t seq, const uint8_t *src_port_id, et
rx_rec_t *r = &s_rx[i];
if (r->used && r->type == msg_type && r->seq == seq && memcmp(r->port_id, src_port_id, 10) == 0) {
*ts = r->ts;
if (src_mac) {
memcpy(src_mac, r->mac, 6);
}
r->used = false;
found = true;
break;
@@ -181,6 +192,9 @@ esp_err_t ptp_hw_init(esp_eth_handle_t eth, esp_netif_t *netif)
}
// IDF enables timestamping for PTP over Ethernet (L2) only; AES67 uses UDP/IPv4.
emac_ll_ts_ptp_ip4_enable(&EMAC_PTP, true);
// The PTP packet filter only stamps multicast PTP; unicast Delay_Req (hybrid mode) would get
// no timestamp. Stamp every frame instead; rx_hook picks the PTP event messages.
emac_ll_ts_all_enable(&EMAC_PTP, true);
// The netif glue registered its own input path; take it over and forward to the netif.
err = esp_eth_update_input_path_info(eth, rx_hook, netif);