wr_mon.c 36.1 KB
Newer Older
1 2
#include <stdio.h>
#include <stdlib.h>
3
#include <string.h>
4
#include <getopt.h>
5
#include <unistd.h>
6
#include <time.h>
7
#include <sys/timex.h>
8
#include <inttypes.h>
9
#include <ppsi/ppsi.h>
10 11
#include <libwr/shmem.h>
#include <libwr/hal_shmem.h>
12
#include <libwr/switch_hw.h>
13
#include <libwr/wrs-msg.h>
14
#include <libwr/pps_gen.h>
15
#include "../../kernel/wbgen-regs/ppsg-regs.h"
16
#include <fpga_io.h>
17
#include <minipc.h>
18
#include <signal.h>
19 20
#include <ppsi-wrs.h>

21 22

#include "term.h"
23
#include <time_lib.h>
24

25
#define PTP_EXPORT_STRUCTURES
26
#include "ptpd_exports.h"
27

28
#define SHOW_GUI		0
29 30
#define SHOW_SLAVE_PORTS	1
#define SHOW_MASTER_PORTS	(1<<1)
31
#define SHOW_OTHER_PORTS	(1<<2) /* non-wr and none */
32 33
#define SHOW_SERVO		(1<<3)
#define SHOW_TEMPERATURES	(1<<4)
34
#define WEB_INTERFACE		(1<<5)
35 36 37 38 39 40 41 42
#define SHOW_WR_TIME		(1<<6)

/* for convenience when any or all ports needs a print statement */
#define SHOW_ALL_PORTS		(SHOW_SLAVE_PORTS | SHOW_MASTER_PORTS | \
				SHOW_OTHER_PORTS)
/* for convenience with -a option */
#define SHOW_ALL		(SHOW_ALL_PORTS | SHOW_SERVO | \
				SHOW_TEMPERATURES | SHOW_WR_TIME)
43

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84

#define MAX_INST_SERVO 2
struct inst_servo_t {
	struct pp_instance * ppi;              /* pointer to the ppi instance */
	int                  valid_servo_data; /* 1 means servo data are vaild */
	TimeInterval         offsetFromMaster; /* currentDS.offsetFromMaster */
	TimeInterval         meanDelay;        /* currentDS.meanDelay */
	TimeInterval         delayAsymmetry;   /* portDS.delayAsymmetry */
	RelativeDifference	 scaledDelayCoefficient; /* AsymmetryCorrectionPortDS.scaledDelayCoefficient */
	TimeInterval         egressLatency;    /* timestampCorrectionPortDS.egressLatency */
	TimeInterval         ingressLatency;   /* timestampCorrectionPortDS.ingressLatency */
	TimeInterval         semistaticLatency;/* timestampCorrectionPortDS.semistaticLatency */
	TimeInterval	     constantAsymmetry;/* asymmetryCorrectionPortDS.constantAsymmetry */
	struct pp_servo      servo_snapshot;  /* image of a the ppsi servo */
	void *               servo_ext_snapshot; /* image of the extension servo */
};

/* protocol extension data */
#define IS_PROTO_EXT_INFO_AVAILABLE( proto_id ) \
	((proto_id < sizeof(proto_ext_info)/sizeof(struct proto_ext_info_t)) \
			&& (proto_ext_info[proto_id].valid==1))

struct proto_ext_info_t {
	int valid;
	char *ext_name; /* Extension name */
	char short_ext_name; /* Very short extension name - just one character */
	int servo_ext_size; /* Size of the extension */
	int ipc_cmd_tacking; /* Command to enable/disable servo tacking*/
	int track_onoff;     /* Tracking on/off */
	time_t lastt;
	int last_count;
};

static struct proto_ext_info_t proto_ext_info [] = {
		[PPSI_EXT_NONE] = {
				.valid=1,
				.ext_name="PTP",
				.short_ext_name='P',
				.ipc_cmd_tacking=-1, /* Invalid */
		},

baujc's avatar
baujc committed
85
#if CONFIG_HAS_EXT_WR
86 87 88 89
		[PPSI_EXT_WR] = {
				.valid=1,
				.ext_name="White-Rabbit",
				.short_ext_name='W',
90
				.servo_ext_size=sizeof(struct wr_data),
91 92 93 94
				.ipc_cmd_tacking=PTPDEXP_COMMAND_WR_TRACKING,
				.track_onoff = 1,
		},
#endif
baujc's avatar
baujc committed
95
#if CONFIG_HAS_EXT_L1SYNC
96 97 98 99
		[PPSI_EXT_L1S] = {
				.valid=1,
				.ext_name="L1Sync",
				.short_ext_name='L',
100
				.servo_ext_size=sizeof(struct l1e_data),
101 102
				.ipc_cmd_tacking=PTPDEXP_COMMAND_L1SYNC_TRACKING,
				.track_onoff = 1,
103 104 105 106 107 108 109 110 111 112 113
		},
#endif
#if CONFIG_HAS_EXT_CUSTOM
		[PPSI_EXT_CUSTOM] = {
				.valid=1,
				.ext_name="Custom",
				.short_ext_name='C',
				.servo_ext_size=sizeof(struct l1e_data),
				.ipc_cmd_tacking=PTPDEXP_COMMAND_L1SYNC_TRACKING,
				.track_onoff = 1,
		},
114
#endif
115

116 117
};

118 119 120 121 122 123 124 125
typedef struct {
	struct pp_instance *ppi;
	portDS_t *portDS;
}pp_instance_ptr_t;

static pp_instance_ptr_t instances[PP_MAX_LINKS];


126 127
static struct inst_servo_t servos[MAX_INST_SERVO];

128
int mode = SHOW_GUI;
129

130
static struct minipc_ch *ptp_ch;
131

132
static struct wrs_shm_head *hal_head;
133
struct hal_port_state *hal_ports;
134 135 136
/* local copy of port state */
static struct hal_port_state hal_ports_local_copy[HAL_MAX_PORTS];
static int hal_nports_local;
137 138
static struct wrs_shm_head *ppsi_head;
static struct pp_globals *ppg;
139
static void *ppg_arch;
140
static 	defaultDS_t *defaultDS;
141
static pid_t ptp_ch_pid; /* pid of ppsi connected via minipc */
142
static struct hal_temp_sensors *temp_sensors;
143
/* local copy of temperature sensor readings */
144
static struct hal_temp_sensors temp_sensors_local;
145

146 147
static uint64_t seconds;
static uint32_t nanoseconds;
148 149
/* ignore checking if process is alive */
static int ignore_alive;
150

151
/* define size of pp_instance_state_to_name as a last element + 1 */
152 153
#define PP_INSTANCE_STATE_MAX (sizeof(pp_instance_state_to_name)/sizeof(char *))

