flexPTP basic excerpt
This commit is contained in:
		
						commit
						ac63947fe1
					
				
							
								
								
									
										45
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
set(FLEXPTP_SRC
 | 
			
		||||
        # core files
 | 
			
		||||
        cli_cmds.c
 | 
			
		||||
        cli_cmds.h
 | 
			
		||||
        clock_utils.c
 | 
			
		||||
        clock_utils.h
 | 
			
		||||
        format_utils.c
 | 
			
		||||
        format_utils.h
 | 
			
		||||
        logging.c
 | 
			
		||||
        logging.h
 | 
			
		||||
        msg_utils.c
 | 
			
		||||
        msg_utils.h
 | 
			
		||||
        ptp_core.c
 | 
			
		||||
        ptp_core.h
 | 
			
		||||
        sbmc.c
 | 
			
		||||
        sbmc.h
 | 
			
		||||
        stats.c
 | 
			
		||||
        stats.h
 | 
			
		||||
        timeutils.c
 | 
			
		||||
        timeutils.h
 | 
			
		||||
        ptp_defs.h
 | 
			
		||||
        ptp_types.h
 | 
			
		||||
 | 
			
		||||
        # servo files
 | 
			
		||||
        servo/pd_controller.c
 | 
			
		||||
        servo/pd_controller.h
 | 
			
		||||
 | 
			
		||||
        # hw-port files
 | 
			
		||||
        hw_port/flexptp_options_simulation.h
 | 
			
		||||
        hw_port/ptp_port_simulation.cpp
 | 
			
		||||
        hw_port/ptp_port_simulation.h
 | 
			
		||||
 | 
			
		||||
        # simulation objects
 | 
			
		||||
        hw_port/simsrc/lwip_simulation.h
 | 
			
		||||
        hw_port/simsrc/lwip_simulation.cpp
 | 
			
		||||
        hw_port/simsrc/FreeRTOS_simulation.h
 | 
			
		||||
        hw_port/simsrc/FreeRTOS_simulation.cpp
 | 
			
		||||
        hw_port/simsrc/PtpClock.h
 | 
			
		||||
        hw_port/simsrc/PtpClock.cpp
 | 
			
		||||
        hw_port/simsrc/PtpMasterClock.h
 | 
			
		||||
        hw_port/simsrc/PtpMasterClock.cpp
 | 
			
		||||
        hw_port/simsrc/PtpSlaveClock.h
 | 
			
		||||
        hw_port/simsrc/PtpSlaveClock.cpp
 | 
			
		||||
 | 
			
		||||
        PARENT_SCOPE)
 | 
			
		||||
							
								
								
									
										171
									
								
								cli_cmds.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								cli_cmds.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,171 @@
 | 
			
		||||
#include "cli_cmds.h"
 | 
			
		||||
 | 
			
		||||
#include "ptp_core.h"
 | 
			
		||||
#include "msg_utils.h"
 | 
			
		||||
#include "format_utils.h"
 | 
			
		||||
#include "logging.h"
 | 
			
		||||
#include "clock_utils.h"
 | 
			
		||||
#include "ptp_profile_presets.h"
 | 
			
		||||
 | 
			
		||||
#include "settings_interface.h"
 | 
			
		||||
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
//#define S (gPtpCoreState)
 | 
			
		||||
 | 
			
		||||
// ---- COMPILE ONLY IF CLI_REG_CMD is provided ----
 | 
			
		||||
 | 
			
		||||
#ifdef CLI_REG_CMD
 | 
			
		||||
 | 
			
		||||
