Commit 8b25e7a5 authored by Tristan Gingold's avatar Tristan Gingold

fip_urv: can remotely control the leds.

parent 303b3a49
# If it exists includes Makefile.specific. In this Makefile, you should put
# specific Makefile code that you want to run before this. For example,
# build a particular environment.
-include Makefile.specific
# define REPO_PARENT to get build environment
REPO_PARENT?=../../masterfip
-include $(REPO_PARENT)/parent_common.mk
-include ../version.mk
MFIP ?= $(REPO_PARENT)
TRTL ?= $(REPO_PARENT)/mockturtle/software
# use delivered version
CFLAGS += --std=gnu99 -O
CFLAGS += -Wall -ggdb $(DBG) -I. -I$(MFIP) -I$(MFIP)/include -I$(MFIP)/lib
CFLAGS += -D__GIT_VER__="\"$(GIT_VER)\"" -D__GIT_USR__="\"$(GIT_USR)\""
CXXFLAGS = $(CFLAGS) -std=c++11
LDLIBS += -Wl,-Bstatic -L$(MFIP)/lib -L$(TRTL)/lib
LDLIBS += -lmasterfip -lmockturtle
LDLIBS += -Wl,-Bdynamic -lpthread -lm -lrt
PROG := fip_urv
all: $(PROG)
.PHONY: all clean
clean:
$(RM) *.{o,so,a} $(PROG)
cleanall:
$(RM) *.{$(ALL_CPUS_COMMAS)}.{o,so,a}
PROGS_LIST=hello
install: install_prog_global
/*
* Copyright (C) 2018 CERN
* Author: Maciej Suminski <maciej.suminski@cern.ch>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* FMC-nanoFIP test program, based on fiptestbed
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include <masterfip/libmasterfip.h>
#include "fip_urv_cmd.h"
static const uint16_t ftb_var_id[2] = {
0x05, /* produced var */
0x06, /* consumed var */
};
#define VAR_LENGTH 8
#define CMD_COUNT 4
struct urv_cmd {
unsigned char cmd;
unsigned char id; /* Set when command is sent. */
unsigned char len; /* Length of args. */
unsigned char args[68];
};
/* counter for various errors */
struct ftb_var_error {
int write_failed; /* writing new value failed */
int missed; /* missed data (not updated) */
int not_freshed; /* other than 0x5 promptness&significance */
int not_significant; /* other than 0x5 promptness&significance */
int tmo; /* time out no reply from agent */
int hw_err; /* hw bit error in the frame */
int hw_bsz; /* hw wrong nb of bytes in the frame */
int hw_ctrl; /* hw bad control byte in the frame */
int hw_pdu; /* hw bad pdu byte in the frame */
};
struct ftb_ba {
struct mstrfip_macrocycle *mc;
struct mstrfip_data *cons_varlist[1];/* consumed var */
struct mstrfip_data *prod_varlist[1];/* produced var */
};
struct ftb_dev {
struct mstrfip_dev *dev;
struct ftb_ba ba;
struct ftb_var_error var_err;
enum mstrfip_bitrate fbus_speed; /* FIP bus speed get from the HW */
int cycle_uslength;
int var_length;
uint32_t tr_nstime;
int error_detected;
/* Commands to be sent. */
struct urv_cmd cmds[4];
unsigned nbr_cmds;
unsigned idx_cmd;
unsigned waitrep;
} *ftb;
static int read_vars(void)
{
struct mstrfip_data *pvar = ftb->ba.cons_varlist[0];
/* Get variable. */
memset(pvar->buffer, 0x00, VAR_LENGTH);
mstrfip_var_update(ftb->dev, pvar);
switch (pvar->status) {
case MSTRFIP_DATA_OK:
if (1) {
printf ("Recv:");
for (unsigned j = 0; j < VAR_LENGTH; j++)
printf(" %02x", pvar->buffer[j]);
printf("\n");
}
if (ftb->idx_cmd < ftb->nbr_cmds) {
struct urv_cmd *cmd = &ftb->cmds[ftb->idx_cmd];
if (pvar->buffer[0] == cmd->cmd
&& pvar->buffer[1] == cmd->id) {
/* Command has been ack-ed, next one. */
ftb->waitrep = 0;
ftb->idx_cmd++;
}
}
return 0;
case MSTRFIP_DATA_PAYLOAD_ERROR:
if (pvar->payload_error & MSTRFIP_FRAME_PAYLOAD_NOT_REFRESH)
++(ftb->var_err.not_freshed);
if (pvar->payload_error & MSTRFIP_FRAME_PAYLOAD_NOT_SIGNIFICANT)
++(ftb->var_err.not_significant);
return 1;
case MSTRFIP_DATA_NOT_RECEIVED:
++(ftb->var_err.missed);
return 1;
case MSTRFIP_DATA_FRAME_ERROR:
if (pvar->frame_error & MSTRFIP_FRAME_TMO)
++(ftb->var_err.tmo);
if (pvar->frame_error & MSTRFIP_FRAME_ERR)
++(ftb->var_err.hw_err);
if (pvar->frame_error & MSTRFIP_FRAME_BAD_CTRL)
++(ftb->var_err.hw_ctrl);
if (pvar->frame_error & MSTRFIP_FRAME_BAD_PDU)
++(ftb->var_err.hw_pdu);
if (pvar->frame_error & MSTRFIP_FRAME_BAD_BSZ)
++(ftb->var_err.hw_bsz);
return 1;
default:
return 1;
}
}
static int update_vars(void)
{
int res;
struct mstrfip_data *pvar = ftb->ba.prod_varlist[0];
/* Stuff. */
pvar->buffer[2] = 0;
pvar->buffer[3] = 0;
if (ftb->waitrep) {
/* Waiting for a reply. Do not transmit any new command. */
pvar->bsz = 72;
pvar->buffer[0] = CMD_ERROR;
pvar->buffer[1] = 0xff;
printf ("Send padding\n");
}
else if (ftb->idx_cmd >= ftb->nbr_cmds) {
kill(getpid(), SIGINT);
return 0;
}
else {
/* Send next command. */
struct urv_cmd *cmd = &ftb->cmds[ftb->idx_cmd];
cmd->id = ftb->idx_cmd + 0x20;
pvar->bsz = 72; // 4 + cmd->len;
pvar->buffer[0] = cmd->cmd;
pvar->buffer[1] = cmd->id;
pvar->buffer[2] = cmd->args[0];
memcpy (pvar->buffer + 4, cmd->args, cmd->len);
printf ("Send command 0x%02x, len=%d\n", cmd->cmd, pvar->bsz);
ftb->waitrep = 1;
}
/* Send new ctrl value. */
res = mstrfip_var_write(ftb->dev, pvar);
if (res != 0) {
++ftb->var_err.write_failed;
fprintf(stderr, "mstrfip_var_write error:%d(%s)\n", res, strerror(res));
return 1;
}
return 0;
}
static void mstrfip_var_handler(struct mstrfip_dev *dev, struct mstrfip_data *pvar,
struct mstrfip_irq *irq)
{
int err1 = read_vars();
int err2 = update_vars();
if (err1 || err2) {
printf ("var_handler: error\n");
if (ftb->var_err.not_freshed)
printf(" agent not_freshed: %d\n", ftb->var_err.not_freshed);
if (ftb->var_err.not_significant)
printf(" agent not_significant: %d\n", ftb->var_err.not_significant);
if (ftb->var_err.missed)
printf(" agent missed: %d\n", ftb->var_err.missed);
if (ftb->var_err.tmo)
printf(" agent tmo: %d\n", ftb->var_err.tmo);
if (ftb->var_err.hw_err)
printf(" agent hw_err: %d\n", ftb->var_err.hw_err);
if (ftb->var_err.hw_ctrl)
printf(" agent hw_ctrl: %d\n", ftb->var_err.hw_ctrl);
if (ftb->var_err.hw_pdu)
printf(" agent hw_pdu: %d\n", ftb->var_err.hw_pdu);
if (ftb->var_err.hw_bsz)
printf(" agent hw_bsz: %d\n", ftb->var_err.hw_bsz);
}
}
static void mstrfip_prod_var_handler(struct mstrfip_dev *dev, struct mstrfip_data *pvar,
struct mstrfip_irq *irq)
{
if (0) {
printf("prod_var_handler\n");
printf(" type: %u, id: %04x, bsz: %u, status: %u, ferr: %u, perr: %u\n",
pvar->type, pvar->id, pvar->bsz, pvar->status,
pvar->frame_error, pvar->payload_error);
}
}
static void mstrfip_error_handler(struct mstrfip_dev *dev, enum mstrfip_error_list error)
{
printf("error_handler\n");
}
static int ftb_create_per_var(struct ftb_ba *ba)
{
struct mstrfip_data_cfg var_cfg;
int agent_idx = 0;
/* build prod varlist (sent by masterfip). */
var_cfg.max_bsz = 72;
var_cfg.id = (0xFF00 & (ftb_var_id[0] << 8)) | (agent_idx + 1);
var_cfg.flags = MSTRFIP_DATA_FLAGS_PROD;
var_cfg.mstrfip_data_handler = mstrfip_prod_var_handler;
ba->prod_varlist[0] = mstrfip_var_create(ba->mc, &var_cfg);
if (ba->prod_varlist[0] == NULL)
return -1;
/* build consumed varlist (received by masterfip). */
var_cfg.max_bsz = 8;
var_cfg.id = (0xFF00 & (ftb_var_id[1] << 8)) | (agent_idx + 1);
var_cfg.flags = MSTRFIP_DATA_FLAGS_CONS;
var_cfg.mstrfip_data_handler = mstrfip_var_handler;
ba->cons_varlist[0] = mstrfip_var_create(ba->mc, &var_cfg);
if (ba->cons_varlist[0] == NULL)
return -1;
return 0;
}
static int ftb_ba_start(struct ftb_dev *ftb)
{
int res;
int agt_addr;
if (mstrfip_ba_reset(ftb->dev) < 0) {
fprintf(stderr, "Reset BA failed: %s\n",
mstrfip_strerror(errno));
return -1;
}
if (mstrfip_ba_load(ftb->dev, ftb->ba.mc) < 0) {
fprintf(stderr, "Loading macrocycle failed: %s\n",
mstrfip_strerror(errno));
return -1;
}
/* get turn around time of each agents */
agt_addr = 1;
res = mstrfip_hw_response_time_get(ftb->dev, 1, &agt_addr, &ftb->tr_nstime);
if (res) {
fprintf(stderr, "Read turn around time failed: %s\n",
mstrfip_strerror(errno));
}
if (mstrfip_ba_start(ftb->dev) < 0) {
fprintf(stderr, "Start BA failed: %s\n",
mstrfip_strerror(errno));
return -1;
}
return 0;
}
static int ftb_set_ba_instr(struct ftb_ba *ba)
{
struct mstrfip_per_var_wind_cfg pwind_cfg = {0};
/* append a periodic window for produced variables */
pwind_cfg.varlist = ba->prod_varlist; /* periodic var list */
pwind_cfg.var_count = 1; /* periodic var count */
if (mstrfip_per_var_wind_append(ba->mc, &pwind_cfg) < 0)
return -1;
/* append a periodic window for consumed varaiables */
pwind_cfg.varlist = ba->cons_varlist; /*periodic var list */
pwind_cfg.var_count = 1; /* periodic var count */
if (mstrfip_per_var_wind_append(ba->mc, &pwind_cfg) < 0)
return -1;
/* append a wait window without padding (silent) */
if (mstrfip_wait_wind_append(ba->mc, 1, ftb->cycle_uslength) < 0)
return -1;
return 0;
}
static int cycle_config(struct mstrfip_hw_cfg *hw_cfg, struct mstrfip_sw_cfg *sw_cfg)
{
if (mstrfip_hw_cfg_set(ftb->dev, hw_cfg) < 0) {
fprintf(stderr, "Cannot configure HW: %s\n", mstrfip_strerror(errno));
return -1;
}
/* set SW config */
if (mstrfip_sw_cfg_set(ftb->dev, sw_cfg) < 0) {
fprintf(stderr, "Cannot configure SW: %s\n", mstrfip_strerror(errno));
return -1;
}
/* create macro cycle */
ftb->ba.mc = mstrfip_macrocycle_create(ftb->dev);
if (ftb->ba.mc == NULL) {
fprintf(stderr, "Create macrocyle failed: %s\n", mstrfip_strerror(errno));
return -1;
}
/* create periodic variable */
if (ftb_create_per_var(&ftb->ba) < 0 ) {
fprintf(stderr, "Create periodic variable failed: %s\n", mstrfip_strerror(errno));
return -1;
}
if (ftb_set_ba_instr(&ftb->ba) < 0) {
fprintf(stderr, "Programming BA failed: %s\n", mstrfip_strerror(errno));
return -1;
}
if (mstrfip_macrocycle_isvalid(ftb->dev, ftb->ba.mc) == 0) {
fprintf(stderr, "Macrocycle invalid: %s\n", mstrfip_strerror(errno));
return -1;
}
return 0;
}
static int append_command(struct ftb_dev *dev, const struct urv_cmd *cmd)
{
if (dev->nbr_cmds >= CMD_COUNT)
return -1;
memcpy (&dev->cmds[dev->nbr_cmds], cmd, sizeof(struct urv_cmd));
dev->nbr_cmds++;
return 0;
}
/* Return the number of arguments consumed.
0: argument unknown,
< 0: bad argument (error). */
static int decode_command (int argc, char *argv[])
{
if (argc == 0)
return 0;
if (strcmp (argv[0], "set-leds") == 0)
{
unsigned long val;
char *e;
struct urv_cmd cmd;
if (argc < 2) {
fprintf (stderr, "set-leds needs a value\n");
return -1;
}
val = strtoul (argv[1], &e, 0);
if (*e != 0 || val > 255) {
fprintf (stderr, "incorrect value for set-leds\n");
return -1;
}
cmd.cmd = CMD_SET_LEDS;
cmd.len = 1;
cmd.args[0] = val;
if (append_command(ftb, &cmd) != 0)
return -1;
return 2;
}
else
return 0;
}
int main(int argc, char *argv[])
{
int res, signo;
siginfo_t siginfo;
sigset_t newmask;
struct mstrfip_hw_cfg hw_cfg = {0};
struct mstrfip_sw_cfg sw_cfg = {0};
int dev_lun = 0;
ftb = malloc(sizeof(struct ftb_dev));
if (ftb == NULL) {
perror("Can't instantiate FTB device\n");
exit(1);
}
memset(ftb, 0, sizeof(struct ftb_dev));
ftb->var_length = VAR_LENGTH;
ftb->cycle_uslength = 500000;
ftb->nbr_cmds = 0;
ftb->idx_cmd = 0;
ftb->waitrep = 0;
if (argc <= 1) {
fprintf (stderr, "no commands\n");
return 1;
}
/* TODO: handle options. */
res = decode_command (argc - 1, argv + 1);
if (res == 0) {
fprintf (stderr, "invalid command\n");
return 1;
}
else if (res < 0)
return 1;
res = mstrfip_init();
if (res) {
fprintf(stderr, "Cannot init fip library: %s\n", mstrfip_strerror(errno));
exit(1);
}
ftb->dev = mstrfip_open_by_lun(dev_lun);
if (ftb->dev == NULL) {
fprintf(stderr, "Cannot open mstrfip dev: %s\n", mstrfip_strerror(errno));
exit(1);
}
/* reset RT app */
if (mstrfip_rtapp_reset(ftb->dev) < 0) {
fprintf(stderr, "Cannot reset rt app: %s\n", mstrfip_strerror(errno));
exit(1);
}
/* Get FIP bus speed */
if (mstrfip_hw_speed_get(ftb->dev, &ftb->fbus_speed)) {
fprintf(stderr, "Can't get FIP speed: %s. Exit\n", mstrfip_strerror(errno));
exit(1);
}
/* Cycle configuration */
hw_cfg.enable_ext_trig = 0;
hw_cfg.enable_int_trig = 0;
hw_cfg.enable_ext_trig_term = 0;
hw_cfg.turn_around_ustime = 14; // 14 us corresponds to 1 Mbit/s
sw_cfg.irq_thread_prio = 50;
sw_cfg.diag_thread_prio = 20;
sw_cfg.mstrfip_error_handler = mstrfip_error_handler;
if (cycle_config(&hw_cfg, &sw_cfg) < 0) {
fprintf(stderr, "Cannot init ba: %s\n", mstrfip_strerror(errno));
exit(1);
}
/* time to start ba */
res = ftb_ba_start(ftb);
if (res) {
fprintf(stderr, "ba_start: %d %s\n", res, mstrfip_strerror(res));
exit(1);
}
/* run for ever till a signal is raised */
sigemptyset(&newmask); /* unblock any signal */
sigaddset(&newmask, SIGINT);
sigaddset(&newmask, SIGTERM);
sigaddset(&newmask, SIGABRT);
sigaddset(&newmask, SIGFPE);
sigaddset(&newmask, SIGILL);
sigaddset(&newmask, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &newmask, NULL);
while(1) {
signo = sigwaitinfo(&newmask, &siginfo);
if(signo > 0)
{
mstrfip_exit();
/* TO be completed if necessary */
if (ftb->dev != NULL)
mstrfip_close(ftb->dev);
exit(1);
}
}
return 0;
}
#define CMD_ERROR 0
#define CMD_SET_LEDS 1
#define CMD_GET_LEDS 2
#include <stdint.h>
#include "fip_urv_regs.h"
#include "fip_urv_cmd.h"
int
main (void)
......@@ -8,7 +9,8 @@ main (void)
volatile struct fip_urv_regs *regs =
(volatile struct fip_urv_regs *)0x100000;
int j;
unsigned char b;
unsigned char cmd;
unsigned char reply[8];
unsigned char rdy;
/* Init. */
......@@ -22,7 +24,20 @@ main (void)
/* Check for FIP message. */
unsigned int status = regs->fip_status;
regs->leds = (leds << 3) | status;
/* Control leds. */
if (leds & 0x80)
regs->leds = leds;
else
{
regs->leds = (leds << 3) | status;
j++;
if (j == 1000000)
{
leds = ((leds << 1) & 0x7) | ((leds >> 2) & 1);
j = 0;
}
}
/* Send leds status. */
if (status & 1)
......@@ -31,27 +46,41 @@ main (void)
/* Consume variable. */
regs->fip_var1 = 1;
b = regs->fip_reg[0x02];
cmd = regs->fip_reg[0x02];
/* Default reply: command + id. */
reply[0] = cmd;
reply[1] = regs->fip_reg[0x03];
switch (cmd)
{
case CMD_GET_LEDS:
reply[4] = leds;
break;
case CMD_SET_LEDS:
leds = regs->fip_reg[0x04];
break;
default:
reply[0] = CMD_ERROR;
break;
}
rdy = 1;
regs->fip_var1 = 0;
}
if ((status & 2) && rdy)
{
int i;
/* Produce variable. */
regs->fip_var3 = 1;
regs->fip_reg[0x102] = b;
regs->fip_reg[0x103] = leds;
for (i = 0; i < sizeof(reply); i++)
regs->fip_reg[0x102 + i] = reply[i];
regs->fip_var3 = 0;
rdy = 0;
}
j++;
if (j == 1000000)
{
leds = ((leds << 1) & 0x7) | ((leds >> 2) & 1);
j = 0;
}
}
}
#define CMD_ERROR 0
#define CMD_SET_LEDS 1
#define CMD_GET_LEDS 2
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