154
/* define conversion array for the field state in the struct pp_instance */
155
static char *pp_instance_state_to_name[] = {
156 157
	/* from ppsi/include/ppsi/ieee1588_types.h, enum pp_std_states */
	/* PPS_END_OF_TABLE = 0 */
158
	[PPS_END_OF_TABLE] =      "EOT       ",
159 160 161 162 163 164 165 166 167
	[PPS_INITIALIZING] =      "INITING   ",
	[PPS_FAULTY] =            "FAULTY    ",
	[PPS_DISABLED] =          "DISABLED  ",
	[PPS_LISTENING] =         "LISTENING ",
	[PPS_PRE_MASTER] =        "PRE_MASTER",
	[PPS_MASTER] =            "MASTER    ",
	[PPS_PASSIVE] =           "PASSIVE   ",
	[PPS_UNCALIBRATED] =      "UNCALIBRAT",
	[PPS_SLAVE] =             "SLAVE     ",
168
	NULL
169
	};
170

171 172
#define EMPTY_EXTENSION_STATE_NAME "          "

baujc's avatar
baujc committed
173
#if CONFIG_HAS_EXT_L1SYNC
174
static char * l1e_instance_extension_state[]={
175
		[__L1SYNC_MISSING   ] = "INVALID   ",
176 177 178 179
		[L1SYNC_DISABLED    ] = "DISABLED  ",
		[L1SYNC_IDLE        ] = "IDLE      ",
		[L1SYNC_LINK_ALIVE  ] = "LINK ALIVE",
		[L1SYNC_CONFIG_MATCH] = "CFG MATCH ",
180 181
		[L1SYNC_UP          ] = "UP        ",
		NULL
182 183 184 185 186
};
#define L1S_INSTANCE_EXTENSION_STATE_MAX (sizeof (l1e_instance_extension_state)/sizeof(char *) )

#endif

187
static char * timind_mode_state[] = {
188 189 190 191
		[WRH_TM_GRAND_MASTER]=     "GM",
		[WRH_TM_FREE_MASTER]=      "FR",
		[WRH_TM_BOUNDARY_CLOCK]=   "BC",
		[WRH_TM_DISABLED]=         "--",
192 193 194 195
		NULL
	};

static char * pll_locking_state[] = {
196 197 198 199 200
		[WRH_TM_LOCKING_STATE_NONE]=     "NONE    ",
		[WRH_TM_LOCKING_STATE_LOCKING]=  "LOCKING ",
		[WRH_TM_LOCKING_STATE_LOCKED]=   "LOCKED  ",
		[WRH_TM_LOCKING_STATE_HOLDOVER]= "HOLDOVER",
		[WRH_TM_LOCKING_STATE_ERROR]=    "ERROR   ",
201 202 203
		NULL
	};

204 205 206 207 208 209 210 211 212 213 214
#if CONFIG_HAS_EXT_WR
static char * wr_instance_extension_state[]={
		[WRS_IDLE ]=              "IDLE      ",
		[WRS_PRESENT] =           "WR_PRESENT",
		[WRS_S_LOCK] =            "WR_S_LOCK ",
		[WRS_M_LOCK] =            "WR_M_LOCK ",
		[WRS_LOCKED] =            "WR_LOCKED ",
		[WRS_CALIBRATION] =       "WR_CAL-ION",
		[WRS_CALIBRATED] =        "WR_CAL-ED ",
		[WRS_RESP_CALIB_REQ] =    "WR_RSP_CAL",
		[WRS_WR_LINK_ON] =        "WR_LINK_ON",
215
		NULL
216 217 218 219 220
};
#define WR_INSTANCE_EXTENSION_STATE_MAX (sizeof (wr_instance_extension_state)/sizeof(char *) )

#endif

221
static char *prot_detection_state_name[]={
222
		"NONE   ", /* No meaning. No extension present */
223 224
		"WA_MSG ", /* Waiting first message */
		"PD_IPRG", /* Protocol detection  */
225 226
		"EXT_ON ", /* Protocol detected */
		"EXT_OFF" /* Protocol not detected */
baujc's avatar
baujc committed
227 228
};

229 230 231
/* prototypes */
int read_instances(void);

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
static inline int extensionStateColor( struct pp_instance *ppi) {
	if ( ppi->protocol_extension==PPSI_EXT_NONE) {
		return C_GREEN; /* No extension */
	}
	switch (ppi->extState) {
	case PP_EXSTATE_ACTIVE :
		return C_GREEN;
	case PP_EXSTATE_PTP :
		return C_WHITE;
	case PP_EXSTATE_DISABLE :
	default:
		return C_RED;
	}
}

247 248 249 250 251 252 253 254 255 256 257 258
char *getStateAsString(char *p[], int index) {
	int i,len;
	char *errMsg="?????????????????????";

	len=strlen(p[0]);
	for (i=0; ;i++) {
		if ( p[i]==NULL )
			return errMsg+strlen(errMsg)-len;
		if ( i==index)
			return p[index];
	}
}
259 260 261 262 263 264 265 266 267 268 269 270

int64_t interval_to_picos(TimeInterval interval)
{
	return (interval * 1000) >>  TIME_INTERVAL_FRACBITS;
}

int64_t pp_time_to_picos(struct pp_time *ts)
{
	return ts->secs * PP_NSEC_PER_SEC
		+ ((ts->scaled_nsecs * 1000 + 0x8000) >> TIME_INTERVAL_FRACBITS);
}

Jean-Claude BAU's avatar
Jean-Claude BAU committed
271 272 273 274 275 276 277 278 279 280 281 282 283 284
TimeInterval pp_time_to_interval (struct pp_time *pptime) {
	return pptime->scaled_nsecs;
}

char *optimized_pp_time_toString(struct pp_time *pptime, char *buf ) {
	char lbuf[128];

	if ( pptime->secs )
		sprintf(buf,"%16s sec",timeToString(pptime,lbuf));
	else
		sprintf(buf,"%16s nsec",timeIntervalToString(pp_time_to_interval(pptime),lbuf));
	return buf;
}

285
#if 0
286 287 288 289 290 291 292 293
static double alpha_to_double(int32_t alpha) {
  double f ;
  int neg = alpha<0;

  if(neg) alpha= ~alpha+1;
  f= (double)alpha/(double)(1LL<<FIX_ALPHA_FRACBITS);
  return  neg ? -f : f;
}
294
#endif
295

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
void help(char *prgname)
{
	fprintf(stderr, "%s: Use: \"%s [<options>] <cmd> [<args>]\n",
		prgname, prgname);
	fprintf(stderr,
		"  The program has the following options\n"
		"  -h   print help\n"
		"  -i   show White Rabbit time.\n"
		"	   very close\n"
		"  -m   show master ports\n"
		"  -s   show slave ports\n"
		"  -o   show other ports\n"
		"  -e   show servo statistics\n"
		"  -t   show temperatures\n"
		"  -a   show all (same as -i -m -s -o -e -t options)\n"
		"  -b   black and white output\n"
		"  -w   web interface mode\n"
313
		"  -H <dir> Open shmem dumps from the given directory\n"
314 315 316 317 318
		"\n"
		"During execution the user can enter 'q' to exit the program\n"
		"and 't' to toggle printing of state information on/off\n");
	exit(1);
}
319

320
int read_hal(void){
321 322 323 324
	unsigned ii;
	unsigned retries = 0;

	/* read data, with the sequential lock to have all data consistent */
325
	while (1) {
326 327 328
		ii = wrs_shm_seqbegin(hal_head);
		memcpy(hal_ports_local_copy, hal_ports,
		       hal_nports_local*sizeof(struct hal_port_state));
329 330
		memcpy(&temp_sensors_local, temp_sensors,
		       sizeof(*temp_sensors));
331
		retries++;
332 333
		if (retries > 100)
			return -1;
334 335
		if (!wrs_shm_seqretry(hal_head, ii))
			break; /* consistent read */
336
		usleep(1000);
337
	}
338 339 340 341

	return 0;
}

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
int read_instances(void) {
	struct pp_instance *pp_array;
	int l;

	bzero(instances,sizeof(instances));

	if ( !(pp_array = wrs_shm_follow(ppsi_head, ppg->pp_instances)) )
		return -1;

	for (l = 0; l < ppg->nlinks; l++) {
		instances[l].ppi=&pp_array[l];
		if ( ! (instances[l].portDS=wrs_shm_follow(ppsi_head, instances[l].ppi->portDS)) )
			return -1;
	}
	return 0;
}

359 360
int read_servo(void){

361 362 363 364 365 366 367 368 369
	unsigned int i, servoIdx;


	/* Clear servo structure */
	for (i=0; i<MAX_INST_SERVO; i++) {
		if (servos[i].ppi ) {
			if ( servos[i].servo_ext_snapshot )
				free(servos[i].servo_ext_snapshot);
		}
370
	}
371 372 373 374
	bzero(&servos, sizeof(servos));

	servoIdx=0;
	for (i = 0; i < ppg->nlinks; i++) {
375
		struct pp_instance *ppi = instances[i].ppi;
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394

		/* we are only interested  on instances in SLAVE state */
		if (ppi->state == PPS_SLAVE ) {
			struct inst_servo_t *servo=&servos[servoIdx++];
			int alloc_size=IS_PROTO_EXT_INFO_AVAILABLE(ppi->protocol_extension) ?
					proto_ext_info[ppi->protocol_extension].servo_ext_size :
					0;

			/* Allocate extension data memory if needed */
			if ( alloc_size > 0 )
				if ( !(servo->servo_ext_snapshot=malloc(alloc_size)) )
					return -1;

			while (1) {
				unsigned ii = wrs_shm_seqbegin(ppsi_head);
				unsigned retries = 0;
				struct pp_servo *ppsi_servo;

				/* Copy common data */
395
				if ( !(ppsi_servo = wrs_shm_follow(ppsi_head, ppi->servo)) )
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
						break;
				memcpy(&servo->servo_snapshot, ppsi_servo, sizeof(struct pp_servo));

				/* Copy extension servo data */
				if ( servo->servo_ext_snapshot ) {
					void *ppsi_servo_ext;

					if ( !(ppsi_servo_ext = wrs_shm_follow(ppsi_head, ppi->ext_data)) )
							break;
					memcpy(servo->servo_ext_snapshot, ppsi_servo_ext,alloc_size);
				}

				/* Copy extra interesting data */
				{
					currentDS_t *currenDS;

					if ( !(currenDS = wrs_shm_follow(ppsi_head, ppg->currentDS) ) )
							break;
414

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
					servo->offsetFromMaster=currenDS->offsetFromMaster; /* currentDS.offsetFromMaster */
					servo->meanDelay=currenDS->meanDelay;    /* currentDS.meanDelay */
				}
				{
					portDS_t *portDS;

					if ( !(portDS = wrs_shm_follow(ppsi_head, ppi->portDS) ) )
							break;
					servo->delayAsymmetry=portDS->delayAsymmetry;   /* portDS.delayAsymmetry */
				}
				servo->scaledDelayCoefficient=ppi->asymmetryCorrectionPortDS.scaledDelayCoefficient; /* AsymmetryCorrectionPortDS.scaledDelayCoefficient */
				servo->constantAsymmetry=ppi->asymmetryCorrectionPortDS.constantAsymmetry;/* asymmetryCorrectionPortDS.constantAsymmetry */
				servo->egressLatency=ppi->timestampCorrectionPortDS.egressLatency;   /* timestampCorrectionPortDS.egressLatency */
				servo->ingressLatency=ppi->timestampCorrectionPortDS.ingressLatency;  /* timestampCorrectionPortDS.ingressLatency */
				servo->semistaticLatency=ppi->timestampCorrectionPortDS.semistaticLatency;  /* timestampCorrectionPortDS.semistaticLatency */
				if (!wrs_shm_seqretry(ppsi_head, ii)) {
					servo->valid_servo_data=1;
					break; /* consistent read */
				}
				retries++;
				if (retries > 100)
					break;
			}
			if ( servo->valid_servo_data ) {
				servo->ppi=ppi;
			} else {
				if ( servo->servo_ext_snapshot ) {
					free (servo->servo_ext_snapshot);
				}
			}
		}
	}
447 448 449
	return 0;
}

450
void ppsi_connect_minipc(void)
451 452 453 454 455 456 457
{
	if (ptp_ch) {
		/* close minipc, if connected before */
		minipc_close(ptp_ch);
	}
	ptp_ch = minipc_client_create("ptpd", 0);
	if (!ptp_ch) {
458 459
		pr_error("Can't establish WRIPC connection to the PTP "
			 "daemon!\n");
460
		exit(1);
461 462 463 464 465
	}
	/* store pid of ppsi connected via minipc */
	ptp_ch_pid = ppsi_head->pid;
}