static int CB_reset(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    ptp_reset();
 | 
			
		||||
    MSG("> PTP reset!\n");
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int CB_offset(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    if (argc > 0) {
 | 
			
		||||
        ptp_set_clock_offset(atoi(ppArgs[0]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MSG("> PTP clock offset: %d ns\n", ptp_get_clock_offset());
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int CB_log(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    bool logEn = false;
 | 
			
		||||
 | 
			
		||||
    if (argc > 1) {
 | 
			
		||||
        if (!strcmp(ppArgs[1], "on")) {
 | 
			
		||||
            logEn = true;
 | 
			
		||||
        } else if (!strcmp(ppArgs[1], "off")) {
 | 
			
		||||
            logEn = false;
 | 
			
		||||
        } else {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!strcmp(ppArgs[0], "def")) {
 | 
			
		||||
            ptp_enable_logging(PTP_LOG_DEF, logEn);
 | 
			
		||||
        } else if (!strcmp(ppArgs[0], "corr")) {
 | 
			
		||||
            ptp_enable_logging(PTP_LOG_CORR_FIELD, logEn);
 | 
			
		||||
        } else if (!strcmp(ppArgs[0], "ts")) {
 | 
			
		||||
            ptp_enable_logging(PTP_LOG_TIMESTAMPS, logEn);
 | 
			
		||||
        } else if (!strcmp(ppArgs[0], "info")) {
 | 
			
		||||
            ptp_enable_logging(PTP_LOG_INFO, logEn);
 | 
			
		||||
        } else if (!strcmp(ppArgs[0], "locked")) {
 | 
			
		||||
            ptp_enable_logging(PTP_LOG_LOCKED_STATE, logEn);
 | 
			
		||||
        } else {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int CB_time(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    char datetime[24];
 | 
			
		||||
    TimestampU t;
 | 
			
		||||
    ptp_time(&t);
 | 
			
		||||
 | 
			
		||||
    if (argc > 0 && !strcmp(ppArgs[0], "ns")) {
 | 
			
		||||
        MSG("%lu %u\n", t.sec, t.nanosec);
 | 
			
		||||
    } else {
 | 
			
		||||
        tsPrint(datetime, (const TimestampI *)&t);
 | 
			
		||||
        MSG("%s\n", datetime);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int CB_master(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    if (argc > 0) {
 | 
			
		||||
        if (!strcmp(ppArgs[0], "prefer")) {
 | 
			
		||||
            uint64_t idM = ptp_get_current_master_clock_identity();
 | 
			
		||||
            if (argc > 1) {
 | 
			
		||||
                idM = hextoclkid(ppArgs[1]);
 | 
			
		||||
            }
 | 
			
		||||
            ptp_prefer_master_clock(idM);
 | 
			
		||||
        } else if (!strcmp(ppArgs[0], "unprefer")) {
 | 
			
		||||
            ptp_unprefer_master_clock();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MSG("Master clock ID: ");
 | 
			
		||||
    ptp_print_clock_identity(ptp_get_current_master_clock_identity());
 | 
			
		||||
    MSG("\n");
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int CB_ptpinfo(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    MSG("Own clock ID: ");
 | 
			
		||||
    ptp_print_clock_identity(ptp_get_own_clock_identity());
 | 
			
		||||
    MSG("\nMaster clock ID: ");
 | 
			
		||||
    ptp_print_clock_identity(ptp_get_current_master_clock_identity());
 | 
			
		||||
    MSG("\n");
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int CB_ptpdomain(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    if (argc > 0) {
 | 
			
		||||
        ptp_set_domain(atoi(ppArgs[0]));
 | 
			
		||||
    }
 | 
			
		||||
    MSG("PTP domain: %d\n", (int)ptp_get_domain());
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int CB_addend(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    if (argc > 0) {
 | 
			
		||||
        ptp_set_addend((uint32_t) atol(ppArgs[0]));
 | 
			
		||||
    }
 | 
			
		||||
    MSG("Addend: %u\n", ptp_get_addend());
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *sTransportTypeHint[] = { "IPv4", "802.3" };
 | 
			
		||||
 | 
			
		||||
// command assignments
 | 
			
		||||
enum PTP_CMD_IDS {
 | 
			
		||||
    CMD_RESET, CMD_OFFSET, CMD_LOG, CMD_TIME, CMD_MASTER, CMD_PTPINFO, CMD_PTPDOMAIN, CMD_ADDEND,
 | 
			
		||||
 | 
			
		||||
    CMD_N
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// command descriptors
 | 
			
		||||
static int sCmds[CMD_N + 1];
 | 
			
		||||
 | 
			
		||||
#endif                          // CLI_REG_CMD
 | 
			
		||||
 | 
			
		||||
// register cli commands
 | 
			
		||||
void ptp_register_cli_commands()
 | 
			
		||||
{
 | 
			
		||||
#ifdef CLI_REG_CMD
 | 
			
		||||
    sCmds[CMD_RESET] = cli_register_command("ptp reset \t\t\tReset PTP subsystem", 2, 0, CB_reset);
 | 
			
		||||
    sCmds[CMD_OFFSET] = cli_register_command("ptp servo offset [offset_ns] \t\t\tSet or query clock offset", 3, 0, CB_offset);
 | 
			
		||||
    sCmds[CMD_LOG] = cli_register_command("ptp log {def|corr|ts|info|locked} {on|off} \t\t\tTurn on or off logging", 2, 2, CB_log);
 | 
			
		||||
    sCmds[CMD_TIME] = cli_register_command("time [ns] \t\t\tPrint time", 1, 0, CB_time);
 | 
			
		||||
    sCmds[CMD_MASTER] = cli_register_command("ptp master [[un]prefer] [clockid] \t\t\tMaster clock settings", 2, 0, CB_master);
 | 
			
		||||
    sCmds[CMD_PTPINFO] = cli_register_command("ptp info \t\t\tPrint PTP info", 2, 0, CB_ptpinfo);
 | 
			
		||||
    sCmds[CMD_PTPDOMAIN] = cli_register_command("ptp domain [domain]\t\t\tPrint or get PTP domain", 2, 0, CB_ptpdomain);
 | 
			
		||||
    sCmds[CMD_ADDEND] = cli_register_command("ptp addend [addend]\t\t\tPrint or set addend", 2, 0, CB_addend);
 | 
			
		||||
 | 
			
		||||
    sCmds[CMD_N] = -1;
 | 
			
		||||
#endif                          // CLI_REG_CMD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_remove_cli_commands()
 | 
			
		||||
{
 | 
			
		||||
#ifdef CLI_REG_CMD
 | 
			
		||||
    cli_remove_command_array(sCmds);
 | 
			
		||||
#endif                          // CLI_REG_CMD
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								cli_cmds.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								cli_cmds.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
#ifndef FLEXPTP_CLI_CMDS_H_
 | 
			
		||||
#define FLEXPTP_CLI_CMDS_H_
 | 
			
		||||
 | 
			
		||||
void ptp_register_cli_commands();
 | 
			
		||||
void ptp_remove_cli_commands();
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_CLI_CMDS_H_ */
 | 
			
		||||
							
								
								
									
										34
									
								
								clock_utils.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								clock_utils.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
#include <flexptp/clock_utils.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include <flexptp_options.h>
 | 
			
		||||
 | 
			
		||||
#include "ptp_core.h"
 | 
			
		||||
 | 
			
		||||
#define S (gPtpCoreState)
 | 
			
		||||
 | 
			
		||||
// print clock identity
 | 
			
		||||
void ptp_print_clock_identity(uint64_t clockID)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t *p = (uint8_t *) & clockID;
 | 
			
		||||
    uint8_t i;
 | 
			
		||||
    for (i = 0; i < 8; i++) {   // reverse byte order due to Network->Host byte order conversion
 | 
			
		||||
        MSG("%02x", p[7 - i]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create clock identity based on MAC address
 | 
			
		||||
void ptp_create_clock_identity()
 | 
			
		||||
{
 | 
			
		||||
    uint8_t *p = (uint8_t *) & S.hwoptions.clockIdentity;
 | 
			
		||||
    // construct clockIdentity
 | 
			
		||||
    memcpy(p, netif_default->hwaddr, 3);        // first 3 octets of MAC address
 | 
			
		||||
    p[3] = 0xff;
 | 
			
		||||
    p[4] = 0xfe;
 | 
			
		||||
    memcpy(&p[5], &netif_default->hwaddr[3], 3);        // last 3 octets of MAC address
 | 
			
		||||
 | 
			
		||||
    // display ID
 | 
			
		||||
    MSG("Own clock ID: ");
 | 
			
		||||
    ptp_print_clock_identity(S.hwoptions.clockIdentity);
 | 
			
		||||
    MSG("\n");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								clock_utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								clock_utils.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
#ifndef FLEXPTP_CLOCK_UTILS_H_
 | 
			
		||||
#define FLEXPTP_CLOCK_UTILS_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
void ptp_print_clock_identity(uint64_t clockID);        // print clock identity
 | 
			
		||||
 | 
			
		||||
void ptp_create_clock_identity();       // create clock identity based on MAC address
 | 
			
		||||
 | 
			
		||||
void ptp_set_clock_offset(int32_t offset);      // set PPS offset
 | 
			
		||||
int32_t ptp_get_clock_offset(); // get PPS offset
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_CLOCK_UTILS_H_ */
 | 
			
		||||
							
								
								
									
										39
									
								
								format_utils.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								format_utils.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
/* (C) András Wiesner, 2020-2022 */
 | 
			
		||||
 | 
			
		||||
#include "format_utils.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
// lookup table for log msg. period to ms conversion (ms values are floor-rounded)
 | 
			
		||||
#define LOG_INTERVAL_LOOKUP_OFFSET (6)
 | 
			
		||||
static uint16_t sLogIntervalMs[] = { 15, 31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 0 };    // terminating zero as last element
 | 
			
		||||
 | 
			
		||||
// log interval to milliseconds
 | 
			
		||||
uint16_t ptp_logi2ms(int8_t logi)
 | 
			
		||||
{
 | 
			
		||||
    return sLogIntervalMs[logi + LOG_INTERVAL_LOOKUP_OFFSET];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// milliseconds to log interval
 | 
			
		||||
int8_t ptp_ms2logi(uint16_t ms)
 | 
			
		||||
{
 | 
			
		||||
    uint16_t *pIter = sLogIntervalMs;
 | 
			
		||||
    while (*pIter != 0) {
 | 
			
		||||
        if (*pIter == ms) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return (int8_t) (pIter - sLogIntervalMs) + LOG_INTERVAL_LOOKUP_OFFSET;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Network->Host byte order conversion for 64-bit values
 | 
			
		||||
uint64_t ntohll(uint64_t in)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char out[8] = { in >> 56, in >> 48, in >> 40, in >> 32, in >> 24, in >> 16, in >> 8, in };
 | 
			
		||||
    return *(uint64_t *) out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t htonll(uint64_t in)
 | 
			
		||||
{
 | 
			
		||||
    return ntohll(in);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								format_utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								format_utils.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
/* (C) András Wiesner, 2020-2022 */
 | 
			
		||||
 | 
			
		||||
#ifndef FLEXPTP_FORMAT_UTILS_H_
 | 
			
		||||
#define FLEXPTP_FORMAT_UTILS_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
uint16_t ptp_logi2ms(int8_t logi);      // log interval to milliseconds
 | 
			
		||||
int8_t ptp_ms2logi(uint16_t ms);        // milliseconds to log interval
 | 
			
		||||
uint64_t ntohll(uint64_t in);   // network->host byte order change
 | 
			
		||||
uint64_t htonll(uint64_t in);   // host->network byte order change
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_FORMAT_UTILS_H_ */
 | 
			
		||||
							
								
								
									
										70
									
								
								hw_port/flexptp_options_simulation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								hw_port/flexptp_options_simulation.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
			
		||||
#ifndef FLEXPTP_OPTIONS_STM32H743_H_
 | 
			
		||||
#define FLEXPTP_OPTIONS_STM32H743_H_
 | 
			
		||||
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
// --- DEFINES FOR PORTING IMPLEMENTATION ----
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
 | 
			
		||||
// Include LwIP headers here
 | 
			
		||||
 | 
			
		||||
//#include "lwip/netif.h"
 | 
			
		||||
//#include "lwip/tcpip.h"
 | 
			
		||||
//#include "lwip/udp.h"
 | 
			
		||||
//#include "lwip/igmp.h"
 | 
			
		||||
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
 | 
			
		||||
#include "simsrc/FreeRTOS_simulation.h"
 | 
			
		||||
#include "simsrc/lwip_simulation.h"
 | 
			
		||||
 | 
			
		||||
// Give a printf-like printing implementation MSG(...)
 | 
			
		||||
// Give a maskable printing implementation CLILOG(en,...)
 | 
			
		||||
 | 
			
		||||
#include <env/utils.h>
 | 
			
		||||
 | 
			
		||||
// Include hardware port files and fill the defines below to port the PTP stack to a physical hardware:
 | 
			
		||||
// - PTP_HW_INIT(increment, addend): function initializing timestamping hardware
 | 
			
		||||
// - PTP_MAIN_OSCILLATOR_FREQ_HZ: clock frequency fed into the timestamp unit [Hz]
 | 
			
		||||
// - PTP_INCREMENT_NSEC: hardware clock increment [ns]
 | 
			
		||||
// - PTP_UPDATE_CLOCK(s,ns): function jumping clock by defined value (negative time value means jumping backward)
 | 
			
		||||
// - PTP_SET_ADDEND(addend): function writing hardware clock addend register
 | 
			
		||||
 | 
			
		||||
#include "ptp_port_simulation.h"
 | 
			
		||||
 | 
			
		||||
#define PTP_MAIN_OSCILLATOR_FREQ_HZ (200000000)
 | 
			
		||||
#define PTP_INCREMENT_NSEC (5)
 | 
			
		||||
 | 
			
		||||
#define PTP_HW_INIT(increment, addend) ptphw_init(increment, addend)
 | 
			
		||||
#define PTP_UPDATE_CLOCK(s,ns) 	ptphw_update_clock(labs(s), abs(ns), (s * NANO_PREFIX + ns) < 0)
 | 
			
		||||
#define PTP_SET_ADDEND(addend) ptphw_set_addend(addend)
 | 
			
		||||
#define PTP_HW_GET_TIME(pt) ptphw_gettime(pt)
 | 
			
		||||
 | 
			
		||||
// Include the clock servo (controller) and define the following:
 | 
			
		||||
// - PTP_SERVO_INIT(): function initializing clock servo
 | 
			
		||||
// - PTP_SERVO_DEINIT(): function deinitializing clock servo
 | 
			
		||||
// - PTP_SERVO_RESET(): function reseting clock servo
 | 
			
		||||
// - PTP_SERVO_RUN(d): function running the servo, input: master-slave time difference (error), return: clock tuning value in PPB
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "../servo/pd_controller.h"
 | 
			
		||||
 | 
			
		||||
#define PTP_SERVO_INIT() pd_ctrl_init()
 | 
			
		||||
#define PTP_SERVO_DEINIT() pd_ctrl_deinit()
 | 
			
		||||
#define PTP_SERVO_RESET() pd_ctrl_reset()
 | 
			
		||||
#define PTP_SERVO_RUN(d,pscd) pd_ctrl_run(d,pscd)
 | 
			
		||||
 | 
			
		||||
// Optionally add interactive, tokenizing CLI-support
 | 
			
		||||
// - CLI_REG_CMD(cmd_hintline,n_cmd,n_min_arg,cb): function for registering CLI-commands
 | 
			
		||||
//      cmd_hintline: text line printed in the help beginning with the actual command, separated from help text by \t charaters
 | 
			
		||||
//      n_cmd: number of tokens (words) the command consists of
 | 
			
		||||
//      n_arg: minimal number of arguments must be passed with the command
 | 
			
		||||
//      cb: callback function cb(const CliToken_Type *ppArgs, uint8_t argc)
 | 
			
		||||
//  return: cmd id (can be null, if discarded)
 | 
			
		||||
 | 
			
		||||
#include <cli/cli.h>
 | 
			
		||||
 | 
			
		||||
#define CLI_REG_CMD(cmd_hintline,n_cmd,n_min_arg,cb) cli_register_command(cmd_hintline, n_cmd, n_min_arg, cb)
 | 
			
		||||
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
 | 
			
		||||
#endif                          // FLEXPTP_OPTIONS_STM32H743_H_
 | 
			
		||||
							
								
								
									
										71
									
								
								hw_port/flexptp_options_stm32h743.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								hw_port/flexptp_options_stm32h743.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
			
		||||
#ifndef FLEXPTP_OPTIONS_STM32H743_H_
 | 
			
		||||
#define FLEXPTP_OPTIONS_STM32H743_H_
 | 
			
		||||
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
// --- DEFINES FOR PORTING IMPLEMENTATION ----
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
 | 
			
		||||
// Include LwIP headers here
 | 
			
		||||
 | 
			
		||||
#include "lwip/netif.h"
 | 
			
		||||
#include "lwip/tcpip.h"
 | 
			
		||||
#include "lwip/udp.h"
 | 
			
		||||
#include "lwip/igmp.h"
 | 
			
		||||
#include "lwip/pbuf.h"
 | 
			
		||||
 | 
			
		||||
// Give a printf-like printing implementation MSG(...)
 | 
			
		||||
// Give a maskable printing implementation CLILOG(en,...)
 | 
			
		||||
// Provide an SPRINTF-implementation SPRINTF(str,n,fmt,...)
 | 
			
		||||
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
 | 
			
		||||
// Include hardware port files and fill the defines below to port the PTP stack to a physical hardware:
 | 
			
		||||
// - PTP_HW_INIT(increment, addend): function initializing timestamping hardware
 | 
			
		||||
// - PTP_MAIN_OSCILLATOR_FREQ_HZ: clock frequency fed into the timestamp unit [Hz]
 | 
			
		||||
// - PTP_INCREMENT_NSEC: hardware clock increment [ns]
 | 
			
		||||
// - PTP_UPDATE_CLOCK(s,ns): function jumping clock by defined value (negative time value means jumping backward)
 | 
			
		||||
// - PTP_SET_ADDEND(addend): function writing hardware clock addend register
 | 
			
		||||
 | 
			
		||||
#include "ptp_port_stm32h743.h"
 | 
			
		||||
 | 
			
		||||
#include "stm32h7xx_hal.h"
 | 
			
		||||
extern ETH_HandleTypeDef EthHandle;
 | 
			
		||||
 | 
			
		||||
#define PTP_MAIN_OSCILLATOR_FREQ_HZ (200000000)
 | 
			
		||||
#define PTP_INCREMENT_NSEC (5)
 | 
			
		||||
 | 
			
		||||
#define PTP_HW_INIT(increment, addend) ptphw_init(increment, addend)
 | 
			
		||||
#define PTP_UPDATE_CLOCK(s,ns) 	ETH_UpdatePTPTime(&EthHandle, labs(s), abs(ns), (s * NANO_PREFIX + ns) < 0)
 | 
			
		||||
#define PTP_SET_CLOCK(s,ns) ETH_InitPTPTime(&EthHandle, labs(s), abs(ns))
 | 
			
		||||
#define PTP_SET_ADDEND(addend) ETH_SetPTPAddend(&EthHandle, addend)
 | 
			
		||||
#define PTP_HW_GET_TIME(pt) ptphw_gettime(pt)
 | 
			
		||||
 | 
			
		||||
// Include the clock servo (controller) and define the following:
 | 
			
		||||
// - PTP_SERVO_INIT(): function initializing clock servo
 | 
			
		||||
// - PTP_SERVO_DEINIT(): function deinitializing clock servo
 | 
			
		||||
// - PTP_SERVO_RESET(): function reseting clock servo
 | 
			
		||||
// - PTP_SERVO_RUN(d): function running the servo, input: master-slave time difference (error), return: clock tuning value in PPB
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "../servo/pd_controller.h"
 | 
			
		||||
 | 
			
		||||
#define PTP_SERVO_INIT() pd_ctrl_init()
 | 
			
		||||
#define PTP_SERVO_DEINIT() pd_ctrl_deinit()
 | 
			
		||||
#define PTP_SERVO_RESET() pd_ctrl_reset()
 | 
			
		||||
#define PTP_SERVO_RUN(d,pscd) pd_ctrl_run(d,pscd)
 | 
			
		||||
 | 
			
		||||
// Optionally add interactive, tokenizing CLI-support
 | 
			
		||||
// - CLI_REG_CMD(cmd_hintline,n_cmd,n_min_arg,cb): function for registering CLI-commands
 | 
			
		||||
//      cmd_hintline: text line printed in the help beginning with the actual command, separated from help text by \t charaters
 | 
			
		||||
//      n_cmd: number of tokens (words) the command consists of
 | 
			
		||||
//      n_arg: minimal number of arguments must be passed with the command
 | 
			
		||||
//      cb: callback function cb(const CliToken_Type *ppArgs, uint8_t argc)
 | 
			
		||||
//  return: cmd id (can be null, if discarded)
 | 
			
		||||
 | 
			
		||||
#include "cli.h"
 | 
			
		||||
 | 
			
		||||
#define CLI_REG_CMD(cmd_hintline,n_cmd,n_min_arg,cb) cli_register_command(cmd_hintline, n_cmd, n_min_arg, cb)
 | 
			
		||||
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
 | 
			
		||||
#endif                          // FLEXPTP_OPTIONS_STM32H743_H_
 | 
			
		||||
							
								
								
									
										68
									
								
								hw_port/flexptp_options_tm4c1294.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								hw_port/flexptp_options_tm4c1294.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
			
		||||
#ifndef FLEXPTP_OPTIONS_STM32H743_H_
 | 
			
		||||
#define FLEXPTP_OPTIONS_STM32H743_H_
 | 
			
		||||
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
// --- DEFINES FOR PORTING IMPLEMENTATION ----
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
 | 
			
		||||
// Include LwIP headers here
 | 
			
		||||
 | 
			
		||||
#include "utils/lwiplib.h"
 | 
			
		||||
#include "utils/uartstdio.h"
 | 
			
		||||
 | 
			
		||||
#include "driverlib/emac.h"
 | 
			
		||||
#include "driverlib/gpio.h"
 | 
			
		||||
#include "inc/hw_memmap.h"
 | 
			
		||||
#include "driverlib/pin_map.h"
 | 
			
		||||
 | 
			
		||||
// Give a printf-like printing implementation MSG(...)
 | 
			
		||||
// Give a maskable printing implementation CLILOG(en,...)
 | 
			
		||||
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
 | 
			
		||||
// Include hardware port files and fill the defines below to port the PTP stack to a physical hardware:
 | 
			
		||||
// - PTP_HW_INIT(increment, addend): function initializing timestamping hardware
 | 
			
		||||
// - PTP_MAIN_OSCILLATOR_FREQ_HZ: clock frequency fed into the timestamp unit [Hz]
 | 
			
		||||
// - PTP_INCREMENT_NSEC: hardware clock increment [ns]
 | 
			
		||||
// - PTP_UPDATE_CLOCK(s,ns): function jumping clock by defined value (negative time value means jumping backward)
 | 
			
		||||
// - PTP_SET_ADDEND(addend): function writing hardware clock addend register
 | 
			
		||||
 | 
			
		||||
#include "ptp_port_tiva_tm4c1295.h"
 | 
			
		||||
 | 
			
		||||
#define PTP_MAIN_OSCILLATOR_FREQ_HZ (25000000)
 | 
			
		||||
#define PTP_INCREMENT_NSEC (50)
 | 
			
		||||
 | 
			
		||||
#define PTP_HW_INIT(increment, addend) ptphw_init(increment, addend)
 | 
			
		||||
#define PTP_UPDATE_CLOCK(s,ns) EMACTimestampSysTimeUpdate(EMAC0_BASE, labs(s), abs(ns), (s * NANO_PREFIX + ns) < 0)
 | 
			
		||||
#define PTP_SET_ADDEND(addend) EMACTimestampAddendSet(EMAC0_BASE, addend)
 | 
			
		||||
#define PTP_HW_GET_TIME(pt) ptphw_gettime(pt)
 | 
			
		||||
 | 
			
		||||
// Include the clock servo (controller) and define the following:
 | 
			
		||||
// - PTP_SERVO_INIT(): function initializing clock servo
 | 
			
		||||
// - PTP_SERVO_DEINIT(): function deinitializing clock servo
 | 
			
		||||
// - PTP_SERVO_RESET(): function reseting clock servo
 | 
			
		||||
// - PTP_SERVO_RUN(d): function running the servo, input: master-slave time difference (error), return: clock tuning value in PPB
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "../servo/pd_controller.h"
 | 
			
		||||
 | 
			
		||||
#define PTP_SERVO_INIT() pd_ctrl_init()
 | 
			
		||||
#define PTP_SERVO_DEINIT() pd_ctrl_deinit()
 | 
			
		||||
#define PTP_SERVO_RESET() pd_ctrl_reset()
 | 
			
		||||
#define PTP_SERVO_RUN(d,pscd) pd_ctrl_run(d,pscd)
 | 
			
		||||
 | 
			
		||||
// Optionally add interactive, tokenizing CLI-support
 | 
			
		||||
// - CLI_REG_CMD(cmd_hintline,n_cmd,n_min_arg,cb): function for registering CLI-commands
 | 
			
		||||
//      cmd_hintline: text line printed in the help beginning with the actual command, separated from help text by \t charaters
 | 
			
		||||
//      n_cmd: number of tokens (words) the command consists of
 | 
			
		||||
//      n_arg: minimal number of arguments must be passed with the command
 | 
			
		||||
//      cb: callback function cb(const CliToken_Type *ppArgs, uint8_t argc)
 | 
			
		||||
//  return: cmd id (can be null, if discarded)
 | 
			
		||||
 | 
			
		||||
#include "cli.h"
 | 
			
		||||
 | 
			
		||||
#define CLI_REG_CMD(cmd_hintline,n_cmd,n_min_arg,cb) cli_register_command(cmd_hintline, n_cmd, n_min_arg, cb)
 | 
			
		||||
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
 | 
			
		||||
#endif                          // FLEXPTP_OPTIONS_STM32H743_H_
 | 
			
		||||
							
								
								
									
										42
									
								
								hw_port/ptp_port_simulation.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								hw_port/ptp_port_simulation.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
			
		||||
#include "ptp_port_simulation.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "simsrc/PtpClock.h"
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<PtpClock> pSlClock;
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
void ptphw_init(uint32_t increment, uint32_t addend) {
 | 
			
		||||
    // create clock
 | 
			
		||||
    PtpClock::ClockProperties ckProps = {
 | 
			
		||||
            0xFFFFFFFF,
 | 
			
		||||
            0xFFFF5DCC,
 | 
			
		||||
            0.0
 | 
			
		||||
    };
 | 
			
		||||
    pSlClock = std::make_shared<PtpClock>(ckProps);
 | 
			
		||||
 | 
			
		||||
    // set default addend
 | 
			
		||||
    pSlClock->setAddend(addend);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptphw_gettime(TimestampU *pTime) {
 | 
			
		||||
    PtpClock::Timestamp ts = pSlClock->getTime();
 | 
			
		||||
    pTime->sec = ts.sec;
 | 
			
		||||
    pTime->nanosec = ts.ns;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptphw_set_addend(uint32_t addend) {
 | 
			
		||||
    pSlClock->setAddend(addend);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptphw_update_clock(uint32_t s, uint32_t ns, int dir) {
 | 
			
		||||
    pSlClock->updateTime(s, ns, dir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								hw_port/ptp_port_simulation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								hw_port/ptp_port_simulation.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
#ifndef HW_PORT_PTP_PORT_SIMULATION_
 | 
			
		||||
#define HW_PORT_PTP_PORT_SIMULATION_
 | 
			
		||||
 | 
			
		||||
#include "../timeutils.h"
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    void ptphw_init(uint32_t increment, uint32_t addend);       // initialize PTP hardware
 | 
			
		||||
    void ptphw_gettime(TimestampU * pTime);     // get time
 | 
			
		||||
    void ptphw_set_addend(uint32_t addend);     // set addend
 | 
			
		||||
    void ptphw_update_clock(uint32_t s, uint32_t ns, int dir);  // update clock
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif                          /* HW_PORT_PTP_PORT_SIMULATION_ */
 | 
			
		||||
							
								
								
									
										146
									
								
								hw_port/ptp_port_stm32h743.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								hw_port/ptp_port_stm32h743.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,146 @@
 | 
			
		||||
#include "ptp_port_stm32h743.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#include "FreeRTOS.h"
 | 
			
		||||
#include "task.h"
 | 
			
		||||
 | 
			
		||||
#include "stm32h7xx_hal.h"
 | 
			
		||||
 | 
			
		||||
#include "flexptp_options_stm32h743.h"
 | 
			
		||||
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
#include "cli.h"
 | 
			
		||||
 | 
			
		||||
extern ETH_HandleTypeDef EthHandle;
 | 
			
		||||
 | 
			
		||||
static unsigned sFreq = 1;
 | 
			
		||||
 | 
			
		||||
#ifdef CLI_REG_CMD
 | 
			
		||||
 | 
			
		||||
static int CB_pps(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    if (argc >= 1) {
 | 
			
		||||
        float freq = atof(ppArgs[0]);
 | 
			
		||||
 | 
			
		||||
        int fc_exp;
 | 
			
		||||
 | 
			
		||||
        if (freq > 0) {
 | 
			
		||||
            fc_exp = round(log2f(freq)) + 1;
 | 
			
		||||
 | 
			
		||||
            // lower limit
 | 
			
		||||
            if (fc_exp < ETH_PTP_PPS_1Hz) {
 | 
			
		||||
                fc_exp = ETH_PTP_PPS_1Hz;
 | 
			
		||||
            }
 | 
			
		||||
            // upper limit
 | 
			
		||||
            if (fc_exp > ETH_PTP_PPS_16384Hz) {
 | 
			
		||||
                fc_exp = ETH_PTP_PPS_16384Hz;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            sFreq = exp2(fc_exp - 1);
 | 
			
		||||
        } else {
 | 
			
		||||
            sFreq = 0;
 | 
			
		||||
            fc_exp = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ETH_SetPTPPPSFreq(&EthHandle, fc_exp);
 | 
			
		||||
 | 
			
		||||
//          // parse frequency [Hz] (integer only!)
 | 
			
		||||
//          uint32_t freq_Hz = atoi(ppArgs[0]);
 | 
			
		||||
//
 | 
			
		||||
//          if (freq_Hz == 0) {
 | 
			
		||||
//              // stop pulse train generation
 | 
			
		||||
//              ETH_StopPTPPPSPulseTrain(&EthHandle);
 | 
			
		||||
//          } else {
 | 
			
		||||
//            // compute period [ns]
 | 
			
		||||
//            uint32_t period_ns = NANO_PREFIX / freq_Hz;
 | 
			
		||||
//
 | 
			
		||||
//            // display warning if frequency is not integer divisor of 1E+09
 | 
			
		||||
//            if ((NANO_PREFIX % freq_Hz) != 0) {
 | 
			
		||||
//                MSG("Warning! PPS frequency is not totally accurate, "
 | 
			
		||||
//                    "choose frequency values corresponding to periods "
 | 
			
		||||
//                    "being integer divisors of 1E+09!\n");
 | 
			
		||||
//            }
 | 
			
		||||
//
 | 
			
		||||
//            // set duty cycle (try 50%) by specifying positive pulse length
 | 
			
		||||
//            uint32_t high_ns = period_ns / 2;
 | 
			
		||||
//
 | 
			
		||||
//            // start pulse train generation
 | 
			
		||||
//            ETH_StartPTPPPSPulseTrain(&EthHandle, high_ns, period_ns);
 | 
			
		||||
//          }
 | 
			
		||||
//
 | 
			
		||||
//          // store frequency setting
 | 
			
		||||
//          sFreq = freq_Hz;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sFreq > 0) {
 | 
			
		||||
        MSG("PPS frequency: %u Hz\n", sFreq);
 | 
			
		||||
    } else {
 | 
			
		||||
        MSG("PPS output is turned off.\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ptphw_register_cli_commands()
 | 
			
		||||
{                               // TODO....
 | 
			
		||||
    cli_register_command("ptp pps {freq} \t\t\tSet or query PPS signal frequency [Hz]", 2, 0, CB_pps);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif                          // CLI_REG_CMD
 | 
			
		||||
 | 
			
		||||
void ptphw_init(uint32_t increment, uint32_t addend)
 | 
			
		||||
{
 | 
			
		||||
    // multicast fogadás engedélyezése
 | 
			
		||||
    ETH_MACFilterConfigTypeDef filterConf;
 | 
			
		||||
    HAL_ETH_GetMACFilterConfig(&EthHandle, &filterConf);
 | 
			
		||||
    filterConf.PassAllMulticast = ENABLE;
 | 
			
		||||
    HAL_ETH_SetMACFilterConfig(&EthHandle, &filterConf);
 | 
			
		||||
 | 
			
		||||
    // timestamp engedélyezése
 | 
			
		||||
    ETH_EnablePTPTimeStamping(&EthHandle);
 | 
			
		||||
 | 
			
		||||
    vTaskDelay(pdMS_TO_TICKS(10));
 | 
			
		||||
 | 
			
		||||
    //ETH_EnablePTPTimeStamping(&EthHandle);
 | 
			
		||||
 | 
			
		||||
    // idő beállítása
 | 
			
		||||
    ETH_InitPTPTime(&EthHandle, 0, 0);
 | 
			
		||||
 | 
			
		||||
    // fine correction engedélyezése
 | 
			
		||||
    ETH_EnablePTPFineCorr(&EthHandle, true);
 | 
			
		||||
 | 
			
		||||
    // addend beállítása
 | 
			
		||||
    ETH_SetPTPAddend(&EthHandle, addend);
 | 
			
		||||
 | 
			
		||||
    // increment beállítása
 | 
			
		||||
    ETH_SetPTPSubsecondIncrement(&EthHandle, increment);
 | 
			
		||||
 | 
			
		||||
    //ETH_StartPTPPPSPulseTrain(&EthHandle, 500E+06, 1E+09);
 | 
			
		||||
    ETH_SetPTPPPSFreq(&EthHandle, ETH_PTP_PPS_1Hz);
 | 
			
		||||
    sFreq = 1;
 | 
			
		||||
 | 
			
		||||
    __HAL_RCC_GPIOG_CLK_ENABLE();
 | 
			
		||||
 | 
			
		||||
    // setup PPS-pin
 | 
			
		||||
    GPIO_InitTypeDef GPIO_InitStructure;
 | 
			
		||||
    GPIO_InitStructure.Pin = GPIO_PIN_8;
 | 
			
		||||
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
 | 
			
		||||
    GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
 | 
			
		||||
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
 | 
			
		||||
    GPIO_InitStructure.Pull = GPIO_NOPULL;
 | 
			
		||||
    HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
 | 
			
		||||
 | 
			
		||||
#ifdef CLI_REG_CMD
 | 
			
		||||
    // register cli commands
 | 
			
		||||
    ptphw_register_cli_commands();
 | 
			
		||||
#endif                          // CLI_REG_CMD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptphw_gettime(TimestampU * pTime)
 | 
			
		||||
{
 | 
			
		||||
    pTime->sec = EthHandle.Instance->MACSTSR;
 | 
			
		||||
    pTime->nanosec = EthHandle.Instance->MACSTNR & ETH_MACSTNR_TSSS;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								hw_port/ptp_port_stm32h743.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								hw_port/ptp_port_stm32h743.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
/*
 | 
			
		||||
 * ptp_port_tiva_tm4c1294.c
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: 2021. szept. 17.
 | 
			
		||||
 *      Author: epagris
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef HW_PORT_PTP_PORT_TIVA_TM4C1294_C_
 | 
			
		||||
#define HW_PORT_PTP_PORT_TIVA_TM4C1294_C_
 | 
			
		||||
 | 
			
		||||
#include "../timeutils.h"
 | 
			
		||||
 | 
			
		||||
void ptphw_init(uint32_t increment, uint32_t addend);   // initialize PTP hardware
 | 
			
		||||
void ptphw_gettime(TimestampU * pTime); // get time
 | 
			
		||||
 | 
			
		||||
#endif                          /* HW_PORT_PTP_PORT_TIVA_TM4C1294_C_ */
 | 
			
		||||
							
								
								
									
										30
									
								
								hw_port/ptp_port_tiva_tm4c1294.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								hw_port/ptp_port_tiva_tm4c1294.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
#include "ptp_port_tiva_tm4c1295.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include "driverlib/emac.h"
 | 
			
		||||
#include "driverlib/gpio.h"
 | 
			
		||||
#include "inc/hw_memmap.h"
 | 
			
		||||
#include "driverlib/pin_map.h"
 | 
			
		||||
 | 
			
		||||
void ptphw_init(uint32_t increment, uint32_t addend)
 | 
			
		||||
{
 | 
			
		||||
    // init clock
 | 
			
		||||
    EMACTimestampConfigSet(EMAC0_BASE, (EMAC_TS_ALL_RX_FRAMES | EMAC_TS_DIGITAL_ROLLOVER | EMAC_TS_PROCESS_IPV4_UDP | EMAC_TS_ALL | EMAC_TS_PTP_VERSION_2 | EMAC_TS_UPDATE_FINE),       // PTPv2 processing
 | 
			
		||||
                           increment);
 | 
			
		||||
    EMACTimestampAddendSet(EMAC0_BASE, addend);
 | 
			
		||||
    EMACTimestampEnable(EMAC0_BASE);
 | 
			
		||||
 | 
			
		||||
    // init PPS output
 | 
			
		||||
    GPIOPinTypePWM(GPIO_PORTG_AHB_BASE, GPIO_PIN_0);
 | 
			
		||||
    GPIOPinConfigure(GPIO_PG0_EN0PPS);
 | 
			
		||||
    EMACTimestampPPSSimpleModeSet(EMAC0_BASE, EMAC_PPS_1HZ);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptphw_gettime(TimestampU * pTime)
 | 
			
		||||
{
 | 
			
		||||
    pTime->sec = 0;
 | 
			
		||||
    pTime->nanosec = 0;
 | 
			
		||||
    EMACTimestampSysTimeGet(EMAC0_BASE, &(pTime->sec), &(pTime->nanosec));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								hw_port/ptp_port_tiva_tm4c1295.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								hw_port/ptp_port_tiva_tm4c1295.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
/*
 | 
			
		||||
 * ptp_port_tiva_tm4c1294.c
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: 2021. szept. 17.
 | 
			
		||||
 *      Author: epagris
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef HW_PORT_PTP_PORT_TIVA_TM4C1294_C_
 | 
			
		||||
#define HW_PORT_PTP_PORT_TIVA_TM4C1294_C_
 | 
			
		||||
 | 
			
		||||
#include "../timeutils.h"
 | 
			
		||||
 | 
			
		||||
void ptphw_init(uint32_t increment, uint32_t addend);   // initialize PTP hardware
 | 
			
		||||
void ptphw_gettime(TimestampU * pTime); // get time
 | 
			
		||||
 | 
			
		||||
#endif                          /* HW_PORT_PTP_PORT_TIVA_TM4C1294_C_ */
 | 
			
		||||
							
								
								
									
										100
									
								
								hw_port/simsrc/FreeRTOS_simulation.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								hw_port/simsrc/FreeRTOS_simulation.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,100 @@
 | 
			
		||||
#include "FreeRTOS_simulation.h"
 | 
			
		||||
 | 
			
		||||
#include <csignal>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
struct TmrInfo {
 | 
			
		||||
    std::string name;
 | 
			
		||||
    uint32_t timeout;
 | 
			
		||||
    bool singleShot;
 | 
			
		||||
    void *timerID;
 | 
			
		||||
    tmrcb cb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static std::map<timer_t, TmrInfo> tmrLut;
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
TimerHandle_t xTimerCreate(const char *name, TickType_t timeout, bool singleShot, void *timerID, tmrcb cb) {
 | 
			
		||||
    // create timer
 | 
			
		||||
    timer_t *pTmr = new timer_t;
 | 
			
		||||
    sigevent sev;
 | 
			
		||||
    //sev.sigev_notify = SIGEV_SIGNAL;
 | 
			
		||||
    sev.sigev_notify = SIGEV_THREAD;
 | 
			
		||||
    sev.sigev_signo = SIGRTMIN;
 | 
			
		||||
    sev.sigev_value.sival_ptr = pTmr;
 | 
			
		||||
    sev.sigev_notify_function = (void(*)(union sigval))cb;
 | 
			
		||||
    sev.sigev_notify_attributes = nullptr;
 | 
			
		||||
 | 
			
		||||
    if (timer_create(CLOCK_REALTIME, &sev, pTmr) != 0) {
 | 
			
		||||
        delete pTmr;
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // put callback function into the lookup-table
 | 
			
		||||
    TmrInfo info = {name, timeout, singleShot, timerID, cb};
 | 
			
		||||
 | 
			
		||||
    tmrLut[*pTmr] = info;
 | 
			
		||||
 | 
			
		||||
    return pTmr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BaseType_t xTimerDelete(TimerHandle_t xTimer, TickType_t xBlockTime) {
 | 
			
		||||
    // delete timer
 | 
			
		||||
    timer_delete(*xTimer);
 | 
			
		||||
 | 
			
		||||
    // remove callback from lut
 | 
			
		||||
    tmrLut.erase(*xTimer);
 | 
			
		||||
 | 
			
		||||
    // release timer ID resource
 | 
			
		||||
    delete xTimer;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BaseType_t xTimerStart(TimerHandle_t xTimer, TickType_t xBlockTime) {
 | 
			
		||||
    const TmrInfo &info = tmrLut.at(*xTimer);
 | 
			
		||||
 | 
			
		||||
    itimerspec its;
 | 
			
		||||
    its.it_value.tv_sec = info.timeout / 1000;
 | 
			
		||||
    its.it_value.tv_nsec = info.timeout % 1000;
 | 
			
		||||
 | 
			
		||||
    if (!info.singleShot) {
 | 
			
		||||
        its.it_interval = its.it_value;
 | 
			
		||||
    } else {
 | 
			
		||||
        its.it_interval.tv_sec = 0;
 | 
			
		||||
        its.it_interval.tv_nsec = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    timer_settime(*xTimer, 0, &its, nullptr);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BaseType_t xTimerStop(TimerHandle_t xTimer, TickType_t xBlockTime) {
 | 
			
		||||
    itimerspec its;
 | 
			
		||||
    its.it_interval.tv_sec = 0;
 | 
			
		||||
    its.it_interval.tv_nsec = 0;
 | 
			
		||||
    its.it_value = its.it_interval;
 | 
			
		||||
 | 
			
		||||
    timer_settime(*xTimer, 0, &its, nullptr);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void tmr_handler(int sig, siginfo_t *si, void *uc) {
 | 
			
		||||
    std::cout << "Timer!" << std::endl;
 | 
			
		||||
    signal(sig, SIG_IGN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//void FreeRTOS_simulation_init() {
 | 
			
		||||
//    struct sigaction sa;
 | 
			
		||||
//    sa.sa_flags = SA_SIGINFO;
 | 
			
		||||
//    sa.sa_sigaction = tmr_handler;
 | 
			
		||||
//    sigemptyset(&sa.sa_mask);
 | 
			
		||||
//    sigaction(SIGRTMIN, &sa, nullptr);
 | 
			
		||||
//}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								hw_port/simsrc/FreeRTOS_simulation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								hw_port/simsrc/FreeRTOS_simulation.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
#ifndef FLEXPTP_SIM_FREERTOS_SIMULATION_H
 | 
			
		||||
#define FLEXPTP_SIM_FREERTOS_SIMULATION_H
 | 
			
		||||
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    typedef timer_t *TimerHandle_t;
 | 
			
		||||
    typedef void (*tmrcb)(TimerHandle_t tmr);
 | 
			
		||||
 | 
			
		||||
    typedef uint32_t TickType_t;
 | 
			
		||||
    typedef uint32_t BaseType_t;
 | 
			
		||||
#define pdMS_TO_TICKS(x) (x)
 | 
			
		||||
 | 
			
		||||
    TimerHandle_t xTimerCreate(const char *name, TickType_t timeout, bool singleShot, void *timerID, tmrcb cb);
 | 
			
		||||
    BaseType_t xTimerDelete(TimerHandle_t xTimer, TickType_t xBlockTime);
 | 
			
		||||
    BaseType_t xTimerStart(TimerHandle_t xTimer, TickType_t xBlockTime);
 | 
			
		||||
    BaseType_t xTimerStop(TimerHandle_t xTimer, TickType_t xBlockTime);
 | 
			
		||||
 | 
			
		||||
//typedef Timer * TimerHandle_t;
 | 
			
		||||
 | 
			
		||||
//void FreeRTOS_simulation_init();
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif                          //FLEXPTP_SIM_FREERTOS_SIMULATION_H
 | 
			
		||||
							
								
								
									
										29
									
								
								hw_port/simsrc/PtpClock.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								hw_port/simsrc/PtpClock.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
#include "PtpClock.h"
 | 
			
		||||
 | 
			
		||||
PtpClock::PtpClock(const PtpClock::ClockProperties &ckProps) : mCkProps(ckProps) {}
 | 
			
		||||
 | 
			
		||||
void PtpClock::setTime(uint32_t s, uint32_t ns) {
 | 
			
		||||
    mTime = s * C_NANO_PREFIX + ns * C_NANO_PREFIX;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PtpClock::updateTime(uint32_t s, uint32_t ns, bool dir) {
 | 
			
		||||
    int64_t diff = s * C_NANO_PREFIX + ns;
 | 
			
		||||
    diff *= dir ? +1 : -1;
 | 
			
		||||
    mTime += diff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PtpClock::Timestamp PtpClock::getTime() const {
 | 
			
		||||
    return { mTime / C_NANO_PREFIX, (uint32_t)(mTime % C_NANO_PREFIX) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PtpClock::setAddend(uint64_t addend) {
 | 
			
		||||
    mAddend = addend;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t PtpClock::getAddend() const {
 | 
			
		||||
    return mAddend;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PtpClock::advanceClock(uint32_t s, uint32_t ns) {
 | 
			
		||||
    mTime += (s * C_NANO_PREFIX + ns) * (mAddend / mCkProps.ckNomAddend);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								hw_port/simsrc/PtpClock.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								hw_port/simsrc/PtpClock.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
#ifndef FLEXPTP_SIM_PTPCLOCK_H
 | 
			
		||||
#define FLEXPTP_SIM_PTPCLOCK_H
 | 
			
		||||
 | 
			
		||||
#include <chrono>
 | 
			
		||||
 | 
			
		||||
class PtpClock {
 | 
			
		||||
 public:
 | 
			
		||||
    using ClockProperties = struct {
 | 
			
		||||
        uint64_t ckDivOF;       // clock division overflow
 | 
			
		||||
        uint64_t ckNomAddend;   // nominal addend value
 | 
			
		||||
        double ckVariance_nsns; // clock variance in ns square
 | 
			
		||||
    };
 | 
			
		||||
    using Timestamp = struct {
 | 
			
		||||
        uint64_t sec;
 | 
			
		||||
        uint32_t ns;
 | 
			
		||||
    };
 | 
			
		||||
 public:
 | 
			
		||||
    static constexpr uint32_t C_NANO_PREFIX = 1000000000;
 | 
			
		||||
 private:
 | 
			
		||||
     uint64_t mTime {
 | 
			
		||||
    };                          // slave clock time
 | 
			
		||||
    uint64_t mAddend {
 | 
			
		||||
    };                          // addend value
 | 
			
		||||
 | 
			
		||||
    const ClockProperties mCkProps;     // slave clock overflow
 | 
			
		||||
 public:
 | 
			
		||||
    explicit PtpClock(const ClockProperties & ckProps); // slave clock overflow
 | 
			
		||||
    void setTime(uint32_t s, uint32_t ns);      // set time
 | 
			
		||||
    void updateTime(uint32_t s, uint32_t ns, bool dir); // update time by value
 | 
			
		||||
    Timestamp getTime() const;  // get time
 | 
			
		||||
    void setAddend(uint64_t addend);    // set addend
 | 
			
		||||
    uint64_t getAddend() const; // get addend
 | 
			
		||||
    void advanceClock(uint32_t s, uint32_t ns); // advance clock with given time difference
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif                          //FLEXPTP_SIM_PTPCLOCK_H
 | 
			
		||||
							
								
								
									
										21
									
								
								hw_port/simsrc/PtpMasterClock.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								hw_port/simsrc/PtpMasterClock.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by epagris on 2022.10.22..
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "PtpMasterClock.h"
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
void PtpMasterClock::setup(const PtpMasterClock::PtpMasterClockSettings &settings) {
 | 
			
		||||
    mSettings = settings;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PtpMasterClock::start() {
 | 
			
		||||
    mBeaconThread = std::make_shared<std::thread>(&PtpMasterClock::mBeaconThread, this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PtpMasterClock::mBeaconThread_CB() {
 | 
			
		||||
    while (mRunning) {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								hw_port/simsrc/PtpMasterClock.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								hw_port/simsrc/PtpMasterClock.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
			
		||||
#ifndef FLEXPTP_SIM_PTPMASTERCLOCK_H
 | 
			
		||||
#define FLEXPTP_SIM_PTPMASTERCLOCK_H
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <list>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include "PtpSlaveClock.h"
 | 
			
		||||
 | 
			
		||||
class PtpMasterClock {
 | 
			
		||||
 public:
 | 
			
		||||
    using PtpMasterClockSettings = struct {
 | 
			
		||||
        uint16_t originCurrentUTCOffset;
 | 
			
		||||
        uint8_t priority1;
 | 
			
		||||
        uint8_t grandmasterClockClass;
 | 
			
		||||
        uint8_t grandmasterClockAccuracy;
 | 
			
		||||
        uint16_t grandmasterClockVariance;
 | 
			
		||||
        uint8_t priority2;
 | 
			
		||||
        uint64_t grandmasterClockIdentity;
 | 
			
		||||
        uint16_t localStepsRemoved;
 | 
			
		||||
        uint8_t timeSource;
 | 
			
		||||
    };
 | 
			
		||||
 private:
 | 
			
		||||
     std::list < std::shared_ptr < PtpSlaveClock >> mSlvs;      // slave clocks connected to this master clock
 | 
			
		||||
    PtpMasterClockSettings mSettings;   // master clock settings
 | 
			
		||||
     std::shared_ptr < std::thread > mBeaconThread;     // thread handling multicasted message transmission
 | 
			
		||||
    bool mRunning {
 | 
			
		||||
    };
 | 
			
		||||
    void mBeaconThread_CB();    // function running in the thread
 | 
			
		||||
 public:
 | 
			
		||||
     PtpMasterClock() = default;
 | 
			
		||||
    void setup(const PtpMasterClockSettings & settings);        // setup master clock
 | 
			
		||||
    void start();               // start master clock
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif                          //FLEXPTP_SIM_PTPMASTERCLOCK_H
 | 
			
		||||
							
								
								
									
										5
									
								
								hw_port/simsrc/PtpSlaveClock.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								hw_port/simsrc/PtpSlaveClock.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
//
 | 
			
		||||
// Created by epagris on 2022.10.22..
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
#include "PtpSlaveClock.h"
 | 
			
		||||
							
								
								
									
										8
									
								
								hw_port/simsrc/PtpSlaveClock.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								hw_port/simsrc/PtpSlaveClock.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
#ifndef FLEXPTP_SIM_PTPSLAVECLOCK_H
 | 
			
		||||
#define FLEXPTP_SIM_PTPSLAVECLOCK_H
 | 
			
		||||
 | 
			
		||||
class PtpSlaveClock {
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif                          //FLEXPTP_SIM_PTPSLAVECLOCK_H
 | 
			
		||||
							
								
								
									
										19
									
								
								hw_port/simsrc/lwip_simulation.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								hw_port/simsrc/lwip_simulation.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
#include "lwip_simulation.h"
 | 
			
		||||
 | 
			
		||||
extern "C" {
 | 
			
		||||
 | 
			
		||||
struct netif netif_default_obj = {{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}};
 | 
			
		||||
struct netif *netif_default = &netif_default_obj;
 | 
			
		||||
 | 
			
		||||
pbuf *pbuf_alloc(enum pbuf_layer layer, uint16_t length, enum pbuf_type type) {
 | 
			
		||||
    pbuf *p = new pbuf;
 | 
			
		||||
    p->payload = new uint8_t[length];
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pbuf_free(pbuf *p) {
 | 
			
		||||
    delete[] (uint8_t *) p->payload;
 | 
			
		||||
    delete p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								hw_port/simsrc/lwip_simulation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								hw_port/simsrc/lwip_simulation.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
#ifndef FLEXPTP_SIM_LWIP_SIMULATION_H
 | 
			
		||||
#define FLEXPTP_SIM_LWIP_SIMULATION_H
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
 | 
			
		||||
    typedef struct ip4_addr {
 | 
			
		||||
        uint32_t addr;
 | 
			
		||||
    } ip4_addr_t;
 | 
			
		||||
 | 
			
		||||
    typedef ip4_addr_t ip_addr_t;
 | 
			
		||||
 | 
			
		||||
#define ipaddr_addr(x) inet_addr(x)
 | 
			
		||||
 | 
			
		||||
    enum pbuf_layer {
 | 
			
		||||
        PBUF_TRANSPORT, PBUF_IP, PBUF_LINK, PBUF_RAW_TX,
 | 
			
		||||
        PBUF_RAW
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum pbuf_type {
 | 
			
		||||
        PBUF_RAM, PBUF_ROM, PBUF_REF, PBUF_POOL
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
/** Main packet buffer struct */
 | 
			
		||||
    struct pbuf {
 | 
			
		||||
        void *payload;
 | 
			
		||||
        /*uint16_t tot_len;
 | 
			
		||||
           uint16_t len; */
 | 
			
		||||
        uint32_t time_s, time_ns;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct pbuf *pbuf_alloc(enum pbuf_layer layer, uint16_t length, enum pbuf_type type);
 | 
			
		||||
    void pbuf_free(struct pbuf *p);
 | 
			
		||||
 | 
			
		||||
    struct netif {
 | 
			
		||||
        uint8_t hwaddr[6];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    extern struct netif *netif_default;
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif                          //FLEXPTP_SIM_LWIP_SIMULATION_H
 | 
			
		||||
							
								
								
									
										60
									
								
								logging.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								logging.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
			
		||||
#include "logging.h"
 | 
			
		||||
 | 
			
		||||
#include <flexptp_options.h>
 | 
			
		||||
 | 
			
		||||
#include "ptp_core.h"
 | 
			
		||||
 | 
			
		||||
#define S (gPtpCoreState)
 | 
			
		||||
 | 
			
		||||
// enable/disable general logging
 | 
			
		||||
static void ptp_log_def_en(bool en)
 | 
			
		||||
{
 | 
			
		||||
    if (en) {                   // on turning on
 | 
			
		||||
        MSG("\n\nT1 [s] | T1 [ns] | T4 [s] | T4 [ns] | Dt [s] | Dt [ns] | Dt [tick] | Addend\n\n");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ------------------------
 | 
			
		||||
 | 
			
		||||
// PTP log pair
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int id;                     // ID of log type
 | 
			
		||||
    void (*logEnFn)(bool);      // callback function on turning on/off logging
 | 
			
		||||
    bool *en;                   // variable storing log state
 | 
			
		||||
} PtpLogPair;
 | 
			
		||||
 | 
			
		||||
static PtpLogPair sLogTable[PTP_LOG_N + 1] = {
 | 
			
		||||
    {PTP_LOG_DEF, ptp_log_def_en, &(S.logging.def)},
 | 
			
		||||
    {PTP_LOG_CORR_FIELD, NULL, &(S.logging.corr)},
 | 
			
		||||
    {PTP_LOG_TIMESTAMPS, NULL, &(S.logging.timestamps)},
 | 
			
		||||
    {PTP_LOG_INFO, NULL, &(S.logging.info)},
 | 
			
		||||
    {PTP_LOG_LOCKED_STATE, NULL, &(S.logging.locked)},
 | 
			
		||||
    {-1, NULL, NULL}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void ptp_enable_logging(int logId, bool en)
 | 
			
		||||
{
 | 
			
		||||
    PtpLogPair *pIter = sLogTable;
 | 
			
		||||
    while (pIter->id != -1) {
 | 
			
		||||
        if (pIter->id == logId && *(pIter->en) != en) { // if callback is found and changing state indeed
 | 
			
		||||
            if (pIter->logEnFn != NULL) {       // callback function is not necessary
 | 
			
		||||
                pIter->logEnFn(en);
 | 
			
		||||
            }
 | 
			
		||||
            *(pIter->en) = en;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        pIter++;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_disable_all_logging()
 | 
			
		||||
{
 | 
			
		||||
    PtpLogPair *pIter = sLogTable;
 | 
			
		||||
    while (pIter->logEnFn != NULL) {
 | 
			
		||||
        if (pIter->logEnFn != NULL) {
 | 
			
		||||
            pIter->logEnFn(false);
 | 
			
		||||
        }
 | 
			
		||||
        *(pIter->en) = false;
 | 
			
		||||
        pIter++;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								logging.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								logging.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
#ifndef FLEXPTP_LOGGING_H_
 | 
			
		||||
#define FLEXPTP_LOGGING_H_
 | 
			
		||||
 | 
			
		||||
#include "ptp_core.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    PTP_LOG_DEF,
 | 
			
		||||
    PTP_LOG_CORR_FIELD,
 | 
			
		||||
    PTP_LOG_TIMESTAMPS,
 | 
			
		||||
    PTP_LOG_INFO,
 | 
			
		||||
    PTP_LOG_LOCKED_STATE,
 | 
			
		||||
    PTP_LOG_N
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void ptp_enable_logging(int logId, bool en);
 | 
			
		||||
void ptp_disable_all_logging();
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_LOGGING_H_ */
 | 
			
		||||
							
								
								
									
										243
									
								
								msg_utils.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								msg_utils.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,243 @@
 | 
			
		||||
/* (C) András Wiesner, 2020-2022 */
 | 
			
		||||
 | 
			
		||||
#include "msg_utils.h"
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "ptp_defs.h"
 | 
			
		||||
#include "format_utils.h"
 | 
			
		||||
 | 
			
		||||
// load ptp flags from bitfield
 | 
			
		||||
void ptp_load_flags(PTPFlags * pFlags, uint16_t bitfield)
 | 
			
		||||
{
 | 
			
		||||
#define GET_FLAG_FROM_BITFIELD(flag,n) (pFlags->flag) = (bitfield >> (n)) & 1
 | 
			
		||||
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(PTP_SECURITY, 15);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(PTP_ProfileSpecific_2, 14);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(PTP_ProfileSpecific_1, 13);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(PTP_UNICAST, 10);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(PTP_TWO_STEP, 9);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(PTP_ALTERNATE_MASTER, 8);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(FREQUENCY_TRACEABLE, 7);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(TIME_TRACEABLE, 4);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(PTP_TIMESCALE, 3);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(PTP_UTC_REASONABLE, 2);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(PTP_LI_59, 1);
 | 
			
		||||
    GET_FLAG_FROM_BITFIELD(PTP_LI_61, 0);
 | 
			
		||||
 | 
			
		||||
/*	pFlags->PTP_SECURITY = (bitfield >> 15) & 1;
 | 
			
		||||
	pFlags->PTP_ProfileSpecific_2 = (bitfield >> 14) & 1;
 | 
			
		||||
	pFlags->PTP_ProfileSpecific_1 = (bitfield >> 13) & 1;
 | 
			
		||||
 | 
			
		||||
	pFlags->PTP_UNICAST = (bitfield >> 10) & 1;
 | 
			
		||||
	pFlags->PTP_TWO_STEP = (bitfield >> 9) & 1;
 | 
			
		||||
	pFlags->PTP_ALTERNATE_MASTER = (bitfield >> 8) & 1;
 | 
			
		||||
 | 
			
		||||
	pFlags->FREQUENCY_TRACEABLE = (bitfield >> 5) & 1;
 | 
			
		||||
	pFlags->TIME_TRACEABLE = (bitfield >> 4) & 1;
 | 
			
		||||
 | 
			
		||||
	pFlags->PTP_TIMESCALE = (bitfield >> 3) & 1;
 | 
			
		||||
	pFlags->PTP_UTC_REASONABLE = (bitfield >> 2) & 1;
 | 
			
		||||
	pFlags->PTP_LI_59 = (bitfield >> 1) & 1;
 | 
			
		||||
	pFlags->PTP_LI_61 = (bitfield >> 0) & 1;*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// write flags to bitfield
 | 
			
		||||
uint16_t ptp_write_flags(PTPFlags * pFlags)
 | 
			
		||||
{
 | 
			
		||||
#define SET_BIT_IN_FLAG_BITFIELD(flag,n) bitfield |= (pFlags->flag) ? (1 << (n)) : 0
 | 
			
		||||
 | 
			
		||||
    uint16_t bitfield = 0;
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(PTP_SECURITY, 15);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(PTP_ProfileSpecific_2, 14);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(PTP_ProfileSpecific_1, 13);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(PTP_UNICAST, 10);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(PTP_TWO_STEP, 9);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(PTP_ALTERNATE_MASTER, 8);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(FREQUENCY_TRACEABLE, 7);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(TIME_TRACEABLE, 4);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(PTP_TIMESCALE, 3);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(PTP_UTC_REASONABLE, 2);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(PTP_LI_59, 1);
 | 
			
		||||
    SET_BIT_IN_FLAG_BITFIELD(PTP_LI_61, 0);
 | 
			
		||||
 | 
			
		||||
    return bitfield;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// extract fields from a PTP header
 | 
			
		||||
void ptp_extract_header(PtpHeader * pHeader, const void *pPayload)
 | 
			
		||||
{
 | 
			
		||||
    // cast header to byte accessible form
 | 
			
		||||
    uint8_t *p = (uint8_t *) pPayload;
 | 
			
		||||
 | 
			
		||||
    uint16_t flags;
 | 
			
		||||
 | 
			
		||||
    // copy header fields
 | 
			
		||||
    memcpy(&pHeader->messageType, p + 0, 1);
 | 
			
		||||
    memcpy(&pHeader->versionPTP, p + 1, 1);
 | 
			
		||||
    memcpy(&pHeader->messageLength, p + 2, 2);
 | 
			
		||||
    memcpy(&pHeader->domainNumber, p + 4, 1);
 | 
			
		||||
    memcpy(&flags, p + 6, 2);
 | 
			
		||||
    memcpy(&pHeader->correction_ns, p + 8, 8);
 | 
			
		||||
    memcpy(&pHeader->clockIdentity, p + 20, 8);
 | 
			
		||||
    memcpy(&pHeader->sourcePortID, p + 28, 2);
 | 
			
		||||
    memcpy(&pHeader->sequenceID, p + 30, 2);
 | 
			
		||||
    memcpy(&pHeader->control, p + 32, 1);
 | 
			
		||||
    memcpy(&pHeader->logMessagePeriod, p + 33, 1);
 | 
			
		||||
 | 
			
		||||
    pHeader->transportSpecific = (0xf0 & pHeader->messageType) >> 4;
 | 
			
		||||
    pHeader->messageType &= 0x0f;
 | 
			
		||||
 | 
			
		||||
    // read flags
 | 
			
		||||
    ptp_load_flags(&pHeader->flags, ntohs(flags));
 | 
			
		||||
 | 
			
		||||
    // read correction field
 | 
			
		||||
    pHeader->correction_subns = ntohll(pHeader->correction_ns) & 0xffff;
 | 
			
		||||
    pHeader->correction_ns = ntohll(pHeader->correction_ns) >> 16;
 | 
			
		||||
 | 
			
		||||
    pHeader->messageLength = ntohs(pHeader->messageLength);
 | 
			
		||||
    pHeader->sourcePortID = ntohs(pHeader->sourcePortID);
 | 
			
		||||
    pHeader->sequenceID = ntohs(pHeader->sequenceID);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// extract announce message
 | 
			
		||||
void ptp_extract_announce_message(PtpAnnounceBody * pAnnounce, void *pPayload)
 | 
			
		||||
{
 | 
			
		||||
    // cast header to byte accessible form
 | 
			
		||||
    uint8_t *p = (uint8_t *) pPayload + (PTP_HEADER_LENGTH + PTP_TIMESTAMP_LENGTH);
 | 
			
		||||
 | 
			
		||||
    // copy header fields
 | 
			
		||||
    memcpy(&pAnnounce->originCurrentUTCOffset, p + 0, 2);
 | 
			
		||||
    memcpy(&pAnnounce->priority1, p + 3, 1);
 | 
			
		||||
    memcpy(&pAnnounce->grandmasterClockClass, p + 4, 1);
 | 
			
		||||
    memcpy(&pAnnounce->grandmasterClockAccuracy, p + 5, 1);
 | 
			
		||||
    memcpy(&pAnnounce->grandmasterClockVariance, p + 6, 2);
 | 
			
		||||
    memcpy(&pAnnounce->priority2, p + 8, 1);
 | 
			
		||||
    memcpy(&pAnnounce->grandmasterClockIdentity, p + 9, 8);
 | 
			
		||||
    memcpy(&pAnnounce->localStepsRemoved, p + 17, 2);
 | 
			
		||||
    memcpy(&pAnnounce->timeSource, p + 19, 1);
 | 
			
		||||
 | 
			
		||||
    pAnnounce->originCurrentUTCOffset = ntohs(pAnnounce->originCurrentUTCOffset);
 | 
			
		||||
    pAnnounce->grandmasterClockVariance = ntohs(pAnnounce->grandmasterClockVariance);
 | 
			
		||||
    pAnnounce->grandmasterClockIdentity = ntohll(pAnnounce->grandmasterClockIdentity);
 | 
			
		||||
    pAnnounce->localStepsRemoved = ntohs(pAnnounce->localStepsRemoved);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// construct binary header from header structure
 | 
			
		||||
void ptp_construct_binary_header(void *pData, const PtpHeader * pHeader)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t *p = (uint8_t *) pData;
 | 
			
		||||
    uint8_t firstByte;
 | 
			
		||||
 | 
			
		||||
    // host->network
 | 
			
		||||
    uint16_t messageLength = htons(pHeader->messageLength);
 | 
			
		||||
    uint16_t sourcePortID = htons(pHeader->sourcePortID);
 | 
			
		||||
    uint16_t sequenceID = htons(pHeader->sequenceID);
 | 
			
		||||
 | 
			
		||||
    // fill in flags FIXME
 | 
			
		||||
    uint16_t flags = htons(ptp_write_flags(&pHeader->flags));   // convert from header fields
 | 
			
		||||
 | 
			
		||||
    // fill in correction value
 | 
			
		||||
    uint64_t correction = htonll((pHeader->correction_ns << 16) | (pHeader->correction_subns)); // TODO: ...
 | 
			
		||||
 | 
			
		||||
    // copy fields
 | 
			
		||||
    firstByte = (pHeader->transportSpecific << 4) | (pHeader->messageType & 0x0f);
 | 
			
		||||
    memcpy(p, &firstByte, 1);
 | 
			
		||||
    memcpy(p + 1, &pHeader->versionPTP, 1);
 | 
			
		||||
    memcpy(p + 2, &messageLength, 2);
 | 
			
		||||
    memcpy(p + 4, &pHeader->domainNumber, 1);
 | 
			
		||||
    memcpy(p + 6, &flags, 2);
 | 
			
		||||
    memcpy(p + 8, &correction, 8);
 | 
			
		||||
    memcpy(p + 20, &pHeader->clockIdentity, 8);
 | 
			
		||||
    memcpy(p + 28, &sourcePortID, 2);
 | 
			
		||||
    memcpy(p + 30, &sequenceID, 2);
 | 
			
		||||
    memcpy(p + 32, &pHeader->control, 1);
 | 
			
		||||
    memcpy(p + 33, &pHeader->logMessagePeriod, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// write n timestamps following the header in to packet
 | 
			
		||||
void ptp_write_binary_timestamps(void *pPayload, TimestampI * ts, uint8_t n)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t *p = ((uint8_t *) pPayload) + PTP_HEADER_LENGTH;
 | 
			
		||||
 | 
			
		||||
    // write n times
 | 
			
		||||
    uint8_t i;
 | 
			
		||||
    for (i = 0; i < n; i++) {
 | 
			
		||||
        // get timestamp data
 | 
			
		||||
        uint64_t sec = htonll(ts->sec << 16);
 | 
			
		||||
        uint64_t nanosec = htonl(ts->nanosec);
 | 
			
		||||
 | 
			
		||||
        // fill in time data
 | 
			
		||||
        memcpy(p, &sec, 6);     // 48-bit
 | 
			
		||||
        p += 6;
 | 
			
		||||
 | 
			
		||||
        memcpy(p, &nanosec, 4);
 | 
			
		||||
        p += 4;
 | 
			
		||||
 | 
			
		||||
        // step onto next element
 | 
			
		||||
        ts++;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// extract n timestamps from a message
 | 
			
		||||
void ptp_extract_timestamps(TimestampI * ts, void *pPayload, uint8_t n)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t *p = ((uint8_t *) pPayload) + PTP_HEADER_LENGTH;    // pointer at the beginning of first timestamp
 | 
			
		||||
 | 
			
		||||
    // read n times
 | 
			
		||||
    uint8_t i;
 | 
			
		||||
    for (i = 0; i < n; i++) {
 | 
			
		||||
        // seconds
 | 
			
		||||
        ts->sec = 0;
 | 
			
		||||
        memcpy(&ts->sec, p, 6); // 48-bit
 | 
			
		||||
        p += 6;
 | 
			
		||||
 | 
			
		||||
        // nanoseconds
 | 
			
		||||
        memcpy(&ts->nanosec, p, 4);
 | 
			
		||||
        p += 4;
 | 
			
		||||
 | 
			
		||||
        // network->host
 | 
			
		||||
        ts->sec = ntohll(ts->sec << 16);
 | 
			
		||||
        ts->nanosec = ntohl(ts->nanosec);
 | 
			
		||||
 | 
			
		||||
        // step to next timestamp
 | 
			
		||||
        ts++;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// extract Delay_Resp ID data
 | 
			
		||||
void ptp_read_delay_resp_id_data(Delay_RespIdentification * pDRData, void *pPayload)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t *p = (uint8_t *) pPayload;
 | 
			
		||||
    memcpy(&pDRData->requestingSourceClockIdentity, p + 44, 8);
 | 
			
		||||
    memcpy(&pDRData->requestingSourcePortIdentity, p + 52, 2);
 | 
			
		||||
 | 
			
		||||
    // network->host
 | 
			
		||||
    pDRData->requestingSourcePortIdentity = ntohs(pDRData->requestingSourcePortIdentity);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// insert Delay_Resp ID data
 | 
			
		||||
void ptp_write_delay_resp_id_data(void *pPayload, const Delay_RespIdentification * pDRData)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t *p = (uint8_t *) pPayload;
 | 
			
		||||
    uint16_t reqSrcPortId = htons(pDRData->requestingSourcePortIdentity);       // host->network
 | 
			
		||||
    memcpy(p + 44, &pDRData->requestingSourceClockIdentity, 8);
 | 
			
		||||
    memcpy(p + 52, &reqSrcPortId, 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// clear flag structure
 | 
			
		||||
void ptp_clear_flags(PTPFlags * pFlags)
 | 
			
		||||
{
 | 
			
		||||
    memset(pFlags, 0, sizeof(PTPFlags));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// construct Sync message (TWO_STEP-mode only!)
 | 
			
		||||
void ptp_construct_binary_sync(void *pData, const PtpHeader * pHeader)
 | 
			
		||||
{
 | 
			
		||||
    // insert header
 | 
			
		||||
    ptp_construct_binary_header(pData, pHeader);
 | 
			
		||||
 | 
			
		||||
    // insert empty timestamps
 | 
			
		||||
    TimestampI zeroTs = { 0, 0 };
 | 
			
		||||
    ptp_write_binary_timestamps(pData, &zeroTs, 1);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								msg_utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								msg_utils.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
/* (C) András Wiesner, 2020-2022 */
 | 
			
		||||
 | 
			
		||||
#ifndef FLEXPTP_MSG_UTILS_H_
 | 
			
		||||
#define FLEXPTP_MSG_UTILS_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "ptp_types.h"
 | 
			
		||||
#include "timeutils.h"
 | 
			
		||||
 | 
			
		||||
void ptp_load_flags(PTPFlags * pFlags, uint16_t bitfield);      // load ptp flags from bitfield
 | 
			
		||||
void ptp_extract_header(PtpHeader * pHeader, const void *pPayload);     // extract fields from a PTP header
 | 
			
		||||
void ptp_extract_announce_message(PtpAnnounceBody * pAnnounce, void *pPayload); // extract announce message
 | 
			
		||||
void ptp_construct_binary_header(void *pData, const PtpHeader * pHeader);       // construct binary header from header structure
 | 
			
		||||
void ptp_write_binary_timestamps(void *pPayload, TimestampI * ts, uint8_t n);   // write n timestamps following the header in to packet
 | 
			
		||||
void ptp_extract_timestamps(TimestampI * ts, void *pPayload, uint8_t n);        // extract n timestamps from a message
 | 
			
		||||
void ptp_read_delay_resp_id_data(Delay_RespIdentification * pDRData, void *pPayload);   // extract Delay_Resp ID data
 | 
			
		||||
void ptp_write_delay_resp_id_data(void *pPayload, const Delay_RespIdentification * pDRData);    // insert Delay_Resp ID data
 | 
			
		||||
void ptp_clear_flags(PTPFlags * pFlags);        // clear flag structure
 | 
			
		||||
void ptp_construct_binary_sync(void *pData, const PtpHeader * pHeader); // create Sync message
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_MSG_UTILS_H_ */
 | 
			
		||||
							
								
								
									
										610
									
								
								ptp_core.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										610
									
								
								ptp_core.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,610 @@
 | 
			
		||||
/* (C) András Wiesner, 2020-2022 */
 | 
			
		||||
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
#include <flexptp_options.h>
 | 
			
		||||
 | 
			
		||||
#include "ptp_core.h"
 | 
			
		||||
 | 
			
		||||
#ifndef SIMULATION
 | 
			
		||||
#include "FreeRTOS.h"
 | 
			
		||||
#include "timers.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "ptp_defs.h"
 | 
			
		||||
#include "ptp_types.h"
 | 
			
		||||
#include "clock_utils.h"
 | 
			
		||||
#include "format_utils.h"
 | 
			
		||||
#include "msg_utils.h"
 | 
			
		||||
#include "sbmc.h"
 | 
			
		||||
#include "stats.h"
 | 
			
		||||
#include "timeutils.h"
 | 
			
		||||
#include "cli_cmds.h"
 | 
			
		||||
#include "logging.h"
 | 
			
		||||
 | 
			
		||||
#ifndef SIMULATION
 | 
			
		||||
#include "ptp_msg_tx.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// --------------
 | 
			
		||||
 | 
			
		||||
// --------------
 | 
			
		||||
 | 
			
		||||
void ptp_init();
 | 
			
		||||
 | 
			
		||||
// global state
 | 
			
		||||
PtpCoreState gPtpCoreState;
 | 
			
		||||
#define S (gPtpCoreState)
 | 
			
		||||
 | 
			
		||||
static PtpHeader sDelayReqHeader;       // header for sending Delay_Reg messages
 | 
			
		||||
 | 
			
		||||
static SyncCallback sSyncCallback = NULL;       // callback function on synchronization
 | 
			
		||||
 | 
			
		||||
// --------------------------
 | 
			
		||||
 | 
			
		||||
#define T1 (0)
 | 
			
		||||
#define T2 (1)
 | 
			
		||||
#define T3 (2)
 | 
			
		||||
#define T4 (3)
 | 
			
		||||
 | 
			
		||||
// --------------------------
 | 
			
		||||
 | 
			
		||||
void ptp_reset();
 | 
			
		||||
 | 
			
		||||
// --------------------------
 | 
			
		||||
 | 
			
		||||
void ptp_set_sync_callback(SyncCallback syncCB)
 | 
			
		||||
{
 | 
			
		||||
    sSyncCallback = syncCB;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ptp_sbmc_tmr_tick(TimerHandle_t timer);
 | 
			
		||||
static void ptp_delreq_tmr_tick(TimerHandle_t xTimer);
 | 
			
		||||
 | 
			
		||||
//#define RESP_TIMEOUT (2000) // allowed maximal Delay_Resp response time
 | 
			
		||||
#define SBMC_TICKRATE (1000)    // 1000ms period for SBMC-ticking
 | 
			
		||||
 | 
			
		||||
void ptp_create_timers()
 | 
			
		||||
{
 | 
			
		||||
    // create smbc timer
 | 
			
		||||
    S.timers.sbmc = xTimerCreate("sbmctimer", pdMS_TO_TICKS(SBMC_TICKRATE),     // timeout
 | 
			
		||||
                                 true,  // timer operates in repeat mode
 | 
			
		||||
                                 (void *)2,     // ID
 | 
			
		||||
                                 ptp_sbmc_tmr_tick);    // callback-function
 | 
			
		||||
 | 
			
		||||
    // create delreq timer
 | 
			
		||||
    S.timers.delreq = xTimerCreate("delreq", pdMS_TO_TICKS(ptp_logi2ms(0)), true, (void *)3, ptp_delreq_tmr_tick);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_delete_timers()
 | 
			
		||||
{
 | 
			
		||||
    xTimerDelete(S.timers.sbmc, 0);
 | 
			
		||||
    xTimerDelete(S.timers.delreq, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// initialize Delay_Req header
 | 
			
		||||
void ptp_init_delay_req_header()
 | 
			
		||||
{
 | 
			
		||||
    sDelayReqHeader.messageType = S.profile.delayMechanism == PTP_DM_E2E ? PTP_MT_Delay_Req : PTP_MT_PDelay_Req;
 | 
			
		||||
    sDelayReqHeader.transportSpecific = (uint8_t) S.profile.transportSpecific;
 | 
			
		||||
    sDelayReqHeader.versionPTP = 2;     // PTPv2
 | 
			
		||||
    sDelayReqHeader.messageLength = PTP_HEADER_LENGTH + PTP_TIMESTAMP_LENGTH + (S.profile.delayMechanism == PTP_DM_P2P ? PTP_TIMESTAMP_LENGTH : 0);
 | 
			
		||||
    sDelayReqHeader.domainNumber = S.profile.domainNumber;
 | 
			
		||||
    ptp_clear_flags(&(sDelayReqHeader.flags));  // no flags
 | 
			
		||||
    sDelayReqHeader.correction_ns = 0;
 | 
			
		||||
    sDelayReqHeader.correction_subns = 0;
 | 
			
		||||
 | 
			
		||||
    memcpy(&sDelayReqHeader.clockIdentity, &S.hwoptions.clockIdentity, 8);
 | 
			
		||||
 | 
			
		||||
    sDelayReqHeader.sourcePortID = 1;   // TODO? No more ports...
 | 
			
		||||
    sDelayReqHeader.sequenceID = 0;     // will change in every sync cycle
 | 
			
		||||
    sDelayReqHeader.control = S.profile.delayMechanism == PTP_DM_E2E ? PTP_CON_Delay_Req : PTP_CON_Other;
 | 
			
		||||
    sDelayReqHeader.logMessagePeriod = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// --------------------------------------
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_SERVO_OFFSET (2800)
 | 
			
		||||
 | 
			
		||||
// initialize PTP module
 | 
			
		||||
void ptp_init()
 | 
			
		||||
{
 | 
			
		||||
    // create clock identity
 | 
			
		||||
    ptp_create_clock_identity();
 | 
			
		||||
 | 
			
		||||
    // seed the randomizer
 | 
			
		||||
    srand(S.hwoptions.clockIdentity);
 | 
			
		||||
 | 
			
		||||
    // reset options
 | 
			
		||||
    nsToTsI(&S.hwoptions.offset, DEFAULT_SERVO_OFFSET);
 | 
			
		||||
 | 
			
		||||
    // initialize hardware
 | 
			
		||||
    PTP_HW_INIT(PTP_INCREMENT_NSEC, PTP_ADDEND_INIT);
 | 
			
		||||
 | 
			
		||||
    // initialize controller
 | 
			
		||||
    PTP_SERVO_INIT();
 | 
			
		||||
 | 
			
		||||
    // create timers
 | 
			
		||||
    ptp_create_timers();
 | 
			
		||||
    xTimerStart(S.timers.sbmc, 0);      // TODO!!
 | 
			
		||||
 | 
			
		||||
    // reset PTP subsystem
 | 
			
		||||
    ptp_reset();
 | 
			
		||||
 | 
			
		||||
#ifdef CLI_REG_CMD
 | 
			
		||||
    // register cli commands
 | 
			
		||||
    ptp_register_cli_commands();
 | 
			
		||||
#endif                          // CLI_REG_CMD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// deinit PTP module
 | 
			
		||||
void ptp_deinit()
 | 
			
		||||
{
 | 
			
		||||
#ifdef CLI_REG_CMD
 | 
			
		||||
    // remove cli commands
 | 
			
		||||
    ptp_remove_cli_commands();
 | 
			
		||||
#endif                          // CLI_REG_CMD
 | 
			
		||||
 | 
			
		||||
    // deinitialize controller
 | 
			
		||||
    PTP_SERVO_DEINIT();
 | 
			
		||||
 | 
			
		||||
    // delete timers
 | 
			
		||||
    ptp_delete_timers();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// construct and send Delay_Req message (NON-REENTRANT!)
 | 
			
		||||
void ptp_send_delay_req_message()
 | 
			
		||||
{
 | 
			
		||||
    static TimestampI zeroTs = { 0, 0 };        // timestamp appended at the end of packet
 | 
			
		||||
 | 
			
		||||
    // PTP message
 | 
			
		||||
    static RawPtpMessage delReqMsg = { 0 };
 | 
			
		||||
    delReqMsg.size = sDelayReqHeader.messageLength;
 | 
			
		||||
    delReqMsg.pTs = &(S.scd.t[T3]);
 | 
			
		||||
    delReqMsg.tx_dm = S.profile.delayMechanism;
 | 
			
		||||
    delReqMsg.tx_mc = PTP_MC_EVENT;
 | 
			
		||||
 | 
			
		||||
    // increment sequenceID
 | 
			
		||||
    sDelayReqHeader.sequenceID = ++S.messaging.delay_reqSequenceID;
 | 
			
		||||
    sDelayReqHeader.domainNumber = S.profile.domainNumber;
 | 
			
		||||
 | 
			
		||||
    // fill in header
 | 
			
		||||
    ptp_construct_binary_header(delReqMsg.data, &sDelayReqHeader);
 | 
			
		||||
 | 
			
		||||
    // fill in timestamp
 | 
			
		||||
    ptp_write_binary_timestamps(delReqMsg.data, &zeroTs, 1);
 | 
			
		||||
 | 
			
		||||
    // send message
 | 
			
		||||
    ptp_transmit_enqueue(&delReqMsg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// perform clock correction based on gathered timestamps (NON-REENTRANT!)
 | 
			
		||||
void ptp_perform_correction()
 | 
			
		||||
{
 | 
			
		||||
    // don't do any processing if no delay_request data is present
 | 
			
		||||
    if (!nonZeroI(&S.network.meanPathDelay)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static TimestampI syncMa_prev = { 0 };
 | 
			
		||||
 | 
			
		||||
    // timestamps and time intervals
 | 
			
		||||
    TimestampI d, syncMa, syncSl, delReqSl, delReqMa;
 | 
			
		||||
 | 
			
		||||
    // copy timestamps to assign them with meaningful names
 | 
			
		||||
    syncMa = S.scd.t[T1];
 | 
			
		||||
    syncSl = S.scd.t[T2];
 | 
			
		||||
    delReqSl = S.scd.t[T3];
 | 
			
		||||
    delReqMa = S.scd.t[T4];
 | 
			
		||||
 | 
			
		||||
    // log timestamps (if enabled)
 | 
			
		||||
 | 
			
		||||
    CLILOG(S.logging.timestamps,
 | 
			
		||||
           "seqID: %u\n"
 | 
			
		||||
           "T1: %d.%09d <- Sync TX (master)\n"
 | 
			
		||||
           "T2: %d.%09d <- Sync RX (slave) \n"
 | 
			
		||||
           "T3: %d.%09d <- Del_Req TX (slave) \n"
 | 
			
		||||
           "T4: %d.%09d <- Del_Req RX (master)\n\n",
 | 
			
		||||
           (uint32_t) S.messaging.sequenceID,
 | 
			
		||||
           (int32_t) syncMa.sec, syncMa.nanosec, (int32_t) syncSl.sec, syncSl.nanosec, (int32_t) delReqSl.sec, delReqSl.nanosec, (int32_t) delReqMa.sec, delReqMa.nanosec);
 | 
			
		||||
 | 
			
		||||
    // compute difference between master and slave clock
 | 
			
		||||
    /*subTime(&d, &syncSl, &syncMa); // t2 - t1 ...
 | 
			
		||||
       subTime(&d, &d, &delReqMa); // - t4 ...
 | 
			
		||||
       addTime(&d, &d, &delReqSl); // + t3
 | 
			
		||||
       divTime(&d, &d, 2); // division by 2 */
 | 
			
		||||
 | 
			
		||||
    subTime(&d, &syncSl, &syncMa);      // t2 - t1 ...
 | 
			
		||||
    subTime(&d, &d, &S.network.meanPathDelay);  // - MPD
 | 
			
		||||
 | 
			
		||||
    // substract offset
 | 
			
		||||
    subTime(&d, &d, &S.hwoptions.offset);
 | 
			
		||||
 | 
			
		||||
    // normalize time difference (eliminate malformed time value issues)
 | 
			
		||||
    normTime(&d);
 | 
			
		||||
 | 
			
		||||
    // translate time difference into clock tick unit
 | 
			
		||||
    int32_t d_ticks = tsToTick(&d, PTP_CLOCK_TICK_FREQ_HZ);
 | 
			
		||||
 | 
			
		||||
    // if time difference is at least one second, then jump the clock
 | 
			
		||||
    int64_t d_ns = nsI(&d);
 | 
			
		||||
    if (llabs(d_ns) > 20000000) {
 | 
			
		||||
        PTP_SET_CLOCK(syncMa.sec, syncMa.nanosec);
 | 
			
		||||
 | 
			
		||||
        CLILOG(S.logging.info, "Time difference is over 20ms [%ldns], performing coarse correction!\n", d_ns);
 | 
			
		||||
 | 
			
		||||
        syncMa_prev = syncMa;
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // prepare data to pass to the controller
 | 
			
		||||
    double measSyncPeriod_ns;
 | 
			
		||||
 | 
			
		||||
    TimestampI measSyncPeriod;
 | 
			
		||||
    subTime(&measSyncPeriod, &syncMa, &syncMa_prev);
 | 
			
		||||
    measSyncPeriod_ns = nsI(&measSyncPeriod);
 | 
			
		||||
 | 
			
		||||
    PtpServoAuxInput saux = { S.scd, S.messaging.logSyncPeriod, S.messaging.syncPeriodMs, measSyncPeriod_ns };
 | 
			
		||||
 | 
			
		||||
    // run controller
 | 
			
		||||
    float corr_ppb = PTP_SERVO_RUN(nsI(&d), &saux);
 | 
			
		||||
 | 
			
		||||
    // compute addend value
 | 
			
		||||
    int64_t compAddend = (int64_t) S.hwclock.addend + (int64_t) (corr_ppb * PTP_ADDEND_CORR_PER_PPB_F); // compute addend value
 | 
			
		||||
    S.hwclock.addend = MIN(compAddend, 0xFFFFFFFF);     // limit to 32-bit range
 | 
			
		||||
 | 
			
		||||
    // write addend into hardware
 | 
			
		||||
    PTP_SET_ADDEND(S.hwclock.addend);
 | 
			
		||||
 | 
			
		||||
    // collect statistics
 | 
			
		||||
    ptp_collect_stats(nsI(&d));
 | 
			
		||||
 | 
			
		||||
    // log on cli (if enabled)
 | 
			
		||||
    CLILOG(S.logging.def, "%d %09d %d %09d %d % 9d %d %u %f %ld %09lu\n",
 | 
			
		||||
           (int32_t) syncMa.sec, syncMa.nanosec, (int32_t) delReqMa.sec, delReqMa.nanosec,
 | 
			
		||||
           (int32_t) d.sec, d.nanosec, d_ticks, S.hwclock.addend, corr_ppb, nsI(&S.network.meanPathDelay), (uint64_t) measSyncPeriod_ns);
 | 
			
		||||
 | 
			
		||||
    // call sync callback if defined
 | 
			
		||||
    //if (sSyncCallback != NULL) {
 | 
			
		||||
    //  sSyncCallback(nsI(&d), &scd, S.addend);
 | 
			
		||||
    //}
 | 
			
		||||
 | 
			
		||||
    syncMa_prev = syncMa;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ptp_delreq_tmr_tick(TimerHandle_t xTimer)
 | 
			
		||||
{
 | 
			
		||||
    // check that our last Delay_Req has been responded
 | 
			
		||||
    CLILOG(S.messaging.delay_reqSequenceID != S.messaging.lastRespondedDelReqId, "(P)Del_Req #%d was unresponded!\n", S.messaging.delay_reqSequenceID);
 | 
			
		||||
    ptp_send_delay_req_message();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ptp_start_delreq_timer()
 | 
			
		||||
{
 | 
			
		||||
    // start DelReq timer if not running yet
 | 
			
		||||
    if (S.profile.logDelayReqPeriod != PTP_LOGPER_SYNCMATCHED) {
 | 
			
		||||
        xTimerReset(S.timers.delreq, 0);
 | 
			
		||||
        xTimerChangePeriod(S.timers.delreq, pdMS_TO_TICKS(ptp_logi2ms(S.profile.logDelayReqPeriod)), 0);
 | 
			
		||||
        xTimerStart(S.timers.delreq, 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ptp_stop_delreq_timer()
 | 
			
		||||
{
 | 
			
		||||
    // stop DelReq timer (since there's no master to talk to)
 | 
			
		||||
    xTimerStop(S.timers.delreq, portMAX_DELAY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ptp_sbmc_tmr_tick(TimerHandle_t timer)
 | 
			
		||||
{
 | 
			
		||||
    PtpSBmcState *s = &(S.sbmc);
 | 
			
		||||
 | 
			
		||||
    // main state machine dropout
 | 
			
		||||
    if (s->mstState == SBMC_MASTER_OK) {
 | 
			
		||||
        s->masterTOCntr += SBMC_TICKRATE;
 | 
			
		||||
        if (s->masterTOCntr > 2 * s->masterAnnPer_ms + SBMC_TICKRATE) {
 | 
			
		||||
            s->mstState = SBMC_NO_MASTER;
 | 
			
		||||
            s->masterProps.priority1 = 255;
 | 
			
		||||
            s->masterProps.grandmasterClockIdentity = 0;
 | 
			
		||||
            CLILOG(S.logging.info, "Master lost!\n");
 | 
			
		||||
 | 
			
		||||
            ptp_stop_delreq_timer();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // candidate switchover machine dropout
 | 
			
		||||
    if (s->candState == SBMC_CANDIDATE_COLLECTION) {
 | 
			
		||||
        s->candTOCntr += SBMC_TICKRATE;
 | 
			
		||||
        if (s->candTOCntr > 2 * s->candAnnPer_ms + SBMC_TICKRATE) {
 | 
			
		||||
            s->candState = SBMC_NO_CANDIDATE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// handle announce messages
 | 
			
		||||
void ptp_handle_announce_msg(PtpAnnounceBody * pAnn, PtpHeader * pHeader)
 | 
			
		||||
{
 | 
			
		||||
    PtpSBmcState *s = &(S.sbmc);
 | 
			
		||||
    bool masterChanged = false;
 | 
			
		||||
 | 
			
		||||
    switch (s->mstState) {
 | 
			
		||||
    case SBMC_NO_MASTER:       // no master, accept the first one announcing itself
 | 
			
		||||
        s->masterProps = *pAnn; // save master settings
 | 
			
		||||
        s->mstState = SBMC_MASTER_OK;   // master found
 | 
			
		||||
        s->candState = SBMC_NO_CANDIDATE;       // stop candidate processing, since master is selected
 | 
			
		||||
        s->masterAnnPer_ms = ptp_logi2ms(pHeader->logMessagePeriod);
 | 
			
		||||
        masterChanged = true;   // indicate that master has changed
 | 
			
		||||
        // no break here!
 | 
			
		||||
    case SBMC_MASTER_OK:       // already bound to master
 | 
			
		||||
        if (pAnn->grandmasterClockIdentity == s->masterProps.grandmasterClockIdentity) {        // only clear when receiving from elected master
 | 
			
		||||
            s->masterTOCntr = 0;        // clear counter
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // run only candidate state evaluation if no main state changed took place
 | 
			
		||||
    if (!masterChanged) {
 | 
			
		||||
        switch (s->candState) {
 | 
			
		||||
        case SBMC_NO_CANDIDATE:{
 | 
			
		||||
                if (ptp_select_better_master(pAnn, &s->masterProps) == 0) {
 | 
			
		||||
                    s->candProps = *pAnn;
 | 
			
		||||
                    s->candAnnPer_ms = ptp_logi2ms(pHeader->logMessagePeriod);
 | 
			
		||||
                    s->candState = SBMC_CANDIDATE_COLLECTION;   // switch to next syncState
 | 
			
		||||
                    s->candCntr = 1;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        case SBMC_CANDIDATE_COLLECTION:{
 | 
			
		||||
                // determine that the received master clock dataset is not better than the previously found one
 | 
			
		||||
                if (ptp_select_better_master(pAnn, &s->candProps) == 0) {       // if better, reset counter and stay in current syncState
 | 
			
		||||
                    s->candProps = *pAnn;
 | 
			
		||||
                    s->candCntr = 1;
 | 
			
		||||
                } else {
 | 
			
		||||
                    // verify, that announce message comes from the same source
 | 
			
		||||
                    if (pAnn->grandmasterClockIdentity == s->candProps.grandmasterClockIdentity) {
 | 
			
		||||
                        s->candCntr++;  // advance counter
 | 
			
		||||
                        s->candTOCntr = 0;      // clear counter
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // if counter expired...
 | 
			
		||||
                    if (s->candCntr == ANNOUNCE_COLLECTION_WINDOW) {
 | 
			
		||||
                        s->masterProps = s->candProps;  // change master
 | 
			
		||||
                        s->candProps.priority1 = 255;   // set to worst value, i.e. make other values meaningless
 | 
			
		||||
                        s->candProps.grandmasterClockIdentity = 0;      // also clear ID
 | 
			
		||||
 | 
			
		||||
                        masterChanged = true;
 | 
			
		||||
                        s->candState = SBMC_NO_CANDIDATE;       // switch back to NO_CANDIDATE syncState
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (masterChanged) {
 | 
			
		||||
        if (S.logging.info) {
 | 
			
		||||
            MSG("Switched to new master: ");
 | 
			
		||||
            ptp_print_clock_identity(s->masterProps.grandmasterClockIdentity);
 | 
			
		||||
            MSG("\n");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ptp_start_delreq_timer();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_handle_correction_field(TimestampI * ts, const PtpHeader * pHeader)
 | 
			
		||||
{
 | 
			
		||||
    TimestampI correctionField;
 | 
			
		||||
    correctionField.sec = 0;
 | 
			
		||||
    correctionField.nanosec = pHeader->correction_ns;
 | 
			
		||||
    subTime(ts, ts, &correctionField);
 | 
			
		||||
    normTime(ts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO TODO TODO ...
 | 
			
		||||
void ptp_compute_mean_path_delay(const TimestampI * pTs, TimestampI * pMPD)
 | 
			
		||||
{
 | 
			
		||||
    //static double a = 0.533488091091103; // fc = 10Hz
 | 
			
		||||
    static double a = 0.00186744273170799;      // fc = 1Hz
 | 
			
		||||
 | 
			
		||||
    double mpd_prev_ns = nsI(pMPD);
 | 
			
		||||
 | 
			
		||||
    //MSG("%f\n", mpd_prev_ns);
 | 
			
		||||
 | 
			
		||||
    // compute difference between master and slave clock
 | 
			
		||||
    subTime(pMPD, &pTs[T2], &pTs[T1]);  // t2 - t1 ...
 | 
			
		||||
    subTime(pMPD, pMPD, &pTs[T3]);      // - t3 ...
 | 
			
		||||
    addTime(pMPD, pMPD, &pTs[T4]);      // + t4
 | 
			
		||||
    divTime(pMPD, pMPD, 2);     // division by 2
 | 
			
		||||
 | 
			
		||||
    // performing time error filtering
 | 
			
		||||
    double mpd_new_ns = nsI(pMPD);
 | 
			
		||||
    mpd_new_ns = a * mpd_prev_ns + (1 - a) * mpd_new_ns;        // filtering equation
 | 
			
		||||
    nsToTsI(pMPD, (int64_t) mpd_new_ns);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// reset PTP subsystem
 | 
			
		||||
void ptp_reset()
 | 
			
		||||
{
 | 
			
		||||
    // reset subsystem states...
 | 
			
		||||
    memset(&S.messaging, 0, sizeof(PtpMessagingState)); // messaging state
 | 
			
		||||
    S.hwclock.addend = PTP_ADDEND_INIT; // HW clock state
 | 
			
		||||
    PTP_SET_ADDEND(PTP_ADDEND_INIT);
 | 
			
		||||
    memset(&S.network, 0, sizeof(PtpNetworkState));     // network state
 | 
			
		||||
    memset(&S.sbmc, 0, sizeof(PtpSBmcState));   // SBMC state
 | 
			
		||||
    memset(&S.scd, 0, sizeof(PtpSyncCycleData));        // Sync cycle data
 | 
			
		||||
 | 
			
		||||
    // remove delreq time
 | 
			
		||||
    ptp_stop_delreq_timer();
 | 
			
		||||
 | 
			
		||||
    // reset controller
 | 
			
		||||
    PTP_SERVO_RESET();
 | 
			
		||||
 | 
			
		||||
    // (re)init header for sending (P)Delay_Req messages
 | 
			
		||||
    ptp_init_delay_req_header();
 | 
			
		||||
 | 
			
		||||
    // reset statistics
 | 
			
		||||
    ptp_clear_stats();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// packet processing (NON-REENTRANT!!)
 | 
			
		||||
void ptp_process_packet(RawPtpMessage * pRawMsg)
 | 
			
		||||
{
 | 
			
		||||
    static PtpHeader header;    // PTP header
 | 
			
		||||
    static Delay_RespIdentification delay_respID;       // identification received in every Delay_Resp packet
 | 
			
		||||
    //TimestampI correctionField;
 | 
			
		||||
 | 
			
		||||
    // header readout
 | 
			
		||||
    ptp_extract_header(&header, pRawMsg->data);
 | 
			
		||||
 | 
			
		||||
    // if other than Announce received
 | 
			
		||||
    //MSG("%d\n", header.messageType);
 | 
			
		||||
 | 
			
		||||
    // consider only messages in our domain
 | 
			
		||||
    if (header.domainNumber != S.profile.domainNumber || header.transportSpecific != S.profile.transportSpecific) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (header.messageType == PTP_MT_Announce) {
 | 
			
		||||
        PtpMasterProperties newMstProp;
 | 
			
		||||
        ptp_extract_announce_message(&newMstProp, pRawMsg->data);
 | 
			
		||||
        ptp_handle_announce_msg(&newMstProp, &header);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // process non-Announce messages
 | 
			
		||||
    if (header.messageType == PTP_MT_Sync || header.messageType == PTP_MT_Follow_Up) {
 | 
			
		||||
        switch (S.messaging.m2sState) {
 | 
			
		||||
            // wait for Sync message
 | 
			
		||||
        case SIdle:{
 | 
			
		||||
                // switch into next state if Sync packet has arrived
 | 
			
		||||
                if (header.messageType == PTP_MT_Sync) {
 | 
			
		||||
                    // save sync interval
 | 
			
		||||
                    S.messaging.logSyncPeriod = header.logMessagePeriod;
 | 
			
		||||
                    S.messaging.syncPeriodMs = ptp_logi2ms(header.logMessagePeriod);
 | 
			
		||||
 | 
			
		||||
                    //MSG("%d\n", header.logMessagePeriod);
 | 
			
		||||
 | 
			
		||||
                    // save reception time
 | 
			
		||||
                    S.scd.t[T2] = pRawMsg->ts;
 | 
			
		||||
 | 
			
		||||
                    // switch to next syncState
 | 
			
		||||
                    S.messaging.sequenceID = header.sequenceID;
 | 
			
		||||
 | 
			
		||||
                    // handle two step/one step messaging
 | 
			
		||||
                    //if (header.flags.PTP_TWO_STEP) {
 | 
			
		||||
                    S.messaging.m2sState = SWaitFollowUp;
 | 
			
		||||
                    //} else {
 | 
			
		||||
                    /*ptp_extract_timestamps(&sSyncData.t1, pRawMsg->data, 1); // extract t1
 | 
			
		||||
                       ptp_handle_correction_field(&sSyncData.t2, &header); // process correction field
 | 
			
		||||
                       ptp_perform_correction(); // run clock correction */
 | 
			
		||||
                    //}
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            // wait for Follow_Up message
 | 
			
		||||
        case SWaitFollowUp:
 | 
			
		||||
            if (header.messageType == PTP_MT_Follow_Up) {
 | 
			
		||||
                // check sequence ID if the response is ours
 | 
			
		||||
                if (header.sequenceID == S.messaging.sequenceID) {
 | 
			
		||||
                    ptp_extract_timestamps(&S.scd.t[T1], pRawMsg->data, 1);     // read t1
 | 
			
		||||
                    ptp_handle_correction_field(&S.scd.t[T2], &header); // process correction field
 | 
			
		||||
 | 
			
		||||
                    // log correction field (if enabled)
 | 
			
		||||
                    CLILOG(S.logging.corr, "C [Follow_Up]: %09lu\n", header.correction_ns);
 | 
			
		||||
 | 
			
		||||
                    // delay Delay_Req transmission with a random amount of time
 | 
			
		||||
                    //vTaskDelay(pdMS_TO_TICKS(rand() % (S.syncIntervalMs / 2)));
 | 
			
		||||
 | 
			
		||||
                    // send Delay_Req message
 | 
			
		||||
                    if (S.profile.logDelayReqPeriod == PTP_LOGPER_SYNCMATCHED) {
 | 
			
		||||
                        ptp_send_delay_req_message();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // jump clock if error is way too big...
 | 
			
		||||
                    TimestampI d;
 | 
			
		||||
                    subTime(&d, &S.scd.t[T2], &S.scd.t[T1]);
 | 
			
		||||
                    if (d.sec != 0) {
 | 
			
		||||
                        PTP_SET_CLOCK(S.scd.t[T1].sec, S.scd.t[T1].nanosec);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // run servo only if not syncmatched
 | 
			
		||||
                    if (S.profile.logDelayReqPeriod != PTP_LOGPER_SYNCMATCHED) {
 | 
			
		||||
                        ptp_perform_correction();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // switch to next syncState
 | 
			
		||||
                    S.messaging.m2sState = SIdle;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ------ (P)DELAY_RESPONSE PROCESSING --------
 | 
			
		||||
 | 
			
		||||
    // wait for (P)Delay_Resp message
 | 
			
		||||
    if ((header.messageType == PTP_MT_Delay_Resp && S.profile.delayMechanism == PTP_DM_E2E)) {
 | 
			
		||||
        if (header.sequenceID == S.messaging.delay_reqSequenceID) {     // read clock ID of requester
 | 
			
		||||
 | 
			
		||||
            ptp_read_delay_resp_id_data(&delay_respID, pRawMsg->data);
 | 
			
		||||
 | 
			
		||||
            // if the response was sent to us as a response to our Delay_Req then continue processing
 | 
			
		||||
            if (delay_respID.requestingSourceClockIdentity == S.hwoptions.clockIdentity && delay_respID.requestingSourcePortIdentity == sDelayReqHeader.sourcePortID) {
 | 
			
		||||
 | 
			
		||||
                ptp_extract_timestamps(&S.scd.t[T4], pRawMsg->data, 1); // store t4
 | 
			
		||||
                ptp_handle_correction_field(&S.scd.t[T4], &header);     // substract correction field from t4
 | 
			
		||||
 | 
			
		||||
                // compute mean path delay
 | 
			
		||||
                ptp_compute_mean_path_delay(S.scd.t, &S.network.meanPathDelay);
 | 
			
		||||
 | 
			
		||||
                // store last response ID
 | 
			
		||||
                S.messaging.lastRespondedDelReqId = header.sequenceID;
 | 
			
		||||
 | 
			
		||||
                // perform correction if operating on syncmatched mode
 | 
			
		||||
                if (S.profile.logDelayReqPeriod == PTP_LOGPER_SYNCMATCHED) {
 | 
			
		||||
                    ptp_perform_correction();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // log correction field (if enabled)
 | 
			
		||||
                CLILOG(S.logging.corr, "C [Del_Resp]: %09lu\n", header.correction_ns);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_store_config(PtpConfig * pConfig)
 | 
			
		||||
{
 | 
			
		||||
    pConfig->profile = S.profile;
 | 
			
		||||
    pConfig->offset = S.hwoptions.offset;
 | 
			
		||||
    pConfig->logging = (int)(S.logging.def) | (int)(S.logging.info) << 1 | (int)(S.logging.corr) << 2 | (int)(S.logging.timestamps) << 3 | (int)(S.logging.locked) << 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_load_config(const PtpConfig * pConfig)
 | 
			
		||||
{
 | 
			
		||||
    S.profile = pConfig->profile;
 | 
			
		||||
    S.hwoptions.offset = pConfig->offset;
 | 
			
		||||
 | 
			
		||||
    S.logging.def = pConfig->logging & 1;
 | 
			
		||||
    S.logging.info = (pConfig->logging >> 1) & 1;
 | 
			
		||||
    S.logging.corr = (pConfig->logging >> 2) & 1;
 | 
			
		||||
    S.logging.timestamps = (pConfig->logging >> 3) & 1;
 | 
			
		||||
    S.logging.locked = (pConfig->logging >> 4) & 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_load_config_from_dump(const void *pDump)
 | 
			
		||||
{
 | 
			
		||||
    PtpConfig config;
 | 
			
		||||
    memcpy(&config, pDump, sizeof(PtpConfig));
 | 
			
		||||
    ptp_load_config(&config);
 | 
			
		||||
    ptp_reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// -----------------------------------------------
 | 
			
		||||
							
								
								
									
										59
									
								
								ptp_core.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								ptp_core.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,59 @@
 | 
			
		||||
/* (C) András Wiesner, 2020 */
 | 
			
		||||
 | 
			
		||||
#ifndef PTP_H
 | 
			
		||||
#define PTP_H
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#ifndef SIMULATION
 | 
			
		||||
#include "FreeRTOS.h"
 | 
			
		||||
#include "task.h"
 | 
			
		||||
#include "timers.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "timeutils.h"
 | 
			
		||||
#include "ptp_types.h"
 | 
			
		||||
#include "stats.h"
 | 
			
		||||
#include "settings_interface.h"
 | 
			
		||||
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
// ----- FLEXPTP_OPTIONS.H INCLUDE AREA ------
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
 | 
			
		||||
#include <flexptp_options.h>
 | 
			
		||||
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
// (End of customizable area)
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
 | 
			
		||||
// -------------------------------------------
 | 
			
		||||
 | 
			
		||||
    void ptp_init();            // initialize PTP subsystem
 | 
			
		||||
    void ptp_deinit();          // deinitialize PTP subsystem
 | 
			
		||||
 | 
			
		||||
    void ptp_reset();           // reset PTP subsystem
 | 
			
		||||
    void ptp_process_packet(RawPtpMessage * pRawMsg);   // process PTP packet
 | 
			
		||||
 | 
			
		||||
    typedef void (*SyncCallback)(int64_t time_error, const PtpSyncCycleData * pSCD, uint32_t freqCodeWord);
 | 
			
		||||
 | 
			
		||||
    void ptp_set_sync_callback(SyncCallback syncCB);
 | 
			
		||||
 | 
			
		||||
#define PTP_IS_LOCKED(th) (ptp_get_stats()->filtTimeErr < (th) && !(ptp_get_current_master_clock_identity() != 0))      // is ptp locked considering threshold passed?
 | 
			
		||||
 | 
			
		||||
    extern PtpCoreState gPtpCoreState;
 | 
			
		||||
 | 
			
		||||
    void ptp_store_config(PtpConfig * pConfig); // store PTP-engine configuration (param: output)
 | 
			
		||||
    void ptp_load_config(const PtpConfig * pConfig);    // load PTP-engine configuration
 | 
			
		||||
    void ptp_load_config_from_dump(const void *pDump);  // load PTP-engine configuration from binary dump (i.e. from unaligned address)
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif                          /* PTP */
 | 
			
		||||
							
								
								
									
										3
									
								
								ptp_defs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								ptp_defs.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
#include "ptp_defs.h"
 | 
			
		||||
 | 
			
		||||
const ip_addr_t PTP_IGMP_PRIMARY = { 0x810100E0 };      // 224.0.1.129
 | 
			
		||||
							
								
								
									
										41
									
								
								ptp_defs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								ptp_defs.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
#ifndef FLEXPTP_PTP_DEFS_H_
 | 
			
		||||
#define FLEXPTP_PTP_DEFS_H_
 | 
			
		||||
 | 
			
		||||
#include "flexptp_options.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
// IP address of PTP-IGMP groups
 | 
			
		||||
#define PTP_IGMP_DEFAULT_STR ("224.0.1.129")
 | 
			
		||||
 | 
			
		||||
extern const ip_addr_t PTP_IGMP_PRIMARY;
 | 
			
		||||
 | 
			
		||||
// Ethernet address of PTP messages
 | 
			
		||||
extern const uint8_t PTP_ETHERNET_PRIMARY[6];
 | 
			
		||||
 | 
			
		||||
// PTP UDP ports
 | 
			
		||||
#define PTP_PORT_EVENT (319)
 | 
			
		||||
#define PTP_PORT_GENERAL (320)
 | 
			
		||||
 | 
			
		||||
#define PTP_HEADER_LENGTH (34)
 | 
			
		||||
#define PTP_TIMESTAMP_LENGTH (10)
 | 
			
		||||
#define PTP_PORT_ID_LENGTH (10)
 | 
			
		||||
 | 
			
		||||
#define PTP_PCKT_SIZE_SYNC (PTP_HEADER_LENGTH + PTP_TIMESTAMP_LENGTH)
 | 
			
		||||
#define PTP_PCKT_SIZE_FOLLOW_UP (PTP_HEADER_LENGTH + PTP_TIMESTAMP_LENGTH)
 | 
			
		||||
#define PTP_PCKT_SIZE_DELAY_REQ (PTP_HEADER_LENGTH + PTP_TIMESTAMP_LENGTH)
 | 
			
		||||
#define PTP_PCKT_SIZE_DELAY_RESP (PTP_HEADER_LENGTH + PTP_TIMESTAMP_LENGTH + PTP_PORT_ID_LENGTH)
 | 
			
		||||
 | 
			
		||||
// ---- AUTODEFINES ----------
 | 
			
		||||
 | 
			
		||||
#ifndef PTP_ACCURACY_LIMIT_NS
 | 
			
		||||
#define PTP_ACCURACY_LIMIT_NS (100)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// ---- CALCULATED VALUES ----
 | 
			
		||||
 | 
			
		||||
#define PTP_CLOCK_TICK_FREQ_HZ (1000000000 / PTP_INCREMENT_NSEC)        // clock tick frequency
 | 
			
		||||
#define PTP_ADDEND_INIT ((uint32_t)(0x100000000 / (PTP_MAIN_OSCILLATOR_FREQ_HZ / (float)PTP_CLOCK_TICK_FREQ_HZ)))       // addend value
 | 
			
		||||
#define PTP_ADDEND_CORR_PER_PPB_F ((float)0x100000000 / ((float)PTP_INCREMENT_NSEC * PTP_MAIN_OSCILLATOR_FREQ_HZ))      // addend/ppb
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_PTP_DEFS_H_ */
 | 
			
		||||
							
								
								
									
										94
									
								
								ptp_msg_tx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								ptp_msg_tx.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,94 @@
 | 
			
		||||
#include <flexptp_options.h>
 | 
			
		||||
 | 
			
		||||
#include "FreeRTOS.h"
 | 
			
		||||
#include "queue.h"
 | 
			
		||||
 | 
			
		||||
#include "ptp_msg_tx.h"
 | 
			
		||||
#include "ptp_defs.h"
 | 
			
		||||
#include "ptp_core.h"
 | 
			
		||||
#include "ptp_raw_msg_circbuf.h"
 | 
			
		||||
 | 
			
		||||
#include "settings_interface.h"
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
    struct udp_pcb *pPri_Ev;
 | 
			
		||||
    struct udp_pcb *pPri_Gen;
 | 
			
		||||
 | 
			
		||||
} sPcbLut = { 0 };
 | 
			
		||||
 | 
			
		||||
static const uint16_t sPortLut[2] = { PTP_PORT_EVENT, PTP_PORT_GENERAL };
 | 
			
		||||
static ip4_addr_t sIpLut[2] = { 0 };
 | 
			
		||||
static const uint8_t *sEthLut[2] = { PTP_ETHERNET_PRIMARY, PTP_ETHERNET_PEER_DELAY };
 | 
			
		||||
 | 
			
		||||
void ptp_transmit_init(struct udp_pcb *pPriE, struct udp_pcb *pPriG,)
 | 
			
		||||
{
 | 
			
		||||
    sPcbLut.pPri_Ev = pPriE;
 | 
			
		||||
    sPcbLut.pPri_Gen = pPriG;
 | 
			
		||||
 | 
			
		||||
    sIpLut[0] = PTP_IGMP_PRIMARY;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// release buffer
 | 
			
		||||
void ptp_transmit_free(struct pbuf *pPBuf)
 | 
			
		||||
{
 | 
			
		||||
    pbuf_free(pPBuf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_transmit_cb_handler(struct pbuf *pPBuf)
 | 
			
		||||
{
 | 
			
		||||
    RawPtpMessage *pMsg = (RawPtpMessage *) pPBuf->tag;
 | 
			
		||||
    pMsg->ts.sec = pPBuf->time_s;
 | 
			
		||||
    pMsg->ts.nanosec = pPBuf->time_ns;
 | 
			
		||||
    if (pMsg->pTxCb) {
 | 
			
		||||
        pMsg->pTxCb(pMsg);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ptp_transmit_enqueue(const RawPtpMessage * pMsg)
 | 
			
		||||
{
 | 
			
		||||
    extern PtpCircBuf gRawTxMsgBuf;
 | 
			
		||||
    extern QueueHandle_t gTxPacketFIFO;
 | 
			
		||||
    RawPtpMessage *pMsgAlloc = ptp_circ_buf_alloc(&gRawTxMsgBuf);
 | 
			
		||||
    if (pMsgAlloc) {
 | 
			
		||||
        *pMsgAlloc = *pMsg;
 | 
			
		||||
        uint8_t idx = ptp_circ_buf_commit(&gRawTxMsgBuf);
 | 
			
		||||
        bool hptWoken = false;
 | 
			
		||||
        if (xPortIsInsideInterrupt()) {
 | 
			
		||||
            xQueueSendFromISR(gTxPacketFIFO, &idx, &hptWoken);
 | 
			
		||||
        } else {
 | 
			
		||||
            xQueueSend(gTxPacketFIFO, &idx, portMAX_DELAY);
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    } else {
 | 
			
		||||
        MSG("enqueue failed!");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_transmit_msg(RawPtpMessage * pMsg)
 | 
			
		||||
{
 | 
			
		||||
    PtpTransportType tp = ptp_get_transport_type();
 | 
			
		||||
    PtpDelayMechanism dm = pMsg->tx_dm;
 | 
			
		||||
    PtpMessageClass mc = pMsg->tx_mc;
 | 
			
		||||
 | 
			
		||||
    // allocate buffer
 | 
			
		||||
    struct pbuf *txbuf = NULL;
 | 
			
		||||
    txbuf = pbuf_alloc(PBUF_TRANSPORT, pMsg->size, PBUF_RAM);
 | 
			
		||||
 | 
			
		||||
    // fill buffer
 | 
			
		||||
    memcpy(txbuf->payload, pMsg->data, pMsg->size);
 | 
			
		||||
    txbuf->ts_writeback_addr[0] = (uint32_t *) & (pMsg->pTs->sec);
 | 
			
		||||
    txbuf->ts_writeback_addr[1] = (uint32_t *) & (pMsg->pTs->nanosec);
 | 
			
		||||
    txbuf->tag = pMsg;
 | 
			
		||||
    txbuf->tx_cb = ptp_transmit_cb_handler;
 | 
			
		||||
 | 
			
		||||
    if (tp == PTP_TP_IPv4) {
 | 
			
		||||
        struct udp_pcb *pPcb = ((struct udp_pcb **)&sPcbLut)[2 * ((int)dm) + (int)mc];
 | 
			
		||||
        uint16_t port = sPortLut[(int)mc];
 | 
			
		||||
        ip_addr_t ipaddr = sIpLut[(int)dm];
 | 
			
		||||
        udp_sendto(pPcb, txbuf, &ipaddr, port);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pbuf_free(txbuf);           // release buffer
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								ptp_msg_tx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								ptp_msg_tx.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
#ifndef FLEXPTP_SIM_PTP_MSG_TX_H
 | 
			
		||||
#define FLEXPTP_SIM_PTP_MSG_TX_H
 | 
			
		||||
 | 
			
		||||
#include "ptp_types.h"
 | 
			
		||||
 | 
			
		||||
void ptp_transmit_init(struct udp_pcb *pPriE, struct udp_pcb *pPriG,);  // initialize PTP transmitter
 | 
			
		||||
void ptp_transmit_msg(RawPtpMessage * pMsg);    // transmit PTP message
 | 
			
		||||
bool ptp_transmit_enqueue(const RawPtpMessage * pMsg);  // enqueue message TODO: refactor...
 | 
			
		||||
 | 
			
		||||
#endif                          //FLEXPTP_SIM_PTP_MSG_TX_H
 | 
			
		||||
							
								
								
									
										53
									
								
								ptp_profile_presets.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								ptp_profile_presets.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
#include "ptp_profile_presets.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_PROFILE_NAME_LENGTH (7)
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    PTP_PROFILE_DEFAULT,        // default profile
 | 
			
		||||
 | 
			
		||||
    PTP_PROFILE_N
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    char name[MAX_PROFILE_NAME_LENGTH + 1];
 | 
			
		||||
    PtpProfile profile;         // profile object
 | 
			
		||||
} PtpProfilePreset;
 | 
			
		||||
 | 
			
		||||
static PtpProfilePreset sPtpProfiles[PTP_PROFILE_N] = {
 | 
			
		||||
    {
 | 
			
		||||
     "default",
 | 
			
		||||
     {
 | 
			
		||||
      PTP_TP_IPv4,
 | 
			
		||||
      PTP_TSPEC_UNKNOWN_DEF,
 | 
			
		||||
      PTP_DM_E2E,
 | 
			
		||||
      0,
 | 
			
		||||
      0}
 | 
			
		||||
     },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const PtpProfile *ptp_profile_preset_get(const char *pName)
 | 
			
		||||
{
 | 
			
		||||
    size_t i = 0;
 | 
			
		||||
    PtpProfile *pProfile = NULL;
 | 
			
		||||
    for (i = 0; i < PTP_PROFILE_N; i++) {
 | 
			
		||||
        if (!strcmp(sPtpProfiles[i].name, pName)) {
 | 
			
		||||
            pProfile = &sPtpProfiles[i].profile;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return pProfile;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t ptp_profile_preset_cnt()
 | 
			
		||||
{
 | 
			
		||||
    return PTP_PROFILE_N;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *ptp_profile_preset_get_name(size_t i)
 | 
			
		||||
{
 | 
			
		||||
    if (i < PTP_PROFILE_N) {
 | 
			
		||||
        return sPtpProfiles[i].name;
 | 
			
		||||
    } else {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								ptp_profile_presets.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								ptp_profile_presets.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
#ifndef PTP_PROFILE_PRESETS_H_
 | 
			
		||||
#define PTP_PROFILE_PRESETS_H_
 | 
			
		||||
 | 
			
		||||
#include "ptp_types.h"
 | 
			
		||||
 | 
			
		||||
const PtpProfile *ptp_profile_preset_get(const char *pName);    // get profile by name
 | 
			
		||||
size_t ptp_profile_preset_cnt();        // get number of preset profiles
 | 
			
		||||
const char *ptp_profile_preset_get_name(size_t i);      // get profile name by index
 | 
			
		||||
 | 
			
		||||
#endif                          /* PTP_PROFILE_PRESETS_H_ */
 | 
			
		||||
							
								
								
									
										46
									
								
								ptp_raw_msg_circbuf.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								ptp_raw_msg_circbuf.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
#include "ptp_raw_msg_circbuf.h"
 | 
			
		||||
 | 
			
		||||
void ptp_circ_buf_init(PtpCircBuf * pCircBuf, RawPtpMessage * pMsgPool, uint8_t n)
 | 
			
		||||
{
 | 
			
		||||
    pCircBuf->msgs = pMsgPool;
 | 
			
		||||
    pCircBuf->totalSize = n;
 | 
			
		||||
    pCircBuf->freeBufs = n;
 | 
			
		||||
    pCircBuf->lastReceived = 0;
 | 
			
		||||
    pCircBuf->allocPending = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// allocate packet (CALL ONLY IF THERE IS SPACE AVAILABLE!)
 | 
			
		||||
RawPtpMessage *ptp_circ_buf_alloc(PtpCircBuf * pCircBuf)
 | 
			
		||||
{
 | 
			
		||||
    if (pCircBuf->freeBufs > 0 && pCircBuf->allocPending == -1) {
 | 
			
		||||
        uint8_t current = (pCircBuf->lastReceived + 1) % pCircBuf->totalSize;   // allocate a new packet
 | 
			
		||||
        pCircBuf->allocPending = current;
 | 
			
		||||
        return &(pCircBuf->msgs[current]);
 | 
			
		||||
    } else {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ptp_circ_buf_commit(PtpCircBuf * pCircBuf)
 | 
			
		||||
{
 | 
			
		||||
    if (pCircBuf->allocPending != -1) {
 | 
			
		||||
        pCircBuf->lastReceived = pCircBuf->allocPending;        // advance last index
 | 
			
		||||
        pCircBuf->freeBufs--;   // decrease amount of free buffers
 | 
			
		||||
        pCircBuf->allocPending = -1;    // turn off allocation pending flag
 | 
			
		||||
        return pCircBuf->lastReceived;
 | 
			
		||||
    } else {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_circ_buf_free(PtpCircBuf * pCircBuf)
 | 
			
		||||
{
 | 
			
		||||
    if (pCircBuf->freeBufs < pCircBuf->totalSize) {
 | 
			
		||||
        pCircBuf->freeBufs++;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RawPtpMessage *ptp_circ_buf_get(PtpCircBuf * pCircBuf, uint8_t idx)
 | 
			
		||||
{
 | 
			
		||||
    return &(pCircBuf->msgs[idx]);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								ptp_raw_msg_circbuf.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								ptp_raw_msg_circbuf.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
			
		||||
#ifndef FLEXPTP_PTP_RAW_MSG_CIRCBUF_H_
 | 
			
		||||
#define FLEXPTP_PTP_RAW_MSG_CIRCBUF_H_
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include "ptp_types.h"
 | 
			
		||||
 | 
			
		||||
// "ring" buffer for PTP-messages
 | 
			
		||||
#define PTP_MSG_BUF_SIZE (32)
 | 
			
		||||
typedef struct {
 | 
			
		||||
    RawPtpMessage *msgs;        // messages
 | 
			
		||||
    uint8_t totalSize;          // total buffer size (element count)
 | 
			
		||||
    uint8_t lastReceived;       // pointer to last received and last processed messages
 | 
			
		||||
    uint8_t freeBufs;           // number of free buffers
 | 
			
		||||
    int allocPending;           // allocation pending (by index)
 | 
			
		||||
} PtpCircBuf;
 | 
			
		||||
 | 
			
		||||
void ptp_circ_buf_init(PtpCircBuf * pCircBuf, RawPtpMessage * pMsgPool, uint8_t n);     // initialize circular buffer
 | 
			
		||||
RawPtpMessage *ptp_circ_buf_alloc(PtpCircBuf * pCircBuf);       // allocate next available circular buffer
 | 
			
		||||
int ptp_circ_buf_commit(PtpCircBuf * pCircBuf); // commit last allocation
 | 
			
		||||
void ptp_circ_buf_free(PtpCircBuf * pCircBuf);  // free oldest allocation
 | 
			
		||||
RawPtpMessage *ptp_circ_buf_get(PtpCircBuf * pCircBuf, uint8_t idx);    // get message by index
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_PTP_RAW_MSG_CIRCBUF_H_ */
 | 
			
		||||
							
								
								
									
										16
									
								
								ptp_servo_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								ptp_servo_types.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
#ifndef FLEXPTP_SIM_PTP_SERVO_TYPES_H
 | 
			
		||||
#define FLEXPTP_SIM_PTP_SERVO_TYPES_H
 | 
			
		||||
 | 
			
		||||
#include "ptp_sync_cycle_data.h"
 | 
			
		||||
 | 
			
		||||
// Data to perform a full synchronization
 | 
			
		||||
typedef struct {
 | 
			
		||||
    PtpSyncCycleData scd;       // sync cycle data
 | 
			
		||||
 | 
			
		||||
    // information about sync interval
 | 
			
		||||
    int8_t logMsgPeriod;        // ...
 | 
			
		||||
    double msgPeriodMs;         // message period in ms
 | 
			
		||||
    double measSyncPeriod;      // measured synchronization period (t1->t1) TODO rename! (suffix: _ns)
 | 
			
		||||
} PtpServoAuxInput;
 | 
			
		||||
 | 
			
		||||
#endif                          //FLEXPTP_SIM_PTP_SERVO_TYPES_H
 | 
			
		||||
							
								
								
									
										11
									
								
								ptp_sync_cycle_data.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								ptp_sync_cycle_data.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
#ifndef FLEXPTP_PTP_SYNC_CYCLE_DATA_H_
 | 
			
		||||
#define FLEXPTP_PTP_SYNC_CYCLE_DATA_H_
 | 
			
		||||
 | 
			
		||||
#include "timeutils.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
 | 
			
		||||
    TimestampI t[6];
 | 
			
		||||
} PtpSyncCycleData;
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_PTP_SYNC_CYCLE_DATA_H_ */
 | 
			
		||||
							
								
								
									
										268
									
								
								ptp_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								ptp_types.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,268 @@
 | 
			
		||||
#ifndef FLEXPTP_PTP_TYPES_H_
 | 
			
		||||
#define FLEXPTP_PTP_TYPES_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include "ptp_sync_cycle_data.h"
 | 
			
		||||
 | 
			
		||||
#include <flexptp_options.h>
 | 
			
		||||
 | 
			
		||||
#ifndef SIMULATION
 | 
			
		||||
#include "FreeRTOS.h"
 | 
			
		||||
#include "timers.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// PTP packet types
 | 
			
		||||
enum PTPMessageType {
 | 
			
		||||
    PTP_MT_Sync = 0,
 | 
			
		||||
    PTP_MT_Delay_Req = 1,
 | 
			
		||||
 | 
			
		||||
    PTP_MT_Follow_Up = 8,
 | 
			
		||||
    PTP_MT_Delay_Resp = 9,
 | 
			
		||||
 | 
			
		||||
    PTP_MT_Announce = 11
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// PTP header control field values
 | 
			
		||||
enum PTPControl {
 | 
			
		||||
    PTP_CON_Sync = 0,
 | 
			
		||||
    PTP_CON_Delay_Req = 1,
 | 
			
		||||
    PTP_CON_Follow_Up = 2,
 | 
			
		||||
    PTP_CON_Delay_Resp = 3,
 | 
			
		||||
    PTP_CON_Other = 5
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// PTP flags structure
 | 
			
		||||
typedef struct {
 | 
			
		||||
    bool PTP_SECURITY;
 | 
			
		||||
    bool PTP_ProfileSpecific_2;
 | 
			
		||||
    bool PTP_ProfileSpecific_1;
 | 
			
		||||
    bool PTP_UNICAST;
 | 
			
		||||
    bool PTP_TWO_STEP;
 | 
			
		||||
    bool PTP_ALTERNATE_MASTER;
 | 
			
		||||
    bool FREQUENCY_TRACEABLE;
 | 
			
		||||
    bool TIME_TRACEABLE;
 | 
			
		||||
    bool PTP_TIMESCALE;
 | 
			
		||||
    bool PTP_UTC_REASONABLE;
 | 
			
		||||
    bool PTP_LI_59;
 | 
			
		||||
    bool PTP_LI_61;
 | 
			
		||||
} PTPFlags;
 | 
			
		||||
 | 
			
		||||
// PTP message header structure
 | 
			
		||||
typedef struct {
 | 
			
		||||
    // 0.
 | 
			
		||||
    uint8_t messageType;        // ID
 | 
			
		||||
    uint8_t transportSpecific;
 | 
			
		||||
 | 
			
		||||
    // 1.
 | 
			
		||||
    uint8_t versionPTP;         // PTP version
 | 
			
		||||
    uint8_t _r1;
 | 
			
		||||
 | 
			
		||||
    // 2-3.
 | 
			
		||||
    uint16_t messageLength;     // length
 | 
			
		||||
 | 
			
		||||
    // 4.
 | 
			
		||||
    uint8_t domainNumber;
 | 
			
		||||
 | 
			
		||||
    // 5.
 | 
			
		||||
    uint8_t _r2;
 | 
			
		||||
 | 
			
		||||
    // 6-7.
 | 
			
		||||
    PTPFlags flags;
 | 
			
		||||
 | 
			
		||||
    // 8-15.
 | 
			
		||||
    uint64_t correction_ns;
 | 
			
		||||
    uint32_t correction_subns;
 | 
			
		||||
 | 
			
		||||
    // 16-19.
 | 
			
		||||
    uint32_t _r3;
 | 
			
		||||
 | 
			
		||||
    // 20-27.
 | 
			
		||||
    uint64_t clockIdentity;
 | 
			
		||||
 | 
			
		||||
    // 28-29
 | 
			
		||||
    uint16_t sourcePortID;
 | 
			
		||||
 | 
			
		||||
    // 30-31.
 | 
			
		||||
    uint16_t sequenceID;
 | 
			
		||||
 | 
			
		||||
    // 32.
 | 
			
		||||
    uint8_t control;
 | 
			
		||||
 | 
			
		||||
    // 33.
 | 
			
		||||
    int8_t logMessagePeriod;    // ...
 | 
			
		||||
} PtpHeader;
 | 
			
		||||
 | 
			
		||||
// identification carrying Delay_Resp message
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint64_t requestingSourceClockIdentity;
 | 
			
		||||
    uint16_t requestingSourcePortIdentity;
 | 
			
		||||
} Delay_RespIdentification;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    PTP_TP_IPv4 = 0,
 | 
			
		||||
 | 
			
		||||
} PtpTransportType;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    PTP_DM_E2E = 0,
 | 
			
		||||
 | 
			
		||||
} PtpDelayMechanism;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    PTP_TSPEC_UNKNOWN_DEF = 0,
 | 
			
		||||
 | 
			
		||||
} PtpTransportSpecific;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    PTP_MC_EVENT = 0,
 | 
			
		||||
    PTP_MC_GENERAL = 1
 | 
			
		||||
} PtpMessageClass;
 | 
			
		||||
 | 
			
		||||
#define MAX_PTP_MSG_SIZE (128)
 | 
			
		||||
typedef struct RawPtpMessage_ {
 | 
			
		||||
    TimestampI ts;              // timestamp
 | 
			
		||||
    uint32_t size;              // packet size
 | 
			
		||||
 | 
			
		||||
    // --- transmit related ---
 | 
			
		||||
    TimestampI *pTs;            // pointer to timestamp
 | 
			
		||||
    void (*pTxCb)(const struct RawPtpMessage_ * pMsg);  // transmit callback function
 | 
			
		||||
    PtpDelayMechanism tx_dm;    // transmit transport type
 | 
			
		||||
    PtpMessageClass tx_mc;      // transmit message class
 | 
			
		||||
 | 
			
		||||
    // --- data ---
 | 
			
		||||
    uint8_t data[MAX_PTP_MSG_SIZE];     // raw packet data
 | 
			
		||||
} RawPtpMessage;
 | 
			
		||||
 | 
			
		||||
// contents of an announce message
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint16_t originCurrentUTCOffset;
 | 
			
		||||
    uint8_t priority1;
 | 
			
		||||
    uint8_t grandmasterClockClass;
 | 
			
		||||
    uint8_t grandmasterClockAccuracy;
 | 
			
		||||
    uint16_t grandmasterClockVariance;
 | 
			
		||||
    uint8_t priority2;
 | 
			
		||||
    uint64_t grandmasterClockIdentity;
 | 
			
		||||
    uint16_t localStepsRemoved;
 | 
			
		||||
    uint8_t timeSource;
 | 
			
		||||
} PtpAnnounceBody;
 | 
			
		||||
 | 
			
		||||
typedef PtpAnnounceBody PtpMasterProperties;
 | 
			
		||||
 | 
			
		||||
// core state machine states
 | 
			
		||||
typedef enum PtpM2SState {
 | 
			
		||||
    SIdle, SWaitFollowUp
 | 
			
		||||
} PtpM2SState;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    SBMC_NO_MASTER = 0,
 | 
			
		||||
    SBMC_MASTER_OK
 | 
			
		||||
} SBmcMasterState;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    SBMC_NO_CANDIDATE = 0,
 | 
			
		||||
    SBMC_CANDIDATE_COLLECTION
 | 
			
		||||
} SBmcCandidateState;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    PTP_LOGPER_MIN = -4,
 | 
			
		||||
    PTP_LOGPER_MAX = 4,
 | 
			
		||||
    PTP_LOGPER_SYNCMATCHED = 127
 | 
			
		||||
} PtpLogMsgPeriods;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    PtpMasterProperties masterProps;    // master clock properties
 | 
			
		||||
    uint16_t masterAnnPer_ms;   // message period of current master
 | 
			
		||||
    PtpMasterProperties candProps;      // new master candidate properties
 | 
			
		||||
    uint16_t candAnnPer_ms;     // message period for master candidate
 | 
			
		||||
    bool preventMasterSwitchOver;       // set if master switchover is prohibited
 | 
			
		||||
    SBmcMasterState mstState;   // master clock state machine
 | 
			
		||||
    SBmcCandidateState candState;       // candidate state machine
 | 
			
		||||
    uint8_t candCntr;           // counter before switching master
 | 
			
		||||
    uint16_t masterTOCntr;      // current master announce dropout counter
 | 
			
		||||
    uint16_t candTOCntr;        // candidate master announce cntr
 | 
			
		||||
} PtpSBmcState;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    PtpTransportType transportType;     // transport layer
 | 
			
		||||
    PtpTransportSpecific transportSpecific;     // majorSdoId ('transportSpecific')
 | 
			
		||||
    PtpDelayMechanism delayMechanism;   // delay mechanism
 | 
			
		||||
    int8_t logDelayReqPeriod;   // logarithm of (P)DelayReq period
 | 
			
		||||
    uint8_t domainNumber;       // PTP domain number
 | 
			
		||||
} PtpProfile;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint16_t sequenceID, delay_reqSequenceID;   // last sequence IDs
 | 
			
		||||
    uint16_t lastRespondedDelReqId;     // ID of the last (P)Delay_Req got responded
 | 
			
		||||
    PtpM2SState m2sState;       // Sync-FollowUp state
 | 
			
		||||
    int8_t logSyncPeriod;       // logarithm of Sync interval
 | 
			
		||||
    uint16_t syncPeriodMs;      // ...
 | 
			
		||||
} PtpMessagingState;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t addend;            // hardware clock addend value
 | 
			
		||||
} PtpHWClockState;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    TimestampI meanPathDelay;   // mean path delay
 | 
			
		||||
} PtpNetworkState;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    double filtTimeErr;         // 0.1Hz lowpass-filtered time error
 | 
			
		||||
    bool locked;                // is the PTP locked to defined limit?
 | 
			
		||||
} PtpStats;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    // PTP profile
 | 
			
		||||
    PtpProfile profile;
 | 
			
		||||
    struct {
 | 
			
		||||
        uint16_t delReqPeriodMs;
 | 
			
		||||
    } auxProfile;               // auxiliary, auto-calculated values for the selected profile
 | 
			
		||||
 | 
			
		||||
    // Messaging state
 | 
			
		||||
    PtpMessagingState messaging;
 | 
			
		||||
 | 
			
		||||
    // Sync cycle data
 | 
			
		||||
    PtpSyncCycleData scd;
 | 
			
		||||
 | 
			
		||||
    // Hardware clock state
 | 
			
		||||
    PtpHWClockState hwclock;
 | 
			
		||||
    struct {
 | 
			
		||||
        TimestampI offset;      // PPS signal offset
 | 
			
		||||
        uint64_t clockIdentity; // clockIdentity calculated from MAC address
 | 
			
		||||
    } hwoptions;
 | 
			
		||||
 | 
			
		||||
    // Slave BMC state
 | 
			
		||||
    PtpSBmcState sbmc;
 | 
			
		||||
 | 
			
		||||
    // Network state
 | 
			
		||||
    PtpNetworkState network;
 | 
			
		||||
 | 
			
		||||
    // Logging
 | 
			
		||||
    struct {
 | 
			
		||||
        bool def;               // default
 | 
			
		||||
        bool corr;              // correction fields
 | 
			
		||||
        bool timestamps;        // timestamps
 | 
			
		||||
        bool info;              // informative messages
 | 
			
		||||
        bool locked;            // clock lock state change
 | 
			
		||||
    } logging;
 | 
			
		||||
 | 
			
		||||
    // Statistics
 | 
			
		||||
    PtpStats stats;
 | 
			
		||||
 | 
			
		||||
    // Timers...
 | 
			
		||||
    struct {
 | 
			
		||||
        TimerHandle_t sbmc;     // timer for managing SBMC operations
 | 
			
		||||
        TimerHandle_t delreq;   // timer for (P)Del_Req
 | 
			
		||||
    } timers;
 | 
			
		||||
} PtpCoreState;
 | 
			
		||||
 | 
			
		||||
// global storable-loadable configuration
 | 
			
		||||
typedef struct {
 | 
			
		||||
    PtpProfile profile;         // PTP-profile
 | 
			
		||||
    TimestampI offset;          // PPS signal offset
 | 
			
		||||
    uint32_t logging;           // logging compressed into a single bitfield
 | 
			
		||||
} PtpConfig;
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_PTP_TYPES_H_ */
 | 
			
		||||
							
								
								
									
										21
									
								
								sbmc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								sbmc.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
#include "sbmc.h"
 | 
			
		||||
#include "ptp_types.h"
 | 
			
		||||
 | 
			
		||||
#define COMPARE_AND_RETURN(pmp1,pmp2,field) {\
 | 
			
		||||
	if (pmp1->field < pmp2->field) {\
 | 
			
		||||
		return 0;\
 | 
			
		||||
	} else if (pmp1->field > pmp2->field) {\
 | 
			
		||||
		return 1;\
 | 
			
		||||
	}\
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ptp_select_better_master(PtpMasterProperties * pMP1, PtpMasterProperties * pMP2)
 | 
			
		||||
{
 | 
			
		||||
    COMPARE_AND_RETURN(pMP1, pMP2, priority1);
 | 
			
		||||
    COMPARE_AND_RETURN(pMP1, pMP2, grandmasterClockClass);
 | 
			
		||||
    COMPARE_AND_RETURN(pMP1, pMP2, grandmasterClockAccuracy);
 | 
			
		||||
    COMPARE_AND_RETURN(pMP1, pMP2, grandmasterClockVariance);
 | 
			
		||||
    COMPARE_AND_RETURN(pMP1, pMP2, priority2);
 | 
			
		||||
    COMPARE_AND_RETURN(pMP1, pMP2, grandmasterClockIdentity);
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								sbmc.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								sbmc.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
#ifndef FLEXPTP_SBMC_H_
 | 
			
		||||
#define FLEXPTP_SBMC_H_
 | 
			
		||||
 | 
			
		||||
#include "ptp_types.h"
 | 
			
		||||
 | 
			
		||||
// select better master
 | 
			
		||||
// return 0: if pMP1 is better than pMP2, 1: if reversed
 | 
			
		||||
int ptp_select_better_master(PtpMasterProperties * pMP1, PtpMasterProperties * pMP2);
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_SBMC_H_ */
 | 
			
		||||
							
								
								
									
										144
									
								
								servo/pd_controller.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								servo/pd_controller.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,144 @@
 | 
			
		||||
/* (C) András Wiesner, 2021 */
 | 
			
		||||
 | 
			
		||||
#include "pd_controller.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
#include <flexptp_options.h>
 | 
			
		||||
 | 
			
		||||
#include "../ptp_core.h"
 | 
			
		||||
 | 
			
		||||
// ----------------------------------
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
    bool internals;
 | 
			
		||||
} sLog;
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
    bool firstRun;
 | 
			
		||||
} sState;
 | 
			
		||||
 | 
			
		||||
// ----------------------------------
 | 
			
		||||
 | 
			
		||||
//static float P_FACTOR = 0.5 * 0.476;
 | 
			
		||||
//static float D_FACTOR = 2.0 * 0.476;
 | 
			
		||||
 | 
			
		||||
static float P_FACTOR = 0.5 * 0.476;
 | 
			
		||||
static float I_FACTOR = 0;
 | 
			
		||||
static float D_FACTOR = 3.0;
 | 
			
		||||
 | 
			
		||||
// ----------------------------------
 | 
			
		||||
 | 
			
		||||
static double rd_prev_ppb;      // relative frequency error measured in previous iteration
 | 
			
		||||
static double integrator_value;
 | 
			
		||||
 | 
			
		||||
// ----------------------------------
 | 
			
		||||
 | 
			
		||||
#ifdef CLI_REG_CMD
 | 
			
		||||
 | 
			
		||||
static int CB_params(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    // set if parameters passed after command
 | 
			
		||||
    if (argc >= 3) {
 | 
			
		||||
        P_FACTOR = atof(ppArgs[0]);
 | 
			
		||||
        I_FACTOR = atof(ppArgs[1]);
 | 
			
		||||
        D_FACTOR = atof(ppArgs[2]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MSG("> PTP params: K_p = %.3f, K_i = %.3f, K_d = %.3f\n", P_FACTOR, I_FACTOR, D_FACTOR);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int CB_logInternals(const CliToken_Type * ppArgs, uint8_t argc)
 | 
			
		||||
{
 | 
			
		||||
    if (argc >= 1) {
 | 
			
		||||
        int en = ONOFF(ppArgs[0]);
 | 
			
		||||
        if (en >= 0) {
 | 
			
		||||
            if (en && !sLog.internals) {
 | 
			
		||||
                MSG("\nSyncIntv. [ns] | dt [ns] | gamma [ppb]\n\n");
 | 
			
		||||
            }
 | 
			
		||||
            sLog.internals = en;
 | 
			
		||||
            return 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
    int params;
 | 
			
		||||
    int internals;
 | 
			
		||||
} sCliCmdIdx = { 0 };
 | 
			
		||||
 | 
			
		||||
static void pd_ctrl_register_cli_commands()
 | 
			
		||||
{
 | 
			
		||||
    sCliCmdIdx.params = cli_register_command("ptp servo params [Kp Kd] \t\t\tSet or query K_p and K_d servo parameters", 3, 0, CB_params);
 | 
			
		||||
    sCliCmdIdx.internals = cli_register_command("ptp servo log internals {on|off} \t\t\tEnable or disable logging of servo internals", 4, 1, CB_logInternals);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void pd_ctrl_remove_cli_commands()
 | 
			
		||||
{
 | 
			
		||||
    cli_remove_command(sCliCmdIdx.params);
 | 
			
		||||
    cli_remove_command(sCliCmdIdx.internals);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif                          // CLI_REG_CMD
 | 
			
		||||
 | 
			
		||||
void pd_ctrl_init()
 | 
			
		||||
{
 | 
			
		||||
    pd_ctrl_reset();
 | 
			
		||||
 | 
			
		||||
#ifdef CLI_REG_CMD
 | 
			
		||||
    pd_ctrl_register_cli_commands();
 | 
			
		||||
#endif                          // CLI_REG_CMD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pd_ctrl_deinit()
 | 
			
		||||
{
 | 
			
		||||
#ifdef CLI_REG_CMD
 | 
			
		||||
    pd_ctrl_remove_cli_commands();
 | 
			
		||||
#endif                          // CLI_REG_CMD
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pd_ctrl_reset()
 | 
			
		||||
{
 | 
			
		||||
    sState.firstRun = true;
 | 
			
		||||
    integrator_value = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float pd_ctrl_run(int32_t dt, PtpServoAuxInput * pAux)
 | 
			
		||||
{
 | 
			
		||||
    if (sState.firstRun) {
 | 
			
		||||
        sState.firstRun = false;
 | 
			
		||||
        rd_prev_ppb = dt;
 | 
			
		||||
        integrator_value = 0;
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // calculate relative frequency error
 | 
			
		||||
    //double rd_ppb = ((double) dt) / (pAux->msgPeriodMs * 1E+06 + dt) * 1E+09;
 | 
			
		||||
    double rd_ppb = ((double)dt) / (pAux->measSyncPeriod + dt) * 1E+09;
 | 
			
		||||
 | 
			
		||||
    // calculate difference
 | 
			
		||||
    double rd_D_ppb = D_FACTOR * (rd_ppb - rd_prev_ppb);
 | 
			
		||||
 | 
			
		||||
    // calculate output (run the PD controller)
 | 
			
		||||
    double corr_ppb = -(P_FACTOR * (rd_ppb + rd_D_ppb) + integrator_value) * exp((pAux->measSyncPeriod * 1E-09) - 1.0);
 | 
			
		||||
 | 
			
		||||
    // update integrator
 | 
			
		||||
    integrator_value += I_FACTOR * rd_ppb;
 | 
			
		||||
 | 
			
		||||
    // store error value (time difference) for use in next iteration
 | 
			
		||||
    rd_prev_ppb = rd_ppb;
 | 
			
		||||
 | 
			
		||||
    CLILOG(sLog.internals, "%d %f\n", dt, rd_ppb);
 | 
			
		||||
 | 
			
		||||
    return corr_ppb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ----------------------------------
 | 
			
		||||
							
								
								
									
										15
									
								
								servo/pd_controller.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								servo/pd_controller.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
/* (C) András Wiesner, 2021 */
 | 
			
		||||
 | 
			
		||||
#ifndef SERVO_PD_CONTROLLER_H_
 | 
			
		||||
#define SERVO_PD_CONTROLLER_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "../ptp_servo_types.h"
 | 
			
		||||
 | 
			
		||||
void pd_ctrl_init();            // initialize PD controller
 | 
			
		||||
void pd_ctrl_deinit();          // deinitialize PD controller
 | 
			
		||||
void pd_ctrl_reset();           // reset controller
 | 
			
		||||
float pd_ctrl_run(int32_t dt, PtpServoAuxInput * pAux); // run the controller (input: time error in nanosec)
 | 
			
		||||
 | 
			
		||||
#endif                          /* SERVO_PD_CONTROLLER_H_ */
 | 
			
		||||
							
								
								
									
										64
									
								
								settings_interface.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								settings_interface.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
#include "settings_interface.h"
 | 
			
		||||
 | 
			
		||||
#include "ptp_core.h"
 | 
			
		||||
 | 
			
		||||
extern PtpCoreState gPtpCoreState;
 | 
			
		||||
#define S (gPtpCoreState)
 | 
			
		||||
 | 
			
		||||
// set PPS offset
 | 
			
		||||
void ptp_set_clock_offset(int32_t offset)
 | 
			
		||||
{
 | 
			
		||||
    nsToTsI(&S.hwoptions.offset, offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// get PPS offset
 | 
			
		||||
int32_t ptp_get_clock_offset()
 | 
			
		||||
{
 | 
			
		||||
    return nsI(&S.hwoptions.offset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_prefer_master_clock(uint64_t clockId)
 | 
			
		||||
{
 | 
			
		||||
    S.sbmc.preventMasterSwitchOver = true;
 | 
			
		||||
    S.sbmc.masterProps.grandmasterClockIdentity = clockId;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_unprefer_master_clock()
 | 
			
		||||
{
 | 
			
		||||
    S.sbmc.preventMasterSwitchOver = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t ptp_get_current_master_clock_identity()
 | 
			
		||||
{
 | 
			
		||||
    return S.sbmc.masterProps.grandmasterClockIdentity;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t ptp_get_own_clock_identity()
 | 
			
		||||
{
 | 
			
		||||
    return S.hwoptions.clockIdentity;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_set_domain(uint8_t domain)
 | 
			
		||||
{
 | 
			
		||||
    S.profile.domainNumber = domain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t ptp_get_domain()
 | 
			
		||||
{
 | 
			
		||||
    return S.profile.domainNumber;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_set_addend(uint32_t addend)
 | 
			
		||||
{
 | 
			
		||||
    S.hwclock.addend = addend;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t ptp_get_addend()
 | 
			
		||||
{
 | 
			
		||||
    return S.hwclock.addend;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ptp_time(TimestampU * pT)
 | 
			
		||||
{
 | 
			
		||||
    PTP_HW_GET_TIME(pT);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								settings_interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								settings_interface.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
#ifndef FLEXPTP_SETTINGS_INTERFACE_H_
 | 
			
		||||
#define FLEXPTP_SETTINGS_INTERFACE_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "ptp_types.h"
 | 
			
		||||
 | 
			
		||||
void ptp_set_clock_offset(int32_t offset);      // set clock offset in nanoseconds
 | 
			
		||||
int32_t ptp_get_clock_offset(); // get clock offset in nanoseconds
 | 
			
		||||
void ptp_prefer_master_clock(uint64_t clockId); // lock slave to a particular master
 | 
			
		||||
void ptp_unprefer_master_clock();       // allow slave to synchronize to the BMCA-elected master
 | 
			
		||||
uint64_t ptp_get_current_master_clock_identity();       // get current master clock ID
 | 
			
		||||
uint64_t ptp_get_own_clock_identity();  // get out clock identity
 | 
			
		||||
void ptp_set_domain(uint8_t domain);    // set PTP domain
 | 
			
		||||
uint8_t ptp_get_domain();       // get PTP domain
 | 
			
		||||
void ptp_set_addend(uint32_t addend);   // set hardware clock addend (frequency tuning!)
 | 
			
		||||
uint32_t ptp_get_addend();      // get hardware clock addend
 | 
			
		||||
 | 
			
		||||
void ptp_time(TimestampU * pT); // get time
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_SETTINGS_INTERFACE_H_ */
 | 
			
		||||
							
								
								
									
										42
									
								
								stats.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								stats.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
			
		||||
#include "stats.h"
 | 
			
		||||
 | 
			
		||||
#include "ptp_core.h"
 | 
			
		||||
#include "ptp_defs.h"
 | 
			
		||||
 | 
			
		||||
#include <memory.h>
 | 
			
		||||
 | 
			
		||||
#define S (gPtpCoreState)
 | 
			
		||||
 | 
			
		||||
// clear statistics
 | 
			
		||||
void ptp_clear_stats()
 | 
			
		||||
{
 | 
			
		||||
    memset(&S.stats, 0, sizeof(PtpStats));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// get statistics
 | 
			
		||||
const PtpStats *ptp_get_stats()
 | 
			
		||||
{
 | 
			
		||||
    return &S.stats;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// filter parameters for statistics calculation
 | 
			
		||||
// WARNING: Data calculation won't be totally accurate due to changing sampling time!
 | 
			
		||||
 | 
			
		||||
#define PTP_TE_FILT_Fc_HZ (0.1) // cutoff frequency (Hz)
 | 
			
		||||
#define PTP_TE_FILT_Ts_S (1)    // sampling time (s)
 | 
			
		||||
 | 
			
		||||
// collect statistics
 | 
			
		||||
void ptp_collect_stats(int64_t d)
 | 
			
		||||
{
 | 
			
		||||
    double a = exp(-PTP_TE_FILT_Fc_HZ * 2 * M_PI * (S.messaging.syncPeriodMs / 1000.0));
 | 
			
		||||
 | 
			
		||||
    // performing time error filtering
 | 
			
		||||
    double y_prev = S.stats.filtTimeErr, y;
 | 
			
		||||
    y = a * y_prev + (1 - a) * d;       // filtering equation
 | 
			
		||||
    S.stats.filtTimeErr = y;
 | 
			
		||||
 | 
			
		||||
    // set locked state
 | 
			
		||||
    bool locked = ((fabs(S.stats.filtTimeErr) < (PTP_ACCURACY_LIMIT_NS)) && (ptp_get_current_master_clock_identity() != 0));
 | 
			
		||||
    CLILOG(S.logging.locked && (locked != S.stats.locked), "PTP %s!", locked ? "LOCKED" : "DIVERGED");
 | 
			
		||||
    S.stats.locked = locked;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								stats.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								stats.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
#ifndef FLEXPTP_STATS_H_
 | 
			
		||||
#define FLEXPTP_STATS_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include "ptp_types.h"
 | 
			
		||||
 | 
			
		||||
void ptp_clear_stats();         // clear statistics
 | 
			
		||||
const PtpStats *ptp_get_stats();        // get statistics
 | 
			
		||||
void ptp_collect_stats(int64_t d);      // collect statistics
 | 
			
		||||
 | 
			
		||||
#endif                          /* FLEXPTP_STATS_H_ */
 | 
			
		||||
							
								
								
									
										244
									
								
								task_ptp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								task_ptp.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,244 @@
 | 
			
		||||
#include "FreeRTOS.h"
 | 
			
		||||
#include "task.h"
 | 
			
		||||
#include "queue.h"
 | 
			
		||||
 | 
			
		||||
#include <flexptp_options.h>
 | 
			
		||||
 | 
			
		||||
#include "ptp_core.h"
 | 
			
		||||
#include "task_ptp.h"
 | 
			
		||||
 | 
			
		||||
#include "lwip/igmp.h"
 | 
			
		||||
 | 
			
		||||
#include "ptp_defs.h"
 | 
			
		||||
 | 
			
		||||
#include "ptp_msg_tx.h"
 | 
			
		||||
 | 
			
		||||
#include "ptp_raw_msg_circbuf.h"
 | 
			
		||||
 | 
			
		||||
#include "settings_interface.h"
 | 
			
		||||
 | 
			
		||||
// ----- TASK PROPERTIES -----
 | 
			
		||||
static TaskHandle_t sTH;        // task handle
 | 
			
		||||
static uint8_t sPrio = 5;       // priority
 | 
			
		||||
static uint16_t sStkSize = 4096;        // stack size
 | 
			
		||||
void task_ptp(void *pParam);    // task routine function
 | 
			
		||||
// ---------------------------
 | 
			
		||||
 | 
			
		||||
static bool sPTP_operating = false;     // does the PTP subsystem operate?
 | 
			
		||||
 | 
			
		||||
// ---------------------------
 | 
			
		||||
 | 
			
		||||
// udp control blocks
 | 
			
		||||
static struct udp_pcb *spPTP_PRIMARY_EVENT_pcb = NULL;
 | 
			
		||||
static struct udp_pcb *spPTP_PRIMARY_GENERAL_pcb = NULL;
 | 
			
		||||
 | 
			
		||||
// callback function receiveing data from udp "sockets"
 | 
			
		||||
void ptp_recv_cb(void *pArg, struct udp_pcb *pPCB, struct pbuf *pP, const ip_addr_t * pAddr, uint16_t port);
 | 
			
		||||
 | 
			
		||||
// FIFO for incoming packets
 | 
			
		||||
#define RX_PACKET_FIFO_LENGTH (32)
 | 
			
		||||
#define TX_PACKET_FIFO_LENGTH (16)
 | 
			
		||||
static QueueHandle_t sRxPacketFIFO;
 | 
			
		||||
QueueHandle_t gTxPacketFIFO;
 | 
			
		||||
static QueueSetHandle_t sRxTxFIFOSet;
 | 
			
		||||
 | 
			
		||||
// create udp listeners
 | 
			
		||||
void create_ptp_listeners()
 | 
			
		||||
{
 | 
			
		||||
    // create packet FIFO
 | 
			
		||||
    sRxPacketFIFO = xQueueCreate(RX_PACKET_FIFO_LENGTH, sizeof(uint8_t));
 | 
			
		||||
    gTxPacketFIFO = xQueueCreate(TX_PACKET_FIFO_LENGTH, sizeof(uint8_t));
 | 
			
		||||
    sRxTxFIFOSet = xQueueCreateSet(RX_PACKET_FIFO_LENGTH + TX_PACKET_FIFO_LENGTH);
 | 
			
		||||
    xQueueAddToSet(sRxPacketFIFO, sRxTxFIFOSet);
 | 
			
		||||
    xQueueAddToSet(gTxPacketFIFO, sRxTxFIFOSet);
 | 
			
		||||
 | 
			
		||||
    // PRIMARY EVENT (...1.129:319)
 | 
			
		||||
    spPTP_PRIMARY_EVENT_pcb = udp_new();
 | 
			
		||||
    udp_bind(spPTP_PRIMARY_EVENT_pcb, &PTP_IGMP_PRIMARY, PTP_PORT_EVENT);
 | 
			
		||||
    udp_recv(spPTP_PRIMARY_EVENT_pcb, ptp_recv_cb, NULL);
 | 
			
		||||
 | 
			
		||||
    // PRIMARY GENERAL (...1.129:320)
 | 
			
		||||
    spPTP_PRIMARY_GENERAL_pcb = udp_new();
 | 
			
		||||
    udp_bind(spPTP_PRIMARY_GENERAL_pcb, &PTP_IGMP_PRIMARY, PTP_PORT_GENERAL);
 | 
			
		||||
    udp_recv(spPTP_PRIMARY_GENERAL_pcb, ptp_recv_cb, NULL);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// remove listeners
 | 
			
		||||
void destroy_ptp_listeners()
 | 
			
		||||
{
 | 
			
		||||
    // disconnect UDP "sockets"
 | 
			
		||||
    udp_disconnect(spPTP_PRIMARY_EVENT_pcb);
 | 
			
		||||
    udp_disconnect(spPTP_PRIMARY_GENERAL_pcb);
 | 
			
		||||
 | 
			
		||||
    // destroy UDP sockets
 | 
			
		||||
    udp_remove(spPTP_PRIMARY_EVENT_pcb);
 | 
			
		||||
    udp_remove(spPTP_PRIMARY_GENERAL_pcb);
 | 
			
		||||
 | 
			
		||||
    // destroy packet FIFO
 | 
			
		||||
    xQueueRemoveFromSet(sRxPacketFIFO, sRxTxFIFOSet);
 | 
			
		||||
    xQueueRemoveFromSet(gTxPacketFIFO, sRxTxFIFOSet);
 | 
			
		||||
    vQueueDelete(sRxPacketFIFO);
 | 
			
		||||
    vQueueDelete(gTxPacketFIFO);
 | 
			
		||||
    vQueueDelete(sRxTxFIFOSet);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// join PTP IGMP groups
 | 
			
		||||
void join_ptp_igmp_groups()
 | 
			
		||||
{
 | 
			
		||||
    // join group for default set of messages (everything except for peer delay)
 | 
			
		||||
    igmp_joingroup(&netif_default->ip_addr, &PTP_IGMP_PRIMARY);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// leave PTP IGMP group
 | 
			
		||||
void leave_ptp_igmp_groups()
 | 
			
		||||
{
 | 
			
		||||
    // leave default group
 | 
			
		||||
    igmp_leavegroup(&netif_default->ip_addr, &PTP_IGMP_PRIMARY);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// "ring" buffer for PTP-messages
 | 
			
		||||
PtpCircBuf gRawRxMsgBuf, gRawTxMsgBuf;
 | 
			
		||||
static RawPtpMessage sRawRxMsgBufPool[RX_PACKET_FIFO_LENGTH];
 | 
			
		||||
static RawPtpMessage sRawTxMsgBufPool[TX_PACKET_FIFO_LENGTH];
 | 
			
		||||
 | 
			
		||||
static void init_raw_buffers()
 | 
			
		||||
{
 | 
			
		||||
    ptp_circ_buf_init(&gRawRxMsgBuf, sRawRxMsgBufPool, RX_PACKET_FIFO_LENGTH);
 | 
			
		||||
    ptp_circ_buf_init(&gRawTxMsgBuf, sRawTxMsgBufPool, TX_PACKET_FIFO_LENGTH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// register PTP task and initialize
 | 
			
		||||
void reg_task_ptp()
 | 
			
		||||
{
 | 
			
		||||
    init_raw_buffers();         // initialize raw buffers
 | 
			
		||||
 | 
			
		||||
    ptp_init();                 // initialize PTP subsystem
 | 
			
		||||
 | 
			
		||||
#ifdef PTP_CONFIG_PTR           // load config if provided
 | 
			
		||||
    MSG("Loading PTP-config!\n");
 | 
			
		||||
    ptp_load_config_from_dump(PTP_CONFIG_PTR());
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // create UDP sockets regardless the transfer type
 | 
			
		||||
    join_ptp_igmp_groups();     // enter PTP IGMP groups
 | 
			
		||||
    create_ptp_listeners();     // create listeners
 | 
			
		||||
#ifndef SIMULATION
 | 
			
		||||
    ptp_transmit_init(spPTP_PRIMARY_EVENT_pcb, spPTP_PRIMARY_GENERAL_pcb,);     // initialize transmit function*/
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // create task
 | 
			
		||||
    BaseType_t result = xTaskCreate(task_ptp, "ptp", sStkSize, NULL, sPrio, &sTH);
 | 
			
		||||
    if (result != pdPASS) {
 | 
			
		||||
        MSG("Failed to create task! (errcode: %d)\n", result);
 | 
			
		||||
        unreg_task_ptp();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sPTP_operating = true;      // the PTP subsystem is operating
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// unregister PTP task
 | 
			
		||||
void unreg_task_ptp()
 | 
			
		||||
{
 | 
			
		||||
    vTaskDelete(sTH);           // taszk törlése
 | 
			
		||||
 | 
			
		||||
    ptp_deinit();               // ptp subsystem de-initialization
 | 
			
		||||
 | 
			
		||||
    // destroy listeners
 | 
			
		||||
    leave_ptp_igmp_groups();    // leave IGMP groups
 | 
			
		||||
    destroy_ptp_listeners();    // delete listeners
 | 
			
		||||
 | 
			
		||||
    sPTP_operating = false;     // the PTP subsystem is operating
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// callback for packet reception on port 319 and 320
 | 
			
		||||
void ptp_recv_cb(void *pArg, struct udp_pcb *pPCB, struct pbuf *pP, const ip_addr_t * pAddr, uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
    // put msg into the queue
 | 
			
		||||
    ptp_enqueue_msg(pP->payload, pP->len, pP->time_s, pP->time_ns, PTP_TP_IPv4);
 | 
			
		||||
 | 
			
		||||
    // release pbuf resources
 | 
			
		||||
    pbuf_free(pP);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// put ptp message onto processing queue
 | 
			
		||||
void ptp_enqueue_msg(void *pPayload, uint32_t len, uint32_t ts_sec, uint32_t ts_ns, int tp)
 | 
			
		||||
{
 | 
			
		||||
    // only consider messages received on the matching transport layer
 | 
			
		||||
    if (tp != ptp_get_transport_type()) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // enqueue message
 | 
			
		||||
    RawPtpMessage *pMsg = ptp_circ_buf_alloc(&gRawRxMsgBuf);
 | 
			
		||||
    if (pMsg) {
 | 
			
		||||
        // copy payload and timestamp
 | 
			
		||||
        uint32_t copyLen = MIN(len, MAX_PTP_MSG_SIZE);
 | 
			
		||||
        memcpy(pMsg->data, pPayload, copyLen);
 | 
			
		||||
        pMsg->size = copyLen;
 | 
			
		||||
        pMsg->ts.sec = ts_sec;
 | 
			
		||||
        pMsg->ts.nanosec = ts_ns;
 | 
			
		||||
        pMsg->pTs = NULL;
 | 
			
		||||
        pMsg->pTxCb = NULL;     // not meaningful...
 | 
			
		||||
 | 
			
		||||
        uint8_t idx = ptp_circ_buf_commit(&gRawRxMsgBuf);
 | 
			
		||||
 | 
			
		||||
        xQueueSend(sRxPacketFIFO, &idx, portMAX_DELAY); // send index
 | 
			
		||||
    } else {
 | 
			
		||||
        MSG("PTP-packet buffer full, a packet has been dropped!\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // MSG("TS: %u.%09u\n", (uint32_t)ts_sec, (uint32_t)ts_ns);
 | 
			
		||||
 | 
			
		||||
    // if the transport layer matches...
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// taszk függvénye
 | 
			
		||||
void task_ptp(void *pParam)
 | 
			
		||||
{
 | 
			
		||||
    while (1) {
 | 
			
		||||
        // wait for received packet or packet to transfer
 | 
			
		||||
        QueueHandle_t activeQueue = xQueueSelectFromSet(sRxTxFIFOSet, pdMS_TO_TICKS(200));
 | 
			
		||||
 | 
			
		||||
        // if packet is on the RX queue
 | 
			
		||||
        if (activeQueue == sRxPacketFIFO) {
 | 
			
		||||
            // pop packet from FIFO
 | 
			
		||||
            uint8_t bufIdx;
 | 
			
		||||
            xQueueReceive(sRxPacketFIFO, &bufIdx, portMAX_DELAY);
 | 
			
		||||
 | 
			
		||||
            // fetch buffer
 | 
			
		||||
            RawPtpMessage *pRawMsg = ptp_circ_buf_get(&gRawRxMsgBuf, bufIdx);
 | 
			
		||||
            pRawMsg->pTs = &pRawMsg->ts;
 | 
			
		||||
 | 
			
		||||
            // process packet
 | 
			
		||||
            ptp_process_packet(pRawMsg);
 | 
			
		||||
 | 
			
		||||
            // free buffer
 | 
			
		||||
            ptp_circ_buf_free(&gRawRxMsgBuf);
 | 
			
		||||
        } else if (activeQueue == gTxPacketFIFO) {
 | 
			
		||||
            // pop packet from FIFO
 | 
			
		||||
            uint8_t bufIdx;
 | 
			
		||||
            xQueueReceive(gTxPacketFIFO, &bufIdx, portMAX_DELAY);
 | 
			
		||||
 | 
			
		||||
            // fetch buffer
 | 
			
		||||
            RawPtpMessage *pRawMsg = ptp_circ_buf_get(&gRawTxMsgBuf, bufIdx);
 | 
			
		||||
            ptp_transmit_msg(pRawMsg);
 | 
			
		||||
 | 
			
		||||
            // free buffer
 | 
			
		||||
            ptp_circ_buf_free(&gRawTxMsgBuf);
 | 
			
		||||
        } else {
 | 
			
		||||
            // ....
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// --------------------------
 | 
			
		||||
 | 
			
		||||
// function to query PTP operation state
 | 
			
		||||
bool task_ptp_is_operating()
 | 
			
		||||
{
 | 
			
		||||
    return sPTP_operating;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								task_ptp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								task_ptp.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
#ifndef TASK_PTP_H_
 | 
			
		||||
#define TASK_PTP_H_
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
void reg_task_ptp();            // register PTP task
 | 
			
		||||
void unreg_task_ptp();          // unregister PTP task
 | 
			
		||||
bool task_ptp_is_operating();   // does PTP task operate?
 | 
			
		||||
void ptp_enqueue_msg(void *pPayload, uint32_t len, uint32_t ts_sec, uint32_t ts_ns, int tp);    // put PTP-message on queue
 | 
			
		||||
 | 
			
		||||
#endif                          // TASK_PTP_H_
 | 
			
		||||
							
								
								
									
										135
									
								
								timeutils.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								timeutils.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,135 @@
 | 
			
		||||
/* (C) András Wiesner, 2020 */
 | 
			
		||||
 | 
			
		||||
#include "timeutils.h"
 | 
			
		||||
 | 
			
		||||
#include <flexptp_options.h>
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
// TimestampU -> TimestampI
 | 
			
		||||
TimestampI *tsUToI(TimestampI * ti, const TimestampU * tu)
 | 
			
		||||
{
 | 
			
		||||
    ti->sec = (int64_t) tu->sec;
 | 
			
		||||
    ti->nanosec = (int32_t) tu->nanosec;
 | 
			
		||||
    return ti;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// r = a + b;
 | 
			
		||||
TimestampI *addTime(TimestampI * r, const TimestampI * a, const TimestampI * b)
 | 
			
		||||
{
 | 
			
		||||
    int64_t ns = nsI(a) + nsI(b);
 | 
			
		||||
    nsToTsI(r, ns);
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// r = a - b;
 | 
			
		||||
TimestampI *subTime(TimestampI * r, const TimestampI * a, const TimestampI * b)
 | 
			
		||||
{
 | 
			
		||||
    int64_t ns = nsI(a) - nsI(b);
 | 
			
		||||
    nsToTsI(r, ns);
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TimestampI *divTime(TimestampI * r, const TimestampI * a, int divisor)
 | 
			
		||||
{
 | 
			
		||||
    int64_t ns = a->sec * NANO_PREFIX + a->nanosec;
 | 
			
		||||
    ns = ns / divisor;          // így a pontosság +-0.5ns
 | 
			
		||||
    r->sec = ns / NANO_PREFIX;
 | 
			
		||||
    r->nanosec = ns - r->sec * NANO_PREFIX;
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t nsU(const TimestampU * t)
 | 
			
		||||
{
 | 
			
		||||
    return t->sec * NANO_PREFIX + t->nanosec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t nsI(const TimestampI * t)
 | 
			
		||||
{
 | 
			
		||||
    return t->sec * NANO_PREFIX + t->nanosec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void normTime(TimestampI * t)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t s = t->nanosec / NANO_PREFIX;
 | 
			
		||||
    t->sec += s;
 | 
			
		||||
    t->nanosec -= s * NANO_PREFIX;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int64_t tsToTick(const TimestampI * ts, uint32_t tps)
 | 
			
		||||
{
 | 
			
		||||
    int64_t ns = ts->sec * NANO_PREFIX + ts->nanosec;
 | 
			
		||||
    int64_t ticks = (ns * tps) / NANO_PREFIX;
 | 
			
		||||
    return ticks;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TimestampI *nsToTsI(TimestampI * r, int64_t ns)
 | 
			
		||||
{
 | 
			
		||||
    r->sec = ns / NANO_PREFIX;
 | 
			
		||||
    r->nanosec = ns % NANO_PREFIX;
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool nonZeroI(const TimestampI * a)
 | 
			
		||||
{
 | 
			
		||||
    return a->sec != 0 || a->nanosec != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned FIRST_DAY_OF_MONTH[] = { 0, 31, 59, 60, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
 | 
			
		||||
 | 
			
		||||
void tsPrint(char *str, const TimestampI * ts)
 | 
			
		||||
{
 | 
			
		||||
    unsigned fouryear, year, month, day, hour, minute, sec, rem;
 | 
			
		||||
 | 
			
		||||
    fouryear = ts->sec / T_SEC_PER_FOURYEAR;    // determine elapsed four year blocks from 1970 (YYLY)
 | 
			
		||||
    rem = ts->sec - fouryear * T_SEC_PER_FOURYEAR;      // compute remaining seconds
 | 
			
		||||
    year = fouryear * 4;        // calculate years fouryear-block part
 | 
			
		||||
 | 
			
		||||
    // split up four-year blocks into distinct years
 | 
			
		||||
    if (rem > T_SEC_PER_YEAR) {
 | 
			
		||||
        year++;
 | 
			
		||||
        rem -= T_SEC_PER_YEAR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rem > T_SEC_PER_YEAR) {
 | 
			
		||||
        year++;
 | 
			
		||||
        rem -= T_SEC_PER_YEAR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rem > T_SEC_PER_LEAPYEAR) {
 | 
			
		||||
        year++;
 | 
			
		||||
        rem -= T_SEC_PER_LEAPYEAR;
 | 
			
		||||
    }
 | 
			
		||||
    // convert remaining seconds to days
 | 
			
		||||
    day = rem / T_SEC_PER_DAY;
 | 
			
		||||
    rem -= day * T_SEC_PER_DAY;
 | 
			
		||||
    day++;
 | 
			
		||||
 | 
			
		||||
    year += 1970;
 | 
			
		||||
    bool leapyear = year % 4 == 0;
 | 
			
		||||
 | 
			
		||||
    // get month from days
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
    for (i = 0; i < 12; i++) {
 | 
			
		||||
        unsigned first1 = FIRST_DAY_OF_MONTH[i] + (((i >= 2) && leapyear) ? 1 : 0);
 | 
			
		||||
        unsigned first2 = FIRST_DAY_OF_MONTH[i + 1] + (((i + 1 >= 2) && leapyear) ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
        if (day > first1 && day <= first2) {
 | 
			
		||||
            month = i + 1;
 | 
			
		||||
            day = day - first1;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // get time
 | 
			
		||||
    hour = rem / T_SEC_PER_HOUR;
 | 
			
		||||
    rem -= hour * T_SEC_PER_HOUR;
 | 
			
		||||
    minute = rem / T_SEC_PER_MINUTE;
 | 
			
		||||
    rem -= minute * T_SEC_PER_MINUTE;
 | 
			
		||||
    sec = rem;
 | 
			
		||||
 | 
			
		||||
    // -------------------------------
 | 
			
		||||
 | 
			
		||||
    // print datetime
 | 
			
		||||
    SPRINTF(str, 20, "%02d-%02d-%04d %02d:%02d:%02d", day, month, year, hour, minute, sec);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								timeutils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								timeutils.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
/* (C) András Wiesner, 2020 */
 | 
			
		||||
 | 
			
		||||
#ifndef TIMEUTILS_H
 | 
			
		||||
#define TIMEUTILS_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
// timestamp (unsigned)
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint64_t sec;
 | 
			
		||||
    uint32_t nanosec;
 | 
			
		||||
} TimestampU;
 | 
			
		||||
 | 
			
		||||
// timestamp (signed)
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int64_t sec;
 | 
			
		||||
    int32_t nanosec;
 | 
			
		||||
} TimestampI;
 | 
			
		||||
 | 
			
		||||
#define NANO_PREFIX (1000000000)
 | 
			
		||||
#define NANO_PREFIX_F (1000000000.0f)
 | 
			
		||||
 | 
			
		||||
#define T_SEC_PER_MINUTE (60)
 | 
			
		||||
#define T_SEC_PER_HOUR (60 * T_SEC_PER_MINUTE)
 | 
			
		||||
#define T_SEC_PER_DAY (24 * T_SEC_PER_HOUR)
 | 
			
		||||
#define T_SEC_PER_YEAR (365 * T_SEC_PER_DAY)
 | 
			
		||||
#define T_SEC_PER_LEAPYEAR (366 * T_SEC_PER_DAY)
 | 
			
		||||
#define T_SEC_PER_FOURYEAR (3 * T_SEC_PER_YEAR + T_SEC_PER_LEAPYEAR)
 | 
			
		||||
 | 
			
		||||
// TIME OPERATIONS
 | 
			
		||||
TimestampI *tsUToI(TimestampI * ti, const TimestampU * tu);     // convert unsigned timestamp to signed
 | 
			
		||||
TimestampI *addTime(TimestampI * r, const TimestampI * a, const TimestampI * b);        // sum timestamps (r = a + b)
 | 
			
		||||
TimestampI *subTime(TimestampI * r, const TimestampI * a, const TimestampI * b);        // substract timestamps (r = a - b)
 | 
			
		||||
TimestampI *divTime(TimestampI * r, const TimestampI * a, int divisor); // divide time value by an integer
 | 
			
		||||
uint64_t nsU(const TimestampU * t);     // convert unsigned time into nanoseconds
 | 
			
		||||
int64_t nsI(const TimestampI * t);      // convert signed time into nanoseconds
 | 
			
		||||
void normTime(TimestampI * t);  // normalize time
 | 
			
		||||
int64_t tsToTick(const TimestampI * ts, uint32_t tps);  // convert time to hardware ticks, tps: ticks per second
 | 
			
		||||
TimestampI *nsToTsI(TimestampI * r, int64_t ns);        // convert nanoseconds to time
 | 
			
		||||
bool nonZeroI(const TimestampI * a);    // does the timestamp differ from zero?
 | 
			
		||||
 | 
			
		||||
void tsPrint(char *str, const TimestampI * ts); // print datetime to string, string must be 20-long at least!
 | 
			
		||||
 | 
			
		||||
#endif                          /* TIMEUTILS_H */
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user