Newer
Older
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini
*
* Released to the public domain
*/
/*
* This is the startup thing for hosted environments. It
* defines main and then calls the main loop.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <minipc.h>
#include <ppsi/ppsi.h>
#include <ppsi/set-param.h>
#include <libwr/shmem.h>
# define WRSW_HAL_RETRIES 1000
#define WRSW_HAL_TIMEOUT 2000000 /* us */
const struct wrh_operations wrh_oper = {
.locking_enable = wrs_locking_enable,
.locking_poll = wrs_locking_poll,
.locking_disable = wrs_locking_disable,
.locking_reset = wrs_locking_reset,
.enable_ptracker = wrs_enable_ptracker,
.adjust_in_progress = wrs_adjust_in_progress,
.adjust_counters = wrs_adjust_counters,
.adjust_phase = wrs_adjust_phase,
.get_clock_period = wrs_get_clock_period,
.set_timing_mode= wrs_set_timing_mode,
.get_timing_mode= wrs_get_timing_mode,
.get_timing_mode_state= wrs_get_timing_mode_state,
struct minipc_ch *hal_ch;
struct minipc_ch *ppsi_ch;
struct hal_port_state *hal_ports;
struct wrs_shm_head *ppsi_head;
extern struct pp_ext_hooks pp_hooks;
static int set_extension(struct pp_instance *ppi, int extension);
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
static int init_extensions(struct pp_instance *ppi)
{
struct pp_ext_mem *ppi_ext_data;
if (!(ppi_ext_data =
wrs_shm_alloc(ppsi_head,
sizeof(struct pp_ext_mem) * (PPSI_EXT_N)))
) {
return -1;
}
/* Clean the allocated memory */
memset(ppi_ext_data, 0, sizeof(struct pp_ext_mem) * PPSI_EXT_N);
ppi->ext_mem = ppi_ext_data;
#if CONFIG_HAS_EXT_WR
/* Add WR extension portDS */
if (!(ppi_ext_data[PPSI_EXT_WR].ext_dsport =
wrs_shm_alloc(ppsi_head, sizeof(struct wr_dsport)))
) {
return -1;
}
/* Allocate WR data extension */
if (!(ppi_ext_data[PPSI_EXT_WR].ext_data =
wrs_shm_alloc(ppsi_head, sizeof(struct wr_data)))
) {
return -1;
}
/* Set WR extension hooks */
ppi_ext_data[PPSI_EXT_WR].ext_hooks = &wr_ext_hooks;
#endif
if (!(ppi_ext_data[PPSI_EXT_L1S].ext_dsport =
wrs_shm_alloc(ppsi_head, sizeof(l1e_ext_portDS_t)))
) {
return -1;
}
/* Allocate L1SYNC data extension */
if (!(ppi_ext_data[PPSI_EXT_L1S].ext_data =
wrs_shm_alloc(ppsi_head,sizeof(struct l1e_data)))
) {
return -1;
}
/* Set L1SYNC extension hooks */
ppi_ext_data[PPSI_EXT_L1S].ext_hooks = &l1e_ext_hooks;
#endif
return 0;
}
/* Should be called when the extension is changed in runtime */
static int set_extension_runtime_init(struct pp_instance *ppi)
{
int tmo;
ppi->pdstate = PP_PDSTATE_NONE;
/* Default value for PTP. Can be overwritten in specific init */
ppi->extState =
(ppi->protocol_extension == PPSI_EXT_NONE)
? PP_EXSTATE_DISABLE : PP_EXSTATE_ACTIVE;
/* WRPC 4.2 and possibly old WRS FW does not send delay_req/delay_resp
* while locking the PLL. Due to that extension setup can timeout. */
tmo = is_ext_hook_available(ppi,get_tmo_lstate_detection) ?
(*ppi->ext_hooks->get_tmo_lstate_detection)(ppi)
: 20000; // 20s per default
pp_timeout_set(ppi, PP_TO_PROT_STATE, tmo);
if (!ppi->link_up) {
/* Skip extension initialization, it will be done when the link
* goes up. */
return 0;
}
if (is_ext_hook_available(ppi, init)
&& ppi->ext_hooks->init(ppi, NULL, 0)
) {
pp_diag(ppi, ext, 1, "%s: can't init profile\n",
__func__);
return 1;
}
if (ppi->state == PPS_SLAVE) {
/* When the extension/profile is changed the servo is not reset
* nor initialized. Initialization of servo (wrh_servo_init) is
* done via new_slave */
if (is_ext_hook_available(ppi, new_slave))
ppi->ext_hooks->new_slave(ppi, NULL, 0);
else
pp_servo_init(ppi);
}
return 0;
}
int set_extension_runtime(struct pp_instance *ppi, int extension)
{
Adam Wujek
committed
if (set_extension_precheck(ppi, extension) < 0)
return -1;
if (set_extension(ppi, extension) < 0) {
/* Error */
return -1;
}
/* Initialize set extenstion */
return set_extension_runtime_init(ppi);
}
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
int set_extension_precheck(struct pp_instance *ppi, int extension)
{
int profile = ppi->cfg.profile;
if (extension == PPSI_EXT_NONE)
return 0;
if (extension == PPSI_EXT_WR) {
if (!CONFIG_HAS_EXT_WR)
return -1;
if (profile == PPSI_PROFILE_HA_WR
|| profile == PPSI_PROFILE_CUSTOM) {
/* Extension is supported for the selected profile */
return 0;
}
return -2;
}
if (extension == PPSI_EXT_L1S) {
if (!CONFIG_HAS_EXT_L1SYNC)
return -1;
if (profile == PPSI_PROFILE_HA_WR
|| profile == PPSI_PROFILE_CUSTOM) {
/* Extension is supported for the selected profile */
return 0;
}
return -2;
}
pp_diag(ppi, config, 1, "BUG: %s: unexpected combination of extension (%d) "
"and profile (%d)\n", __func__, extension, profile);
return -2;
}
static int set_extension(struct pp_instance *ppi, int extension)
{
pp_diag(ppi, config, 3, "%s: set extension: %s (%d)\n",
__func__, lut_extension_name[extension], extension);
switch (extension) {
#if CONFIG_HAS_EXT_WR
case PPSI_EXT_WR:
ppi->portDS->ext_dsport = ppi->ext_mem[PPSI_EXT_WR].ext_dsport;
ppi->ext_data = ppi->ext_mem[PPSI_EXT_WR].ext_data;
ppi->ext_hooks = ppi->ext_mem[PPSI_EXT_WR].ext_hooks;
ppi->protocol_extension = PPSI_EXT_WR;
Adam Wujek
committed
#if CONFIG_HAS_EXT_L1SYNC
/* Disable L1Sync just in case it was enabled */
L1E_DSPOR_BS(ppi)->L1SyncState = L1SYNC_DISABLED;
L1E_DSPOR_BS(ppi)->L1SyncEnabled = FALSE;
#endif /* CONFIG_HAS_EXT_L1SYNC */
break;
#endif
#if CONFIG_HAS_EXT_L1SYNC
case PPSI_EXT_L1S:
ppi->portDS->ext_dsport = ppi->ext_mem[PPSI_EXT_L1S].ext_dsport;
ppi->ext_data = ppi->ext_mem[PPSI_EXT_L1S].ext_data;
ppi->ext_hooks = ppi->ext_mem[PPSI_EXT_L1S].ext_hooks;
ppi->protocol_extension=PPSI_EXT_L1S;
/* Set L1SYNC state. Must be done here because the init hook is
* called only in the initializing state. If the port is not
* connected, the initializing is then never called so the
* L1SYNC state is invalid (0)
L1E_DSPOR_BS(ppi)->L1SyncState = L1SYNC_DISABLED;
L1E_DSPOR_BS(ppi)->L1SyncEnabled = TRUE;
break;
#endif
case PPSI_EXT_NONE:
ppi->portDS->ext_dsport = NULL;
ppi->ext_data = NULL;
ppi->ext_hooks = &pp_hooks;
ppi->protocol_extension = PPSI_EXT_NONE;
Adam Wujek
committed
#if CONFIG_HAS_EXT_L1SYNC
/* Disable L1Sync just in case it was enabled */
L1E_DSPOR_BS(ppi)->L1SyncState = L1SYNC_DISABLED;
L1E_DSPOR_BS(ppi)->L1SyncEnabled = FALSE;
#endif /* CONFIG_HAS_EXT_L1SYNC */
break;
default:
fprintf(stderr, "ppsi: Extension not supported\n");
return -1;
break;
set_param_ptpVersion(ppi);
Adam Wujek
committed
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
static void set_profile_params(struct pp_instance *ppi)
{
/* When switching a profile, set the default values for the new profile. */
/* For don't change any parametres when switching to
* PPSI_PROFILE_CUSTOM */
if (ppi->cfg.profile == PPSI_PROFILE_CUSTOM) {
/* Don't change parameters for the custom profile */
return;
}
if (!is_profile_supported(ppi->cfg.profile)) {
/* Profile not supported */
return;
}
if (DSPOR(ppi)->logMinDelayReqInterval != lut_profile_logMinDelayReqInterval_default[ppi->cfg.profile]) {
pp_diag(ppi, config, 1,
"Seting logMinDelayReqInterval (current %d) to the default value (%d) for %s profile\n",
DSPOR(ppi)->logMinDelayReqInterval,
lut_profile_logMinDelayReqInterval_default[ppi->cfg.profile],
lut_profile_name[ppi->cfg.profile]);
set_param_inst_logMinDelayReqInterval(ppi, lut_profile_logMinDelayReqInterval_default[ppi->cfg.profile]);
}
if (DSPOR(ppi)->logMinPdelayReqInterval != lut_profile_logMinPdelayReqInterval_default[ppi->cfg.profile]) {
pp_diag(ppi, config, 1,
"Seting logMinPdelayReqInterval (current %d) to the default value (%d) for %s profile\n",
DSPOR(ppi)->logMinPdelayReqInterval,
lut_profile_logMinPdelayReqInterval_default[ppi->cfg.profile],
lut_profile_name[ppi->cfg.profile]);
set_param_inst_logMinPdelayReqInterval(ppi, lut_profile_logMinPdelayReqInterval_default[ppi->cfg.profile]);
}
if (DSPOR(ppi)->logSyncInterval != lut_profile_logSyncInterval_default[ppi->cfg.profile]) {
pp_diag(ppi, config, 1,
"Seting logSyncInterval (current %d) to the default value (%d) for %s profile\n",
DSPOR(ppi)->logSyncInterval,
lut_profile_logSyncInterval_default[ppi->cfg.profile],
lut_profile_name[ppi->cfg.profile]);
set_param_inst_logSyncInterval(ppi, lut_profile_logSyncInterval_default[ppi->cfg.profile]);
}
}
static void set_l1sync_params(struct pp_instance *ppi)
{
/* Force mandatory attributes - Do not take care of the configuration */
L1E_DSPOR_BS(ppi)->rxCoherentIsRequired = TRUE;
L1E_DSPOR_BS(ppi)->txCoherentIsRequired = TRUE;
L1E_DSPOR_BS(ppi)->congruentIsRequired = TRUE;
L1E_DSPOR_BS(ppi)->optParamsEnabled = FALSE;
}
static int set_profile(struct pp_instance *ppi, int profile, int extension,
int startup)
ppi->cfg.profile = profile;
pp_diag(ppi, config, 3, "%s: set profile: %s (%d)\n",
__func__, lut_profile_name[ppi->cfg.profile],
ppi->cfg.profile);
switch (profile) {
case PPSI_PROFILE_PTP :
/* Disable extension */
if (set_extension(ppi, PPSI_EXT_NONE) < 0) {
/* Error */
return -1;
}
/* Disable extension autonegotiation in case it was enabled */
ppi->cfg.extAutonegEnable = 0;
/* Do not take care of L1SYNC */
enable_asymmetryCorrection(ppi, ppi->cfg.asymmetryCorrectionEnable);
Adam Wujek
committed
if (!startup) {
set_profile_params(ppi);
}
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
case PPSI_PROFILE_HA_WR:
#if CONFIG_HAS_PROFILE_HA_WR
if (startup) {
/* Change the extension to the configured one at
* startup */
if (set_extension(ppi, extension) < 0) {
/* Error */
return -1;
}
} else if (CONFIG_HAS_EXT_WR
/* if autonegotiation is used use L1Sync as
* extension */
&& ppi->cfg.extAutonegEnable == FALSE) {
if (set_extension(ppi, PPSI_EXT_WR) < 0) {
/* Error */
return -1;
}
} else if (CONFIG_HAS_EXT_L1SYNC) {
if (set_extension(ppi, PPSI_EXT_L1S) < 0) {
/* Error */
return -1;
}
} else {
if (set_extension(ppi, PPSI_EXT_NONE) < 0) {
/* Error */
return -1;
}
Adam Wujek
committed
if (!startup) {
set_profile_params(ppi);
}
if (CONFIG_HAS_EXT_L1SYNC) {
/* Set L1Sync params even for WR profile, since we allow
* configuration WR profile with L1Sync extension */
set_l1sync_params(ppi);
}
enable_asymmetryCorrection(ppi, TRUE);
break;
#else
fprintf(stderr, "ppsi: Profile HA/WR not supported\n");
#endif /* CONFIG_HAS_PROFILE_HA_WR */
case PPSI_PROFILE_CUSTOM :
#if CONFIG_HAS_PROFILE_CUSTOM
if (startup
&& set_extension(ppi, extension) < 0) {
/* Error */
return -1;
}
#if CONFIG_HAS_EXT_L1SYNC
if (!startup) {
/* Set extension and other parameters used by CUSTOM
* profile only at startup. The intention is that
* no parameters are changed at the switch to CUSTOM
* profile in runtime. If some parametres need
* to be adjusted when running CUSTOM profile, they
* shall be changed using other ways (e.g. runtime
* reconfiguration). */
break;
}
if (ppi->cfg.l1SyncEnabled ) {
/* Read L1SYNC parameters from configuration */
L1E_DSPOR_BS(ppi)->rxCoherentIsRequired = ppi->cfg.l1SyncRxCoherentIsRequired;
L1E_DSPOR_BS(ppi)->txCoherentIsRequired = ppi->cfg.l1SyncTxCoherentIsRequired;
L1E_DSPOR_BS(ppi)->congruentIsRequired = ppi->cfg.l1SyncCongruentIsRequired;
L1E_DSPOR_BS(ppi)->optParamsEnabled = ppi->cfg.l1SyncOptParamsEnabled;
if (L1E_DSPOR_BS(ppi)->optParamsEnabled) {
L1E_DSPOR_OP(ppi)->timestampsCorrectedTx = ppi->cfg.l1SyncOptParamsTimestampsCorrectedTx;
}
}
#endif /* CONFIG_HAS_EXT_L1SYNC*/
enable_asymmetryCorrection(ppi, ppi->cfg.asymmetryCorrectionEnable);
#else
fprintf(stderr, "ppsi: Profile CUSTOM not supported\n");
return -1;
break;
default:
fprintf(stderr, "ppsi: Not supported profile %d\n", profile);
return -1;
}
return 0;
}
int set_profile_runtime(struct pp_instance *ppi, int profile)
{
if (set_profile(ppi, profile, 0 /* ignored */, 0 /* no startup */))
/* Initialize set extenstion */
return set_extension_runtime_init(ppi);
/**
* Enable/disable asymmetry correction
*/
void enable_asymmetryCorrection(struct pp_instance *ppi, Boolean enable ) {
if ( (ppi->asymmetryCorrectionPortDS.enable=enable)==TRUE ) {
/* Enabled: The delay asymmetry will be calculated */
ppi->asymmetryCorrectionPortDS.scaledDelayCoefficient =( ppi->cfg.scaledDelayCoefficient != 0) ?
ppi->cfg.scaledDelayCoefficient :
(RelativeDifference)(ppi->cfg.delayCoefficient * REL_DIFF_TWO_POW_FRACBITS);
ppi->portDS->delayAsymCoeff=pp_servo_calculateDelayAsymCoefficient(ppi->asymmetryCorrectionPortDS.scaledDelayCoefficient);
ppi->asymmetryCorrectionPortDS.constantAsymmetry=picos_to_interval(ppi->cfg.constantAsymmetry_ps);
/* Functions to set global parameters */
void set_param_global_prio1(struct pp_globals *ppg, int prio1)
{
ppg->rt_opts->priority1 = prio1;
bmc_apply_configured_device_attributes(ppg);
}
void set_param_global_prio2(struct pp_globals *ppg, int prio2)
{
ppg->rt_opts->priority2 = prio2;
bmc_apply_configured_device_attributes(ppg);
}
void set_param_global_bmca(struct pp_globals *ppg, int bmca)
{
ppg->rt_opts->bmca = bmca;
pp_set_bmca(ppg, bmca);
}
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
/* Functions to set parameters specific to instance */
void set_param_inst_logMinDelayReqInterval(struct pp_instance *ppi,
int logMinDelayReqInterval)
{
int millisec;
DSPOR(ppi)->logMinDelayReqInterval = logMinDelayReqInterval;
ppi->cfg.min_delay_req_interval = logMinDelayReqInterval;
millisec = pp_timeout_log_to_ms(logMinDelayReqInterval);
if (is_delayMechanismE2E(ppi))
pp_timeout_set_rename(ppi, PP_TO_REQUEST, millisec);
}
void set_param_inst_logMinPdelayReqInterval(struct pp_instance *ppi,
int logMinPdelayReqInterval)
{
int millisec;
DSPOR(ppi)->logMinPdelayReqInterval = logMinPdelayReqInterval;
ppi->cfg.min_pdelay_req_interval = logMinPdelayReqInterval;
millisec = pp_timeout_log_to_ms(logMinPdelayReqInterval);
if (is_delayMechanismP2P(ppi))
pp_timeout_set_rename(ppi, PP_TO_REQUEST, millisec);
}
void set_param_inst_logSyncInterval(struct pp_instance *ppi,
int logSyncInterval)
{
int millisec;
DSPOR(ppi)->logSyncInterval = logSyncInterval;
ppi->cfg.sync_interval = logSyncInterval;
millisec = pp_timeout_log_to_ms(logSyncInterval);
pp_timeout_set_rename(ppi, PP_TO_SYNC_SEND, millisec);
}
static char *strCodeOpt="CODEOPT=("
#if CONFIG_HAS_CODEOPT_EPC_ENABLED
" EPC"
#endif
#if CONFIG_HAS_CODEOPT_SO_ENABLED
" SO"
#endif
#if CONFIG_HAS_CODEOPT_SINGLE_FMASTER
" SFM"
#endif
#if CONFIG_HAS_CODEOPT_SINGLE_PORT
" SP"
#endif
")";
int main(int argc, char **argv)
{
struct pp_globals *ppg;
struct wrs_shm_head *hal_head;
setbuf(stdout, NULL);
pp_printf("PPSi. Commit %s, built on " __DATE__ ", %s\n",
PPSI_VERSION,
strCodeOpt);
/* Check for -h or --help in params list */
pp_parse_cmdline_early(argc, argv);
/* check if there is another instance of PPSi already running */
ppsi_head = wrs_shm_get(wrs_shm_ptp, "", WRS_SHM_READ);
if (!ppsi_head) {
pp_printf("Unable to open shm for PPSi! Unable to check if "
"there is another PPSi instance running. Error: %s\n",
strerror(errno));
exit(1);
}
/* check if pid is 0 (shm not filled) or process with provided
* pid does not exist (probably crashed) */
{
int nbTry=1;
while ( nbTry >= 0 ) {
if ((ppsi_head->pid != 0) && (kill(ppsi_head->pid, 0) == 0)) {
nbTry--;
sleep(1);
}
else
break;
}
if ( nbTry<0 ) {
wrs_shm_put(ppsi_head);
pp_printf("Fatal: There is another PPSi instance running. "
"Exit...\n\n");
exit(1);
}
Adam Wujek
committed
/* it will be opened later for write */
wrs_shm_put(ppsi_head);
/* try connecting to HAL multiple times in case it's still not ready */
hal_retries = WRSW_HAL_RETRIES;
while (hal_retries) { /* may be never, if built without WR extension */
hal_ch = minipc_client_create(WRSW_HAL_SERVER_ADDR,
MINIPC_FLAG_VERBOSE);
usleep(WRSW_HAL_TIMEOUT);
}
if (!hal_ch) {
pp_printf("ppsi: could not connect to HAL RPC");
exit(1);
/* If we connected, we also know "for sure" shmem is there */
hal_head = wrs_shm_get(wrs_shm_hal,"", WRS_SHM_READ);
if (!hal_head || !hal_head->data_off) {
pp_printf("ppsi: Can't connect with HAL "
"shared memory\n");
exit(1);
}
if (hal_head->version != HAL_SHMEM_VERSION) {
pp_printf("ppsi: unknown HAL's shm version %i "
"(known is %i)\n", hal_head->version,
HAL_SHMEM_VERSION);
exit(1);
}
hal_shmem = (void *)hal_head + hal_head->data_off;
hal_nports = hal_shmem->nports;
hal_ports = wrs_shm_follow(hal_head, hal_shmem->ports);
if (!hal_ports) {
pp_printf("ppsi: unable to follow hal_ports pointer "
"in HAL's shmem\n");
exit(1);
}
/* And create your own channel, until we move to shmem too */
ppsi_ch = minipc_server_create("ptpd", 0);
if (!ppsi_ch) { /* FIXME should we retry ? */
pp_printf("ppsi: could not create minipc server\n");
exit(1);
}
ppsi_head = wrs_shm_get(wrs_shm_ptp, "ppsi",
WRS_SHM_WRITE | WRS_SHM_LOCKED);
if (!ppsi_head) {
fprintf(stderr, "Fatal: could not create shmem: %s\n",
strerror(errno));
exit(1);
ppsi_head->version = WRS_PPSI_SHMEM_VERSION;
ppg = wrs_shm_alloc(ppsi_head, sizeof(*ppg));
ppg->defaultDS = wrs_shm_alloc(ppsi_head, sizeof(*ppg->defaultDS));
ppg->currentDS = wrs_shm_alloc(ppsi_head, sizeof(*ppg->currentDS));
ppg->parentDS = wrs_shm_alloc(ppsi_head, sizeof(*ppg->parentDS));
ppg->timePropertiesDS = wrs_shm_alloc(ppsi_head,sizeof(*ppg->timePropertiesDS));
ppg->gmPrev = wrs_shm_alloc(ppsi_head, sizeof(*ppg->gmPrev));
ppg->rt_opts = &__pp_default_rt_opts;
ppg->max_links = PP_MAX_LINKS;
ppg->arch_glbl_data = wrs_shm_alloc(ppsi_head, sizeof(wrs_arch_data_t));
ppg->pp_instances = wrs_shm_alloc(ppsi_head,
ppg->max_links * sizeof(struct pp_instance));
if ((!ppg->arch_glbl_data) || (!ppg->pp_instances)) {
fprintf(stderr, "ppsi: out of memory\n");
exit(1);
}
/* Set default configuration value for all instances */
for (i = 0; i < ppg->max_links; i++) {
memcpy(&INST(ppg, i)->cfg, &__pp_default_instance_cfg,sizeof(__pp_default_instance_cfg));
/* Set offset here, so config parsing can override it */
memset(&t, 0, sizeof(t));
ppg->timePropertiesDS->currentUtcOffset = (Integer16)t.tai;
if (pp_parse_cmdline(ppg, argc, argv) != 0)
return -1;
/* If no item has been parsed, provide a default file or string */
if (ppg->cfg.cfg_items == 0)
pp_config_file(ppg, 0, PP_DEFAULT_CONFIGFILE);
if (ppg->cfg.cfg_items == 0) {
/* Default configuration for switch is all ports - Priority given to HA */
char s[128];
for (i = 0; i < WRS_NUMBER_PHYSICAL_PORTS; i++) {
sprintf(s, "port %i; iface wri%i; proto raw;", i + 1, i + 1);
if (CONFIG_HAS_PROFILE_HA_WR) {
sprintf(s, "profile ha_wr;");
if (CONFIG_HAS_EXT_L1SYNC)
sprintf(s, "extension ha;");
else if (CONFIG_HAS_EXT_WR)
sprintf(s, "extension wr");
} else
sprintf(s, "profile ptp;");
pp_config_string(ppg, s);
}
}
for (i = 0; i < ppg->nlinks; i++) {
struct pp_instance *ppi= INST(ppg, i);
ppi->ch[PP_NP_EVT].fd = -1;
ppi->ch[PP_NP_GEN].fd = -1;
ppi->vlans_array_len = CONFIG_VLAN_ARRAY_SIZE;
ppi->port_idx = i; /* port_idx is also filled in pp_init_globals
* in proto-standard/open-close.c, but make
* it available also earlier. */
ppi->iface_name = ppi->cfg.iface_name;
ppi->port_name = ppi->cfg.port_name;
ppi->delayMechanism = ppi->cfg.delayMechanism;
ppi->portDS = wrs_shm_alloc(ppsi_head, sizeof(*ppi->portDS));
ppi->servo = wrs_shm_alloc(ppsi_head, sizeof(*ppi->servo));
ppi->ext_hooks=&pp_hooks; /* Default value. Can be overwritten by an extension */
if (init_extensions(ppi) < 0)
goto exit_out_of_memory;
ppi->protocol_extension = ppi->cfg.extension;
if (set_profile(ppi, ppi->cfg.profile, ppi->cfg.extension, 1 /* startup */) < 0) {
fprintf(stderr,
"ppsi: Profile %d not supported\n",
ppi->cfg.profile);
/* Parameters profile independent */
ppi->timestampCorrectionPortDS.egressLatency=picos_to_interval(ppi->cfg.egressLatency_ps);
ppi->timestampCorrectionPortDS.ingressLatency=picos_to_interval(ppi->cfg.ingressLatency_ps);
ppi->timestampCorrectionPortDS.messageTimestampPointLatency=0;
ppi->portDS->masterOnly= ppi->cfg.masterOnly; /* can be overridden in pp_init_globals() */
} else {
goto exit_out_of_memory;
/* The following default names depend on TIME= at build time */
ppi->n_ops = &DEFAULT_NET_OPS;
ppi->t_ops = &DEFAULT_TIME_OPS;
ppi->__tx_buffer = malloc(PP_MAX_FRAME_LENGTH);
ppi->__rx_buffer = malloc(PP_MAX_FRAME_LENGTH);
if (!ppi->__tx_buffer || !ppi->__rx_buffer) {
goto exit_out_of_memory;
pp_init_globals(ppg, &__pp_default_rt_opts);
wrh_timing_mode_pll_state_t timing_mode_pll_state;
struct pp_instance *ppi=INST(ppg,0);
wrh_timing_mode_t current_timing_mode;
int ret=WRH_OPER()->get_timing_mode(ppg,¤t_timing_mode);
if (ret<0) {
fprintf(stderr, "ppsi: Cannot get current timing mode\n");
exit(1);
}
WRS_ARCH_G(ppg)->timingModeLockingState=WRH_TM_LOCKING_STATE_LOCKING;
switch (current_timing_mode) {
case WRH_TM_FREE_MASTER :
// FR mode is OK for starting in all cases. We are not going to touch it
// -> GM will be set in the main loop
// -> BC will be set when a port will become slave
WRS_ARCH_G(ppg)->timingMode=WRH_TM_FREE_MASTER; // set here because set_timing_mode() is not called
break;
case WRH_TM_GRAND_MASTER :
if ( ppg->defaultDS->clockQuality.clockClass == PP_PTP_CLASS_GM_LOCKED ) {
// Already the correct timing mode. Not touched to avoid an unlock of the PLL
WRS_ARCH_G(ppg)->timingMode=WRH_TM_GRAND_MASTER; // set here because set_timing_mode() is not called
break;
}
// No break here to set the timing mode to FR
case WRH_TM_BOUNDARY_CLOCK :
case WRH_TM_DISABLED :
// Must be reseted to FR
WRH_OPER()->set_timing_mode(ppg,WRH_TM_FREE_MASTER);
/* Waiting for PLL locking. We do not need a precise time-out here */
/* We are waiting up to 3s for PLL locking.
* We do that to avoid to jump too quickly to a degraded clock class.
*/
nbRetry=2;
while(nbRetry>0) {
int ret=WRH_OPER()->get_timing_mode_state(ppg,&timing_mode_pll_state);
if ( ret==0 && timing_mode_pll_state==WRH_TM_PLL_STATE_LOCKED )
if ( timing_mode_pll_state==WRH_TM_PLL_STATE_UNLOCKED) {
WRS_ARCH_G(ppg)->timingModeLockingState = WRH_TM_LOCKING_STATE_LOCKING;
} else if (timing_mode_pll_state==WRH_TM_PLL_STATE_LOCKED) {
TOPS(ppi)->set(ppi,NULL); // GM locked: set the time
WRS_ARCH_G(ppg)->timingModeLockingState = WRH_TM_LOCKING_STATE_LOCKED;
}
/* Enable the PPS generation only if
* - Grand master and PLL is locked
* OR
* - Free running master (no condition required)
enablePPS=(WRS_ARCH_G(ppg)->timingModeLockingState== WRH_TM_LOCKING_STATE_LOCKED &&
ppg->defaultDS->clockQuality.clockClass == PP_PTP_CLASS_GM_LOCKED) ||
GOPTS(ppg)->forcePpsGen;
TOPS(ppi)->enable_timing_output(ppg,enablePPS);
wrs_init_ipcserver(ppg, ppsi_ch);
/* release lock from wrs_shm_get */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
wrs_main_loop(ppg);
return 0; /* never reached */
exit_out_of_memory:;
fprintf(stderr, "ppsi: out of memory\n");
exit(1);