Commit 4ed73046 authored by Jose Jimenez's avatar Jose Jimenez

debugger_sw/fmc-delay: fine delay related software

debugger_sw/fmc-delay/fine-delay.mk: to be used by ../Makefile
debugger_sw/fmc-delay/fine-delay-cmds: Command line tools for stand-alone mode
Signed-off-by: 's avatarJose Jimenez <ppjm@correo.ugr.es>
parent efd941f8
/* This work is part of the White Rabbit project
*
* Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014.
*
* Released according to the GNU GPL version 3 (GPLv3) or later.
*
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdarg.h>
#include <dbg.h>
#include "uart.h"
#include "eeprom.h"
#include "fine-delay.h"
#include "hw/fd_channel_regs.h"
#include "hw/fd_main_regs.h"
#include <pp-printf.h>
#include "errno.h"
#include "shell.h"
#include "irq.h"
#include "linux/jiffies.h"
#include "linux/delay.h"
#include "linux/math64.h"
#include <irq_ctrl.h>
#include <string.h>
#include <unistd.h> /* usleep */
#define sw_ctrl 0
#define mprintf pp_printf
#define vprintf pp_vprintf
#define sprintf pp_sprintf
#define stop 1000
struct fd_dev fd;
struct fmc_device fmc_loc;
extern unsigned char *BASE_TIMER;
extern uint32_t _endram;
extern uint32_t _fstack;
extern caddr_t heap;
extern uint32_t _HEAP_START;
extern uint32_t _HEAP_END;
int init_iterator=0;
extern int fd_calib_period_s;
int irq_count = 0;
#define ENDRAM_MAGIC 0xbadc0ffe
void _irq_entry()
{
irq_count++;
irq_ctrl_pop();
clear_irq();
}
void kernel_dev(int subsys, const char *fmt, ...)
{
va_list ap;
if (subsys == 0)
mprintf("Error: ");
else if (subsys == 1)
mprintf("Warning: ");
else if (subsys == 2)
mprintf("Info: ");
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
static void check_stack(void)
{
while (_endram != ENDRAM_MAGIC)
{
mprintf("Stack overflow!\n");
init_iterator+=1000*ENOMEM;
}
}
void mprint_64bit (uint64_t value)
{
char valstr[128];
uint64_t low;
uint32_t high;
high=(uint32_t) div64_u64_rem(value, (1000LLU*1000LLU*1000LLU), &low);
if (high != 0)
pp_sprintf(valstr, "%d%08d", high, (unsigned int) (low));
else
pp_sprintf(valstr, "%d", (unsigned int) (low));
mprintf("%s", valstr);
}
/* The reset function (by Tomasz) */
static void fd_do_reset(struct fd_dev *fd, int hw_reset)
{
uint32_t val, adr;
if (hw_reset) {
val= FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_CORE_MASK;
adr=FD_REG_RSTR;
fd_writel(fd, val, adr);
udelay(10000);
val= FD_RSTR_LOCK_W(0xdead)|FD_RSTR_RST_CORE_MASK|FD_RSTR_RST_FMC_MASK;
adr=FD_REG_RSTR;
fd_writel(fd, val, adr);
}
val = FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_FMC_MASK;
adr = FD_REG_RSTR;
fd_writel(fd, val, adr);
udelay(1000);
val = FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_FMC_MASK | FD_RSTR_RST_CORE_MASK;
adr = FD_REG_RSTR;
fd_writel(fd, val, adr);
udelay(1000);
}
int fd_reset_again(struct fd_dev *fd)
{
unsigned long j;
/* Reset the FD core once we have proper reference/TDC clocks */
fd_do_reset(fd, 0 /* not hw */);
j = jiffies + 2 * HZ;
while (time_before(jiffies, j)) {
if (fd_readl(fd, FD_REG_GCR) & FD_GCR_DDR_LOCKED)
break;
msleep(10);
}
if (time_after_eq(jiffies, j))
dev_err(&fd->fmc->dev,
"%s: timeout waiting for GCR lock bit\n", __func__);
fd_do_reset(fd, 0 /* not hw */);
return 0;
}
/* *************************************************** */
int fd_gpio_defaults(struct fd_dev *fd)
{
fd_gpio_dir(fd, FD_GPIO_TRIG_INTERNAL, FD_GPIO_OUT);
fd_gpio_set(fd, FD_GPIO_TRIG_INTERNAL);
fd_gpio_set(fd, FD_GPIO_OUTPUT_MASK);
fd_gpio_dir(fd, FD_GPIO_OUTPUT_MASK, FD_GPIO_OUT);
fd_gpio_dir(fd, FD_GPIO_TERM_EN, FD_GPIO_OUT);
fd_gpio_clr(fd, FD_GPIO_TERM_EN);
return 0;
}
static inline void manage_error (int err_value)
{
if (err_value < 0)
init_iterator += 1000*err_value;
}
int main(void)
{
int ch;
_endram = ENDRAM_MAGIC;
sdb_find_devices();
uart_init_hw();
mprintf("\nWR-Dbg: starting up...\n");
usleep_init();
usleep(750*1000);
shell_init();
mprintf("_endram %08x\n", &_endram);
mprintf("_fstack %08x\n", &_fstack);
mprintf("heap %08x\n", &heap);
mprintf("_HEAP_START %08x\n", &_HEAP_START);
mprintf("_HEAP_END %08x\n", &_HEAP_END);
mprintf(
"\n\n**********************************************************\n"
"* FMC DEALY on-SPEC STAND-ALONE NODE *\n"
"* by *\n"
"* Jose Jimenez *\n"
"* *\n");
mprintf("* *\n"
"* - WARNING - *\n"
"* This is a beta version, please report bugs to: *\n"
"* <fmc-delay-1ns-8cha-sa@ohwr.org> *\n"
"**********************************************************\n\n");
fd.fd_regs_base = BASE_FINE_DELAY;
fd.fd_owregs_base= fd.fd_regs_base + 0x500;
fd.temp_timer.itmr.timer_addr_base = BASE_TIMER;
fd.temp_timer.itmr.cascade = cascade_disable;
fd.temp_timer.itmr.time_source = diff_time_periodic;
fd.temp_timer.itmr.timer_id_num = 0x0;
fd.temp_timer.itmr.timer_mode = 0x0;
while(init_iterator != stop){
check_stack();
switch(init_iterator){
case 0:
fd_i2c_init(&fd);
fd.fmc = &fmc_loc; /* to prevent a malloc */
fd.fmc->eeprom_len = SPEC_I2C_EEPROM_SIZE;
heap = NULL;
if((fd.fmc->eeprom=malloc((size_t)(fd.fmc->eeprom_len)))==NULL)
{
kernel_dev(0, "Malloc failed.");
init_iterator = stop+1;
}
manage_error(fd_eeprom_read(&fd, 0x50, 0, fd.fmc->eeprom,
(size_t) (fd.fmc->eeprom_len)));
manage_error(fd_handle_eeprom_calibration(&fd));
free(fd.fmc->eeprom);
init_iterator++;
break;
case 1:
fd_do_reset(&fd, 1);
manage_error(fd_spi_init(&fd));
usleep(500*1000);
init_iterator++;
break;
case 2:
manage_error(fd_gpio_init(&fd));
init_iterator++;
break;
case 3:
fd_gpio_defaults(&fd);
manage_error(fd_pll_init(&fd));
init_iterator++;
break;
case 4:
manage_error(fd_onewire_init (&fd));
init_iterator++;
break;
case 5:
fd_reset_again(&fd);
enable_irq();
manage_error(fd_acam_init(&fd));
init_iterator++;
break;
case 6:
manage_error(fd_time_init(&fd));
int tcr = fd_readl(&fd, FD_REG_TCR);
/* let it run... */
fd_writel(&fd, FD_GCR_INPUT_EN, FD_REG_GCR);
/* stay put*/
if(tcr != fd_readl(&fd, FD_REG_TCR))
fd_writel(&fd, tcr, FD_REG_TCR);
init_iterator++;
break;
case 7:
for (ch = 1; ch <= FD_CH_NUMBER; ch++)
fd_gpio_set(&fd, FD_GPIO_OUTPUT_EN(ch));
init_iterator++;
mprintf("\n*-*-*-*- Node initialized -*-*-*-*\n");
break;
case 8:
mprintf("\n*-*-*-*- Demo test -*-*-*-*\n");
shell_exec("pulse -o 4 -1");
shell_exec("pulse -o 3 -p");
mprintf("\n\n");
dev_info(NULL,"Type \"help\" to see command list.\n");
dev_info(NULL,
"Use \"<command_name -h>\" to explore commands usage.\n");
mprintf("\n");
init_iterator++;
break;
case 9:
if(irq_count >= fd_calib_period_s)
{
irq_count=0;
mprintf("%i, %i, %i\n",irq_count, (irq_count%fd_calib_period_s), !(irq_count%fd_calib_period_s));
fd.temp_timer.function(fd.temp_timer.data);
}
shell_interactive();
break;
default:
init_iterator = stop;
break;
}
}
mprintf("\n");
kernel_dev(0,"That thing died, sorry... Shit happens!!!\n");
mprintf(" Don't go crying to your mama!! You are a full grown up.\n"
" Instead of that restart the node.\n"
" I'm worried what you just read was *RESET* the node...\n"
" What I wrote was *RESTART* the node (unplug stuff...)\n\n");
mprintf(" This is a beta version, please report bugs to: \n"
" <fmc-delay-1ns-8cha-sa@ohwr.org> \n"
"\nAttach the following info:\n"
" Step %i code %i\n", init_iterator/1000, init_iterator&1000);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <wrc.h>
#include "shell.h"
/*#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "fdelay-lib.h"
#include "tools-common.h"
//void fprintf(NULL, )*/
void help(char *name)
{
/*fprintf(stderr, "%s: Use \"%s [-i <index>] [-d <dev>] [<opts>]\n",
name, name);
fprintf(stderr, " options:\n"
" -o <output> ouput channel: 1..4 (default 1)\n"
" -c <count> default is 0 and means forever\n"
" -m <mode> \"pulse\" (default), \"delay\", \"disable\"\n"
" -r <reltime> relative time, e.g. \"10m+20u\" -- use m,u,n,p and add/sub\n"
" -D <date> absolute time, <secs>:<nano>\n"
" -T <period> period, e.g. \"50m-20n\" -- use m,u,n,p and add/sub\n"
" -w <width> like period; defaults to 50%% period\n"
" -t wait for trigger before exiting\n"
" -p pulse per seconds (sets -D -T -w)\n"
" -1 10MHz (sets -D -T -w)\n"
" -v verbose (report action)\n");*/
//mprintf("%s: Use \"%s [-i <index>] [-d <dev>] [<opts>]\n", name, name);
mprintf(" options:\n"
" -o <output> ouput channel: 1..4 (default 1)\n"
" -c <count> default is 0 and means forever\n"
" -m <mode> \"pulse\" (default), \"delay\", \"disable\"\n"
" -r <reltime> relative time, e.g. \"10m+20u\" -- use m,u,n,p and add/sub\n"
" -D <date> absolute time, <secs>:<nano>\n"
" -T <period> period, e.g. \"50m-20n\" -- use m,u,n,p and add/sub\n"
" -w <width> like period; defaults to 50%% period\n"
" -t wait for trigger before exiting\n"
" -p pulse per seconds (sets -D -T -w)\n"
" -1 10MHz (sets -D -T -w)\n"
" -v verbose (report action)\n");
//exit(1);
}
/*struct fdelay_time t_width; /* save width here, add to start before acting */
/* This comes from oldtools/fdelay-pulse-tom.c, unchanged */
/*static void parse_time(char *s, struct fdelay_time *t)
{
int64_t time_ps = 0;
int64_t extra_seconds = 0;
int64_t sign = 1;
int64_t term = 0;
int64_t scale = 1;
const int64_t one_second = 1000000000000LL;
char c, *buf = s;
while ((c = *buf++) != 0) {
switch (c) {
case '+':
if (scale == one_second)
extra_seconds += sign * term;
else
time_ps += sign * term * scale;
term = 0;
sign = 1;
break;
case '-':
if (scale == one_second)
extra_seconds += sign * term;
else
time_ps += sign * term * scale;
term = 0;
sign = -1;
break;
case 's':
scale = one_second;
break;
case 'm':
scale = 1000000000LL;
break;
case 'u':
scale = 1000000LL;
break;
case 'n':
scale = 1000LL;
break;
case 'p':
scale = 1LL;
break;
default:
if (isdigit(c)) {
term *= 10LL;
term += (int64_t) (c - '0');
break;
} else {
fprintf(stderr,
"Error while parsing time string '%s'\n",
s);
exit(-1);
}
}
}
if (scale == one_second)
extra_seconds += sign * term;
else
time_ps += sign * term * scale;
while (time_ps < 0) {
time_ps += one_second;
extra_seconds--;
}
fdelay_pico_to_time((uint64_t *) & time_ps, t);
t->utc += extra_seconds;
if (0)
printf("dbg: raw %lld, %lld, converted: %lld s %d ns %d ps\n",
extra_seconds,time_ps, t->utc, t->coarse * 8,
t->frac * 8000 / 4096);
}
/* This comes from oldtools/fdelay-pulse-tom.c, unchanged */
/*static struct fdelay_time ts_add(struct fdelay_time a, struct fdelay_time b)
{
a.frac += b.frac;
if (a.frac >= 4096) {
a.frac -= 4096;
a.coarse++;
}
a.coarse += b.coarse;
if (a.coarse >= 125000000) {
a.coarse -= 125000000;
a.utc++;
}
a.utc += b.utc;
return a;
}
/*
* Some argument parsing is non-trivial, including setting
* the default. These helpers just return void and exit on error
*/
/*#define COARSE_PER_SEC (125 * 1000 * 1000)
void parse_default(struct fdelay_pulse *p)
{
memset(p, 0, sizeof(*p));
memset(&t_width, 0, sizeof(&t_width));
p->mode = FD_OUT_MODE_PULSE;
p->rep = -1; /* 1 pulse */
/* Default settings are for 10Hz, 1us width
p->loop.coarse = COARSE_PER_SEC / 10;
t_width.coarse = 125;
}
void parse_pps(struct fdelay_pulse *p)
{
parse_default(p);
t_width.coarse = COARSE_PER_SEC / 100; /* 10ms width
p->loop.coarse = 0;
p->loop.utc = 1;
}
void parse_10mhz(struct fdelay_pulse *p)
{
parse_default(p);
t_width.coarse = 6 /* 48ns *;
p->loop.coarse = 12 /* 96ns *;
p->loop.frac = 2048 /* 4ns *;
}
void parse_reltime(struct fdelay_pulse *p, char *s)
{
memset(&p->start, 0, sizeof(p->start));
parse_time(s, &p->start);
}
void parse_abstime(struct fdelay_pulse *p, char *s)
{
unsigned long long utc;
unsigned long nanos;
char c;
if (sscanf(s, "%llu:%lu%c", &utc, &nanos, &c) != 2) {
fprintf(stderr, "Wrong <sec>:<nano> string \"%s\"\n", s);
exit(1);
}
p->start.utc = utc;
p->start.coarse = nanos / 8;
p->start.frac = (nanos % 8) * 512;
}
void parse_period(struct fdelay_pulse *p, char *s)
{
memset(&p->loop, 0, sizeof(p->loop));
parse_time(s, &p->loop);
}
void parse_width(struct fdelay_pulse *p, char *s)
{
memset(&t_width, 0, sizeof(&t_width));
parse_time(s, &t_width);
}
*/
int cmd_fmc_fdelay_pulse(char **argv)
{
/*struct fdelay_board *b;
int nboards;
int i, opt, index = -1, dev = -1;
/* our parameters */
/*int count = 0, channel = 1;
int trigger_wait = 0, verbose = 0;
struct fdelay_pulse p;
/* Standard part of the file (repeated code) */
//if (tools_need_help(argc, argv))
help(argv[0]);
/*nboards = fdelay_init();
if (nboards < 0) {
fprintf(stderr, "%s: fdelay_init(): %s\n", argv[0],
strerror(errno));
exit(1);
}
if (nboards == 0) {
fprintf(stderr, "%s: no boards found\n", argv[0]);
exit(1);
}
if (nboards == 1)
index = 0; /* so it works with no arguments *
parse_default(&p);
/* Parse our specific arguments *
while ((opt = getopt(argc, argv, "d:i:ho:c:m:r:D:T:w:tp1v")) != -1) {
switch (opt) {
char *rest;
case 'i':
index = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'd':
dev = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'h':
help(argv[0]);
case 'o':
channel = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
if (channel < 1 || channel > 4) {
fprintf(stderr, "%s: channel \"%s\" out of range\n",
argv[0], optarg);
exit(1);
}
break;
case 'c':
count = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
exit(1);
}
p.rep = count ? count : -1 /* infinite *;
break;
case 'm':
if (!strcmp(optarg, "disable"))
p.mode = FD_OUT_MODE_DISABLED;
else if (!strcmp(optarg, "pulse"))
p.mode = FD_OUT_MODE_PULSE;
else if (!strcmp(optarg, "delay"))
p.mode = FD_OUT_MODE_DELAY;
else {
fprintf(stderr, "%s: invalid mode \"%s\"\n",
argv[0], optarg);
exit(1);
}
break;
case 'r':
parse_reltime(&p, optarg);
break;
case 'D':
parse_abstime(&p, optarg);
break;
#if 0 /* no frequency *
case 'f':
parse_freq(&p, optarg);
break;
#endif
case 'T':
parse_period(&p, optarg);
break;
case 'w':
parse_width(&p, optarg);
break;
case 't':
trigger_wait = 1;
break;
case 'p':
parse_pps(&p);
break;
case '1':
parse_10mhz(&p);
break;
case 'v':
verbose = 1;
break;
}
}
if (optind != argc)
help(argv[0]); /* too many arguments *
if (index < 0 && dev < 0) {
fprintf(stderr, "%s: several boards, please pass -i or -d\n",
argv[0]);
exit(1);
}
b = fdelay_open(index, dev);
if (!b) {
fprintf(stderr, "%s: fdelay_open(): %s\n", argv[0],
strerror(errno));
exit(1);
}
/* Final fixes: if reltime in pulse mode, add current time *
if (p.mode == FD_OUT_MODE_PULSE && p.start.utc == 0) {
struct fdelay_time current_board_time;
fdelay_get_time(b, &current_board_time);
/* Start next second, or next again if too near to overlap *
p.start.utc = current_board_time.utc + 1;
if (current_board_time.coarse > COARSE_PER_SEC * 9 / 10)
p.start.utc++;
}
/* Report to user how parsing turned out to be *
if(verbose)
{
printf("Parsed times:\n");
tools_report_time(" start time: ", &p.start, TOOLS_UMODE_USER);
tools_report_time(" pulse width:", &t_width, TOOLS_UMODE_USER);
tools_report_time(" period: ", &p.loop, TOOLS_UMODE_USER);
}
/* End is start + width, in every situation *
p.end = ts_add(p.start, t_width);
/* In delay mode, default is one pulse only; recover if wrong *
if (p.mode == FD_OUT_MODE_DELAY && p.rep <= 0)
p.rep = 1;
/* Done. Report verbosely and activate the information we parsed *
channel = FDELAY_OUTPUT_USER_TO_HW(channel);
report_output_config(channel, &p, TOOLS_UMODE_USER);
if (fdelay_config_pulse(b, channel, &p) < 0) {
fprintf(stderr, "%s: fdelay_config_pulse(): %s\n",
argv[0], strerror(errno));
exit(1);
}
while (trigger_wait) {
usleep(10 * 1000);
i = fdelay_has_triggered(b, channel);
if (i < 0) {
fprintf(stderr, "%s: waiting for trigger: %s\n",
argv[0], strerror(errno));
exit(1);
}
trigger_wait = !i;
}
fdelay_close(b);
fdelay_exit();*/
return 0;
}
DEFINE_WRC_COMMAND(fmc_fdelay_pulse) = {
.name = "fmc-fdelay-pulse",
.exec = cmd_fmc_fdelay_pulse,
};
/* This work is part of the White Rabbit project
*
* Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014 UGR.
*
* Released according to the GNU GPL version 3 (GPLv3) or later.
*
* Adapted from cmd_fmc_fdelay_pulse.c within fine-delay-sw
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <shell.h>
#include <opt.h>
#include "fdelay-lib.h"
#include "tools-common.h"
struct fdelay_time t_width; /* save width here, add to start before acting */
/* This comes from oldtools/fdelay-pulse-tom.c, unchanged */
static void parse_time(char *s, struct fdelay_time *t)
{
int64_t time_ps = 0;
int64_t extra_seconds = 0;
int64_t sign = 1;
int64_t term = 0;
int64_t scale = 1;
const int64_t one_second = 1000000000000LL;
char c, *buf = s;
while ((c = *buf++) != 0) {
switch (c) {
case '+':
if (scale == one_second)
extra_seconds += sign * term;
else
time_ps += sign * term * scale;
term = 0;
sign = 1;
break;
case '-':
if (scale == one_second)
extra_seconds += sign * term;
else
time_ps += sign * term * scale;
term = 0;
sign = -1;
break;
case 's':
scale = one_second;
break;
case 'm':
scale = 1000000000LL;
break;
case 'u':
scale = 1000000LL;
break;
case 'n':
scale = 1000LL;
break;
case 'p':
scale = 1LL;
break;
default:
if (isdigit(c)) {
term *= 10LL;
term += (int64_t) (c - '0');
break;
} else {
mprintf("Error while parsing time string '%s'\n", s);
return 0;
}
}
}
if (scale == one_second)
extra_seconds += sign * term;
else
time_ps += sign * term * scale;
while (time_ps < 0) {
time_ps += one_second;
extra_seconds--;
}
fdelay_pico_to_time((uint64_t *) & time_ps, t);
t->utc += extra_seconds;
}
/* This comes from oldtools/fdelay-pulse-tom.c, unchanged */
static struct fdelay_time ts_add(struct fdelay_time a, struct fdelay_time b)
{
a.frac += b.frac;
if (a.frac >= 4096) {
a.frac -= 4096;
a.coarse++;
}
a.coarse += b.coarse;
if (a.coarse >= 125000000) {
a.coarse -= 125000000;
a.utc++;
}
a.utc += b.utc;
return a;
}
/*
* Some argument parsing is non-trivial, including setting
* the default. These helpers just return void and //exit on error
*/
#define COARSE_PER_SEC (125 * 1000 * 1000)
void parse_default(struct fdelay_pulse *p)
{
memset(p, 0, sizeof(*p));
memset(&t_width, 0, sizeof(&t_width));
p->mode = FD_OUT_MODE_PULSE;
p->rep = -1; /* 1 pulse */
/* Default settings are for 10Hz, 1us width */
p->loop.coarse = COARSE_PER_SEC / 10;
t_width.coarse = 125;
}
void parse_pps(struct fdelay_pulse *p)
{
parse_default(p);
t_width.coarse = COARSE_PER_SEC / 100; /* 10ms width **/
p->loop.coarse = 0;
p->loop.utc = 1;
}
void parse_10mhz(struct fdelay_pulse *p)
{
parse_default(p);
t_width.coarse = 6 /* 48ns */;
p->loop.coarse = 12 /* 96ns */;
p->loop.frac = 2048 /* 4ns */;
}
void parse_reltime(struct fdelay_pulse *p, char *s)
{
memset(&p->start, 0, sizeof(p->start));
parse_time(s, &p->start);
}
void parse_abstime(struct fdelay_pulse *p, char *s)
{
unsigned long long utc;
unsigned long nanos;
if (sscanf_addhoc_replacement(s, &utc, &nanos) < 2) {
mprintf("Wrong <sec>:<nano> string \"%s\"\n", s);
return -1;
}
p->start.utc = utc;
p->start.coarse = nanos / 8;
p->start.frac = (nanos % 8) * 512;
}
void parse_period(struct fdelay_pulse *p, char *s)
{
memset(&p->loop, 0, sizeof(p->loop));
parse_time(s, &p->loop);
}
void parse_width(struct fdelay_pulse *p, char *s)
{
memset(&t_width, 0, sizeof(&t_width));
parse_time(s, &t_width);
}
static int main_pulse(const char **argv)
{
struct fdelay_board *b;
int nboards = 1;
int argc =0;
int i, opt, index = -1, dev = -1;
/* our parameters */
int count = 0, channel = -1;
int trigger_wait = 0, verbose = 0;
struct fdelay_pulse p;
optind = 0;
argc=str_vector_length (argv);
/* Standard part of the file (repeated code) */
if (tools_need_help(argc, argv)){
help(FD_CMD_PULS_HELP);
return 0;
}
parse_default(&p);
/* Parse our specific arguments */
while ((opt = getopt(argc, argv, "ho:c:m:r:D:T:w:tp1v")) != -1) {
switch (opt) {
char *rest;
case 'h':
help(FD_CMD_PULS_HELP);
return 0;
case 'o':
channel = strtol(optarg, &rest, 0);
if (rest && *rest) {
fprintf(stderr, "%s: Not a number \"%s\"\n",
argv[0], optarg);
return 0;
}
if (channel < 1 || channel > 4) {
mprintf("pulse: channel \"%s\" out of range\n", optarg);
return 0;
}
break;
case 'c':
count = strtol(optarg, &rest, 0);
if (rest && *rest) {
mprintf("pulse: Not a number \"%s\"\n", optarg);
return 0;
}
p.rep = count ? count : -1 /* infinite */;
break;
case 'm':
if (!strcmp(optarg, "disable")){
p.mode = FD_OUT_MODE_DISABLED;
}
else if (!strcmp(optarg, "pulse")){
p.mode = FD_OUT_MODE_PULSE;
}
else if (!strcmp(optarg, "delay")){
p.mode = FD_OUT_MODE_DELAY;
}
else {
mprintf("pulse: invalid mode \"%s\"\n", optarg);
return 0;
}
break;
case 'r':
parse_reltime(&p, optarg);
break;
case 'D':
parse_abstime(&p, optarg);
break;
#if 0 /* no frequency */
case 'f':
parse_freq(&p, optarg);
break;
#endif
case 'T':
parse_period(&p, optarg);
break;
case 'w':
parse_width(&p, optarg);
break;
case 't':
trigger_wait = 1;
break;
case 'p':
parse_pps(&p);
break;
case '1':
parse_10mhz(&p);
break;
case 'v':
verbose = 1;
break;
default:
help(FD_CMD_PULS_HELP);
return 0;
}
}
if (optind != argc){
help(FD_CMD_PULS_HELP); /* too many arguments */
return 0;
}
else if ((opt != '?') && (opt != ':')) { /* opt.c */
if(channel < 0)
{
mprintf("pulse: no channel specified (-o option missing).\n");
return 0;
}
/* Final fixes: if reltime in pulse mode, add current time */
if (p.mode == FD_OUT_MODE_PULSE && p.start.utc == 0) {
struct fd_time current_board_time;
fd_time_get(&fd, &current_board_time, NULL);
/* Start next second, or next again if too near to overlap */
p.start.utc = current_board_time.utc + 1;
if (current_board_time.coarse > COARSE_PER_SEC * 9 / 10)
p.start.utc++;
}
/* Report to user how parsing turned out to be */
if(verbose){
printf("Parsed times:\n");
tools_report_time(" start time: ", &p.start, TOOLS_UMODE_USER);
tools_report_time(" pulse width:", &t_width, TOOLS_UMODE_USER);
tools_report_time(" period: ", &p.loop, TOOLS_UMODE_USER);
}
/* End is start + width, in every situation */
p.end = ts_add(p.start, t_width);
/* In delay mode, default is one pulse only; recover if wrong */
if (p.mode == FD_OUT_MODE_DELAY && p.rep <= 0)
p.rep = 1;
/* Done. Report verbosely and activate the information we parsed */
channel = FDELAY_OUTPUT_USER_TO_HW(channel);
report_output_config(channel, &p, TOOLS_UMODE_USER);
int err = fdelay_config_pulse(&fd, channel, &p);
if (err < 0)
mprintf("pulse: error: %s\n", strerror(-err));
}
return 0;
}
DEFINE_WRC_COMMAND(pulse) = {
.name = "pulse",
.exec = main_pulse,
};
/* This work is part of the White Rabbit project
*
* Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014 UGR.
*
* Released according to the GNU GPL version 3 (GPLv3) or later.
*
* Adapted from cmd_fmc_fdelay_status.c within fine-delay-sw
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "fdelay-lib.h"
#include <shell.h>
#include "tools-common.h"
#include "opt.h"
int main_status(const char **argv)
{
struct fdelay_pulse p;
int ch, raw = 0, opt, argc;
optind=0;
argc = str_vector_length (argv);
/* Standard part of the file (repeated code) */
if (tools_need_help(argc, argv)){
help(FD_CMD_STAT_HELP);
return 0;
}
while ((opt = getopt(argc, argv, "rh")) != -1) {
switch (opt) {
case 'r':
raw = 1;
break;
case 'h':
help(FD_CMD_STAT_HELP);
return 0;
}
}
for (ch = 1; ch <= 4; ch++) {
if (fdelay_get_config_pulse(&fd, FDELAY_OUTPUT_USER_TO_HW(ch), &p) <0){
mprintf("status: get_config(channel %i): %s\n", ch, strerror(errno));
}
/* pass hw number again, as the function is low-level */
report_output_config(FDELAY_OUTPUT_USER_TO_HW(ch),
&p, raw ? TOOLS_UMODE_RAW : TOOLS_UMODE_USER);
}
return 0;
}
DEFINE_WRC_COMMAND(status) = {
.name = "status",
.exec = main_status,
};
/* This work is part of the White Rabbit project
*
* Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014 UGR.
*
* Released according to the GNU GPL version 3 (GPLv3) or later.
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "fdelay-lib.h"
#include <shell.h>
#include "tools-common.h"
int main_temp(const char **argv)
{
if (str_vector_length(argv) != 0){
help(FD_CMD_TEMP_HELP);
return 0;
}
int temp = fd_read_temp(&fd, 0);
mprintf("Temperature %i.%03i\n", temp / 16, (temp & 0xf) * 1000 / 16);
return 0;
}
DEFINE_WRC_COMMAND(temp) = {
.name = "temp",
.exec = main_temp,
};
/* This work is part of the White Rabbit project
*
* Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014 UGR.
*
* Released according to the GNU GPL version 3 (GPLv3) or later.
*
* Adapted from cmd_fmc_fdelay_term.c within fine-delay-sw:
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "fdelay-lib.h"
#include <opt.h>
#include "tools-common.h"
#include <shell.h>
int main_term (const char **argv)
{
int newval, argc = 0;
optind = 0;
argc=str_vector_length(argv);
/* Standard part of the file (repeated code) */
if (tools_need_help(argc, argv)){
help(FD_CMD_TERM_HELP);
return 0;
}
newval = -1;
if (optind + 1 == argc) {
char *s = argv[optind];
if (!strcmp(s, "0") || !strcmp(s, "off"))
newval = 0;
else if (!strcmp(s, "1") || !strcmp(s, "on"))
newval = 1;
else{
help(FD_CMD_TERM_HELP);
return 0;
}
}
int err = 0;
switch(newval) {
case 1:
fd.tdc_flags |= FD_TDCF_TERM_50;
fd_gpio_set(&fd, FD_GPIO_TERM_EN);
break;
case 0:
fd.tdc_flags &= ~FD_TDCF_TERM_50;
fd_gpio_clr(&fd, FD_GPIO_TERM_EN);
break;
}
if (err)
{
mprintf("term: error setting termination: %s", strerror(err));
return 0;
}
printf("termination is %s\n",
fd.tdc_flags & FD_TDCF_TERM_50 ? "on" : "off");
return 0;
}
DEFINE_WRC_COMMAND(term) = {
.name = "term",
.exec = main_term,
};
/* This work is part of the White Rabbit project
*
* Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014 UGR.
*
* Released according to the GNU GPL version 3 (GPLv3) or later.
*
* Adapted from cmd_fmc_fdelay_time.c within fine-delay-sw:
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "fdelay-lib.h"
#include "hw/fd_main_regs.h"
#include <shell.h>
#include <opt.h>
#include "tools-common.h"
#include <linux/jiffies.h>
int fd_wr_mode(struct fd_dev *fd, int on)
{
uint32_t tcr = fd_readl(fd, FD_REG_TCR);
if (on) {
fd_writel(fd, FD_TCR_WR_ENABLE, FD_REG_TCR);
set_bit(FD_FLAG_WR_MODE, fd->flags);
} else {
fd_writel(fd, 0, FD_REG_TCR);
clear_bit(FD_FLAG_WR_MODE, fd->flags);
/* not white-rabbit: write default to DAC for VCXO */
fd_spi_xfer(fd, FD_CS_DAC, 24,
fd->calib.vcxo_default_tune & 0xffff, NULL);
}
if(! (tcr & FD_TCR_WR_PRESENT)){
return -EOPNOTSUPP;
}
else if( ! (tcr & FD_TCR_WR_LINK)){
return -ENOLINK;
}
else
return 0;
}
int fd_wr_query(struct fd_dev *fd)
{
int ena = test_bit(FD_FLAG_WR_MODE, fd->flags);
if (!ena)
return -ENODEV;
if (! (fd_readl(fd, FD_REG_TCR) & FD_TCR_WR_LINK))
return -ENOLINK;
if (fd_readl(fd, FD_REG_TCR) & FD_TCR_WR_LOCKED){
return 0;
}
return -EAGAIN;
}
int main_time(const char **argv)
{
struct fdelay_time t;
int i, err, get = 0, wr_on = 0, wr_off = 0, argc=0;
char *s;
optind = 0;
argc=str_vector_length(argv);
/* Standard part of the file (repeated code) */
if (tools_need_help(argc, argv))
help(FD_CMD_TIME_HELP);
/* Parse the mandatory extra argument */
if (optind != argc - 1 || !strcmp (argv[optind], "-h")){
help(FD_CMD_TIME_HELP);
return 0;
}
s = argv[optind];
/* Crappy parser */
if (!strcmp(s, "get"))
get = 1;
else if (!strcmp(s, "wr"))
wr_on = 1;
else if (!strcmp(s, "local"))
wr_off = 1;
else {
unsigned long long nano;
unsigned long long sec;
memset(&t, 0, sizeof(t));
i = sscanf_addhoc_replacement(s, &sec, &nano);
if (i < 1) {
mprintf("time: Not a number \"%s\"\n", s);
return 0;
}
t.utc = sec;
t.coarse = nano * 1000 * 1000 * 1000 / 8;
}
if (get) {
if ((err = fd_time_get(&fd, &t, NULL)) < 0) {
mprintf("time: fdelay_get_time(): %s\n", strerror(err));
return -1;
}
err = fd_wr_query(&fd);
mprintf("WR Status: ");
switch(err)
{
case -ENODEV: mprintf("disabled.\n"); break;
case -ENOLINK: mprintf("link down.\n"); break;
case -EAGAIN: mprintf("synchronization in progress.\n"); break;
case 0: mprintf("synchronized.\n"); break;
default: mprintf("error: %s\n", strerror(errno)); break;
}
//When 64 bit pritting is supported
//mprintf("Time: %i.%09i\n", (long long)t.utc, (long)t.coarse * 8);
//Until that glorious day
mprintf("Time: ");
mprint_64bit (t.utc);
mprintf(".%09i\n", t.coarse * 8);
return 0;
}
if (wr_on) {
printf("Locking the card to WR: ");
err = fd_wr_mode(&fd, 1);
if(err == -ENOTSUP)
{
mprintf("time: no support for White Rabbit (check the gateware).\n");
return 0;
} else if (err) {
mprintf("time: fdelay_wr_mode(): %s\n", strerror(err));
return 0;
}
int j = jiffies + 1000 * 90;
while ((err = fd_wr_query(&fd)) != 0) {
if( err == -ENOLINK )
{
mprintf("time: no White Rabbit link (check the cable and the switch).\n");
return 0;
}
printf(".");
usleep(1000*1000);
if (jiffies>j) {
fd_wr_mode(&fd, 0);
mprintf("\ntime: fdelay_wr_mode(): %s\n", strerror(ETIME));
return 0;
}
}
mprintf(" locked!\n");
return 0;
}
if (wr_off) {
if ((err=fd_wr_mode(&fd, 0)) < 0) {
mprintf("time: fdelay_wr_mode(): %s\n", strerror(err));
}
return 0;
}
if (test_bit(FD_FLAG_WR_MODE, fd.flags)){
mprintf("time: fdelay_set_time(): %s\n", strerror(EAGAIN));
return 0;
}
else if ((err=fd_time_set(&fd, &t, NULL)) < 0) {
mprintf("time: fdelay_set_time(): %s\n", strerror(err));
return 0;
}
/* wtf */
fd_writel(&fd, 0, FD_REG_TCR);
return 0;
}
DEFINE_WRC_COMMAND(time) = {
.name = "time",
.exec = main_time,
};
This diff is collapsed.
/* This work is part of the White Rabbit project
*
* Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014 UGR.
* Released according to the GNU GPL version 3 (GPLv3) or later.
*
* Adapted from tools-util fine-delay-sw
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <opt.h>
#include "fdelay-lib.h"
#include "tools-common.h"
#define sprintf pp_sprintf
void help (enum fd_command_help param){
switch (param){
case FD_CMD_PULS_HELP:
mprintf("pulse: Use \"pulse [<opts>]\"\n"
" -o <output> ouput channel: 1..4 (default 1)\n"
" -c <count> default is 0 and means forever\n"
" -m <mode> \"pulse\" (default), \"delay\", \"disable\"\n"
" -r <reltime> relative time, e.g. \"10m+20u\" -- use m,u,n,p and add/sub\n"
" -D <date> absolute time, <secs>:<nano>\n");
mprintf(" -T <period> period, e.g. \"50m-20n\" -- use m,u,n,p and add/sub\n"
" -w <width> like period; defaults to 50%% period\n"
" -t wait for trigger before //exiting\n"
" -p pulse per seconds (sets -D -T -w)\n"
" -1 10MHz (sets -D -T -w)\n"
" -v verbose (report action)\n");
break;
case FD_CMD_TIME_HELP:
mprintf("time: a tool for manipulating the FMC Fine Delay time base.\n"
"Use: \"time <command>\"\n");
mprintf(" where the <command> can be:\n"
" get - shows current time and White Rabbit status.\n"
" local - sets the time source to the card's local oscillator.\n");
mprintf(" wr - sets the time source to White Rabbit.\n"
" seconds:[nanoseconds]: - sets local time to the given value.\n");
break;
case FD_CMD_TERM_HELP:
mprintf("term: Use \"term [on|off]\n"
" on: enables termination\n"
" off: disables termination (default value)\n");
break;
case FD_CMD_STAT_HELP:
mprintf("status: reports channel programming\n"
"Use: \"status [-r]\"\n"
" -r: display raw hardware configuration\n");
break;
case FD_CMD_TEMP_HELP:
mprintf("temp: shows FMC Dealy temperature\n"
"Use: \"temp\"\n");
break;
}
mprintf("\nReport bugs to <fmc-delay-1ns-8cha-sa@ohwr.org>\n\n");
}
void tools_getopt_d_i(int argc, const char **argv, enum fd_command_help param)
{
char *rest;
int opt;
while ((opt = getopt(argc, argv, "h")) != -1) {
if (opt =='h') {
help (param);
}
}
}
int tools_need_help(int argc, const char **argv)
{
if (argc != 1)
return 0;
if (!strcmp(argv[0], "--help"))
return 1;
return 0;
}
//crappy adhoc replacement for sscanf just to save time and minimize memory ocupation
int sscanf_addhoc_replacement(char *str, unsigned long long *var1, unsigned long long *var2){
char *c, *ptr, *rest, tok[]= ":";
int processed = 0;
c=str;
if ((ptr = strpbrk (c, tok)) > 0){
ptr[0] = 0;
*var1=strtol(c, &rest, 0);
c = ptr+1;
if (!(rest && *rest))
{
processed++;
while (ptr++){
if (isalpha(ptr[0]) || (ptr[0] == '/0')){
if (ptr[0] != 0)
ptr[0]=0;
break;
}
}
*var2=strtol(c, &rest, 0);
if (! (rest && *rest))
processed ++;
} //if ((offset = strpbrk (c, tok) - c) > 0)
}
return processed;
}
/*
* What it should if we had 64 bit printing
*
* Note: LM32-base cores can not divide LL use functions form linux/math64.c
* I provide you with (that means the fuction donw below has te be fixed)
* /
/*void tools_report_time(char *name, struct fdelay_time *t, int umode)
{
unsigned long long picoseconds =
t->coarse * 8000ULL +
t->frac * 8000ULL / 4096ULL;
printf("%s ", name);
switch(umode) {
case TOOLS_UMODE_USER:
printf ("%10llu:%03llu,%03llu,%03llu,%03llu ps\n",
(long long)(t->utc),
(picoseconds / (1000LL * 1000 * 1000)),
(picoseconds / (1000LL * 1000) % 1000),
(picoseconds / (1000LL) % 1000),
(picoseconds % 1000LL));
break;
case TOOLS_UMODE_FLOAT:
printf ("float %10llu.%012llu\n", (long long)(t->utc),
picoseconds);
break;
case TOOLS_UMODE_RAW:
printf("raw utc %10lli, coarse %9li, frac %9li\n",
(long long)t->utc, (long)t->coarse, (long)t->frac);
break;
}
}*/
void tools_report_time(char *name, struct fdelay_time *t, int umode)
{
uint64_t temp = mul_u64 ((u64)t->frac, 8000LLU);
uint64_t picoseconds =
mul_u64 ((u64)t->coarse ,8000LLU) +
div64_u64_rem(temp, 4096LLU, NULL);
printf("%s ", name);
switch(umode) {
case TOOLS_UMODE_USER:
/*
* This fix make the following looks like sheet (at running time).
* It looks way cooler in the user space!
*
*/
mprint_64bit((uint64_t)(t->utc));
mprintf("s ");
mprint_64bit(picoseconds);
mprintf("ps\n");
break;
case TOOLS_UMODE_FLOAT:
//Again sorry for the crappy looks
mprintf ("float ");
mprint_64bit((uint64_t)(t->utc));
mprintf (".");
mprint_64bit(picoseconds);
mprintf("\n");
break;
case TOOLS_UMODE_RAW:
// And not so bad this time!
mprintf("raw utc ");
mprint_64bit((uint64_t)(t->utc));
mprintf (", coarse %9li, frac %9li\n",
t->coarse, t->frac);
break;
}
}
static struct fdelay_time fd_ts_sub(struct fdelay_time a, struct fdelay_time b)
{
struct fdelay_time rv;
int f, c = 0;
int64_t u = 0;
f = a.frac - b.frac;
if(f < 0)
{
f += 4096;
c--;
}
c += a.coarse - b.coarse;
if(c < 0)
{
c += 125 * 1000 * 1000;
u--;
}
u += a.utc - b.utc;
rv.utc = u;
rv.coarse = c;
rv.frac = f;
rv.seq_id = 0;
rv.channel = 0;
return rv;
}
static void report_output_config_human(int channel, struct fdelay_pulse *p)
{
struct fdelay_time width;
printf("Channel %i: ", FDELAY_OUTPUT_HW_TO_USER(channel));
int m = p->mode & 0x7f;
switch(m)
{
case FD_OUT_MODE_DISABLED:
printf("disabled\n");
return;
case FD_OUT_MODE_PULSE:
printf("pulse generator mode");
break;
case FD_OUT_MODE_DELAY:
printf("delay mode");
break;
default:
printf("unknown mode\n");
return;
}
if(p->mode & 0x80)
printf(" (triggered) ");
tools_report_time(m == FD_OUT_MODE_DELAY ? "\n delay: " : "\n start at: ",
&p->start, TOOLS_UMODE_USER);
width = fd_ts_sub(p->end, p->start);
tools_report_time(" pulse width: ", &width, TOOLS_UMODE_USER);
if(p->rep != 1)
{
printf(" repeat: ");
if(p->rep == -1)
printf("infinite\n");
else
printf("%d times\n", p->rep);
tools_report_time(" period: ", &p->loop, TOOLS_UMODE_USER);
}
}
void report_output_config_raw(int channel, struct fdelay_pulse *p, int umode)
{
char mode[80];
int m = p->mode & 0x7f;
if (m == FD_OUT_MODE_DISABLED) strcpy(mode, "disabled");
else if (m == FD_OUT_MODE_PULSE) strcpy(mode, "pulse");
else if (m == FD_OUT_MODE_DELAY) strcpy(mode, "delay");
else sprintf(mode, "%i (0x%04x)", p->mode, p->mode);
if (p->mode & 0x80)
strcat(mode, " (triggered)");
printf("Channel %i, mode %s, repeat %i %s\n",
FDELAY_OUTPUT_HW_TO_USER(channel), mode,
p->rep, p->rep == -1 ? "(infinite)" : "");
tools_report_time("start", &p->start, umode);
tools_report_time("end ", &p->end, umode);
tools_report_time("loop ", &p->loop, umode);
}
void report_output_config(int channel, struct fdelay_pulse *p, int umode)
{
switch(umode)
{
case TOOLS_UMODE_USER:
report_output_config_human(channel, p);
break;
case TOOLS_UMODE_RAW:
case TOOLS_UMODE_FLOAT:
report_output_config_raw(channel, p, umode);
default:
break;
}
}
# This work is part of the White Rabbit project
#
# Jose Jimenez <jjimenez.wr@gmail.com>, Copyright (C) 2014.
# Released according to the GNU GPL version 3 (GPLv3) or later.
#
#kernel
FINE_DEL_KERNEL_DIR = fmc-delay/fine-delay-sw/kernel
obj-$(CONFIG_FINE_DEL_NODE) += \
$(FINE_DEL_KERNEL_DIR)/spi.o \
$(FINE_DEL_KERNEL_DIR)/gpio.o \
$(FINE_DEL_KERNEL_DIR)/pll.o \
$(FINE_DEL_KERNEL_DIR)/onewire.o \
$(FINE_DEL_KERNEL_DIR)/time.o \
$(FINE_DEL_KERNEL_DIR)/i2c.o \
$(FINE_DEL_KERNEL_DIR)/calibrate.o \
$(FINE_DEL_KERNEL_DIR)/acam.o \
$(FINE_DEL_KERNEL_DIR)/calibration.o
#/kernel
#commands
FINE_DEL_CMP_DIR = fmc-delay/fine-delay-cmds
obj-$(CONFIG_FINE_DEL_NODE) += \
$(FINE_DEL_CMP_DIR)/cmd_fmc_fdelay_pulse.o \
$(FINE_DEL_CMP_DIR)/cmd_fmc_fdelay_term.o \
$(FINE_DEL_CMP_DIR)/cmd_fmc_fdelay_status.o \
$(FINE_DEL_CMP_DIR)/cmd_fmc_fdelay_time.o \
$(FINE_DEL_CMP_DIR)/cmd_fmc_fdelay_temp.o \
$(FINE_DEL_CMP_DIR)/tools-util.o \
$(FINE_DEL_CMP_DIR)/fdelay-output.o
#/commands
#main
FINE_DEL_DIR = fmc-delay
obj-$(CONFIG_FINE_DEL_NODE) += $(FINE_DEL_DIR)/fd_stand_alone_main.o
#/main
#ouput
output-$(CONFIG_FINE_DEL_NODE) = fd_std
#/ouput
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