Commit 2e0e8ca3 authored by Federico Vaga's avatar Federico Vaga

sw:lib: split loading in two parts: input and output

For convenience the first verison of WRTD assumed that a WRTD node
is always in/out. Actually this is not true, we may have only input
and only output nodes. for this reason we need to split the firmware
loading and validation in two parts
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent c09a0168
......@@ -95,38 +95,58 @@ void wrtd_exit()
}
/**
* Check if the RT-app running version is compatible with the current
* library
* @param[in] dev device token
* @return 1 if the version is correct, 0 otherwise and errno is
* appropriately set
*/
int wrtd_version_is_valid(struct wrtd_node *dev)
static int __wrtd_load(struct wrtd_desc *wrtd, char *fw,
unsigned int cpu, uint16_t id)
{
struct trtl_fw_version version;
int err;
errno = 0;
err = wrtd_in_version(dev, &version);
err = trtl_cpu_load_application_file(wrtd->trtl, cpu, fw);
if (err)
return 0;
return err;
if (version.rt_id != WRTD_IN_RT_ID) {
errno = EWRTD_INVALID_IN_APP;
return 0;
}
err = trtl_cpu_enable(wrtd->trtl, cpu);
if (err)
return err;
err = wrtd_out_version(dev, &version);
err = trtl_fw_version(wrtd->trtl, cpu, 0, &version);
if (err)
return 0;
return err;
if (version.rt_id != WRTD_OUT_RT_ID) {
if (version.rt_id != id) {
errno = EWRTD_INVALID_IN_APP;
return 0;
return -1;
}
return 1;
return 0;
}
/**
* It loads the input firmare (TDC)
* @param[in] dev device token
* @param[in] fw path to firmware
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
int wrtd_in_load(struct wrtd_node *dev, char *fw)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
return __wrtd_load(wrtd, fw, WRTD_CPU_TDC, WRTD_IN_RT_ID);
}
/**
* It loads the output firmare (FD)
* @param[in] dev device token
* @param[in] fw path to firmware
* @return 0 on success, otherwise -1 and errno is appropriately set
*/
int wrtd_out_load(struct wrtd_node *dev, char *fw)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
return __wrtd_load(wrtd, fw, WRTD_CPU_FD, WRTD_OUT_RT_ID);
}
......@@ -187,75 +207,6 @@ struct trtl_dev *wrtd_get_trtl_dev(struct wrtd_node *dev)
}
/**
* It restarts both real-time applications
* @param[in] dev device token
* @return 0 on success, -1 on error and errno is set appropriately
*/
int wrtd_cpu_restart(struct wrtd_node *dev)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
int err;
err = trtl_cpu_disable(wrtd->trtl,WRTD_CPU_TDC);
if (err)
return err;
err = trtl_cpu_disable(wrtd->trtl,WRTD_CPU_FD);
if (err)
return err;
err = trtl_cpu_enable(wrtd->trtl,WRTD_CPU_TDC);
if (err)
return err;
return trtl_cpu_enable(wrtd->trtl,WRTD_CPU_FD);
}
/**
* It loads a set of real-time applications for TDC and FD
* @param[in] dev device token
* @param[in] rt_tdc path to the TDC application
* @param[in] rt_fd path to the Fine Delay application
*/
int wrtd_load_application(struct wrtd_node *dev, char *rt_tdc,
char *rt_fd)
{
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
uint32_t reg_old;
int err;
if (!rt_tdc || !rt_fd) {
errno = EWRTD_INVALID_BINARY;
return -1;
}
err = trtl_cpu_reset_get(wrtd->trtl, &reg_old);
if (err)
return err;
/* Keep the CPUs in reset state */
err = trtl_cpu_reset_set(wrtd->trtl,
(1 << WRTD_CPU_TDC) | (1 << WRTD_CPU_FD));
if (err)
return err;
/* Program CPUs application */
err = trtl_cpu_load_application_file(wrtd->trtl, WRTD_CPU_TDC, rt_tdc);
if (err)
return err;
err = trtl_cpu_load_application_file(wrtd->trtl, WRTD_CPU_FD, rt_fd);
if (err)
return err;
/* Re-enable the CPUs */
err = trtl_cpu_reset_set(wrtd->trtl, reg_old);
if (err)
return err;
return 0;
}
/**
* It converts the white rabbit time stamp to a pico seconds
* @param[in] ts time-stamp
......
......@@ -730,3 +730,27 @@ int wrtd_in_version(struct wrtd_node *dev, struct trtl_fw_version *version)
return trtl_fw_version(wrtd->trtl, WRTD_CPU_TDC, 0, version);
}
/**
* It tells if the input firmware is valid
* @param[in] dev device token
* @param[out] version the RT application version
* @return 1 when valid, 0 if invalid or error (and errno is set appropriately)
*/
int wrtd_in_is_valid(struct wrtd_node *dev)
{
struct trtl_fw_version version;
int err;
err = wrtd_in_version(dev, &version);
if (err)
return 0;
if (version.rt_id != WRTD_IN_RT_ID) {
errno = EWRTD_INVALID_IN_APP;
return 0;
}
return 1;
}
......@@ -1097,3 +1097,26 @@ int wrtd_out_version(struct wrtd_node *dev, struct trtl_fw_version *version)
return trtl_fw_version(wrtd->trtl, WRTD_CPU_FD, 0, version);
}
/**
* It tells if the ouput firmware is valid
* @param[in] dev device token
* @param[out] version the RT application version
* @return 1 when valid, 0 if invalid or error (and errno is set appropriately)
*/
int wrtd_out_is_valid(struct wrtd_node *dev)
{
struct trtl_fw_version version;
int err;
err = wrtd_out_version(dev, &version);
if (err)
return 0;
if (version.rt_id != WRTD_OUT_RT_ID) {
errno = EWRTD_INVALID_IN_APP;
return 0;
}
return 1;
}
......@@ -163,8 +163,13 @@ extern void wrtd_exit();
extern struct wrtd_node *wrtd_open(uint32_t device_id);
extern void wrtd_close(struct wrtd_node *dev);
extern struct trtl_dev *wrtd_get_trtl_dev(struct wrtd_node *dev);
extern int wrtd_load_application(struct wrtd_node *dev, char *rt_tdc,
char *rt_fd);
extern int wrtd_in_load(struct wrtd_node *dev, char *fw);
extern int wrtd_out_load(struct wrtd_node *dev, char *fw);
extern int wrtd_out_is_valid(struct wrtd_node *dev);
extern int wrtd_in_is_valid(struct wrtd_node *dev);
extern int wrtd_white_rabbit_sync(struct wrtd_node *dev,
unsigned long timeout_s);
extern int wrtd_cpu_restart(struct wrtd_node *dev);
......@@ -177,7 +182,6 @@ extern int wrtd_time_get(struct wrtd_node *dev, unsigned int input,
* Set of utilities
* @{
*/
extern int wrtd_version_is_valid(struct wrtd_node *dev);
extern const char *wrtd_strerror(int err);
extern void wrtd_ts_to_pico(struct wr_timestamp *ts, uint64_t *pico);
extern void wrtd_pico_to_ts(uint64_t *pico, struct wr_timestamp *ts);
......
......@@ -28,6 +28,9 @@
#define WRTD_BOOT_WR_FMC_OFFSET 0x2
static int setoff;
static uint32_t dev_id;
enum wrtb_boot_tdc_offset_type {
OFFSET_ZERO,
OFFSET_USER,
......@@ -131,18 +134,70 @@ static int offset_get(unsigned int dev_id, unsigned int channel, int32_t *offset
return 0;
}
static int wrtd_boot_init_tdc(struct wrtd_node *wrtd, char *fw)
{
int err = -1, i;
int32_t offset;
if (!fw) {
errno = EINVAL;
goto out;
}
err = wrtd_in_load(wrtd, fw);
if (err)
goto out;
if (!setoff)
goto out;
/* Inform the input real-time channels about the offset */
for (i = 0; i < TDC_NUM_CHANNELS; ++i) {
err = offset_get(dev_id, i, &offset);
if (err) {
fprintf(stderr,
"Channel %d cannot calculate offset: %s\n",
i, wrtd_strerror(errno));
continue;
}
err = wrtd_in_timebase_offset_set(wrtd, i, offset);
if (err) {
fprintf(stderr,
"Channel %d cannot set offset: %s\n",
i, wrtd_strerror(errno));
continue;
}
}
err = 0; /* errors reported above, lets the system run with a potential
* "wrong" offset that someone will debug
*/
out:
return err;
}
static int wrtd_boot_init_fd(struct wrtd_node *wrtd, char *fw)
{
int err = -1;
if (!fw) {
errno = EINVAL;
goto out;
}
err = wrtd_out_load(wrtd, fw);
out:
return err;
}
int main(int argc, char *argv[])
{
int err, cerr = 0, i, setoff = 0;
uint32_t dev_id = 0;
int err;
char *tdc = NULL, *fd =NULL, c;
struct wrtd_node *wrtd;
struct trtl_dev *trtl;
int32_t offset;
atexit(wrtd_exit);
while ((c = getopt (argc, argv, "hD:t:f:o")) != -1) {
while ((c = getopt (argc, argv, "hD:i:o:t")) != -1) {
switch (c) {
case 'h':
case '?':
......@@ -151,23 +206,18 @@ int main(int argc, char *argv[])
case 'D':
sscanf(optarg, "0x%x", &dev_id);
break;
case 't':
case 'i':
tdc = optarg;
break;
case 'f':
case 'o':
fd = optarg;
break;
case 'o':
case 't':
setoff = 1;
break;
}
}
if (!fd || !tdc) {
fprintf(stderr, "Missing binary file to load\n");
exit(1);
}
if (!dev_id) {
fprintf(stderr, "Invalid trtl device\n");
exit(1);
......@@ -179,71 +229,30 @@ int main(int argc, char *argv[])
trtl_strerror(errno));
exit(1);
}
atexit(wrtd_exit);
wrtd = wrtd_open(dev_id);
if (!wrtd) {
fprintf(stderr, "Cannot open WRNC: %s\n", wrtd_strerror(errno));
fprintf(stderr, "Cannot open WRTD: %s\n", wrtd_strerror(errno));
exit(1);
}
/* Load the application into the WRNC CPUs */
fprintf(stdout, "Programming on TDC: %s\n", tdc);
fprintf(stdout, "Programming on FD: %s\n", fd);
err = wrtd_load_application(wrtd, tdc, fd);
if (err) {
fprintf(stderr, "Cannot program binary to WRNC: %s\n",
err = wrtd_boot_init_tdc(wrtd, tdc);
if (err < 0) {
fprintf(stderr,
"Failed to program TDC firmware: %s\n"
"We will not be able to send triggers\n",
wrtd_strerror(errno));
exit(1);
}
/* Get the WRNC token */
trtl = wrtd_get_trtl_dev(wrtd);
fprintf(stdout, "Reboot applications\n");
/* Start running application on TDC and FD CPUs */
err = trtl_cpu_enable(trtl, 0);
if (err)
exit(1);
err = trtl_cpu_enable(trtl, 1);
if (err)
exit(1);
if (!wrtd_version_is_valid(wrtd)) {
fprintf(stderr, "Invalid version %s: %s\n",
basename(argv[0]), wrtd_strerror(errno));
goto out;
}
if (setoff) {
/* Inform the input real-time channels about the offset */
for (i = 0; i < TDC_NUM_CHANNELS; ++i) {
err = offset_get(dev_id, i, &offset);
if (err) {
fprintf(stderr,
"Channel %d cannot calculate offset: %s\n",
i, wrtd_strerror(errno));
cerr++;
continue;
}
err = wrtd_in_timebase_offset_set(wrtd, i, offset);
if (err) {
fprintf(stderr,
"Channel %d cannot set offset: %s\n",
i, wrtd_strerror(errno));
cerr++;
continue;
}
}
err = wrtd_boot_init_fd(wrtd, fd);
if (err < 0) {
fprintf(stderr,
"Failed to program FD firmware: %s\n"
"We will not be able to receive triggers\n",
wrtd_strerror(errno));
}
if (cerr)
fprintf(stderr, "White Rabbit Trigger Distribution programmed but with %d problems\n", cerr);
else
fprintf(stdout,
"White Rabbit Trigger Distribution node succesfully programmed\n");
out:
wrtd_close(wrtd);
exit(0);
}
......@@ -361,7 +361,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "Cannot open WRNC: %s\n", wrtd_strerror(errno));
exit(1);
}
if (!wrtd_version_is_valid(wrtd)) {
if (!wrtd_in_is_valid(wrtd)) {
fprintf(stderr, "Cannot run %s: %s\n",
basename(argv[0]), wrtd_strerror(errno));
goto out;
......
......@@ -55,7 +55,26 @@ static void *logging_thread(void *arg)
{
struct wrtd_log_th *th_data = arg;
struct wrtd_log_entry log;
int i, count;
int i, count, valid;
switch (th_data->core) {
case WRTD_CORE_IN:
valid = wrtd_in_is_valid(th_data->wrtd);
break;
case WRTD_CORE_OUT:
valid = wrtd_out_is_valid(th_data->wrtd);
break;
default:
valid = 0;
break;
}
if (!valid) {
fprintf(stderr, "Cannot run logging, invalid %s firmware: %s\n",
th_data->core == WRTD_CORE_IN ? "input" : "output",
wrtd_strerror(errno));
return NULL;
}
while (i < th_data->n_read || th_data->n_read == 0) {
count = wrtd_log_read(th_data->wrtd, &log, 1, -1);
......@@ -166,12 +185,6 @@ int main(int argc, char *argv[])
}
th_data[1].wrtd = th_data[0].wrtd;
if (!wrtd_version_is_valid(th_data[0].wrtd)) {
fprintf(stderr, "Cannot run %s: %s\n",
basename(argv[0]), wrtd_strerror(errno));
goto out;
}
if (show_log) {
show_logging_level(th_data[WRTD_CORE_IN].wrtd, WRTD_CORE_IN);
show_logging_level(th_data[WRTD_CORE_OUT].wrtd, WRTD_CORE_OUT);
......@@ -192,7 +205,6 @@ int main(int argc, char *argv[])
for (i = 0; i < N_LOG; i++)
pthread_join(tid[i], NULL);
out:
wrtd_close(th_data[0].wrtd);
exit(0);
}
......@@ -628,7 +628,7 @@ int main(int argc, char *argv[])
exit(1);
}
if (!wrtd_version_is_valid(wrtd)) {
if (!wrtd_out_is_valid(wrtd)) {
fprintf(stderr, "Cannot run %s: %s\n",
basename(argv[0]), wrtd_strerror(errno));
goto out;
......
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