466
void init_shm(void)
467
{
468
	struct hal_shmem_header *h;
469 470 471 472
	int ret;
	int n_wait = 0;
	while ((ret = wrs_shm_get_and_check(wrs_shm_hal, &hal_head)) != 0) {
		n_wait++;
473
		if (ret == WRS_SHM_OPEN_FAILED) {
474 475
			pr_error("Unable to open HAL's shm !\n");
		}
476
		if (ret == WRS_SHM_WRONG_VERSION) {
477 478
			pr_error("Unable to read HAL's version!\n");
		}
479 480 481 482
		if (ret == WRS_SHM_INCONSISTENT_DATA) {
			pr_error("Unable to read consistent data from HAL's "
				 "shmem!\n");
		}
483 484 485 486 487
		if (n_wait > 10) {
			/* timeout! */
			exit(-1);
		}
		sleep(1);
488
	}
489

490
	if (hal_head->version != HAL_SHMEM_VERSION) {
491 492
		pr_error("Unknown HAL's shm version %i (known is %i)\n",
			 hal_head->version, HAL_SHMEM_VERSION);
493
		exit(1);
494
	}
495 496 497 498
	h = (void *)hal_head + hal_head->data_off;
	/* Assume number of ports does not change in runtime */
	hal_nports_local = h->nports;
	if (hal_nports_local > HAL_MAX_PORTS) {
499 500
		pr_error("Too many ports reported by HAL. %d vs %d "
			 "supported\n", hal_nports_local, HAL_MAX_PORTS);
501
		exit(1);
502
	}
503
	/* Even after HAL restart, HAL will place structures at the same
504 505
	 * addresses. No need to re-dereference pointer at each read.
	 */
506 507
	hal_ports = wrs_shm_follow(hal_head, h->ports);
	if (!hal_ports) {
508 509
		pr_error("Unable to follow hal_ports pointer in HAL's "
			 "shmem\n");
510
		exit(1);
511
	}
512
	temp_sensors = &(h->temp);
513

514 515 516
	n_wait = 0;
	while ((ret = wrs_shm_get_and_check(wrs_shm_ptp, &ppsi_head)) != 0) {
		n_wait++;
517
		if (ret == WRS_SHM_OPEN_FAILED) {
518 519
			pr_error("Unable to open PPSI's shm !\n");
		}
520
		if (ret == WRS_SHM_WRONG_VERSION) {
521 522
			pr_error("Unable to read PPSI's version!\n");
		}
523 524 525 526
		if (ret == WRS_SHM_INCONSISTENT_DATA) {
			pr_error("Unable to read consistent data from PPSI's "
				 "shmem!\n");
		}
527 528 529 530 531
		if (n_wait > 10) {
			/* timeout! */
			exit(-1);
		}
		sleep(1);
532 533 534 535
	}

	/* check hal's shm version */
	if (ppsi_head->version != WRS_PPSI_SHMEM_VERSION) {
536 537
		pr_error("Unknown PPSI's shm version %i (known is %i)\n",
			 ppsi_head->version, WRS_PPSI_SHMEM_VERSION);
538
		exit(1);
539 540 541
	}
	ppg = (void *)ppsi_head + ppsi_head->data_off;

542 543 544 545
	/* Access to ppg arch data */
	if ( ppg->arch_data!=NULL)
		ppg_arch=wrs_shm_follow(ppsi_head, ppg->arch_data);

546 547 548 549 550 551 552 553 554 555
	/* Access to defaultDS data */
	defaultDS = wrs_shm_follow(ppsi_head, ppg->defaultDS);
	if (!defaultDS) {
		pr_error("Unable to follow defaultDS pointer in PPSI's shmem\n");
		exit(1);
	}

	if ( read_instances()==-1 )
		exit(1);

556
	ppsi_connect_minipc();
557 558
}

559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
static struct desired_state_t{
	char *str_state;
	int state;
} desired_states[] = {
	{ "initializing", PPS_INITIALIZING},
	{ "faulty", PPS_FAULTY},
	{ "disabled", PPS_DISABLED},
	{ "listening", PPS_LISTENING},
	{ "pre-master", PPS_PRE_MASTER},
	{ "master", PPS_MASTER},
	{ "passive", PPS_PASSIVE},
	{ "uncalibrated", PPS_UNCALIBRATED},
	{ "slave", PPS_SLAVE},
	{}
};

