Commit ca626c92 authored by Alessandro Rubini's avatar Alessandro Rubini

userspace: copy libptpnetif from ptp-noposix

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent a5b624eb
......@@ -12,7 +12,7 @@ WR_INSTALL_ROOT ?= $(WRS_OUTPUT_DIR)/images/wr
WRDEV_DIR ?= $(WRS_BASE_DIR)/..
# subdirectories we want to compile
SUBDIRS = mini-rpc libswitchhw wrsw_hal wrsw_rtud tools
SUBDIRS = libptpnetif mini-rpc libswitchhw wrsw_hal wrsw_rtud tools
# all variables are exported
export
......
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
CFLAGS = -Wall -ggdb -O2 -I../wrsw_hal -I../mini-rpc
all: libptpnetif.a
libptpnetif.a: ptpd_netif.o hal_client.o
$(AR) r $@ $^
clean:
rm -f *.a *.o *~
install:
@echo "We have no install rule by now"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <minipc.h>
#define HAL_EXPORT_STRUCTURES
#include "hal_exports.h"
#define DEFAULT_TO 200000 /* ms */
static struct minipc_ch *hal_ch;
int halexp_check_running()
{
//int res_int;
//return wripc_call(hal_ipc, "halexp_check_running", ;
return 0;
}
int halexp_reset_port(const char *port_name)
{
// TRACE(TRACE_INFO, "resetting port %s\n", port_name);
return 0;
}
int halexp_calibration_cmd(const char *port_name, int command, int on_off)
{
int ret, rval;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_calibration_cmd,
&rval, port_name, command, on_off);
if (ret < 0)
return ret;
return rval;
}
int halexp_lock_cmd(const char *port_name, int command, int priority)
{
int ret, rval;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_lock_cmd,
&rval, port_name, command, priority);
if (ret < 0)
return ret;
return rval;
}
int halexp_query_ports(hexp_port_list_t *list)
{
int ret;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_query_ports,
list /* return val */);
return ret;
}
int halexp_get_port_state(hexp_port_state_t *state, const char *port_name)
{
int ret;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_get_port_state,
state /* retval */, port_name);
return ret;
}
int halexp_pps_cmd(int cmd, hexp_pps_params_t *params)
{
int ret, rval;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_pps_cmd,
&rval, cmd, params);
if (ret < 0)
return ret;
return rval;
}
int halexp_get_timing_state(hexp_timing_state_t *tstate)
{
int ret;
ret = minipc_call(hal_ch, DEFAULT_TO, &__rpcdef_get_timing_state,
tstate);
if (ret < 0)
return ret;
return 0;
}
int halexp_client_try_connect(int retries, int timeout)
{
for(;;) {
hal_ch = minipc_client_create(WRSW_HAL_SERVER_ADDR, MINIPC_FLAG_VERBOSE);
if (hal_ch == 0)
retries--;
else
return 0;
if(!retries)
return -1;
usleep(timeout);
}
return -1;
}
int halexp_client_init()
{
return halexp_client_try_connect(0, 0);
}
\ No newline at end of file
#ifndef __HAL_CLIENT_H
#define __HAL_CLIENT_H
#include "hal_exports.h"
int halexp_client_init();
int halexp_client_try_connect(int retries, int timeout);
#endif
// Wrapper functions for network/timestamping/adjustment operations
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/net_tstamp.h>
#include <linux/errqueue.h>
#include <linux/sockios.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <fcntl.h>
#include <errno.h>
#include <asm/socket.h>
#include "ptpd_netif.h"
#include "hal_client.h"
#ifdef NETIF_VERBOSE
#define netif_dbg(...) printf(__VA_ARGS__)
#else
#define netif_dbg(...)
#endif
#define ETHER_MTU 1518
#define DMTD_UPDATE_INTERVAL 500
struct scm_timestamping {
struct timespec systime;
struct timespec hwtimetrans;
struct timespec hwtimeraw;
};
PACKED struct etherpacket {
struct ethhdr ether;
char data[ETHER_MTU];
};
typedef struct
{
uint64_t start_tics;
uint64_t timeout;
} timeout_t ;
struct my_socket {
int fd;
wr_sockaddr_t bind_addr;
mac_addr_t local_mac;
int if_index;
// parameters for linearization of RX timestamps
uint32_t clock_period;
uint32_t phase_transition;
uint32_t dmtd_phase;
int dmtd_phase_valid;
timeout_t dmtd_update_tmo;
};
static uint64_t get_tics()
{
struct timezone tz = {0, 0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (uint64_t) tv.tv_sec * 1000000ULL + (uint64_t) tv.tv_usec;
}
static inline int tmo_init(timeout_t *tmo, uint32_t milliseconds)
{
tmo->start_tics = get_tics();
tmo->timeout = (uint64_t) milliseconds * 1000ULL;
return 0;
}
static inline int tmo_restart(timeout_t *tmo)
{
tmo->start_tics = get_tics();
return 0;
}
static inline int tmo_expired(timeout_t *tmo)
{
return (get_tics() - tmo->start_tics > tmo->timeout);
}
// cheks if x is inside range <min, max>
static inline int inside_range(int min, int max, int x)
{
if(min < max)
return (x>=min && x<=max);
else
return (x<=max || x>=min);
}
/* For debugging/testing purposes */
int ptpd_netif_get_dmtd_phase(wr_socket_t *sock, int32_t *phase)
{
struct my_socket *s = (struct my_socket *) sock;
hexp_port_state_t pstate;
halexp_get_port_state(&pstate, s->bind_addr.if_name);
if(phase) *phase = pstate.phase_val;
return pstate.phase_val_valid;
}
static void update_dmtd(wr_socket_t *sock)
{
struct my_socket *s = (struct my_socket *) sock;
hexp_port_state_t pstate;
if(tmo_expired(&s->dmtd_update_tmo))
{
halexp_get_port_state(&pstate, s->bind_addr.if_name);
// FIXME: ccheck if phase value is ready
s->dmtd_phase = pstate.phase_val;
s->dmtd_phase_valid = pstate.phase_val_valid;
tmo_restart(&s->dmtd_update_tmo);
}
}
void ptpd_netif_linearize_rx_timestamp(wr_timestamp_t *ts, int32_t dmtd_phase, int cntr_ahead, int transition_point, int clock_period)
{
int trip_lo, trip_hi;
int phase;
// "phase" transition: DMTD output value (in picoseconds)
// at which the transition of rising edge
// TS counter will appear
ts->raw_phase = dmtd_phase;
phase = clock_period -1 -dmtd_phase;
// calculate the range within which falling edge timestamp is stable
// (no possible transitions)
trip_lo = transition_point - clock_period / 4;
if(trip_lo < 0) trip_lo += clock_period;
trip_hi = transition_point + clock_period / 4;
if(trip_hi >= clock_period) trip_hi -= clock_period;
if(inside_range(trip_lo, trip_hi, phase))
{
// We are within +- 25% range of transition area of
// rising counter. Take the falling edge counter value as the
// "reliable" one. cntr_ahead will be 1 when the rising edge
//counter is 1 tick ahead of the falling edge counter
ts->nsec -= cntr_ahead ? (clock_period / 1000) : 0;
// check if the phase is before the counter transition value
// and eventually increase the counter by 1 to simulate a
// timestamp transition exactly at s->phase_transition
//DMTD phase value
if(inside_range(trip_lo, transition_point, phase))
ts->nsec += clock_period / 1000;
}
ts->phase = phase - transition_point - 1;
if(ts->phase < 0) ts->phase += clock_period;
ts->phase = clock_period - 1 -ts->phase;
}
#define HAL_CONNECT_RETRIES 1000
#define HAL_CONNECT_TIMEOUT 2000000 /* us */
int ptpd_netif_init()
{
if(halexp_client_try_connect(HAL_CONNECT_RETRIES, HAL_CONNECT_TIMEOUT) < 0)
return PTPD_NETIF_ERROR;
return PTPD_NETIF_OK;
}
wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags,
wr_sockaddr_t *bind_addr)
{
struct my_socket *s;
struct sockaddr_ll sll;
struct ifreq f;
hexp_port_state_t pstate;
int fd;
// fprintf(stderr,"CreateSocket!\n");
if(sock_type != PTPD_SOCK_RAW_ETHERNET)
return NULL;
if(halexp_get_port_state(&pstate, bind_addr->if_name) < 0)
return NULL;
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(fd < 0)
{
perror("socket()");
return NULL;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
// Put the controller in promiscious mode, so it receives everything
strcpy(f.ifr_name, bind_addr->if_name);
if(ioctl(fd, SIOCGIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
f.ifr_flags |= IFF_PROMISC;
if(ioctl(fd, SIOCSIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
// Find the inteface index
strcpy(f.ifr_name, bind_addr->if_name);
ioctl(fd, SIOCGIFINDEX, &f);
sll.sll_ifindex = f.ifr_ifindex;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(bind_addr->ethertype);
sll.sll_halen = 6;
memcpy(sll.sll_addr, bind_addr->mac, 6);
if(bind(fd, (struct sockaddr *)&sll, sizeof(struct sockaddr_ll)) < 0)
{
close(fd);
perror("bind()");
return NULL;
}
// timestamping stuff:
int so_timestamping_flags = SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
struct ifreq ifr;
struct hwtstamp_config hwconfig;
strncpy(ifr.ifr_name, bind_addr->if_name, sizeof(ifr.ifr_name));
hwconfig.tx_type = HWTSTAMP_TX_ON;
hwconfig.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
ifr.ifr_data = &hwconfig;
if (ioctl(fd, SIOCSHWTSTAMP, &ifr) < 0)
{
perror("SIOCSHWTSTAMP");
return NULL;
}
if(setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &so_timestamping_flags,
sizeof(int)) < 0)
{
perror("setsockopt(SO_TIMESTAMPING)");
return NULL;
}
s=calloc(sizeof(struct my_socket), 1);
if (!s) return NULL;
s->if_index = f.ifr_ifindex;
// get interface MAC address
if (ioctl(fd, SIOCGIFHWADDR, &f) < 0) {
perror("ioctl()"); return NULL;
}
memcpy(s->local_mac, f.ifr_hwaddr.sa_data, 6);
memcpy(&s->bind_addr, bind_addr, sizeof(wr_sockaddr_t));
s->fd = fd;
// store the linearization parameters
s->clock_period = pstate.clock_period;
s->phase_transition = pstate.t2_phase_transition;
s->dmtd_phase_valid = 0;
s->dmtd_phase = pstate.phase_val;
tmo_init(&s->dmtd_update_tmo, DMTD_UPDATE_INTERVAL);
return (wr_socket_t*)s;
}
int ptpd_netif_close_socket(wr_socket_t *sock)
{
struct my_socket *s = (struct my_socket *) sock;
if(!s)
return 0;
close(s->fd);
free(s);
return 0;
}
static void poll_tx_timestamp(wr_socket_t *sock, wr_timestamp_t *tx_timestamp);
int ptpd_netif_sendto(wr_socket_t *sock, wr_sockaddr_t *to, void *data,
size_t data_length, wr_timestamp_t *tx_ts)
{
struct etherpacket pkt;
struct my_socket *s = (struct my_socket *)sock;
struct sockaddr_ll sll;
int rval;
if(s->bind_addr.family != PTPD_SOCK_RAW_ETHERNET)
return -ENOTSUP;
if(data_length > ETHER_MTU-8) return -EINVAL;
memset(&pkt, 0, sizeof(struct etherpacket));
memcpy(pkt.ether.h_dest, to->mac, 6);
memcpy(pkt.ether.h_source, s->local_mac, 6);
pkt.ether.h_proto =htons(to->ethertype);
memcpy(pkt.data, data, data_length);
size_t len = data_length + sizeof(struct ethhdr);
if(len < 60) /* pad to the minimum allowed packet size */
len = 60;
memset(&sll, 0, sizeof(struct sockaddr_ll));
sll.sll_ifindex = s->if_index;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(to->ethertype);
sll.sll_halen = 6;
rval = sendto(s->fd, &pkt, len, 0, (struct sockaddr *)&sll,
sizeof(struct sockaddr_ll));
poll_tx_timestamp(sock, tx_ts);
return rval;
}
#if 0
static void hdump(uint8_t *buf, int size)
{
int i;
netif_dbg("Dump: ");
for(i=0;i<size;i++) netif_dbg("%02x ", buf[i]);
netif_dbg("\n");
}
#endif
/* Waits for the transmission timestamp and stores it in tx_timestamp (if not null). */
static void poll_tx_timestamp(wr_socket_t *sock, wr_timestamp_t *tx_timestamp)
{
char data[16384];
struct my_socket *s = (struct my_socket *) sock;
struct msghdr msg;
struct iovec entry;
struct sockaddr_ll from_addr;
struct {
struct cmsghdr cm;
char control[1024];
} control;
struct cmsghdr *cmsg;
int res;
uint32_t rtag;
struct sock_extended_err *serr = NULL;
struct scm_timestamping *sts = NULL;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &entry;
msg.msg_iovlen = 1;
entry.iov_base = data;
entry.iov_len = sizeof(data);
msg.msg_name = (caddr_t)&from_addr;
msg.msg_namelen = sizeof(from_addr);
msg.msg_control = &control;
msg.msg_controllen = sizeof(control);
res = recvmsg(s->fd, &msg, MSG_ERRQUEUE); //|MSG_DONTWAIT);
if(tx_timestamp) tx_timestamp->correct = 0;
if(res <= 0)
return;
memcpy(&rtag, data+res-4, 4);
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
void *dp = CMSG_DATA(cmsg);
if(cmsg->cmsg_level == SOL_PACKET
&& cmsg->cmsg_type == PACKET_TX_TIMESTAMP)
serr = (struct sock_extended_err *) dp;
if(cmsg->cmsg_level == SOL_SOCKET
&& cmsg->cmsg_type == SO_TIMESTAMPING)
sts = (struct scm_timestamping *) dp;
//fprintf(stderr, "Serr %x sts %x\n", serr, sts);
if(serr && sts && tx_timestamp)
{
tx_timestamp->correct = 1;
tx_timestamp->phase = 0;
tx_timestamp->nsec = sts->hwtimeraw.tv_nsec;
tx_timestamp->sec = (uint64_t) sts->hwtimeraw.tv_sec & 0x7fffffff;
}
}
}
int ptpd_netif_recvfrom(wr_socket_t *sock, wr_sockaddr_t *from, void *data,
size_t data_length, wr_timestamp_t *rx_timestamp)
{
struct my_socket *s = (struct my_socket *)sock;
struct etherpacket pkt;
struct msghdr msg;
struct iovec entry;
struct sockaddr_ll from_addr;
struct {
struct cmsghdr cm;
char control[1024];
} control;
struct cmsghdr *cmsg;
struct scm_timestamping *sts = NULL;
size_t len = data_length + sizeof(struct ethhdr);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &entry;
msg.msg_iovlen = 1;
entry.iov_base = &pkt;
entry.iov_len = len;
msg.msg_name = (caddr_t)&from_addr;
msg.msg_namelen = sizeof(from_addr);
msg.msg_control = &control;
msg.msg_controllen = sizeof(control);
int ret = recvmsg(s->fd, &msg, MSG_DONTWAIT);
if(ret < 0 && errno == EAGAIN) return 0; // would be blocking
if(ret == -EAGAIN) return 0;
if(ret <= 0) return ret;
memcpy(data, pkt.data, ret - sizeof(struct ethhdr));
from->ethertype = ntohs(pkt.ether.h_proto);
memcpy(from->mac, pkt.ether.h_source, 6);
memcpy(from->mac_dest, pkt.ether.h_dest, 6);
if(rx_timestamp)
rx_timestamp->correct = 0;
for (cmsg = CMSG_FIRSTHDR(&msg);
cmsg;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
void *dp = CMSG_DATA(cmsg);
if(cmsg->cmsg_level == SOL_SOCKET
&& cmsg->cmsg_type == SO_TIMESTAMPING)
sts = (struct scm_timestamping *) dp;
}
if(sts && rx_timestamp)
{
int cntr_ahead = sts->hwtimeraw.tv_sec & 0x80000000 ? 1: 0;
rx_timestamp->nsec = sts->hwtimeraw.tv_nsec;
rx_timestamp->sec =
(uint64_t) sts->hwtimeraw.tv_sec & 0x7fffffff;
rx_timestamp->raw_nsec = sts->hwtimeraw.tv_nsec;
rx_timestamp->raw_ahead = cntr_ahead;
update_dmtd(sock);
if(s->dmtd_phase_valid)
{
ptpd_netif_linearize_rx_timestamp(rx_timestamp, s->dmtd_phase, cntr_ahead, s->phase_transition, s->clock_period);
rx_timestamp->correct = 1;
}
}
return ret - sizeof(struct ethhdr);
}
/*
* Turns on locking
*/
int ptpd_netif_locking_enable(int txrx, const char *ifaceName, int priority)
{
netif_dbg("(PTPD_NETIF): start locking\n");
int ret = halexp_lock_cmd(ifaceName, HEXP_LOCK_CMD_START, 0);
return (ret < 0 ? PTPD_NETIF_ERROR : PTPD_NETIF_OK);
}
int ptpd_netif_locking_disable(int txrx, const char *ifaceName, int priority)
{
return PTPD_NETIF_OK;
}
int ptpd_netif_locking_poll(int txrx, const char *ifaceName, int priority)
{
if( halexp_lock_cmd(ifaceName, HEXP_LOCK_CMD_CHECK, 0) == HEXP_LOCK_STATUS_LOCKED)
return PTPD_NETIF_READY;
else
return PTPD_NETIF_NOT_READY;
}
/* We don't need these functions in V3/spec anymore - the transceivers are deterministic! */
int ptpd_netif_calibration_pattern_enable(const char *ifaceName,
unsigned int calibrationPeriod,
unsigned int calibrationPattern,
unsigned int calibrationPatternLen)
{
return PTPD_NETIF_OK;
}
int ptpd_netif_calibrating_disable(int txrx, const char *ifaceName)
{
return PTPD_NETIF_OK;
}
int ptpd_netif_calibrating_enable(int txrx, const char *ifaceName)
{
return PTPD_NETIF_OK;
}
int ptpd_netif_calibrating_poll(int txrx, const char *ifaceName,
uint64_t *delta)
{
uint64_t delta_rx, delta_tx;
ptpd_netif_read_calibration_data(ifaceName, &delta_tx, &delta_rx, NULL, NULL);
if(txrx == PTPD_NETIF_TX)
*delta = delta_tx;
else
*delta = delta_rx;
return PTPD_NETIF_READY;
}
int ptpd_netif_calibration_pattern_disable(const char *ifaceName)
{
return PTPD_NETIF_OK;
}
int ptpd_netif_read_calibration_data(const char *ifaceName, uint64_t *deltaTx,
uint64_t *deltaRx, int32_t *fix_alpha, int32_t *clock_period)
{
hexp_port_state_t state;
//read the port state
halexp_get_port_state(&state, ifaceName);
// check if the data is available
if(state.valid && state.tx_calibrated && state.rx_calibrated)
{
fprintf(stderr, "servo:ifaceName: %s (%d / %d)\n", ifaceName, state.delta_tx ,state.delta_rx);
if(deltaTx)
*deltaTx = state.delta_tx;
if(deltaRx)
*deltaRx = state.delta_rx;
if(fix_alpha)
*fix_alpha = state.fiber_fix_alpha;
if(clock_period)
*clock_period = state.clock_period;
return PTPD_NETIF_OK;
}
return PTPD_NETIF_NOT_FOUND;
}
int ptpd_netif_select( wr_socket_t *wrSock)
{
struct my_socket *s = (struct my_socket *)wrSock;
int ret;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(s->fd, &readfds);
ret = select(s->fd + 1, &readfds, 0, 0, 0) > 0;
if(ret < 0)
{
if(errno == EAGAIN || errno == EINTR)
return 0;
}
return 1;
}
int ptpd_netif_get_hw_addr(wr_socket_t *sock, mac_addr_t *mac)
{
struct my_socket *s = (struct my_socket *)sock;
memcpy(mac, s->local_mac, 6);
return 0;
}
int ptpd_netif_get_port_state(const char *ifaceName)
{
hexp_port_state_t state;
//read the port state
halexp_get_port_state(&state, ifaceName);
// check if the data is available
if(state.valid)
{
//check if link is UP
if(state.up > 0)
return PTPD_NETIF_OK;
else
{
// if(!strcmp(ifaceName,"wru1") || !strcmp(ifaceName,"wru0"))
// printf("(ptpd_netif) linkdown detected on port: %s\n",ifaceName);
return PTPD_NETIF_ERROR;
}
}
/* printf("(ptpd_netif) linkdown detected on port: %s "
"[no valid port state data)\n",ifaceName);*/
//should not get here
return PTPD_NETIF_ERROR;
}
int ptpd_netif_extsrc_detection()
{
return 0;
}
int ptpd_netif_get_ifName(char *ifname, int number)
{
int i;
int j = 0;
hexp_port_list_t list;
halexp_query_ports(&list);
for( i = 0; i < list.num_ports; i++)
{
if(j == number)
{
strcpy(ifname,list.port_names[i]);
return PTPD_NETIF_OK;
}
else
j++;
}
return PTPD_NETIF_ERROR;
}
uint64_t ptpd_netif_get_msec_tics()
{
// printf("getmsec: %lld\n", get_tics() / 1000ULL);
return get_tics() / 1000ULL;
}
int ptpd_netif_adjust_counters(int64_t adjust_sec, int32_t adjust_nsec)
{
hexp_pps_params_t p;
int cmd;
if(!adjust_nsec && !adjust_sec)
return PTPD_NETIF_OK;
if(adjust_sec && adjust_nsec)
{
fprintf(stderr, " FATAL : trying to adjust both the SEC and the NS counters simultaneously. \n");
exit(-1);
}
if(adjust_sec)
{
cmd = HEXP_PPSG_CMD_ADJUST_SEC;
p.adjust_sec = adjust_sec;
} else {
cmd = HEXP_PPSG_CMD_ADJUST_NSEC;
p.adjust_nsec = adjust_nsec;
}
if(!halexp_pps_cmd(cmd, &p))
return PTPD_NETIF_OK;
return PTPD_NETIF_ERROR;
}
int ptpd_netif_adjust_phase(int32_t phase_ps)
{
hexp_pps_params_t p;
p.adjust_phase_shift = phase_ps;
if(!halexp_pps_cmd(HEXP_PPSG_CMD_ADJUST_PHASE, &p))
return PTPD_NETIF_OK;
return PTPD_NETIF_ERROR;
}
int ptpd_netif_adjust_in_progress()
{
hexp_pps_params_t p;
if(halexp_pps_cmd(HEXP_PPSG_CMD_POLL, &p))
return PTPD_NETIF_OK;
else
return PTPD_NETIF_NOT_READY;
}
int ptpd_netif_enable_timing_output(int enable)
{
hexp_pps_params_t p;
p.pps_valid = enable;
if(halexp_pps_cmd(HEXP_PPSG_CMD_SET_VALID, &p))
return PTPD_NETIF_OK;
else
return PTPD_NETIF_NOT_READY;
}
int ptpd_netif_enable_phase_tracking(const char *if_name)
{
int ret = halexp_lock_cmd(if_name, HEXP_LOCK_CMD_ENABLE_TRACKING, 0);
return (ret < 0 ? PTPD_NETIF_ERROR : PTPD_NETIF_OK);
}
// Network API for WR-PTPd
#ifndef __PTPD_NETIF_H
#define __PTPD_NETIF_H
#include <stdio.h>
//#include <inttypes.h>
#define PTPD_SOCK_RAW_ETHERNET 1
#define PTPD_SOCK_UDP 2
#define PTPD_FLAGS_MULTICAST 0x1
// error codes (to be extended)
#define PTPD_NETIF_READY 1
#define PTPD_NETIF_OK 0
#define PTPD_NETIF_ERROR -1
#define PTPD_NETIF_NOT_READY -2
#define PTPD_NETIF_NOT_FOUND -3
// GCC-specific
#define PACKED __attribute__((packed))
#define PHYS_PORT_ANY (0xffff)
#define PTPD_NETIF_TX 1
#define PTPD_NETIF_RX 2
#define IFACE_NAME_LEN 16
#define SLAVE_PRIORITY_0 0
#define SLAVE_PRIORITY_1 1
#define SLAVE_PRIORITY_2 2
#define SLAVE_PRIORITY_3 3
#define SLAVE_PRIORITY_4 4
// Some system-independent definitions
typedef uint8_t mac_addr_t[6];
typedef uint32_t ipv4_addr_t;
// WhiteRabbit socket - it's void pointer as the real socket structure is private and probably platform-specific.
typedef void *wr_socket_t;
// Socket address for ptp_netif_ functions
typedef struct {
// Network interface name (eth0, ...)
char if_name[IFACE_NAME_LEN];
// Socket family (RAW ethernet/UDP)
int family;
// MAC address
mac_addr_t mac;
// Destination MASC address, filled by recvfrom() function on interfaces bound to multiple addresses
mac_addr_t mac_dest;
// IP address
ipv4_addr_t ip;
// UDP port
uint16_t port;
// RAW ethertype
uint16_t ethertype;
// physical port to bind socket to
uint16_t physical_port;
} wr_sockaddr_t;
PACKED struct _wr_timestamp {
// Seconds
int64_t sec;
// Nanoseconds
int32_t nsec;
// Phase (in picoseconds), linearized for receive timestamps, zero for send timestamps
int32_t phase; // phase(picoseconds)
/* Raw time (non-linearized) for debugging purposes */
int32_t raw_phase;
int32_t raw_nsec;
int32_t raw_ahead;
// correctness flag: when 0, the timestamp MAY be incorrect (e.g. generated during timebase adjustment)
int correct;
//int cntr_ahead;
};
typedef struct _wr_timestamp wr_timestamp_t;
/* OK. These functions we'll develop along with network card driver. You can write your own UDP-based stubs for testing purposes. */
// Initialization of network interface:
// - opens devices
// - does necessary ioctls()
// - initializes connection with the mighty HAL daemon
int ptpd_netif_init();
// Creates UDP or Ethernet RAW socket (determined by sock_type) bound to bind_addr. If PTPD_FLAG_MULTICAST is set, the socket is
// automatically added to multicast group. User can specify physical_port field to bind the socket to specific switch port only.
wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags, wr_sockaddr_t *bind_addr);
// Sends a UDP/RAW packet (data, data_length) to address provided in wr_sockaddr_t.
// For raw frames, mac/ethertype needs to be provided, for UDP - ip/port.
// Every transmitted frame has assigned a tag value, stored at tag parameter. This value is later used
// for recovering the precise transmit timestamp. If user doesn't need it, tag parameter can be left NULL.
int ptpd_netif_sendto(wr_socket_t *sock, wr_sockaddr_t *to, void *data, size_t data_length, wr_timestamp_t *tx_ts);
// Receives an UDP/RAW packet. Data is written to (data) and length is returned. Maximum buffer length can be specified
// by data_length parameter. Sender information is stored in structure specified in 'from'. All RXed packets are timestamped and the timestamp
// is stored in rx_timestamp (unless it's NULL).
int ptpd_netif_recvfrom(wr_socket_t *sock, wr_sockaddr_t *from, void *data, size_t data_length, wr_timestamp_t *rx_timestamp);
// Closes the socket.
int ptpd_netif_close_socket(wr_socket_t *sock);
int ptpd_netif_poll(wr_socket_t*);
int ptpd_netif_get_hw_addr(wr_socket_t *sock, mac_addr_t *mac);
/*
* Function start HW locking of freq on WR Slave
* return:
* PTPD_NETIF_ERROR - locking not started
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_locking_enable(int txrx, const char *ifaceName, int priority);
/*
*
* return:
*
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_locking_disable(int txrx, const char *ifaceName, int priority);
int ptpd_netif_locking_poll(int txrx, const char *ifaceName, int priority);
/*
* Function turns on calibration (measurement of delay)
* Tx or Rx depending on the txrx param
* return:
* PTPD_NETIF_NOT_READY - if there is calibratin going on on another port
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibrating_enable(int txrx, const char *ifaceName);
/*
* Function turns off calibration (measurement of delay)
* Tx or Rx depending on the txrx param
* return:
* PTPD_NETIF_ERROR - if there is calibratin going on on another port
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibrating_disable(int txrx, const char *ifaceName);
/*
* Function checks if Rx/Tx (depending on the param) calibration is finished
* if finished, returns measured delay in delta
* return:
*
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_calibrating_poll(int txrx, const char *ifaceName, uint64_t *delta);
/*
* Function turns on calibration pattern.
* return:
* PTPD_NETIF_NOT_READY - if WRSW is busy with calibration on other switch or error occured
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibration_pattern_enable(const char *ifaceName, unsigned int calibrationPeriod, unsigned int calibrationPattern, unsigned int calibrationPatternLen);
/*
* Function turns off calibration pattern
* return:
* PTPD_NETIF_ERROR - turning off not successful
* PTPD_NETIF_OK - turning off successful
*/
int ptpd_netif_calibration_pattern_disable(const char *ifaceName);
/*
* Function reads calibration data if it's available, used at the beginning of PTPWRd to check if
* HW knows already the interface's deltax, and therefore no need for calibration
* return:
* PTPD_NETIF_NOT_FOUND - if deltas are not known
* PTPD_NETIF_OK - if deltas are known, in such case, deltaTx and deltaRx have valid data
*/
int ptpd_netif_read_calibration_data(const char *ifaceName, uint64_t *deltaTx,
uint64_t *deltaRx, int32_t *fix_alpha, int32_t *clock_period);
int ptpd_netif_select(wr_socket_t*);
int ptpd_netif_get_hw_addr(wr_socket_t *sock, mac_addr_t *mac);
/*
* Function reads state of the given port (interface in our case), if the port is up, everything is OK, otherwise ERROR
* return:
* PTPD_NETIF_ERROR - if the port is down
* PTPD_NETIF_OK - if the port is up
*/
int ptpd_netif_get_port_state(const char *ifaceName);
/*
* Function looks for a port (interface) for the port number 'number'
* it will return in the argument ifname the port name
* return:
* PTPD_NETIF_ERROR - port not found
* PTPD_NETIF_OK - if the port found
*/
int ptpd_netif_get_ifName(char *ifname, int number);
/* Returns the millisecond "tics" counter value */
uint64_t ptpd_netif_get_msec_tics();
/*
* Function detects external source lock,
*
* return:
* HEXP_EXTSRC_STATUS_LOCKED 0
* HEXP_LOCK_STATUS_BUSY 1
* HEXP_EXTSRC_STATUS_NOSRC 2
*/
int ptpd_netif_extsrc_detection();
/* Timebase adjustment functions - the servo should not call the HAL directly */
int ptpd_netif_adjust_counters(int64_t adjust_sec, int32_t adjust_nsec);
int ptpd_netif_adjust_phase(int32_t phase_ps);
int ptpd_netif_adjust_in_progress();
int ptpd_netif_get_dmtd_phase(wr_socket_t *sock, int32_t *phase);
void ptpd_netif_linearize_rx_timestamp(wr_timestamp_t *ts, int32_t dmtd_phase, int cntr_ahead, int transition_point, int clock_period);
int ptpd_netif_enable_timing_output(int enable);
int ptpd_netif_enable_phase_tracking(const char *if_name);
#endif
......@@ -21,7 +21,7 @@ GIT_USR = $(shell git config --get-all user.name)
CFLAGS = -O2 -DDEBUG -g -Wall \
-I$(LINUX)/include \
-I$(LINUX)/arch/arm/mach-at91/include \
-I../ptp-noposix/libptpnetif \
-I../libptpnetif \
-I../wrsw_hal \
-I../wrsw_rtud \
-I../mini-rpc \
......@@ -29,7 +29,7 @@ CFLAGS = -O2 -DDEBUG -g -Wall \
-I../include
LDFLAGS = -L../mini-rpc \
-L../ptp-noposix \
-L../libptpnetif \
-L../libswitchhw \
-lminipc -lptpnetif -lswitchhw
......
PROGRAM = wrsw_rtud
SRCFILES = mac.c rtu_drv.c rtu_hash.c rtu_fd.c rtud.c \
rtud_exports.c utils.c ../ptp-noposix/libptpnetif/hal_client.c
rtud_exports.c utils.c
OBJFILES = $(patsubst %.c,%.o,$(SRCFILES))
CC = $(CROSS_COMPILE)gcc
......@@ -13,12 +13,12 @@ WR_INCLUDE = $(WR_INSTALL_ROOT)/include
WR_LIB = $(WR_INSTALL_ROOT)/lib
CFLAGS = -O2 -DDEBUG -Wall -ggdb \
-I../ptp-noposix/libptpnetif -I../wrsw_hal \
-I../libptpnetif -I../wrsw_hal \
-I../mini-rpc -I../include -I$(WR_INCLUDE) -I$(LINUX)/include
# -I$(CROSS_COMPILE_ARM_PATH)/../include
LDFLAGS := -L../libptpnetif -L../libswitchhw -L../mini-rpc\
-lswitchhw -lpthread -lminipc
-lswitchhw -lptpnetif -lpthread -lminipc
RM := rm -f
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment