diff --git a/fsm.c b/fsm.c new file mode 100644 index 0000000..1f142e4 --- /dev/null +++ b/fsm.c @@ -0,0 +1,301 @@ +/** + * @file fsm.c + * @note Copyright (C) 2011 Richard Cochran + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "fsm.h" + +enum port_state ptp_fsm(enum port_state state, enum fsm_event event) +{ + enum port_state next = state; + + if (EV_INITIALIZE == event || EV_POWERUP == event) + return PS_INITIALIZING; + + switch (state) { + case PS_INITIALIZING: + next = PS_LISTENING; + break; + + case PS_FAULTY: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_CLEARED: + next = PS_INITIALIZING; + break; + default: + break; + } + break; + + case PS_DISABLED: + if (EV_DESIGNATED_ENABLED == event) + next = PS_INITIALIZING; + break; + + case PS_LISTENING: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: + next = PS_MASTER; + break; + case EV_RS_MASTER: + next = PS_PRE_MASTER; + break; + case EV_RS_SLAVE: + next = PS_UNCALIBRATED; + break; + case EV_RS_PASSIVE: + next = PS_PASSIVE; + break; + default: + break; + } + break; + + case PS_PRE_MASTER: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + case EV_QUALIFICATION_TIMEOUT_EXPIRES: + next = PS_MASTER; + break; + case EV_RS_SLAVE: + next = PS_UNCALIBRATED; + break; + case EV_RS_PASSIVE: + next = PS_PASSIVE; + break; + default: + break; + } + break; + + case PS_MASTER: + case PS_GRAND_MASTER: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + case EV_RS_SLAVE: + next = PS_UNCALIBRATED; + break; + case EV_RS_PASSIVE: + next = PS_PASSIVE; + break; + default: + break; + } + break; + + case PS_PASSIVE: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: + next = PS_MASTER; + break; + case EV_RS_MASTER: + next = PS_PRE_MASTER; + break; + case EV_RS_SLAVE: + next = PS_UNCALIBRATED; + break; + default: + break; + } + break; + + case PS_UNCALIBRATED: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: + next = PS_MASTER; + break; + case EV_MASTER_CLOCK_SELECTED: + next = PS_SLAVE; + break; + case EV_RS_MASTER: + next = PS_PRE_MASTER; + break; + case EV_RS_SLAVE: + next = PS_UNCALIBRATED; + break; + case EV_RS_PASSIVE: + next = PS_PASSIVE; + break; + default: + break; + } + break; + + case PS_SLAVE: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: + next = PS_MASTER; + break; + case EV_SYNCHRONIZATION_FAULT: + next = PS_UNCALIBRATED; + break; + case EV_RS_MASTER: + next = PS_PRE_MASTER; + break; + case EV_RS_SLAVE: + next = PS_UNCALIBRATED; + break; + case EV_RS_PASSIVE: + next = PS_PASSIVE; + break; + default: + break; + } + break; + } + + return next; +} + +enum port_state ptp_slave_fsm(enum port_state state, enum fsm_event event) +{ + enum port_state next = state; + + if (EV_INITIALIZE == event || EV_POWERUP == event) + return PS_INITIALIZING; + + switch (state) { + case PS_INITIALIZING: + next = PS_LISTENING; + break; + + case PS_FAULTY: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_CLEARED: + next = PS_INITIALIZING; + break; + default: + break; + } + break; + + case PS_DISABLED: + if (EV_DESIGNATED_ENABLED == event) + next = PS_INITIALIZING; + break; + + case PS_LISTENING: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: + case EV_RS_MASTER: + case EV_RS_PASSIVE: + next = PS_LISTENING; + break; + case EV_RS_SLAVE: + next = PS_UNCALIBRATED; + break; + default: + break; + } + break; + + case PS_UNCALIBRATED: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: + case EV_RS_MASTER: + case EV_RS_PASSIVE: + next = PS_LISTENING; + break; + case EV_MASTER_CLOCK_SELECTED: + next = PS_SLAVE; + break; + default: + break; + } + break; + + case PS_SLAVE: + switch (event) { + case EV_DESIGNATED_DISABLED: + next = PS_DISABLED; + break; + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: + case EV_RS_MASTER: + case EV_RS_PASSIVE: + next = PS_LISTENING; + break; + case EV_SYNCHRONIZATION_FAULT: + next = PS_UNCALIBRATED; + break; + case EV_RS_SLAVE: + next = PS_UNCALIBRATED; + break; + default: + break; + } + break; + + default: + break; + } + + return next; +} diff --git a/fsm.h b/fsm.h new file mode 100644 index 0000000..c24d82c --- /dev/null +++ b/fsm.h @@ -0,0 +1,72 @@ +/** + * @file fsm.h + * @brief The finite state machine for ports on boundary and ordinary clocks. + * @note Copyright (C) 2011 Richard Cochran + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef HAVE_FSM_H +#define HAVE_FSM_H + +/** Defines the state of a port. */ +enum port_state { + PS_INITIALIZING = 1, + PS_FAULTY, + PS_DISABLED, + PS_LISTENING, + PS_PRE_MASTER, + PS_MASTER, + PS_GRAND_MASTER, + PS_PASSIVE, + PS_UNCALIBRATED, + PS_SLAVE, +}; + +/** Defines the events for the port state machine. */ +enum fsm_event { + EV_NONE, + EV_POWERUP, + EV_INITIALIZE, + EV_DESIGNATED_ENABLED, + EV_DESIGNATED_DISABLED, + EV_FAULT_CLEARED, + EV_FAULT_DETECTED, + EV_STATE_DECISION_EVENT, + EV_QUALIFICATION_TIMEOUT_EXPIRES, + EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES, + EV_SYNCHRONIZATION_FAULT, + EV_MASTER_CLOCK_SELECTED, + EV_RS_MASTER, + EV_RS_SLAVE, + EV_RS_PASSIVE, +}; + +/** + * Run the state machine for a BC or OC port. + * @param state The current state of the port. + * @param event The event to be processed. + * @return The new state for the port. + */ +enum port_state ptp_fsm(enum port_state state, enum fsm_event event); + +/** + * Run the state machine for a slave only clock. + * @param state The current state of the port. + * @param event The event to be processed. + * @return The new state for the port. + */ +enum port_state ptp_slave_fsm(enum port_state state, enum fsm_event event); + +#endif diff --git a/makefile b/makefile index 952063f..0d5d9ce 100644 --- a/makefile +++ b/makefile @@ -24,7 +24,7 @@ CFLAGS = -Wall $(INC) $(DEBUG) LDFLAGS = LDLIBS = -lm -lrt PRG = linuxptp -OBJ = phc.o print.o +OBJ = fsm.o phc.o print.o SRC = $(OBJ:.o=.c) DEPEND = $(OBJ:.o=.d)