void show_ports(int hal_alive, int ppsi_alive)
576
{
577
	int i, j;
578 579
	uint32_t tai_l,tmp2,nsec;
	struct timeval sw, hw;
580
	struct timex timex_val;
581 582
	struct tm *tm;
	char datestr[32];
583
	struct hal_port_state *port_state;
584 585
	int vlan_i;
	int nvlans;
586
	int *p;
587

588 589
	struct PPSG_WB *pps=(struct PPSG_WB *)(_fpga_base_virt+FPGA_BASE_PPS_GEN);

590
	if (!hal_alive) {
591 592 593 594 595 596 597 598
		if (mode == SHOW_GUI)
			term_cprintf(C_RED, "HAL is dead!\n");
		else if (mode == SHOW_ALL)
			printf("HAL is dead!\n");
		return;
	}

	if (mode == SHOW_GUI) {
599 600 601 602 603 604 605 606 607 608 609 610
		//First get all the times at the "same instant"
		do {
			tai_l = pps->CNTR_UTCLO;
			nsec = pps->CNTR_NSEC * 16; /* we count a 16.5MHz */
			tmp2 = pps->CNTR_UTCLO;
		} while((tmp2 != tai_l));
		gettimeofday(&sw, NULL);

		hw.tv_usec = nsec/1000;
		hw.tv_sec  = (time_t)(tai_l);

		tm = gmtime(&(hw.tv_sec));
611
		strftime(datestr, sizeof(datestr), "%Y-%m-%d %H:%M:%S", tm);
612 613
		term_cprintf(C_BLUE, "WR time (TAI)    : ");
		term_cprintf(C_WHITE, "%s.%06li", datestr,hw.tv_usec);
614

615
		term_cprintf(C_BLUE, "   Leap seconds: ");
616
		bzero(&timex_val,sizeof(timex_val));
617 618 619 620 621 622 623
		if (adjtimex(&timex_val) < 0) {
			term_cprintf(C_WHITE, "error\n");
		} else {
			p = (int *)(&timex_val.stbcnt) + 1;
			term_cprintf(C_WHITE, "%3d\n", *p);
		}

624 625 626 627 628 629 630 631 632
		tm = gmtime(&(sw.tv_sec));
		strftime(datestr, sizeof(datestr), "%Y-%m-%d %H:%M:%S", tm);
		term_cprintf(C_BLUE, "Switch time (UTC): ");
		term_cprintf(C_WHITE, "%s.%06li", datestr,sw.tv_usec);

		term_cprintf(C_BLUE, "   TAI-UTC     : ");
		{
			struct timeval diff;
			int neg=0;
633

634 635 636 637 638 639 640 641 642 643 644
			neg=timeval_subtract(&diff, &hw, &sw);
			term_cprintf(C_WHITE, "%c%li.%06li\n",neg?'-':'+',labs(diff.tv_sec),labs(diff.tv_usec));

		}

		if ( ppsi_alive && ppg_arch!=NULL) {
			term_cprintf(C_BLUE, "TimingMode: ");
			term_cprintf(C_WHITE, "%s",getStateAsString(timind_mode_state,((wrs_arch_data_t *)ppg_arch)->timingMode));
			term_cprintf(C_BLUE, "    PLL locking state: ");
			term_cprintf(C_WHITE, "%s\n",getStateAsString(pll_locking_state,((wrs_arch_data_t *)ppg_arch)->timingModeLockingState));
		}
baujc's avatar
baujc committed
645
		term_cprintf(C_CYAN, "----- HAL ---|---------------------------------- PPSI --------------------------------------------------------\n");
646
		term_cprintf(C_CYAN, " Iface| Freq |Inst|     Name     |   Config   | MAC of peer port  |    PTP/EXT/PDETECT States    | Pro | VLANs\n");
baujc's avatar
baujc committed
647
		term_cprintf(C_CYAN, "------+------+----+--------------+------------+-------------------+------------------------------+-----+------\n");
648

649 650 651 652
	}
	if (mode & (SHOW_SLAVE_PORTS|SHOW_MASTER_PORTS)) {
		printf("PORTS ");
	}
653

654 655 656
	for (i = 0; i < hal_nports_local; i++) {
		char if_name[10];
		int print_port = 0;
657
		int instance_port = 0;
baujc's avatar
baujc committed
658
		int color;
659

660
		snprintf(if_name, 10, "wri%d", i + 1);
661

662 663 664 665 666 667
		port_state = hal_lookup_port(hal_ports_local_copy,
						hal_nports_local, if_name);
		if (!port_state)
			continue;

		if (mode == SHOW_GUI) {
668 669
			/* check if link is up */
			if (state_up(port_state->state))
670
				term_cprintf(C_GREEN, " %-5s", if_name);
671
			else
672 673
				term_cprintf(C_RED, "*%-5s", if_name);
			term_cprintf(C_CYAN, "| ");
674
			if (port_state->locked)
675
				term_cprintf(C_GREEN, "Lock ");
676
			else
677 678 679
				term_cprintf(C_RED, "     ");

			term_cprintf(C_CYAN, "|");
680

681
			instance_port = 0;
682 683 684 685
			/*
			 * Actually, what is interesting is the PTP state.
			 * For this lookup, the port in ppsi shmem
			 */
686 687 688 689 690 691 692 693 694 695 696 697 698
			if ( ppsi_alive ) {
				for (j = 0; j < ppg->nlinks; j++) {
					char str_config[15];
					pp_instance_ptr_t *ppi_pt=&instances[j];
					struct pp_instance *ppi=ppi_pt->ppi;
					int proto_extension=ppi->protocol_extension;
					struct proto_ext_info_t *pe_info= IS_PROTO_EXT_INFO_AVAILABLE(proto_extension) ? &proto_ext_info[proto_extension] :  &proto_ext_info[0] ;

					if (strcmp(if_name,
							ppi->cfg.iface_name)) {
						/* Instance not for this interface
						 * skip */
						continue;
699
					}
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
					if (instance_port > 0) {
						term_cprintf(C_CYAN, "\n      |      |");
					}
					instance_port++;
					// Evaluate the instance configuration
					strcpy(str_config,"unknown");
					if ( defaultDS->slaveOnly) {
						strncpy(str_config,"slaveOnly",sizeof(str_config)-1);
					} else {
						if ( defaultDS->externalPortConfigurationEnabled ) {
							int s=0;
							for ( s=0; s<sizeof(desired_states)/sizeof(struct desired_state_t); s++ ) {
								if (desired_states[s].state == ppi->externalPortConfigurationPortDS.desiredState) {
									strncpy(str_config,desired_states[s].str_state,sizeof(str_config)-1);
									break;
								}
							}
717

718 719 720 721 722
						} else {
							if ( ppi_pt->portDS->masterOnly ) {
								strncpy(str_config,"masterOnly",sizeof(str_config)-1);
							} else {
								strncpy(str_config,"auto",sizeof(str_config)-1);
723 724 725
							}
						}
					}
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745
					str_config[sizeof(str_config)-1]=0; // Force the string to be well terminated
					/* print instance number */
					term_cprintf(C_WHITE, " %2d ", j);
					term_cprintf(C_CYAN, "|");
					/* print instance name */
					term_cprintf(C_WHITE, "%-14s",ppi->cfg.port_name);
					term_cprintf(C_CYAN, "|");
					term_cprintf(C_WHITE, "%-12s",str_config);
					term_cprintf(C_CYAN, "| ");

					/* Note: we may have more pp instances per port */
/*					if (state_up(port_state->state)) */ {
						unsigned char *p = ppi->peer;
						char * extension_state_name=EMPTY_EXTENSION_STATE_NAME;

						term_cprintf(C_WHITE, "%02x:%02x"
								 ":%02x:%02x:%02x:%02x ",
								 p[0], p[1], p[2], p[3],
								 p[4], p[5]);
						term_cprintf(C_CYAN, "| ");
746
						term_cprintf(C_GREEN, "%s/",getStateAsString(pp_instance_state_to_name,ppi->state));
747 748
						/* print extension state */
						switch (ppi->protocol_extension ) {
749
#if CONFIG_HAS_EXT_WR
750
						case PPSI_EXT_WR :
751 752 753
						{
							portDS_t *portDS;

754 755
							extension_state_name=getStateAsString(wr_instance_extension_state,-1); // Default value

756 757 758
							if ( (portDS = wrs_shm_follow(ppsi_head, ppi->portDS) ) ) {
								struct wr_dsport *extPortDS;

759 760
								if ( (extPortDS = wrs_shm_follow(ppsi_head, portDS->ext_dsport) ) )
										extension_state_name=getStateAsString(wr_instance_extension_state,extPortDS->state);
761
							}
762
							break;
763 764
						}
#endif
baujc's avatar
baujc committed
765
#if CONFIG_HAS_EXT_L1SYNC
766 767 768 769
						case PPSI_EXT_L1S :
						{
							portDS_t *portDS;

770
							extension_state_name=getStateAsString(l1e_instance_extension_state,-1); // Default value
771 772 773 774
							if ( (portDS = wrs_shm_follow(ppsi_head, ppi->portDS) ) ) {
								l1e_ext_portDS_t *extPortDS;

								if ( (extPortDS = wrs_shm_follow(ppsi_head, portDS->ext_dsport) ) ) {
775
										extension_state_name=getStateAsString(l1e_instance_extension_state,extPortDS->basic.L1SyncState);
776 777 778 779
								}
							}
							break;
						}
780
#endif
781
						}
782
						term_cprintf(C_GREEN, "%s/%s",extension_state_name,getStateAsString(prot_detection_state_name,ppi->pdstate));
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
					} // else {
//						term_cprintf(C_WHITE, "                  ");
//						term_cprintf(C_CYAN, "|");
//						term_cprintf(C_WHITE, "                      ");
//					}
					term_cprintf(C_CYAN, "| ");
					if (ppi->proto == PPSI_PROTO_RAW) {
						term_cprintf(C_WHITE, "R");
					} else if (ppi->proto
						   == PPSI_PROTO_UDP) {
						term_cprintf(C_WHITE, "U");
					} else if (ppi->proto
						   == PPSI_PROTO_VLAN) {
						term_cprintf(C_WHITE, "V");
					} else {
						term_cprintf(C_WHITE, "?");
					}
800
					color=extensionStateColor(ppi);
baujc's avatar
baujc committed
801
					term_cprintf(color, "-%c",pe_info->short_ext_name);
802 803 804 805 806 807 808 809

					nvlans = ppi->nvlans;
					term_cprintf(C_CYAN, " | ");
					for (vlan_i = 0; vlan_i < nvlans; vlan_i++) {
						term_cprintf(C_WHITE, "%d",
								ppi->vlans[vlan_i]);
						if (vlan_i < nvlans - 1)
							term_cprintf(C_WHITE, ",");
810
					}
811
				}
812
			}
813
			if (!instance_port || !ppsi_alive) {
814
				term_cprintf(C_WHITE, " -- ");
baujc's avatar
baujc committed
815
				term_cprintf(C_CYAN, "|              |            |                   |                              |     |");
816
			}
817
			term_cprintf(C_WHITE, "\n");
818 819 820 821 822
		} else if (mode & WEB_INTERFACE) {
			printf("%s ", state_up(port_state->state)
				? "up" : "down");
			printf("%s ", port_state->locked
				? "Locked" : "NoLock");
823
			printf("%s ", port_state->calib.rx_calibrated
824 825 826
				&& port_state->calib.tx_calibrated
				? "Calibrated" : "Uncalibrated");
		} else if (print_port) {
827
			printf("port:%s ", if_name);
828 829
			printf("lnk:%d ", state_up(port_state->state));
			printf("lock:%d ", port_state->locked);
830
			print_port = 0;
831
		}
832
	}
833 834 835 836
	if (mode == SHOW_GUI) {
		term_cprintf(C_BLUE, "Pro - Protocol mapping: V-Ethernet over "
			     "VLAN; U-UDP; R-Ethernet\n");
	}
837 838
}

