1 /*
2 * Copyright (c) 2024 BayLibre SAS
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(ptp, CONFIG_PTP_LOG_LEVEL);
9
10 #include <errno.h>
11 #include <stdbool.h>
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/net/net_if.h>
15 #include <zephyr/net/ptp.h>
16
17 #include "clock.h"
18 #include "port.h"
19 #include "transport.h"
20
21 K_KERNEL_STACK_DEFINE(ptp_stack, CONFIG_PTP_STACK_SIZE);
22
23 static struct k_thread ptp_thread_data;
24
ptp_thread(void * p1,void * p2,void * p3)25 static void ptp_thread(void *p1, void *p2, void *p3)
26 {
27 static const size_t timer_offset[] = {
28 offsetof(struct ptp_port, timers.announce),
29 offsetof(struct ptp_port, timers.delay),
30 offsetof(struct ptp_port, timers.sync),
31 offsetof(struct ptp_port, timers.qualification)
32 };
33 static const int timeout_bit[] = {
34 PTP_PORT_TIMER_ANNOUNCE_TO,
35 PTP_PORT_TIMER_DELAY_TO,
36 PTP_PORT_TIMER_SYNC_TO,
37 PTP_PORT_TIMER_QUALIFICATION_TO,
38 };
39
40 struct k_timer *timer;
41 struct ptp_port *port;
42 struct zsock_pollfd *fd;
43 enum ptp_port_event event;
44
45 ARG_UNUSED(p1);
46 ARG_UNUSED(p2);
47 ARG_UNUSED(p3);
48
49 while (1) {
50 fd = ptp_clock_poll_sockets();
51
52 SYS_SLIST_FOR_EACH_CONTAINER(ptp_clock_ports_list(), port, node) {
53
54 for (int i = 0; i < ARRAY_SIZE(timer_offset); i++) {
55 timer = (struct k_timer *)((uint8_t *)port +
56 timer_offset[i]);
57
58 if (!atomic_test_bit(&port->timeouts, timeout_bit[i])) {
59 continue;
60 }
61
62 event = ptp_port_timer_event_gen(port, timer);
63
64 if (event == PTP_EVT_STATE_DECISION ||
65 event == PTP_EVT_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES) {
66 ptp_clock_state_decision_req();
67 }
68
69 ptp_port_event_handle(port, event, false);
70 }
71
72 for (int i = 0; i < PTP_SOCKET_CNT; i++, fd++) {
73 if (!(fd->revents & (ZSOCK_POLLIN | ZSOCK_POLLPRI))) {
74 continue;
75 }
76
77 event = ptp_port_event_gen(port, i);
78
79 if (event == PTP_EVT_STATE_DECISION ||
80 event == PTP_EVT_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES) {
81 ptp_clock_state_decision_req();
82 }
83
84 ptp_port_event_handle(port, event, false);
85 }
86 }
87
88 ptp_clock_handle_state_decision_evt();
89 }
90 }
91
ptp_init(void)92 static int ptp_init(void)
93 {
94 k_tid_t tid;
95 const struct ptp_clock *domain = ptp_clock_init();
96 struct ptp_port *port;
97
98 if (!domain) {
99 return -ENODEV;
100 }
101
102 net_if_foreach(ptp_port_init, NULL);
103
104 SYS_SLIST_FOR_EACH_CONTAINER(ptp_clock_ports_list(), port, node) {
105 ptp_port_event_handle(port, PTP_EVT_INITIALIZE, false);
106 }
107
108 tid = k_thread_create(&ptp_thread_data, ptp_stack, K_KERNEL_STACK_SIZEOF(ptp_stack),
109 ptp_thread, NULL, NULL, NULL,
110 K_PRIO_COOP(1), 0, K_NO_WAIT);
111 k_thread_name_set(&ptp_thread_data, "PTP");
112
113 return 0;
114 }
115
116 SYS_INIT(ptp_init, APPLICATION, CONFIG_PTP_INIT_PRIO);
117