Commit ff95de0b authored by Federico Vaga's avatar Federico Vaga

Port output application to librt

parents 3862a8df f0312ecf
......@@ -13,6 +13,17 @@ uint32_t msg_seq = 0;
struct rt_application *_app;
/**
* Since the hardware does not allow byte addressing, copy word by word
*/
void rt_memcpy(uint32_t *dest, uint32_t *src, size_t n)
{
int i;
for (i = 0; i < n / 4; ++i)
dest[i] = src[i];
}
/**
* it sets a structure coming from the host
*/
......@@ -34,13 +45,13 @@ int rt_structure_setter(struct wrnc_proto_header *hin, void *pin,
delay(100000);
#endif
if (_app->structures[index].len == size) {
memcpy(_app->structures[index].struct_ptr,
&din[offset], size);
rt_memcpy((uint32_t *)_app->structures[index].struct_ptr,
&din[offset], size);
}
#ifdef LIBRT_ERROR
else {
pp_printf("%s:%d structure len not correct %d != %d\n",
__func__, __LINE__,
pp_printf("%s:%d structure %d len not correct %d != %d\n",
__func__, __LINE__, index,
_app->structures[index].len, size);
}
#endif
......@@ -82,13 +93,14 @@ int rt_structure_getter(struct wrnc_proto_header *hin, void *pin,
delay(100000);
#endif
if (_app->structures[index].len == size) {
memcpy(&dout[offset], _app->structures[index].struct_ptr,
size);
rt_memcpy(&dout[offset],
(uint32_t *)_app->structures[index].struct_ptr,
size);
}
#ifdef LIBRT_ERROR
else {
pp_printf("%s: structure len not correct %d != %d\n",
__func__, _app->structures[index].len, size);
pp_printf("%s: structure %d len not correct %d != %d\n",
__func__, index, _app->structures[index].len, size);
}
#endif
offset += (size / 4); /* Next TLV record */
......@@ -109,7 +121,8 @@ int rt_version_getter(struct wrnc_proto_header *hin, void *pin,
hout->msg_id = RT_ACTION_SEND_VERSION;
hout->len = sizeof(struct wrnc_rt_version) / 4;
memcpy(dout, &_app->version, sizeof(struct wrnc_rt_version));
rt_memcpy(dout, (uint32_t *)&_app->version,
sizeof(struct wrnc_rt_version));
return 0;
}
......@@ -256,7 +269,7 @@ static inline int rt_action_run(struct wrnc_proto_header *hin, void *pin)
/* Do not write directly the header on the buffer because it does not
work for fields size different than 32bit */
pout = rt_proto_payload_get((void *) out_buf.data);
memcpy(&hout, hin, sizeof(struct wrnc_proto_header));
rt_memcpy((uint32_t *)&hout, (uint32_t *)hin, sizeof(struct wrnc_proto_header));
err = action(hin, pin, &hout, pout);
if (err)
......
......@@ -22,7 +22,7 @@
#define SMEM_RANGE_CLEAR 0x40000
#define SMEM_RANGE_FLIP 0x50000
#define SMEM __attribute__((section(".smem")))
#define SMEM volatile __attribute__((section(".smem")))
/**
* Perform an operation on a given pointer. Operation can be performed only
......
Dictionary
==========
The main purpose of this dictionary is to explain the
White-Rabbit Trigger-Distribution terminology.
channel
dead time
delay
input
output
pulse
trigger
trigger condition
\ No newline at end of file
......@@ -103,6 +103,15 @@ enum wrtd_in_actions {
WRTD_IN_ACTION_SW_TRIG = __RT_ACTION_RECV_STANDARD_NUMBER,
WRTD_IN_ACTION_LOG,
};
enum wrtd_out_actions {
WRTD_OUT_ACTION_SW_TRIG = __RT_ACTION_RECV_STANDARD_NUMBER,
WRTD_OUT_ACTION_TRIG_IDX,
WRTD_OUT_ACTION_TRIG_FRE,
WRTD_OUT_ACTION_TRIG_ADD,
WRTD_OUT_ACTION_TRIG_DEL,
WRTD_OUT_ACTION_LOG,
WRTD_OUT_ACTION_DISABLE,
};
enum wrtd_in_variables_indexes {
IN_VAR_CHAN_ENABLE = 0,
......@@ -122,6 +131,19 @@ enum wrtd_in_structures_indexes {
IN_STRUCT_CHAN_4,
__WRTD_IN_STRUCT_MAX,
};
enum wrtd_out_variables_indexes {
OUT_VAR_DEVICE_TIME_S=0,
OUT_VAR_DEVICE_TIME_T,
__WRTD_OUT_VAR_MAX,
};
enum wrtd_out_structures_indexes {
OUT_STRUCT_DEVICE = 0,
OUT_STRUCT_CHAN_0,
OUT_STRUCT_CHAN_1,
OUT_STRUCT_CHAN_2,
OUT_STRUCT_CHAN_3,
__WRTD_OUT_STRUCT_MAX,
};
/**
* availables trigger mode
......@@ -215,7 +237,12 @@ struct wrtd_trig_id {
/**
* Trigger event
* Trigger event. It is shared between the user-space and the
* real time application. Those end-point use this structure to share
* information.
* It should have 32bit fields to avoid toubles with the muck turtle
* bit swapping. If not possible on user space you must fix the bit swapping
* manually where necessary.
*/
struct wrtd_trigger_entry {
struct wr_timestamp ts; /**< when it fired */
......@@ -341,4 +368,128 @@ struct wrtd_in {
uint32_t dead_time; /**< TDC dead time, in 8ns ticks */
};
enum wrtd_out_state_machine_steps {
OUT_ST_IDLE = 0,
OUT_ST_ARMED,
OUT_ST_TEST_PENDING,
OUT_ST_CONDITION_HIT,
};
/**
* Rule defining the behaviour of a trigger output upon reception of a
* trigger message with matching ID
*/
struct lrt_output_rule {
uint32_t delay_cycles; /**< Delay to add to the timestamp enclosed
within the trigger message */
uint16_t delay_frac;
uint16_t state; /**< State of the rule (empty, disabled,
conditional action, condition, etc.) */
uint32_t cond_ptr; /**< index pointing do the condition trigger */
uint32_t latency_worst; /**< Worst-case latency (in 8ns ticks)*/
uint32_t latency_avg_sum; /**< Average latency accumulator and
number of samples */
uint32_t latency_avg_nsamples;
uint32_t hits; /**< Number of times the rule has successfully produced
a pulse */
uint32_t misses; /**< Number of times the rule has missed a pulse
(for any reason) */
};
/* Structure describing a single pulse in the Fine Delay software output queue */
struct pulse_queue_entry {
/* Trigger that produced the pulse */
struct wrtd_trigger_entry trig;
/* Origin timestamp cycles count (for latency statistics) */
int origin_cycles;
/* Rule that produced the pulse */
struct lrt_output_rule *rule;
};
/* Pulse FIFO for a single Fine Delay output */
struct lrt_pulse_queue {
struct pulse_queue_entry data[FD_MAX_QUEUE_PULSES];
int head, tail, count;
};
struct wrtd_out_trigger {
unsigned int flags;
struct wrtd_trig_id id; /**< trigger identifier */
struct lrt_output_rule ocfg[FD_NUM_CHANNELS]; /**< specific rule
for each channel*/
};
#define ENTRY_FLAG_VALID (1 << 0)
struct wrtd_out_channel_stats {
uint32_t hits;
uint32_t miss_timeout;
uint32_t miss_deadtime;
uint32_t miss_overflow;
uint32_t miss_no_timing;
struct wrtd_trigger_entry last_executed; /**< Last enqueued trigger
(i.e. the last one that
entered the output queue) */
struct wrtd_trigger_entry last_enqueued; /**< Last timestamp value
written to output config */
struct wr_timestamp last_programmed; /**< Last timestamp value written
to output config */
struct wrtd_trigger_entry last_lost;
};
/**
* Channel configuration parameters. It is shared between the user-space and the
* real time application. Those end-point use this structure to share
* information.
* It should have 32bit fields to avoid toubles with the muck turtle
* bit swapping. If not possible on user space you must fix the bit swapping
* manually where necessary.
*/
struct wrtd_out_channel_config {
uint32_t state; /**< Arm state */
uint32_t mode; /**< Trigger mode */
uint32_t flags; /**< Flags (logging, etc) */
uint32_t log_level; /**< Current logging level */
uint32_t dead_time; /**< Dead time (8ns cycles) */
uint32_t width_cycles; /**< Pulse width (8ns cycles) */
};
struct wrtd_out_channel_private {
uint32_t idle; /**< Idle flag */
struct lrt_pulse_queue queue; /**< Output pulse queue */
struct lrt_output_rule *pending_trig; /**< Pending conditonal trigger */
struct wr_timestamp prev_pulse; /**< Last enqueued trigger + delay
(for dead time checking). */
};
struct wrtd_out_channel {
uint32_t base_addr;
uint32_t n;
struct wrtd_out_channel_stats stats;
struct wrtd_out_channel_config config;
struct wrtd_out_channel_private priv;
};
struct wrtd_out {
uint32_t counter_loopback;
uint32_t counter_etherbone;
struct wrtd_trigger_entry last_received;
};
/**
* Hash function, returing the hash table index corresponding to a given
* trigger ID
*/
static inline int wrtd_hash_func(struct wrtd_trig_id *id)
{
int h = 0;
h += id->system * 10291;
h += id->source_port * 10017;
h += id->trigger * 3111;
return h & (FD_HASH_ENTRIES - 1); // hash table size must be a power of 2
}
#endif
......@@ -108,3 +108,13 @@ void wrtd_timestamp_endianess_fix(struct wr_timestamp *ts)
ts->seconds = ((ts->seconds & 0xFFFFFFFF) << 32) |
((ts->seconds >> 32) & 0xFFFFFFFF);
}
void wrtd_output_rule_endianess_fix(struct lrt_output_rule *rule)
{
uint16_t tmp = rule->state;
rule->state = (rule->delay_frac & 0x00FF) << 8 |
(rule->delay_frac & 0xFF00) >> 8;
rule->delay_frac = (tmp & 0x00FF) << 8 |
(tmp & 0xFF00) >> 8;
}
......@@ -42,4 +42,6 @@ extern int wrtd_send_and_receive_sync(struct wrtd_desc *wrtd,
struct wrnc_msg *msg,
enum wrtd_core core);
extern void wrtd_timestamp_endianess_fix(struct wr_timestamp *ts);
extern void wrtd_output_rule_endianess_fix(struct lrt_output_rule *rule);
#endif
......@@ -250,49 +250,48 @@ void wrtd_log_close(struct wrnc_hmq *hmq)
static int wrtd_log_level_set(struct wrtd_node *dev, unsigned int channel,
uint32_t log_level, enum wrtd_core core)
{
struct wrnc_msg msg = wrnc_msg_init(4);
uint32_t seq = 0;
if (core) { /* Output */
uint32_t id = WRTD_CMD_FD_CHAN_SET_LOG_LEVEL;
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrnc_structure_tlv tlv;
struct wrnc_proto_header hdr;
struct wrtd_out_channel ochan;
struct wrtd_in_channel ichan;
int err;
hdr.flags = WRNC_PROTO_FLAG_SYNC;
if (core) {
if (channel >= FD_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
/* Build the message */
wrnc_msg_header(&msg, &id, &seq);
wrnc_msg_uint32(&msg, &channel);
wrnc_msg_uint32(&msg, &log_level);
return wrtd_trivial_request(dev, &msg, core);
} else { /* Input */
struct wrtd_desc *wrtd = (struct wrtd_desc *)dev;
struct wrtd_in_channel chan;
struct wrnc_structure_tlv tlv = {
.index = IN_STRUCT_CHAN_0 + channel,
.size = sizeof(struct wrtd_in_channel),
.structure = &chan,
};
struct wrnc_proto_header hdr = {
.slot_io = (WRTD_IN_TDC_CONTROL << 4) |
(WRTD_OUT_TDC_CONTROL & 0xF),
.flags = WRNC_PROTO_FLAG_SYNC,
};
int err;
tlv.index = OUT_STRUCT_CHAN_0 + channel;
tlv.size = sizeof(struct wrtd_out_channel);
tlv.structure = &ochan;
hdr.slot_io = (WRTD_IN_FD_CONTROL << 4) |
(WRTD_OUT_FD_CONTROL & 0xF);
/* TODO set promiscuous mode */
} else {
if (channel >= TDC_NUM_CHANNELS) {
errno = EWRTD_INVALID_CHANNEL;
return -1;
}
err = wrnc_rt_structure_get(wrtd->wrnc, &hdr, &tlv, 1);
if (err)
return err;
chan.config.log_level = log_level;
return wrnc_rt_structure_set(wrtd->wrnc, &hdr, &tlv, 1);
tlv.index = IN_STRUCT_CHAN_0 + channel;
tlv.size = sizeof(struct wrtd_in_channel);
tlv.structure = &ichan;
hdr.slot_io = (WRTD_IN_TDC_CONTROL << 4) |
(WRTD_OUT_TDC_CONTROL & 0xF);
}
err = wrnc_rt_structure_get(wrtd->wrnc, &hdr, &tlv, 1);
if (err)
return err;
if (core)
ochan.config.log_level = log_level;
else
ichan.config.log_level = log_level;
return wrnc_rt_structure_set(wrtd->wrnc, &hdr, &tlv, 1);
}
......
This diff is collapsed.
......@@ -303,7 +303,8 @@ extern int wrtd_out_trig_enable(struct wrtd_node *dev,
struct wrtd_trigger_handle *handle, int enable);
extern int wrtd_out_ping(struct wrtd_node *dev);
extern int wrtd_out_base_time(struct wrtd_node *dev, struct wr_timestamp *ts);
extern int wrtd_out_version(struct wrtd_node *dev, uint32_t *gitsha1);
extern int wrtd_out_version(struct wrtd_node *dev,
struct wrnc_rt_version *version);
extern int wrtd_out_trigger_mode_set(struct wrtd_node *dev,
unsigned int output,
enum wrtd_trigger_mode mode);
......
......@@ -19,17 +19,20 @@
#define LOOP_QUEUE_SIZE 16
static SMEM int head, tail, count;
static SMEM unsigned int head, tail, count;
static SMEM struct wrtd_trigger_entry buf[16];
void loop_queue_init()
{
head = tail = count = 0;
head = 0;
tail = 0;
count = 0;
}
void loop_queue_push(struct wrtd_trig_id *id, uint32_t seq, struct wr_timestamp *ts)
void loop_queue_push(struct wrtd_trig_id *id, uint32_t seq,
struct wr_timestamp *ts)
{
if(count == LOOP_QUEUE_SIZE)
if (count >= LOOP_QUEUE_SIZE)
return;
buf[head].id = *id;
......@@ -37,25 +40,23 @@ void loop_queue_push(struct wrtd_trig_id *id, uint32_t seq, struct wr_timestamp
buf[head].ts = *ts;
smem_atomic_add(&head, 1);
if (head == LOOP_QUEUE_SIZE)
if (head >= LOOP_QUEUE_SIZE)
head = 0;
smem_atomic_add(&count, 1);
}
struct wrtd_trigger_entry *loop_queue_pop()
struct wrtd_trigger_entry *loop_queue_pop(void)
{
if(!count)
return NULL;
struct wrtd_trigger_entry *rv;
struct wrtd_trigger_entry *rv = &buf[tail];
if (count == 0)
return NULL; /* No entry */
smem_atomic_add(&tail, 1);
rv = &buf[tail];
if(tail == LOOP_QUEUE_SIZE)
smem_atomic_add(&tail, 1);
if(tail >= LOOP_QUEUE_SIZE)
tail = 0;
smem_atomic_sub(&count, 1);
return rv;
......
......@@ -7,4 +7,8 @@ WRNC = ../../../../
EXTRA_CFLAGS += -I../../include
EXTRA_CFLAGS += -I../common
EXTRA_CFLAGS += -DLIBRT_ERROR
#EXTRA_CFLAGS += -DLIBRT_DEBUG
#EXTRA_CFLAGS += -DRTDEBUG
RT_USE_LIBRT := 1
include $(WRNC)/applications/common/rt/Makefile
This diff is collapsed.
......@@ -8,5 +8,6 @@ WRNC = ../../../../
EXTRA_CFLAGS += -I../../include
EXTRA_CFLAGS += -I../common
EXTRA_CFLAGS += -DLIBRT_ERROR
#EXTRA_CFLAGS += -DLIBRT_DEBUG
RT_USE_LIBRT := 1
include $(WRNC)/applications/common/rt/Makefile
......@@ -196,7 +196,7 @@ int parse_mode (char *mode_str, enum wrtd_trigger_mode *mode)
int parse_trigger_id(const char *str, struct wrtd_trig_id *id)
{
return (sscanf(str,"%i:%i:%i", &id->system, &id->source_port, &id->trigger) == 3 ? 0 : -1);
return (sscanf(str,"%x:%x:%x", &id->system, &id->source_port, &id->trigger) == 3 ? 0 : -1);
}
int parse_log_level (char *list[], int count, int *log_level)
......
......@@ -25,11 +25,31 @@ void help()
fprintf(stderr, " -v show device version\n");
}
static void print_time(struct wr_timestamp *t)
{
fprintf(stdout, "\tbase time\ts:%"PRIu64" t:%d f:%d\n",
t->seconds, t->ticks, t->frac);
}
static void print_version(struct wrnc_rt_version *v)
{
fprintf(stdout, "\tRealTime Application Version:");
fprintf(stdout, "\tfpga_id\t\t%x\n",
v->fpga_id);
fprintf(stdout, "\trt_id\t\t%x\n",
v->rt_id);
fprintf(stdout, "\trt_version\t\t%x\n",
v->rt_version);
fprintf(stdout, "\tgit_version\t\t%x\n",
v->git_version);
}
int main(int argc, char *argv[])
{
struct wrtd_node *wrtd;
uint32_t dev_id = 0, n = 1, vo;
struct wrnc_rt_version vi;
uint32_t dev_id = 0, n = 1;
struct wrnc_rt_version vi, vo;
uint64_t period = 0;
struct wr_timestamp tsi, tso;
int err, time = 0, version = 0;
......@@ -108,20 +128,9 @@ int main(int argc, char *argv[])
fprintf(stdout, "input : it is running!\n");
if (time)
fprintf(stdout,
"\tbase time\ts:%"PRIu64" t:%d f:%d\n",
tsi.seconds, tsi.ticks, tsi.frac);
if (version) {
fprintf(stdout, "\tRealTime Application Version:");
fprintf(stdout, "\tfpga_id\t\t%x\n",
vi.fpga_id);
fprintf(stdout, "\trt_id\t\t%x\n",
vi.rt_id);
fprintf(stdout, "\trt_version\t\t%x\n",
vi.rt_version);
fprintf(stdout, "\tgit_version\t\t%x\n",
vi.git_version);
}
print_time(&tsi);
if (version)
print_version(&vi);
skip_input:
/* check output */
err = wrtd_out_ping(wrtd);
......@@ -133,12 +142,10 @@ int main(int argc, char *argv[])
fprintf(stdout, "output : it is running!\n");
if (time)
fprintf(stdout,
"\tbase time\ts:%"PRIu64" t:%d f:%d\n",
tso.seconds, tso.ticks, tso.frac);
print_time(&tso);
if (version)
fprintf(stdout,
"\tversion\t\t%x\n", vo);
print_version(&vo);
skip_output:
fprintf(stdout, "\n");
usleep(period);
......
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