839
void show_servo(struct inst_servo_t *servo, int alive)
840
{
841

842 843 844
	wrh_servo_t * wr_servo;
	wr_servo_ext_t * wr_servo_ext;

845
	char buf[128];
846
	wrh_servo_t * l1e_servo;
847
	int proto_extension=servo->ppi->extState!=PP_EXSTATE_DISABLE ? servo->ppi->protocol_extension : PPSI_EXT_NONE;
848 849
	struct proto_ext_info_t *pe_info= IS_PROTO_EXT_INFO_AVAILABLE(proto_extension) ? &proto_ext_info[proto_extension] :  &proto_ext_info[0] ;

850
	wr_servo= (servo->ppi->protocol_extension==PPSI_EXT_WR && servo->ppi->extState==PP_EXSTATE_ACTIVE) ?
851 852 853 854
			( wrh_servo_t* ) servo->servo_ext_snapshot : NULL;
	if ( wr_servo ) {
		wr_servo_ext= &((struct wr_data *)wr_servo)->servo_ext;
	}
855
	l1e_servo= (servo->ppi->protocol_extension==PPSI_EXT_L1S && servo->ppi->extState==PP_EXSTATE_ACTIVE) ?
856
			( wrh_servo_t * ) servo->servo_ext_snapshot : NULL;
857

858 859 860
	if (mode == SHOW_GUI) {
		term_cprintf(C_CYAN, "\n--------------------------- Synchronization status ----------------------------\n");
	}
861

862 863 864 865 866 867 868
	if (!alive) {
		if (mode == SHOW_GUI)
			term_cprintf(C_RED, "PPSI is dead!\n");
		return;
	}

	if (mode == SHOW_GUI) {
Jean-Claude BAU's avatar
Jean-Claude BAU committed
869

870
		if (!(servo->servo_snapshot.flags & PP_SERVO_FLAG_VALID)) {
871 872
			term_cprintf(C_RED,
				     "Master mode or sync info not valid\n");
873 874
			return;
		}
875

876
		term_cprintf(C_BLUE, "Servo state:          ");
877
		if (pe_info->lastt && time(NULL) - pe_info->lastt > 5) {
878
			term_cprintf(C_RED, "--- not updating ---\n");
879
		} else {
880 881 882 883 884
			term_cprintf(C_WHITE, "%s:%s: %s%s\n",
				     servo->ppi->cfg.iface_name,
					 pe_info->ext_name,
					 servo->servo_snapshot.servo_state_name,
					 servo->servo_snapshot.flags & PP_SERVO_FLAG_WAIT_HW ?
885 886
				     " (wait for hw)" : "");
		}
887

888
		/* "tracking disabled" is just a testing tool */
889
		if (wr_servo  && !wr_servo->tracking_enabled)
890
			term_cprintf(C_RED, "Tracking forcibly disabled\n");
891 892 893
		term_cprintf(C_CYAN, "\n +- Timing parameters ---------------------------------------------------------\n");

		term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE,  "meanDelay        : ");
894
		term_cprintf(C_WHITE, "%16s nsec\n", timeIntervalToString(servo->meanDelay,buf) );
895

896
		term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE,  "delayMS          : ");
Jean-Claude BAU's avatar
Jean-Claude BAU committed
897 898 899 900
		term_cprintf(C_WHITE,"%s\n",optimized_pp_time_toString(&servo->servo_snapshot.delayMS,buf));

		term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE,  "delayMM          : ");
		term_cprintf(C_WHITE,"%s\n",optimized_pp_time_toString(&servo->servo_snapshot.delayMM,buf));
901

902
		//term_cprintf(C_BLUE, "Estimated link length:     ");
903 904
		/* (RTT - deltas) / 2 * c / ri
		 c = 299792458 - speed of light in m/s
905 906 907 908
		 ri = 1.4682 - refractive index for fiber g.652. However,
			       experimental measurements using long (~5km) and
			       short (few m) fibers gave a value 1.4827
		 */
909 910
		//term_cprintf(C_WHITE, "%10.2f meters\n",
		//	crtt / 2 / 1e6 * 299.792458 / 1.4827);
911

912

913
		term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE,  "delayAsymmetry   : ");
914
		term_cprintf(C_WHITE, "%16s nsec\n",   timeIntervalToString(servo->delayAsymmetry,buf));
915
		term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE,  "delayCoefficient : ");
916
		term_cprintf(C_WHITE, "%s", relativeDifferenceToString(servo->scaledDelayCoefficient,buf));
917 918
		term_cprintf(C_BLUE,  " fpa : ");
		term_cprintf(C_WHITE, "%lld",servo->scaledDelayCoefficient);
919 920
		term_cprintf(C_WHITE, "\n");
		term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE,  "ingressLatency   : ");
921
		term_cprintf(C_WHITE, "%16s nsec\n",   timeIntervalToString(servo->ingressLatency,buf));
922
		term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE,  "egressLatency    : ");
923
		term_cprintf(C_WHITE, "%16s nsec\n",   timeIntervalToString(servo->egressLatency,buf));
924
		term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE,  "semistaticLatency: ");
925
		term_cprintf(C_WHITE, "%16s nsec\n",   timeIntervalToString(servo->semistaticLatency,buf));
