main-loop.c 2.67 KB
Newer Older
1
/*
2
 * Copyright (C) 2013 CERN (www.cern.ch)
3 4 5 6
 * Author: Pietro Fezzardi (pietrofezzardi@gmail.com)
 *
 * Released to the public domain
 */
7 8 9 10 11 12 13 14 15

/*
 * This is the main loop for the simulator.
 */
#include <stdlib.h>
#include <errno.h>
#include <sys/select.h>
#include <linux/if_ether.h>

16
#include <ppsi/ppsi.h>
17
#include <common-fun.h>
18 19
#include "ppsi-sim.h"

20 21 22 23 24 25 26 27
/* Call pp_state_machine for each instance. To be called periodically,
 * when no packets are incoming */
static int run_all_state_machines(struct pp_globals *ppg)
{
	int j;
	int delay_ms = 0, delay_ms_j;

	for (j = 0; j < ppg->nlinks; j++) {
28
		struct pp_instance *ppi = INST(ppg, j);
29 30 31 32 33 34 35 36 37 38 39 40 41 42
		sim_set_global_DS(ppi);
		delay_ms_j = pp_state_machine(ppi, NULL, 0);

		/* delay_ms is the least delay_ms among all instances */
		if (j == 0)
			delay_ms = delay_ms_j;
		if (delay_ms_j < delay_ms)
			delay_ms = delay_ms_j;
	}

	return delay_ms;
}


43 44
void sim_main_loop(struct pp_globals *ppg)
{
45 46 47 48 49 50 51
	struct pp_instance *ppi;
	struct sim_ppg_arch_data *data = SIM_PPG_ARCH(ppg);
	int64_t delay_ns, tmp_ns;
	int j, i;

	/* Initialize each link's state machine */
	for (j = 0; j < ppg->nlinks; j++) {
52
		ppi = INST(ppg, j);
53 54 55 56 57
		ppi->is_new_state = 1;
	}

	delay_ns = run_all_state_machines(ppg) * 1000LL * 1000LL;

58
	while (data->sim_iter_n <= data->sim_iter_max) {
59 60 61 62 63 64 65 66
		/*
		 * If Ebest was changed in previous loop, run best
		 * master clock before checking for new packets, which
		 * would affect port state again
		 */
		if (ppg->ebest_updated) {
			for (j = 0; j < ppg->nlinks; j++) {
				int new_state;
67
				struct pp_instance *ppi = INST(ppg ,j);
68 69 70 71 72 73 74 75 76 77
				new_state = bmc(ppi);
				if (new_state != ppi->state) {
					ppi->state = new_state;
					ppi->is_new_state = 1;
				}
			}
			ppg->ebest_updated = 0;
		}

		while (data->n_pending && data->pending->delay_ns <= delay_ns) {
78
			ppi = INST(ppg, data->pending->which_ppi);
79 80 81 82

			sim_fast_forward_ns(ppg, data->pending->delay_ns);
			delay_ns -= data->pending->delay_ns;

83
			i = __recv_and_count(ppi, ppi->rx_frame,
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
						PP_MAX_FRAME_LENGTH - 4,
						&ppi->last_rcv_time);

			if (i < PP_MINIMUM_LENGTH) {
				pp_diag(ppi, frames, 1,	"Error or short frame: "
					"%d < %d\n", i,	PP_MINIMUM_LENGTH);
				continue;
			}

			sim_set_global_DS(ppi);
			tmp_ns = 1000LL * 1000LL * pp_state_machine(ppi,
					ppi->rx_ptp, i - NP(ppi)->ptp_offset);

			if (tmp_ns < delay_ns)
				delay_ns = tmp_ns;
		}
		/* here we have no pending packets or the timeout for a state
		 * machine is expired (so delay_ns == 0). If the timeout is not
		 * expired we just fast forward till it's not expired, since we
		 * know that there are no packets pending. */
		sim_fast_forward_ns(ppg, delay_ns);
		delay_ns = run_all_state_machines(ppg) * 1000LL * 1000LL;
	}
107
	return;
108
}