926

927
		/*if (0) {
928
			term_cprintf(C_BLUE, "Fiber asymmetry:   ");
929 930
			term_cprintf(C_WHITE, "%.3f nsec\n",
				ss.fiber_asymmetry/1000.0);
931
		}*/
932

933
		term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE, "offsetFromMaster : ");
934
		term_cprintf(C_WHITE, "%16s nsec\n", timeIntervalToString (servo->offsetFromMaster,buf));
935

936 937
		if ( wr_servo ) {
			term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE, "Phase setpoint   : ");
Jean-Claude BAU's avatar
Jean-Claude BAU committed
938
			term_cprintf(C_WHITE, "%16.3f nsec\n",wr_servo->cur_setpoint_ps/1000.0);
939

940
			term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE, "Skew             : ");
Jean-Claude BAU's avatar
Jean-Claude BAU committed
941
			term_cprintf(C_WHITE, "%16.3f nsec\n",wr_servo->skew_ps/1000.0);
942
		}
943

944 945
		if ( l1e_servo ) {
			term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE, "Phase setpoint   : ");
946
			term_cprintf(C_WHITE, "%16.3f nsec\n",l1e_servo->cur_setpoint_ps/1000.0);
947 948

			term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE, "Skew             : ");
949
			term_cprintf(C_WHITE, "%16.3f nsec\n",l1e_servo->skew_ps/1000.0);
950
		}
951 952
		term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE, "Update counter   : ");
		term_cprintf(C_WHITE, "%16u times\n", servo->servo_snapshot.update_count);
953 954 955 956 957 958 959 960
		if (servo->servo_snapshot.update_count != pe_info->last_count) {
			pe_info->lastt = time(NULL);
			pe_info->last_count = servo->servo_snapshot.update_count;
		}

		if ( wr_servo ) {
			term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE, "Master PHY delays ");
			term_cprintf(C_BLUE, "TX: ");
Jean-Claude BAU's avatar
Jean-Claude BAU committed
961 962 963
			term_cprintf(C_WHITE,"%s",optimized_pp_time_toString(&wr_servo_ext->delta_txm,buf));
			term_cprintf(C_BLUE, "  RX: ");
			term_cprintf(C_WHITE,"%s\n",optimized_pp_time_toString(&wr_servo_ext->delta_rxm,buf));
964 965 966

			term_cprintf(C_CYAN," | ");term_cprintf(C_BLUE, "Slave  PHY delays ");
			term_cprintf(C_BLUE, "TX: ");
Jean-Claude BAU's avatar
Jean-Claude BAU committed
967 968 969 970
			term_cprintf(C_WHITE,"%s",optimized_pp_time_toString(&wr_servo_ext->delta_txs,buf));
			term_cprintf(C_BLUE, "  RX: ");
			term_cprintf(C_WHITE,"%s\n",optimized_pp_time_toString(&wr_servo_ext->delta_rxs,buf));
			printf("\n");
971
		}
972 973 974 975 976 977 978 979
	} else {
		/* TJP: commented out fields are present on the SPEC,
		 *      does the switch have similar fields?
		 */
		printf("SERVO ");
/*		printf("lnk:");*/
/*		printf("rx:");*/
/*		printf("tx:");*/
980 981
		printf("sv:%d ", servo->servo_snapshot.flags & PP_SERVO_FLAG_VALID ? 1 : 0);
		printf("ss:'%s' ", servo->servo_snapshot.servo_state_name);
982
/*		printf("aux:");*/
983 984
		printf("md:%s ", timeIntervalToString(servo->meanDelay,buf));
		printf("dms:%s ", timeToString(&servo->servo_snapshot.delayMS,buf));
985
		if ( wr_servo ) {
986 987 988
			int64_t crtt= wr_servo->delayMM_ps - pp_time_to_picos(&wr_servo_ext->delta_txm) -
					pp_time_to_picos(&wr_servo_ext->delta_rxm) - pp_time_to_picos(&wr_servo_ext->delta_txs) -
					pp_time_to_picos(&wr_servo_ext->delta_rxs);
989 990

			printf("lock:%i ", wr_servo->tracking_enabled);
991 992 993 994
			printf("dtxm:%s ", timeToString(&wr_servo_ext->delta_txm,buf));
			printf("drxm:%s ", timeToString(&wr_servo_ext->delta_rxm,buf));
			printf("dtxs:%s ", timeToString(&wr_servo_ext->delta_txs,buf));
			printf("drxs:%s ", timeToString(&wr_servo_ext->delta_rxs,buf));
995
		/* (RTT - deltas) / 2 * c / ri
996
		 c = 299792458 - speed of light in m/s
997 998 999 1000
		 ri = 1.4682 - refractive index for fiber g.652. However,
			       experimental measurements using long (~5km) and
			       short (few m) fibers gave a value 1.4827
		 */
1001 1002 1003
		//printf("ll:%d ",
		//       (int) (crtt / 2 / 1e6 * 299.792458 / 1.4827 * 100));
			printf("crtt:%llu ", crtt);
1004
			printf("setp:%d ", wr_servo->cur_setpoint_ps);
1005 1006 1007 1008 1009
		}
		if ( l1e_servo ) {
			printf("lock:%i ", l1e_servo->tracking_enabled);
			printf("setp:%d ", l1e_servo->cur_setpoint_ps);
		}
1010 1011
		printf("asym:%s ", timeIntervalToString(servo->delayAsymmetry,buf));
		printf("cko:%s ", timeIntervalToString(servo->offsetFromMaster,buf));
1012 1013 1014
/*		printf("hd:");*/
/*		printf("md:");*/
/*		printf("ad:");*/
1015
		printf("ucnt:%u ", servo->servo_snapshot.update_count);
1016 1017 1018
		/* SPEC shows temperature, but that can be selected separately
		 * in this program
		 */
1019
	}
1020 1021
}

1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
void show_servos(int alive) {

	int i;

	for (i=0; i<MAX_INST_SERVO; i++)
		if (servos[i].ppi )
			show_servo(&servos[i], alive);
}


1032 1033
void show_temperatures(void)
{
1034 1035 1036 1037 1038 1039 1040
	if ((mode == SHOW_GUI) || (mode & WEB_INTERFACE)) {
		if (mode == SHOW_GUI) {
/*                                              -------------------------------------------------------------------------------*/
			term_cprintf(C_CYAN, "\n-------------------------------- Temperatures ---------------------------------\n");
		} else {
			term_cprintf(C_CYAN, "\nTemperatures:\n");
		}
1041

1042
		term_cprintf(C_BLUE, "FPGA: ");
1043 1044
		term_cprintf(C_WHITE, "%2.2f ",
			     temp_sensors_local.fpga/256.0);
1045
		term_cprintf(C_BLUE, "PLL: ");
1046 1047
		term_cprintf(C_WHITE, "%2.2f ",
			     temp_sensors_local.pll/256.0);
1048
		term_cprintf(C_BLUE, "PSL: ");
1049 1050
		term_cprintf(C_WHITE, "%2.2f ",
			     temp_sensors_local.psl/256.0);
1051
		term_cprintf(C_BLUE, "PSR: ");
1052 1053
		term_cprintf(C_WHITE, "%2.2f\n",
			     temp_sensors_local.psr/256.0);
1054 1055 1056 1057 1058 1059
	} else {
		printf("TEMP ");
		printf("fpga:%2.2f ", temp_sensors_local.fpga/256.0);
		printf("pll:%2.2f ", temp_sensors_local.pll/256.0);
		printf("psl:%2.2f ", temp_sensors_local.psl/256.0);
		printf("psr:%2.2f", temp_sensors_local.psr/256.0);
1060 1061 1062
	}
}

1063 1064 1065 1066
void show_time(void)
{
	printf("TIME sec:%lld nsec:%d ", seconds, nanoseconds);
}
1067

1068
void show_all(void)
1069
{
1070 1071 1072
	int hal_alive;
	int ppsi_alive;

1073 1074
	if (mode == SHOW_GUI) {
		term_clear();
1075 1076 1077
		term_pcprintf(1, 1, C_BLUE, "WR Switch Sync Monitor ");
		term_cprintf(C_WHITE, "%s", __GIT_VER__);
		term_cprintf(C_BLUE, " [q = quit]\n\n");
1078
	}
1079

1080 1081 1082 1083
	hal_alive = (hal_head->pid && (kill(hal_head->pid, 0) == 0))
								+ ignore_alive;
	ppsi_alive = (ppsi_head->pid && (kill(ppsi_head->pid, 0) == 0))
								+ ignore_alive;
1084

1085
	if (mode & SHOW_WR_TIME) {
1086 1087 1088 1089 1090 1091 1092
		if (ppsi_alive)
			show_time();
		else if (mode == SHOW_ALL)
			printf("PPSI is dead!\n");
	}

	if ((mode & (SHOW_ALL_PORTS|WEB_INTERFACE)) || mode == SHOW_GUI) {
1093
		show_ports(hal_alive,ppsi_alive);
1094
	}
1095

1096 1097
	if (mode & SHOW_SERVO || mode == SHOW_GUI) {
		show_servos(ppsi_alive);
1098
	}
1099

1100
	if (mode & (SHOW_TEMPERATURES | WEB_INTERFACE) || mode == SHOW_GUI) {
1101 1102 1103
		if (hal_alive)
			show_temperatures();
	}
1104

1105 1106 1107 1108
	if (!(mode & WEB_INTERFACE || mode == SHOW_GUI)) {
		/* the newline for all in non-GUI or non-WEB mode... */
		printf("\n");
	}
1109 1110 1111
	fflush(stdout);
}

1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
static void enable_disable_tracking(int proto_extension) {

	if ( IS_PROTO_EXT_INFO_AVAILABLE(proto_extension)  ) {
		struct proto_ext_info_t *pe_info= &proto_ext_info[proto_extension];

		if ( pe_info->ipc_cmd_tacking!=-1 ) {
			int rval;

			pe_info->track_onoff = 1-pe_info->track_onoff;
			if (ptp_ch_pid != ppsi_head->pid) {
				/* ppsi was restarted since minipc
				 * connection, reconnect now */
				ppsi_connect_minipc();
			}
			minipc_call(ptp_ch, 200, &__rpcdef_cmd,
				&rval, pe_info->ipc_cmd_tacking,pe_info->track_onoff);
		}
	}
}

1132 1133 1134
int main(int argc, char *argv[])
{
	int opt;
1135
	int usecolor = 1;
1136 1137 1138

	/* try a pps_gen based approach */
	uint64_t last_seconds = 0;
1139

1140
	wrs_msg_init(argc, argv, LOG_USER);
1141

1142
	while ((opt = getopt(argc, argv, "himsoetabwqvH:")) != -1) {
1143 1144
		switch(opt)
		{
1145 1146 1147 1148 1149
			case 'h':
				help(argv[0]);
			case 'i':
				mode |= SHOW_WR_TIME;
				break;
1150
			case 's':
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166
				mode |= SHOW_SLAVE_PORTS;
				break;
			case 'm':
				mode |= SHOW_MASTER_PORTS;
				break;
			case 'o':
				mode |= SHOW_OTHER_PORTS;
				break;
			case 'e':
				mode |= SHOW_SERVO;
				break;
			case 't':
				mode |= SHOW_TEMPERATURES;
				break;
			case 'a':
				mode |= SHOW_ALL;
1167 1168 1169 1170
				break;
			case 'b':
				usecolor = 0;
				break;
1171 1172 1173
			case 'w':
				mode |= WEB_INTERFACE;
				break;
1174 1175 1176 1177 1178 1179
			case 'H':
				wrs_shm_set_path(optarg);
				/* ignore WRS_SHM_LOCKED flag */
				wrs_shm_ignore_flag_locked(1);
				ignore_alive = 1;
				break;
1180 1181
			case 'q': break; /* done in wrs_msg_init() */
			case 'v': break; /* done in wrs_msg_init() */
1182
			default:
1183
				help(argv[0]);
1184 1185 1186
		}
	}

1187 1188
	init_shm();

1189 1190 1191 1192 1193
	if (shw_fpga_mmap_init() < 0) {
		pr_error("Can't initialize FPGA mmap\n");
		exit(1);
	}

1194
	if (mode & WEB_INTERFACE) {
1195
		shw_pps_gen_read_time(&seconds, &nanoseconds);
1196 1197 1198 1199 1200 1201
		read_servo();
		read_hal();
		show_all();
		exit(0);
	}

1202
	term_init(usecolor);
1203
	setvbuf(stdout, NULL, _IOFBF, 4096);
1204 1205

	/* main loop */
1206 1207
	for(;;)
	{
1208
		if (term_poll(10)) {
1209
			int c = term_get();
1210

1211 1212 1213 1214 1215 1216 1217 1218
			switch (c) {
			case 'q':
				goto quit;
			case 'w' :
				enable_disable_tracking (PPSI_EXT_WR);
				break;
			case 'l' :
				enable_disable_tracking (PPSI_EXT_L1S);
1219
				break;
1220 1221
			}
		}
1222 1223

		shw_pps_gen_read_time(&seconds, &nanoseconds);
1224
		if (seconds != last_seconds) {
1225 1226 1227 1228 1229 1230 1231
			read_servo();
			read_hal();
			show_all();

			last_seconds = seconds;
		}

1232 1233 1234
		/* If we got broken pipe or anything, exit */
		if (ferror(stdout))
			exit(1);
1235
	}
1236

1237
	quit:;
1238
	term_restore();
1239 1240
	setlinebuf(stdout);
	printf("\n");
1241
	return 0;
1242
}