Commit 1a084cab authored by Evangelia Gousiou's avatar Evangelia Gousiou

more cleanup; removed fmc-delay folder, updated fmceeprom files; still not stable though

parent 7a8148c5
From 39f005c1b8d78075841eef18e8a5e4bb78f3c611 Mon Sep 17 00:00:00 2001
From: user <user@baraka.(none)>
Date: Thu, 19 Apr 2012 15:31:57 +0200
Subject: [PATCH 1/2] Add pulse generator support in the pyhton library.
Modify C library for multiple SPEC board control from Python.
---
software/include/fdelay_lib.h | 2 +-
software/include/rr_io.h | 1 +
software/lib/fdelay_bus.c | 4 +-
software/lib/fdelay_cal.c | 2 +-
software/lib/fdelay_lib.c | 7 ++--
software/lib/rr_io.c | 6 ++++
software/python/fdelay_lib.py | 66 ++++++++++++++++++++++++++++-------------
7 files changed, 60 insertions(+), 28 deletions(-)
diff --git a/software/include/fdelay_lib.h b/software/include/fdelay_lib.h
index e3da3f7..e11e009 100644
--- a/software/include/fdelay_lib.h
+++ b/software/include/fdelay_lib.h
@@ -51,7 +51,7 @@ PUBLIC API
*/
-fdelay_device_t *fdelay_create_rawrabbit(uint32_t base_addr);
+fdelay_device_t *fdelay_create_rawrabbit(int fd, uint32_t base_addr);
fdelay_device_t *fdelay_create_minibone(char *iface, char *mac_addr, uint32_t base_addr);
fdelay_time_t fdelay_from_picos(const uint64_t ps);
diff --git a/software/include/rr_io.h b/software/include/rr_io.h
index 713d7bf..f59ebbd 100644
--- a/software/include/rr_io.h
+++ b/software/include/rr_io.h
@@ -4,6 +4,7 @@
#include <stdint.h>
#include <rawrabbit.h>
+int rr_bind(int a_fd);
int rr_init(int bus, int devfn);
int rr_writel(uint32_t data, uint32_t addr);
uint32_t rr_readl(uint32_t addr);
diff --git a/software/lib/fdelay_bus.c b/software/lib/fdelay_bus.c
index c79790f..b9976ee 100644
--- a/software/lib/fdelay_bus.c
+++ b/software/lib/fdelay_bus.c
@@ -36,10 +36,10 @@ uint32_t d = mbn_readl(priv, addr >> 2);
return d;
}
-fdelay_device_t *fdelay_create_rawrabbit(uint32_t base_addr)
+fdelay_device_t *fdelay_create_rawrabbit(int fd, uint32_t base_addr)
{
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
- rr_init(RR_DEVSEL_UNUSED, RR_DEVSEL_UNUSED);
+ rr_bind(fd);
dev->writel = my_rr_writel;
dev->readl = my_rr_readl;
dev->base_addr = base_addr;
diff --git a/software/lib/fdelay_cal.c b/software/lib/fdelay_cal.c
index 74adc50..afae401 100644
--- a/software/lib/fdelay_cal.c
+++ b/software/lib/fdelay_cal.c
@@ -71,7 +71,7 @@ main()
{
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
- rr_init();
+ rr_init(RR_DEVSEL_UNUSED, RR_DEVSEL_UNUSED);
dev->writel = my_writel;
dev->readl = my_readl;
diff --git a/software/lib/fdelay_lib.c b/software/lib/fdelay_lib.c
index 3dc5d72..8c6eafd 100644
--- a/software/lib/fdelay_lib.c
+++ b/software/lib/fdelay_lib.c
@@ -1224,9 +1224,10 @@ int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel, int enable, fd
start = t_start;
end = ts_add(start, fdelay_from_picos(width_ps));
- delta = fdelay_from_picos(delta_ps);
+ delta = fdelay_from_picos(delta_ps);
-// printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
+ printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
+ printf("width: %lld delta: %lld rep: %d\n", width_ps, delta_ps, rep_count);
chan_writel(hw->frr_cur[channel-1], FD_REG_FRR);
@@ -1390,4 +1391,4 @@ int fd_update_spll(fdelay_device_t *dev)
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/software/lib/rr_io.c b/software/lib/rr_io.c
index 99e39b0..75be14e 100644
--- a/software/lib/rr_io.c
+++ b/software/lib/rr_io.c
@@ -18,6 +18,12 @@
static int fd;
+int rr_bind(int a_fd)
+{
+ fd = a_fd;
+ return 0;
+}
+
int rr_init(int bus, int devfn)
{
struct rr_devsel devsel;
diff --git a/software/python/fdelay_lib.py b/software/python/fdelay_lib.py
index edda05f..0e8881b 100755
--- a/software/python/fdelay_lib.py
+++ b/software/python/fdelay_lib.py
@@ -3,12 +3,14 @@
from ctypes import *
import sys
import re
+import os
class fd_timestamp(Structure):
- _fields_ = [("utc", c_ulong),
- ("coarse", c_ulong),
- ("frac", c_ulong),
- ("seq_id", c_ushort)]
+ _fields_ = [("utc", c_ulonglong),
+ ("coarse", c_ulong),
+ ("frac", c_ulong),
+ ("seq_id", c_ushort),
+ ("channel", c_int)]
def nsecs(self):
return (float(self.frac) * 8000.0 / 4096.0 + float(self.coarse) * 8000.0) / 1000.0;
@@ -21,6 +23,8 @@ class fd_timestamp(Structure):
class FineDelay:
+ BASE_ADDR = 0x84000
+
FREE_RUNNING = 0x10
WR_OFFLINE = 0x8
WR_READY = 0x1
@@ -29,46 +33,66 @@ class FineDelay:
SYNC_LOCAL = 0x1
SYNC_WR = 0x2
- def __init__(self, dev_path):
+ def __init__(self, fd):
+ cwd = os.path.dirname(__file__)
+ self.fdelay = CDLL(cwd+'/../lib/libfinedelay.so')
+ self.handle = c_voidp(self.fdelay.fdelay_create_rawrabbit(c_int(fd), c_ulong(self.BASE_ADDR)));
+ """
s = re.split("\/", dev_path)
- self.fd = CDLL('../lib/libfinedelay.so')
+ self.fdelay = CDLL('../lib/libfinedelay.so')
if(s[0] == "local"):
print("Initializing local at %x" % int(s[1], 16))
- self.handle = c_voidp(self.fd.fdelay_create_rawrabbit(int(s[1],16)));
+ self.handle = c_voidp(self.fdelay.fdelay_create_rawrabbit(int(s[1],16)));
elif(s[0] == "minibone"):
print("Initializing minibone at %s [%s]\n" %( s[1], s[2]))
- self.handle = c_voidp(self.fd.fdelay_create_minibone(c_char_p(s[1]), c_char_p(s[2]), int(s[3], 16)));
-
- if(self.fd.fdelay_init(self.handle) < 0):
+ self.handle = c_voidp(self.fdelay.fdelay_create_minibone(c_char_p(s[1]), c_char_p(s[2]), int(s[3], 16)));
+ """
+ if(self.fdelay.fdelay_init(self.handle) < 0):
print ("Init failed..");
# sys.exit(-1)
+
def conf_trigger(self, enable, termination):
- self.fd.fdelay_configure_trigger(self.handle, c_int(enable), c_int(termination))
-
+ self.fdelay.fdelay_configure_trigger(self.handle, c_int(enable), c_int(termination))
+
def conf_output(self, channel, enable, delay, width):
- self.fd.fdelay_configure_output(self.handle, c_int(channel), c_int(enable), c_ulonglong(delay), c_ulonglong(width))
-
+ self.fdelay.fdelay_configure_output(self.handle, c_int(channel), c_int(enable), c_ulonglong(delay), c_ulonglong(width))
+
def conf_readout(self, enable):
- self.fd.fdelay_configure_readout(self.handle, enable)
-
+ self.fdelay.fdelay_configure_readout(self.handle, enable)
+
def conf_sync(self, mode):
- self.fd.fdelay_configure_sync(self.handle, mode)
-
+ self.fdelay.fdelay_configure_sync(self.handle, mode)
+
+ def conf_pulsegen(self, channel, enable, t_start_utc, width, delta, count):
+ t = fd_timestamp(utc=c_ulonglong(t_start_utc), coarse=c_ulong(0))
+ #print "channel:%d enable:%d start_t:%d width:%d delta:%d count:%d"%(channel, enable, t.utc, width, delta, count)
+ self.fdelay.fdelay_configure_pulse_gen(self.handle, c_int(channel), c_int(enable), t,
+ c_ulonglong(width), c_ulonglong(delta), c_int(count))
+
+ def set_time(self, utc, coarse):
+ t = fd_timestamp(utc=c_ulonglong(utc), coarse=c_ulong(coarse))
+ self.fdelay.fdelay_set_time(self.handle, t)
+
+ def get_time(self):
+ t = fd_timestamp()
+ self.fdelay.fdelay_get_time(self.handle, byref(t))
+ return t
+
def get_sync_status(self):
htab = { self.FREE_RUNNING : "oscillator free-running",
self.WR_OFFLINE : "WR core offline",
self.WR_READY : "WR core ready",
self.WR_SYNCING : "Syncing local clock with WR",
self.WR_SYNCED : "Synced with WR" }
-# status = c_int(self.fd.fdelay_get_sync_status(self.handle));
+# status = c_int(self.fdelay.fdelay_get_sync_status(self.handle));
# print("GetSyncStatus %x" % status.value);
return "none"; #htab[status.value]
-
+
def read_ts(self):
buf = (fd_timestamp * 256)();
ptr = pointer(buf)
- n = self.fd.fdelay_read(self.handle, ptr, 256)
+ n = self.fdelay.fdelay_read(self.handle, ptr, 256)
arr = [];
for i in range(0,n):
arr.append(buf[i])
--
1.7.4.1
From b5c7ac0bd61db02dd2c37e9c8d21752f6b761812 Mon Sep 17 00:00:00 2001
From: user <user@baraka.(none)>
Date: Wed, 25 Apr 2012 15:37:59 +0200
Subject: [PATCH 2/2] Change pulse generator configuration function in the python lib, allows set start time with 8ns resolution (instead of only UTC).
Remove 4ns of the pulse width in the C library, due to a hardware bug.
---
software/lib/fdelay_lib.c | 14 ++++++++++----
software/python/fdelay_lib.py | 5 +++--
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/software/lib/fdelay_lib.c b/software/lib/fdelay_lib.c
index 8c6eafd..b0ab7dc 100644
--- a/software/lib/fdelay_lib.c
+++ b/software/lib/fdelay_lib.c
@@ -1171,7 +1171,8 @@ int fdelay_configure_output(fdelay_device_t *dev, int channel, int enable, int64
delay_ps -= hw->calib.zero_offset[channel-1];
start = fdelay_from_picos(delay_ps);
end = fdelay_from_picos(delay_ps + width_ps);
- delta = fdelay_from_picos(delta_ps);
+ delta = fdelay_from_picos(delta_ps);
+
// printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
@@ -1222,12 +1223,17 @@ int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel, int enable, fd
if(channel < 1 || channel > 4)
return -1;
+
start = t_start;
- end = ts_add(start, fdelay_from_picos(width_ps));
+ end = fdelay_from_picos(fdelay_to_picos(start) + width_ps - 4000);
delta = fdelay_from_picos(delta_ps);
- printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
- printf("width: %lld delta: %lld rep: %d\n", width_ps, delta_ps, rep_count);
+ //start = t_start;
+ //end = ts_add(start, fdelay_from_picos(width_ps));
+ //delta = fdelay_from_picos(delta_ps);
+
+ //printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
+ //printf("width: %lld delta: %lld rep: %d\n", width_ps, delta_ps, rep_count);
chan_writel(hw->frr_cur[channel-1], FD_REG_FRR);
diff --git a/software/python/fdelay_lib.py b/software/python/fdelay_lib.py
index 0e8881b..8eb2bd3 100755
--- a/software/python/fdelay_lib.py
+++ b/software/python/fdelay_lib.py
@@ -47,6 +47,7 @@ class FineDelay:
print("Initializing minibone at %s [%s]\n" %( s[1], s[2]))
self.handle = c_voidp(self.fdelay.fdelay_create_minibone(c_char_p(s[1]), c_char_p(s[2]), int(s[3], 16)));
"""
+ print "Initialising Fine Delay board..."
if(self.fdelay.fdelay_init(self.handle) < 0):
print ("Init failed..");
# sys.exit(-1)
@@ -64,8 +65,8 @@ class FineDelay:
def conf_sync(self, mode):
self.fdelay.fdelay_configure_sync(self.handle, mode)
- def conf_pulsegen(self, channel, enable, t_start_utc, width, delta, count):
- t = fd_timestamp(utc=c_ulonglong(t_start_utc), coarse=c_ulong(0))
+ def conf_pulsegen(self, channel, enable, t_start_utc, t_start_coarse, width, delta, count):
+ t = fd_timestamp(utc=c_ulonglong(t_start_utc), coarse=c_ulong(t_start_coarse))
#print "channel:%d enable:%d start_t:%d width:%d delta:%d count:%d"%(channel, enable, t.utc, width, delta, count)
self.fdelay.fdelay_configure_pulse_gen(self.handle, c_int(channel), c_int(enable), t,
c_ulonglong(width), c_ulonglong(delta), c_int(count))
--
1.7.4.1
From 39f005c1b8d78075841eef18e8a5e4bb78f3c611 Mon Sep 17 00:00:00 2001
From: user <user@baraka.(none)>
Date: Thu, 19 Apr 2012 15:31:57 +0200
Subject: [PATCH 1/2] Add pulse generator support in the pyhton library.
Modify C library for multiple SPEC board control from Python.
---
software/include/fdelay_lib.h | 2 +-
software/include/rr_io.h | 1 +
software/lib/fdelay_bus.c | 4 +-
software/lib/fdelay_cal.c | 2 +-
software/lib/fdelay_lib.c | 7 ++--
software/lib/rr_io.c | 6 ++++
software/python/fdelay_lib.py | 66 ++++++++++++++++++++++++++++-------------
7 files changed, 60 insertions(+), 28 deletions(-)
diff --git a/software/include/fdelay_lib.h b/software/include/fdelay_lib.h
index e3da3f7..e11e009 100644
--- a/software/include/fdelay_lib.h
+++ b/software/include/fdelay_lib.h
@@ -51,7 +51,7 @@ PUBLIC API
*/
-fdelay_device_t *fdelay_create_rawrabbit(uint32_t base_addr);
+fdelay_device_t *fdelay_create_rawrabbit(int fd, uint32_t base_addr);
fdelay_device_t *fdelay_create_minibone(char *iface, char *mac_addr, uint32_t base_addr);
fdelay_time_t fdelay_from_picos(const uint64_t ps);
diff --git a/software/include/rr_io.h b/software/include/rr_io.h
index 713d7bf..f59ebbd 100644
--- a/software/include/rr_io.h
+++ b/software/include/rr_io.h
@@ -4,6 +4,7 @@
#include <stdint.h>
#include <rawrabbit.h>
+int rr_bind(int a_fd);
int rr_init(int bus, int devfn);
int rr_writel(uint32_t data, uint32_t addr);
uint32_t rr_readl(uint32_t addr);
diff --git a/software/lib/fdelay_bus.c b/software/lib/fdelay_bus.c
index c79790f..b9976ee 100644
--- a/software/lib/fdelay_bus.c
+++ b/software/lib/fdelay_bus.c
@@ -36,10 +36,10 @@ uint32_t d = mbn_readl(priv, addr >> 2);
return d;
}
-fdelay_device_t *fdelay_create_rawrabbit(uint32_t base_addr)
+fdelay_device_t *fdelay_create_rawrabbit(int fd, uint32_t base_addr)
{
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
- rr_init(RR_DEVSEL_UNUSED, RR_DEVSEL_UNUSED);
+ rr_bind(fd);
dev->writel = my_rr_writel;
dev->readl = my_rr_readl;
dev->base_addr = base_addr;
diff --git a/software/lib/fdelay_cal.c b/software/lib/fdelay_cal.c
index 74adc50..afae401 100644
--- a/software/lib/fdelay_cal.c
+++ b/software/lib/fdelay_cal.c
@@ -71,7 +71,7 @@ main()
{
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
- rr_init();
+ rr_init(RR_DEVSEL_UNUSED, RR_DEVSEL_UNUSED);
dev->writel = my_writel;
dev->readl = my_readl;
diff --git a/software/lib/fdelay_lib.c b/software/lib/fdelay_lib.c
index 3dc5d72..8c6eafd 100644
--- a/software/lib/fdelay_lib.c
+++ b/software/lib/fdelay_lib.c
@@ -1224,9 +1224,10 @@ int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel, int enable, fd
start = t_start;
end = ts_add(start, fdelay_from_picos(width_ps));
- delta = fdelay_from_picos(delta_ps);
+ delta = fdelay_from_picos(delta_ps);
-// printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
+ printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
+ printf("width: %lld delta: %lld rep: %d\n", width_ps, delta_ps, rep_count);
chan_writel(hw->frr_cur[channel-1], FD_REG_FRR);
@@ -1390,4 +1391,4 @@ int fd_update_spll(fdelay_device_t *dev)
}
}
-#endif
\ No newline at end of file
+#endif
diff --git a/software/lib/rr_io.c b/software/lib/rr_io.c
index 99e39b0..75be14e 100644
--- a/software/lib/rr_io.c
+++ b/software/lib/rr_io.c
@@ -18,6 +18,12 @@
static int fd;
+int rr_bind(int a_fd)
+{
+ fd = a_fd;
+ return 0;
+}
+
int rr_init(int bus, int devfn)
{
struct rr_devsel devsel;
diff --git a/software/python/fdelay_lib.py b/software/python/fdelay_lib.py
index edda05f..0e8881b 100755
--- a/software/python/fdelay_lib.py
+++ b/software/python/fdelay_lib.py
@@ -3,12 +3,14 @@
from ctypes import *
import sys
import re
+import os
class fd_timestamp(Structure):
- _fields_ = [("utc", c_ulong),
- ("coarse", c_ulong),
- ("frac", c_ulong),
- ("seq_id", c_ushort)]
+ _fields_ = [("utc", c_ulonglong),
+ ("coarse", c_ulong),
+ ("frac", c_ulong),
+ ("seq_id", c_ushort),
+ ("channel", c_int)]
def nsecs(self):
return (float(self.frac) * 8000.0 / 4096.0 + float(self.coarse) * 8000.0) / 1000.0;
@@ -21,6 +23,8 @@ class fd_timestamp(Structure):
class FineDelay:
+ BASE_ADDR = 0x84000
+
FREE_RUNNING = 0x10
WR_OFFLINE = 0x8
WR_READY = 0x1
@@ -29,46 +33,66 @@ class FineDelay:
SYNC_LOCAL = 0x1
SYNC_WR = 0x2
- def __init__(self, dev_path):
+ def __init__(self, fd):
+ cwd = os.path.dirname(__file__)
+ self.fdelay = CDLL(cwd+'/../lib/libfinedelay.so')
+ self.handle = c_voidp(self.fdelay.fdelay_create_rawrabbit(c_int(fd), c_ulong(self.BASE_ADDR)));
+ """
s = re.split("\/", dev_path)
- self.fd = CDLL('../lib/libfinedelay.so')
+ self.fdelay = CDLL('../lib/libfinedelay.so')
if(s[0] == "local"):
print("Initializing local at %x" % int(s[1], 16))
- self.handle = c_voidp(self.fd.fdelay_create_rawrabbit(int(s[1],16)));
+ self.handle = c_voidp(self.fdelay.fdelay_create_rawrabbit(int(s[1],16)));
elif(s[0] == "minibone"):
print("Initializing minibone at %s [%s]\n" %( s[1], s[2]))
- self.handle = c_voidp(self.fd.fdelay_create_minibone(c_char_p(s[1]), c_char_p(s[2]), int(s[3], 16)));
-
- if(self.fd.fdelay_init(self.handle) < 0):
+ self.handle = c_voidp(self.fdelay.fdelay_create_minibone(c_char_p(s[1]), c_char_p(s[2]), int(s[3], 16)));
+ """
+ if(self.fdelay.fdelay_init(self.handle) < 0):
print ("Init failed..");
# sys.exit(-1)
+
def conf_trigger(self, enable, termination):
- self.fd.fdelay_configure_trigger(self.handle, c_int(enable), c_int(termination))
-
+ self.fdelay.fdelay_configure_trigger(self.handle, c_int(enable), c_int(termination))
+
def conf_output(self, channel, enable, delay, width):
- self.fd.fdelay_configure_output(self.handle, c_int(channel), c_int(enable), c_ulonglong(delay), c_ulonglong(width))
-
+ self.fdelay.fdelay_configure_output(self.handle, c_int(channel), c_int(enable), c_ulonglong(delay), c_ulonglong(width))
+
def conf_readout(self, enable):
- self.fd.fdelay_configure_readout(self.handle, enable)
-
+ self.fdelay.fdelay_configure_readout(self.handle, enable)
+
def conf_sync(self, mode):
- self.fd.fdelay_configure_sync(self.handle, mode)
-
+ self.fdelay.fdelay_configure_sync(self.handle, mode)
+
+ def conf_pulsegen(self, channel, enable, t_start_utc, width, delta, count):
+ t = fd_timestamp(utc=c_ulonglong(t_start_utc), coarse=c_ulong(0))
+ #print "channel:%d enable:%d start_t:%d width:%d delta:%d count:%d"%(channel, enable, t.utc, width, delta, count)
+ self.fdelay.fdelay_configure_pulse_gen(self.handle, c_int(channel), c_int(enable), t,
+ c_ulonglong(width), c_ulonglong(delta), c_int(count))
+
+ def set_time(self, utc, coarse):
+ t = fd_timestamp(utc=c_ulonglong(utc), coarse=c_ulong(coarse))
+ self.fdelay.fdelay_set_time(self.handle, t)
+
+ def get_time(self):
+ t = fd_timestamp()
+ self.fdelay.fdelay_get_time(self.handle, byref(t))
+ return t
+
def get_sync_status(self):
htab = { self.FREE_RUNNING : "oscillator free-running",
self.WR_OFFLINE : "WR core offline",
self.WR_READY : "WR core ready",
self.WR_SYNCING : "Syncing local clock with WR",
self.WR_SYNCED : "Synced with WR" }
-# status = c_int(self.fd.fdelay_get_sync_status(self.handle));
+# status = c_int(self.fdelay.fdelay_get_sync_status(self.handle));
# print("GetSyncStatus %x" % status.value);
return "none"; #htab[status.value]
-
+
def read_ts(self):
buf = (fd_timestamp * 256)();
ptr = pointer(buf)
- n = self.fd.fdelay_read(self.handle, ptr, 256)
+ n = self.fdelay.fdelay_read(self.handle, ptr, 256)
arr = [];
for i in range(0,n):
arr.append(buf[i])
--
1.7.4.1
From b5c7ac0bd61db02dd2c37e9c8d21752f6b761812 Mon Sep 17 00:00:00 2001
From: user <user@baraka.(none)>
Date: Wed, 25 Apr 2012 15:37:59 +0200
Subject: [PATCH 2/2] Change pulse generator configuration function in the python lib, allows set start time with 8ns resolution (instead of only UTC).
Remove 4ns of the pulse width in the C library, due to a hardware bug.
---
software/lib/fdelay_lib.c | 14 ++++++++++----
software/python/fdelay_lib.py | 5 +++--
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/software/lib/fdelay_lib.c b/software/lib/fdelay_lib.c
index 8c6eafd..b0ab7dc 100644
--- a/software/lib/fdelay_lib.c
+++ b/software/lib/fdelay_lib.c
@@ -1171,7 +1171,8 @@ int fdelay_configure_output(fdelay_device_t *dev, int channel, int enable, int64
delay_ps -= hw->calib.zero_offset[channel-1];
start = fdelay_from_picos(delay_ps);
end = fdelay_from_picos(delay_ps + width_ps);
- delta = fdelay_from_picos(delta_ps);
+ delta = fdelay_from_picos(delta_ps);
+
// printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
@@ -1222,12 +1223,17 @@ int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel, int enable, fd
if(channel < 1 || channel > 4)
return -1;
+
start = t_start;
- end = ts_add(start, fdelay_from_picos(width_ps));
+ end = fdelay_from_picos(fdelay_to_picos(start) + width_ps - 4000);
delta = fdelay_from_picos(delta_ps);
- printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
- printf("width: %lld delta: %lld rep: %d\n", width_ps, delta_ps, rep_count);
+ //start = t_start;
+ //end = ts_add(start, fdelay_from_picos(width_ps));
+ //delta = fdelay_from_picos(delta_ps);
+
+ //printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
+ //printf("width: %lld delta: %lld rep: %d\n", width_ps, delta_ps, rep_count);
chan_writel(hw->frr_cur[channel-1], FD_REG_FRR);
diff --git a/software/python/fdelay_lib.py b/software/python/fdelay_lib.py
index 0e8881b..8eb2bd3 100755
--- a/software/python/fdelay_lib.py
+++ b/software/python/fdelay_lib.py
@@ -47,6 +47,7 @@ class FineDelay:
print("Initializing minibone at %s [%s]\n" %( s[1], s[2]))
self.handle = c_voidp(self.fdelay.fdelay_create_minibone(c_char_p(s[1]), c_char_p(s[2]), int(s[3], 16)));
"""
+ print "Initialising Fine Delay board..."
if(self.fdelay.fdelay_init(self.handle) < 0):
print ("Init failed..");
# sys.exit(-1)
@@ -64,8 +65,8 @@ class FineDelay:
def conf_sync(self, mode):
self.fdelay.fdelay_configure_sync(self.handle, mode)
- def conf_pulsegen(self, channel, enable, t_start_utc, width, delta, count):
- t = fd_timestamp(utc=c_ulonglong(t_start_utc), coarse=c_ulong(0))
+ def conf_pulsegen(self, channel, enable, t_start_utc, t_start_coarse, width, delta, count):
+ t = fd_timestamp(utc=c_ulonglong(t_start_utc), coarse=c_ulong(t_start_coarse))
#print "channel:%d enable:%d start_t:%d width:%d delta:%d count:%d"%(channel, enable, t.utc, width, delta, count)
self.fdelay.fdelay_configure_pulse_gen(self.handle, c_int(channel), c_int(enable), t,
c_ulonglong(width), c_ulonglong(delta), c_int(count))
--
1.7.4.1
*.o
fd_test
\ No newline at end of file
#ifndef __ACAM_GPX_H
#define __ACAM_GPX_H
#define AR0_ROsc (1<<0)
#define AR0_RiseEn0 (1<<1)
#define AR0_FallEn0 (1<<2)
#define AR0_RiseEn1 (1<<3)
#define AR0_FallEn1 (1<<4)
#define AR0_RiseEn2 (1<<5)
#define AR0_FallEn2 (1<<6)
#define AR0_HQSel (1<<7)
#define AR0_TRiseEn(port) (1<<(10+port))
#define AR0_TFallEn(port) (1<<(19+port))
#define AR1_Adj(chan, value) (((value) & 0xf) << (chan * 4))
#define AR2_GMode (1<<0)
#define AR2_IMode (1<<1)
#define AR2_RMode (1<<2)
#define AR2_Disable(chan) (1<<(3+chan))
#define AR2_Adj(chan, value) (((value)&0xf)<<(12+4*(chan-7)))
#define AR3_RaSpeed(num,val) (val << (num*2 + 21))
#define AR3_Zero (0) // nothing interesting for the Fine Delay
#define AR4_StartTimer(value) ((value) & 0xff)
#define AR4_Quiet (1<<8)
#define AR4_MMode (1<<9)
#define AR4_MasterReset (1<<22)
#define AR4_PartialReset (1<<23)
#define AR4_AluTrigSoft (1<<24)
#define AR4_EFlagHiZN (1<<25)
#define AR4_MTimerStart (1<<26)
#define AR4_MTimerStop (1<<27)
#define AR5_StartOff1(value) ((value)&0x3ffff)
#define AR5_StopDisStart (1<<21)
#define AR5_StartDisStart (1<<22)
#define AR5_MasterAluTrig (1<<23)
#define AR5_PartialAluTrig (1<<24)
#define AR5_MasterOenTrig (1<<25)
#define AR5_PartialOenTrig (1<<26)
#define AR5_StartRetrig (1<<27)
#define AR6_Fill(value) ((value)&0xff)
#define AR6_StartOff2(value) (((value)&0x3ffff)<<8)
#define AR6_InSelECL (1<<26)
#define AR6_PowerOnECL (1<<27)
#define AR7_HSDiv(value) ((value)&0xff)
#define AR7_RefClkDiv(value) (((value)&0x7)<<8)
#define AR7_ResAdj (1<<11)
#define AR7_NegPhase (1<<12)
#define AR7_Track (1<<13)
#define AR7_MTimer(value) (((value) & 0x1ff)<<15)
#define AR14_16BitMode (1<<4)
#define AR8I_IFIFO1(reg) ((reg) & 0x1ffff)
#define AR8I_Slope1(reg) ((reg) & (1<<17) ? 1 : 0)
#define AR8I_StartN1(reg) (((reg) >> 18) & 0xff)
#define AR8I_ChaCode1(reg) (((reg) >> 26) & 0x3)
#define AR9I_IFIFO2(reg) ((reg) & 0x1ffff)
#define AR9I_Slope2(reg) ((reg) & (1<<17) ? 1 : 0)
#define AR9I_StartN2(reg) (((reg) >> 18) & 0xff)
#define AR9I_ChaCode2(reg) (((reg) >> 26) & 0x3)
#define AR8R_IFIFO1(reg) ((reg) & 0x3fffff)
#define AR9R_IFIFO2(reg) ((reg) & 0x3fffff)
#define AR11_StopCounter0(num) ((num) & 0xff)
#define AR11_StopCounter1(num) (((num) & 0xff) << 8)
#define AR11_HFifoErrU(num) (1 << (num+16))
#define AR11_IFifoErrU(num) (1 << (num+24))
#define AR11_NotLockErrU (1 << 26)
#define AR12_HFifoE (1<<11)
#define AR12_NotLocked (1<<10)
#endif
/*
Register definitions for slave core: Fine Delay Channel WB Slave
* File : fd_channel_regs.h
* Author : auto-generated by wbgen2 from fd_channel_wishbone_slave.wb
* Created : Wed Apr 11 11:05:22 2012
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE fd_channel_wishbone_slave.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_FD_CHANNEL_WISHBONE_SLAVE_WB
#define __WBGEN2_REGDEFS_FD_CHANNEL_WISHBONE_SLAVE_WB
#include <inttypes.h>
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Delay Control Register */
/* definitions for field: Enable channel in reg: Delay Control Register */
#define FD_DCR_ENABLE WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Delay mode select in reg: Delay Control Register */
#define FD_DCR_MODE WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Pulse generator arm in reg: Delay Control Register */
#define FD_DCR_PG_ARM WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Pulse generator triggered in reg: Delay Control Register */
#define FD_DCR_PG_TRIG WBGEN2_GEN_MASK(3, 1)
/* definitions for field: Start Delay Update in reg: Delay Control Register */
#define FD_DCR_UPDATE WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Delay Update Done in reg: Delay Control Register */
#define FD_DCR_UPD_DONE WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Force Calibration Delay in reg: Delay Control Register */
#define FD_DCR_FORCE_DLY WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Disable Fine Part update in reg: Delay Control Register */
#define FD_DCR_NO_FINE WBGEN2_GEN_MASK(7, 1)
/* definitions for register: Fine Range Register */
/* definitions for register: Pulse start time / offset (MSB TAI seconds) */
/* definitions for register: Pulse start time / offset (LSB TAI seconds) */
/* definitions for register: Pulse start time / offset (8 ns cycles) */
/* definitions for register: Pulse start time / offset (sub-cycle fine part) */
/* definitions for register: Pulse end time / offset (MSB TAI seconds) */
/* definitions for register: Pulse end time / offset (LSB TAI seconds) */
/* definitions for register: Pulse end time / offset (8 ns cycles) */
/* definitions for register: Pulse end time / offset (sub-cycle fine part) */
/* definitions for register: Pulse spacing (TAI seconds) */
/* definitions for register: Pulse spacing (8 ns cycles) */
/* definitions for register: Pulse spacing (sub-cycle fine part) */
/* definitions for register: Repeat Count Register */
/* definitions for field: Repeat Count in reg: Repeat Count Register */
#define FD_RCR_REP_CNT_MASK WBGEN2_GEN_MASK(0, 16)
#define FD_RCR_REP_CNT_SHIFT 0
#define FD_RCR_REP_CNT_W(value) WBGEN2_GEN_WRITE(value, 0, 16)
#define FD_RCR_REP_CNT_R(reg) WBGEN2_GEN_READ(reg, 0, 16)
/* definitions for field: Continuous Waveform Mode in reg: Repeat Count Register */
#define FD_RCR_CONT WBGEN2_GEN_MASK(16, 1)
/* [0x0]: REG Delay Control Register */
#define FD_REG_DCR 0x00000000
/* [0x4]: REG Fine Range Register */
#define FD_REG_FRR 0x00000004
/* [0x8]: REG Pulse start time / offset (MSB TAI seconds) */
#define FD_REG_U_STARTH 0x00000008
/* [0xc]: REG Pulse start time / offset (LSB TAI seconds) */
#define FD_REG_U_STARTL 0x0000000c
/* [0x10]: REG Pulse start time / offset (8 ns cycles) */
#define FD_REG_C_START 0x00000010
/* [0x14]: REG Pulse start time / offset (sub-cycle fine part) */
#define FD_REG_F_START 0x00000014
/* [0x18]: REG Pulse end time / offset (MSB TAI seconds) */
#define FD_REG_U_ENDH 0x00000018
/* [0x1c]: REG Pulse end time / offset (LSB TAI seconds) */
#define FD_REG_U_ENDL 0x0000001c
/* [0x20]: REG Pulse end time / offset (8 ns cycles) */
#define FD_REG_C_END 0x00000020
/* [0x24]: REG Pulse end time / offset (sub-cycle fine part) */
#define FD_REG_F_END 0x00000024
/* [0x28]: REG Pulse spacing (TAI seconds) */
#define FD_REG_U_DELTA 0x00000028
/* [0x2c]: REG Pulse spacing (8 ns cycles) */
#define FD_REG_C_DELTA 0x0000002c
/* [0x30]: REG Pulse spacing (sub-cycle fine part) */
#define FD_REG_F_DELTA 0x00000030
/* [0x34]: REG Repeat Count Register */
#define FD_REG_RCR 0x00000034
#endif
/*
Register definitions for slave core: Fine Delay Main WB Slave
* File : fd_main_regs.h
* Author : auto-generated by wbgen2 from fd_main_wishbone_slave.wb
* Created : Wed Apr 11 11:05:22 2012
* Standard : ANSI C
THIS FILE WAS GENERATED BY wbgen2 FROM SOURCE FILE fd_main_wishbone_slave.wb
DO NOT HAND-EDIT UNLESS IT'S ABSOLUTELY NECESSARY!
*/
#ifndef __WBGEN2_REGDEFS_FD_MAIN_WISHBONE_SLAVE_WB
#define __WBGEN2_REGDEFS_FD_MAIN_WISHBONE_SLAVE_WB
#include <inttypes.h>
#if defined( __GNUC__)
#define PACKED __attribute__ ((packed))
#else
#error "Unsupported compiler?"
#endif
#ifndef __WBGEN2_MACROS_DEFINED__
#define __WBGEN2_MACROS_DEFINED__
#define WBGEN2_GEN_MASK(offset, size) (((1<<(size))-1) << (offset))
#define WBGEN2_GEN_WRITE(value, offset, size) (((value) & ((1<<(size))-1)) << (offset))
#define WBGEN2_GEN_READ(reg, offset, size) (((reg) >> (offset)) & ((1<<(size))-1))
#define WBGEN2_SIGN_EXTEND(value, bits) (((value) & (1<<bits) ? ~((1<<(bits))-1): 0 ) | (value))
#endif
/* definitions for register: Reset Register */
/* definitions for field: State of the reset Line of the FMC Card in reg: Reset Register */
#define FD_RSTR_RST_FMC_MASK WBGEN2_GEN_MASK(0, 1)
#define FD_RSTR_RST_FMC_SHIFT 0
#define FD_RSTR_RST_FMC_W(value) WBGEN2_GEN_WRITE(value, 0, 1)
#define FD_RSTR_RST_FMC_R(reg) WBGEN2_GEN_READ(reg, 0, 1)
/* definitions for field: State of the reset of the Fine Delay HDL Core in reg: Reset Register */
#define FD_RSTR_RST_CORE_MASK WBGEN2_GEN_MASK(1, 1)
#define FD_RSTR_RST_CORE_SHIFT 1
#define FD_RSTR_RST_CORE_W(value) WBGEN2_GEN_WRITE(value, 1, 1)
#define FD_RSTR_RST_CORE_R(reg) WBGEN2_GEN_READ(reg, 1, 1)
/* definitions for field: Reset magic value in reg: Reset Register */
#define FD_RSTR_LOCK_MASK WBGEN2_GEN_MASK(16, 16)
#define FD_RSTR_LOCK_SHIFT 16
#define FD_RSTR_LOCK_W(value) WBGEN2_GEN_WRITE(value, 16, 16)
#define FD_RSTR_LOCK_R(reg) WBGEN2_GEN_READ(reg, 16, 16)
/* definitions for register: ID Register */
/* definitions for register: Global Control Register */
/* definitions for field: Bypass Hardware TDC/Delay Controller in reg: Global Control Register */
#define FD_GCR_BYPASS WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Enable trigger input in reg: Global Control Register */
#define FD_GCR_INPUT_EN WBGEN2_GEN_MASK(1, 1)
/* definitions for field: PLL Locked in reg: Global Control Register */
#define FD_GCR_DDR_LOCKED WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Mezzanice Present in reg: Global Control Register */
#define FD_GCR_FMC_PRESENT WBGEN2_GEN_MASK(3, 1)
/* definitions for register: Timing Control Register */
/* definitions for field: DMTD Clock Status in reg: Timing Control Register */
#define FD_TCR_DMTD_STAT WBGEN2_GEN_MASK(0, 1)
/* definitions for field: WR Timing Enable in reg: Timing Control Register */
#define FD_TCR_WR_ENABLE WBGEN2_GEN_MASK(1, 1)
/* definitions for field: WR Timing Locked in reg: Timing Control Register */
#define FD_TCR_WR_LOCKED WBGEN2_GEN_MASK(2, 1)
/* definitions for field: WR Core Present in reg: Timing Control Register */
#define FD_TCR_WR_PRESENT WBGEN2_GEN_MASK(3, 1)
/* definitions for field: WR Core Time Ready in reg: Timing Control Register */
#define FD_TCR_WR_READY WBGEN2_GEN_MASK(4, 1)
/* definitions for field: WR Core Link Up in reg: Timing Control Register */
#define FD_TCR_WR_LINK WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Capture Current Time in reg: Timing Control Register */
#define FD_TCR_CAP_TIME WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Set Current Time in reg: Timing Control Register */
#define FD_TCR_SET_TIME WBGEN2_GEN_MASK(7, 1)
/* definitions for register: Time Register - TAI seconds (MSB) */
/* definitions for register: Time Register - TAI seconds (LSB) */
/* definitions for register: Time Register - sub-second 125 MHz clock cycles */
/* definitions for register: TDC Data Register */
/* definitions for register: TDC control/status reg */
/* definitions for field: Start TDC write in reg: TDC control/status reg */
#define FD_TDCSR_WRITE WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Start TDC read in reg: TDC control/status reg */
#define FD_TDCSR_READ WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Empty flag in reg: TDC control/status reg */
#define FD_TDCSR_EMPTY WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Start enable in reg: TDC control/status reg */
#define FD_TDCSR_STOP_EN WBGEN2_GEN_MASK(3, 1)
/* definitions for field: Start disable in reg: TDC control/status reg */
#define FD_TDCSR_START_DIS WBGEN2_GEN_MASK(4, 1)
/* definitions for field: Stop enable in reg: TDC control/status reg */
#define FD_TDCSR_START_EN WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Stop disable in reg: TDC control/status reg */
#define FD_TDCSR_STOP_DIS WBGEN2_GEN_MASK(6, 1)
/* definitions for field: write 1: Pulse the Alutrigger line in reg: TDC control/status reg */
#define FD_TDCSR_ALUTRIG WBGEN2_GEN_MASK(7, 1)
/* definitions for register: Calibration register */
/* definitions for field: Triggers calibration pulses in reg: Calibration register */
#define FD_CALR_CAL_PULSE WBGEN2_GEN_MASK(0, 1)
/* definitions for field: PPS Calibration output enable in reg: Calibration register */
#define FD_CALR_CAL_PPS WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Triggers calibration pulses in reg: Calibration register */
#define FD_CALR_CAL_DMTD WBGEN2_GEN_MASK(2, 1)
/* definitions for field: Enable pulse generation in reg: Calibration register */
#define FD_CALR_PSEL_MASK WBGEN2_GEN_MASK(3, 4)
#define FD_CALR_PSEL_SHIFT 3
#define FD_CALR_PSEL_W(value) WBGEN2_GEN_WRITE(value, 3, 4)
#define FD_CALR_PSEL_R(reg) WBGEN2_GEN_READ(reg, 3, 4)
/* definitions for field: DMTD Feedback Channel Select in reg: Calibration register */
#define FD_CALR_DMTD_FBSEL WBGEN2_GEN_MASK(7, 1)
/* definitions for field: DMTD Tag in reg: Calibration register */
#define FD_CALR_DMTD_TAG_MASK WBGEN2_GEN_MASK(8, 23)
#define FD_CALR_DMTD_TAG_SHIFT 8
#define FD_CALR_DMTD_TAG_W(value) WBGEN2_GEN_WRITE(value, 8, 23)
#define FD_CALR_DMTD_TAG_R(reg) WBGEN2_GEN_READ(reg, 8, 23)
/* definitions for field: DMTD Tag Ready in reg: Calibration register */
#define FD_CALR_DMTD_TAG_RDY WBGEN2_GEN_MASK(31, 1)
/* definitions for register: Softpll Register */
/* definitions for field: Frequency/Phase tag in reg: Softpll Register */
#define FD_SPLLR_TAG_MASK WBGEN2_GEN_MASK(0, 20)
#define FD_SPLLR_TAG_SHIFT 0
#define FD_SPLLR_TAG_W(value) WBGEN2_GEN_WRITE(value, 0, 20)
#define FD_SPLLR_TAG_R(reg) WBGEN2_GEN_READ(reg, 0, 20)
/* definitions for field: Tag Ready in reg: Softpll Register */
#define FD_SPLLR_TAG_RDY WBGEN2_GEN_MASK(20, 1)
/* definitions for field: Freq/Phase mode select in reg: Softpll Register */
#define FD_SPLLR_MODE WBGEN2_GEN_MASK(21, 1)
/* definitions for register: Softpll DAC Register */
/* definitions for field: DAC Value in reg: Softpll DAC Register */
#define FD_SDACR_DAC_VAL_MASK WBGEN2_GEN_MASK(0, 16)
#define FD_SDACR_DAC_VAL_SHIFT 0
#define FD_SDACR_DAC_VAL_W(value) WBGEN2_GEN_WRITE(value, 0, 16)
#define FD_SDACR_DAC_VAL_R(reg) WBGEN2_GEN_READ(reg, 0, 16)
/* definitions for register: Acam to Delay line fractional part Scale Factor Register */
/* definitions for register: Acam Timestamp Merging Control Register */
/* definitions for field: Wraparound Coarse Threshold in reg: Acam Timestamp Merging Control Register */
#define FD_ATMCR_C_THR_MASK WBGEN2_GEN_MASK(0, 4)
#define FD_ATMCR_C_THR_SHIFT 0
#define FD_ATMCR_C_THR_W(value) WBGEN2_GEN_WRITE(value, 0, 4)
#define FD_ATMCR_C_THR_R(reg) WBGEN2_GEN_READ(reg, 0, 4)
/* definitions for field: Wraparound Fine Threshold in reg: Acam Timestamp Merging Control Register */
#define FD_ATMCR_F_THR_MASK WBGEN2_GEN_MASK(4, 23)
#define FD_ATMCR_F_THR_SHIFT 4
#define FD_ATMCR_F_THR_W(value) WBGEN2_GEN_WRITE(value, 4, 23)
#define FD_ATMCR_F_THR_R(reg) WBGEN2_GEN_READ(reg, 4, 23)
/* definitions for register: Acam Start Offset Register */
/* definitions for field: Start Offset in reg: Acam Start Offset Register */
#define FD_ASOR_OFFSET_MASK WBGEN2_GEN_MASK(0, 23)
#define FD_ASOR_OFFSET_SHIFT 0
#define FD_ASOR_OFFSET_W(value) WBGEN2_GEN_WRITE(value, 0, 23)
#define FD_ASOR_OFFSET_R(reg) WBGEN2_GEN_READ(reg, 0, 23)
/* definitions for register: Raw Input Events Counter Register */
/* definitions for register: Tagged Input Events Counter Register */
/* definitions for register: Input Event Processing Delay Register */
/* definitions for field: Reset stats in reg: Input Event Processing Delay Register */
#define FD_IEPD_RST_STAT WBGEN2_GEN_MASK(0, 1)
/* definitions for field: Processing delay in reg: Input Event Processing Delay Register */
#define FD_IEPD_PDELAY_MASK WBGEN2_GEN_MASK(1, 8)
#define FD_IEPD_PDELAY_SHIFT 1
#define FD_IEPD_PDELAY_W(value) WBGEN2_GEN_WRITE(value, 1, 8)
#define FD_IEPD_PDELAY_R(reg) WBGEN2_GEN_READ(reg, 1, 8)
/* definitions for register: SPI Control Register */
/* definitions for field: Data in reg: SPI Control Register */
#define FD_SCR_DATA_MASK WBGEN2_GEN_MASK(0, 24)
#define FD_SCR_DATA_SHIFT 0
#define FD_SCR_DATA_W(value) WBGEN2_GEN_WRITE(value, 0, 24)
#define FD_SCR_DATA_R(reg) WBGEN2_GEN_READ(reg, 0, 24)
/* definitions for field: Select DAC in reg: SPI Control Register */
#define FD_SCR_SEL_DAC WBGEN2_GEN_MASK(24, 1)
/* definitions for field: Select PLL in reg: SPI Control Register */
#define FD_SCR_SEL_PLL WBGEN2_GEN_MASK(25, 1)
/* definitions for field: Select GPIO in reg: SPI Control Register */
#define FD_SCR_SEL_GPIO WBGEN2_GEN_MASK(26, 1)
/* definitions for field: Ready flag in reg: SPI Control Register */
#define FD_SCR_READY WBGEN2_GEN_MASK(27, 1)
/* definitions for field: Clock Polarity in reg: SPI Control Register */
#define FD_SCR_CPOL WBGEN2_GEN_MASK(28, 1)
/* definitions for field: Transfer Start in reg: SPI Control Register */
#define FD_SCR_START WBGEN2_GEN_MASK(29, 1)
/* definitions for register: Reference Clock Rate Register */
/* definitions for register: Timestamp Buffer Control Register */
/* definitions for field: Channel Mask in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_CHAN_MASK_MASK WBGEN2_GEN_MASK(0, 5)
#define FD_TSBCR_CHAN_MASK_SHIFT 0
#define FD_TSBCR_CHAN_MASK_W(value) WBGEN2_GEN_WRITE(value, 0, 5)
#define FD_TSBCR_CHAN_MASK_R(reg) WBGEN2_GEN_READ(reg, 0, 5)
/* definitions for field: Buffer enable in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_ENABLE WBGEN2_GEN_MASK(5, 1)
/* definitions for field: Buffer purge in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_PURGE WBGEN2_GEN_MASK(6, 1)
/* definitions for field: Reset TS Sequence Numbers in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_RST_SEQ WBGEN2_GEN_MASK(7, 1)
/* definitions for field: Buffer full in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_FULL WBGEN2_GEN_MASK(8, 1)
/* definitions for field: Buffer empty in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_EMPTY WBGEN2_GEN_MASK(9, 1)
/* definitions for field: Buffer entries count in reg: Timestamp Buffer Control Register */
#define FD_TSBCR_COUNT_MASK WBGEN2_GEN_MASK(10, 12)
#define FD_TSBCR_COUNT_SHIFT 10
#define FD_TSBCR_COUNT_W(value) WBGEN2_GEN_WRITE(value, 10, 12)
#define FD_TSBCR_COUNT_R(reg) WBGEN2_GEN_READ(reg, 10, 12)
/* definitions for register: Timestamp Buffer Interrupt Register */
/* definitions for field: IRQ timeout [milliseconds] in reg: Timestamp Buffer Interrupt Register */
#define FD_TSBIR_TIMEOUT_MASK WBGEN2_GEN_MASK(0, 10)
#define FD_TSBIR_TIMEOUT_SHIFT 0
#define FD_TSBIR_TIMEOUT_W(value) WBGEN2_GEN_WRITE(value, 0, 10)
#define FD_TSBIR_TIMEOUT_R(reg) WBGEN2_GEN_READ(reg, 0, 10)
/* definitions for field: Interrupt threshold in reg: Timestamp Buffer Interrupt Register */
#define FD_TSBIR_THRESHOLD_MASK WBGEN2_GEN_MASK(10, 12)
#define FD_TSBIR_THRESHOLD_SHIFT 10
#define FD_TSBIR_THRESHOLD_W(value) WBGEN2_GEN_WRITE(value, 10, 12)
#define FD_TSBIR_THRESHOLD_R(reg) WBGEN2_GEN_READ(reg, 10, 12)
/* definitions for register: Timestamp Buffer Readout Seconds Register (MSB) */
/* definitions for register: Timestamp Buffer Readout Seconds Register (LSB) */
/* definitions for register: Timestamp Buffer Readout Cycles Register */
/* definitions for register: Timestamp Buffer Readout Fine / Channel / Seq ID Register */
/* definitions for field: Channel ID in reg: Timestamp Buffer Readout Fine / Channel / Seq ID Register */
#define FD_TSBR_FID_CHANNEL_MASK WBGEN2_GEN_MASK(0, 4)
#define FD_TSBR_FID_CHANNEL_SHIFT 0
#define FD_TSBR_FID_CHANNEL_W(value) WBGEN2_GEN_WRITE(value, 0, 4)
#define FD_TSBR_FID_CHANNEL_R(reg) WBGEN2_GEN_READ(reg, 0, 4)
/* definitions for field: Fine Value [in phase units] in reg: Timestamp Buffer Readout Fine / Channel / Seq ID Register */
#define FD_TSBR_FID_FINE_MASK WBGEN2_GEN_MASK(4, 12)
#define FD_TSBR_FID_FINE_SHIFT 4
#define FD_TSBR_FID_FINE_W(value) WBGEN2_GEN_WRITE(value, 4, 12)
#define FD_TSBR_FID_FINE_R(reg) WBGEN2_GEN_READ(reg, 4, 12)
/* definitions for field: Timestamp Sequence ID in reg: Timestamp Buffer Readout Fine / Channel / Seq ID Register */
#define FD_TSBR_FID_SEQID_MASK WBGEN2_GEN_MASK(16, 16)
#define FD_TSBR_FID_SEQID_SHIFT 16
#define FD_TSBR_FID_SEQID_W(value) WBGEN2_GEN_WRITE(value, 16, 16)
#define FD_TSBR_FID_SEQID_R(reg) WBGEN2_GEN_READ(reg, 16, 16)
/* definitions for register: I2C bitbanged IO register */
/* definitions for field: SCL Line out in reg: I2C bitbanged IO register */
#define FD_I2CR_SCL_OUT WBGEN2_GEN_MASK(0, 1)
/* definitions for field: SDA Line out in reg: I2C bitbanged IO register */
#define FD_I2CR_SDA_OUT WBGEN2_GEN_MASK(1, 1)
/* definitions for field: SCL Line in in reg: I2C bitbanged IO register */
#define FD_I2CR_SCL_IN WBGEN2_GEN_MASK(2, 1)
/* definitions for field: SDA Line in in reg: I2C bitbanged IO register */
#define FD_I2CR_SDA_IN WBGEN2_GEN_MASK(3, 1)
/* definitions for register: Test/Debug register 1 */
/* definitions for field: VCXO Frequency in reg: Test/Debug register 1 */
#define FD_TDER1_VCXO_FREQ_MASK WBGEN2_GEN_MASK(0, 32)
#define FD_TDER1_VCXO_FREQ_SHIFT 0
#define FD_TDER1_VCXO_FREQ_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define FD_TDER1_VCXO_FREQ_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: Test/Debug register 1 */
/* definitions for field: Peltier PWM drive in reg: Test/Debug register 1 */
#define FD_TDER2_PELT_DRIVE_MASK WBGEN2_GEN_MASK(0, 32)
#define FD_TDER2_PELT_DRIVE_SHIFT 0
#define FD_TDER2_PELT_DRIVE_W(value) WBGEN2_GEN_WRITE(value, 0, 32)
#define FD_TDER2_PELT_DRIVE_R(reg) WBGEN2_GEN_READ(reg, 0, 32)
/* definitions for register: Interrupt disable register */
/* definitions for field: TS Buffer not empty. in reg: Interrupt disable register */
#define FD_EIC_IDR_TS_BUF_NOTEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for field: DMTD Softpll interrupt in reg: Interrupt disable register */
#define FD_EIC_IDR_DMTD_SPLL WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Sync Status Changed in reg: Interrupt disable register */
#define FD_EIC_IDR_SYNC_STATUS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: Interrupt enable register */
/* definitions for field: TS Buffer not empty. in reg: Interrupt enable register */
#define FD_EIC_IER_TS_BUF_NOTEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for field: DMTD Softpll interrupt in reg: Interrupt enable register */
#define FD_EIC_IER_DMTD_SPLL WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Sync Status Changed in reg: Interrupt enable register */
#define FD_EIC_IER_SYNC_STATUS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: Interrupt mask register */
/* definitions for field: TS Buffer not empty. in reg: Interrupt mask register */
#define FD_EIC_IMR_TS_BUF_NOTEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for field: DMTD Softpll interrupt in reg: Interrupt mask register */
#define FD_EIC_IMR_DMTD_SPLL WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Sync Status Changed in reg: Interrupt mask register */
#define FD_EIC_IMR_SYNC_STATUS WBGEN2_GEN_MASK(2, 1)
/* definitions for register: Interrupt status register */
/* definitions for field: TS Buffer not empty. in reg: Interrupt status register */
#define FD_EIC_ISR_TS_BUF_NOTEMPTY WBGEN2_GEN_MASK(0, 1)
/* definitions for field: DMTD Softpll interrupt in reg: Interrupt status register */
#define FD_EIC_ISR_DMTD_SPLL WBGEN2_GEN_MASK(1, 1)
/* definitions for field: Sync Status Changed in reg: Interrupt status register */
#define FD_EIC_ISR_SYNC_STATUS WBGEN2_GEN_MASK(2, 1)
/* [0x0]: REG Reset Register */
#define FD_REG_RSTR 0x00000000
/* [0x4]: REG ID Register */
#define FD_REG_IDR 0x00000004
/* [0x8]: REG Global Control Register */
#define FD_REG_GCR 0x00000008
/* [0xc]: REG Timing Control Register */
#define FD_REG_TCR 0x0000000c
/* [0x10]: REG Time Register - TAI seconds (MSB) */
#define FD_REG_TM_SECH 0x00000010
/* [0x14]: REG Time Register - TAI seconds (LSB) */
#define FD_REG_TM_SECL 0x00000014
/* [0x18]: REG Time Register - sub-second 125 MHz clock cycles */
#define FD_REG_TM_CYCLES 0x00000018
/* [0x1c]: REG TDC Data Register */
#define FD_REG_TDR 0x0000001c
/* [0x20]: REG TDC control/status reg */
#define FD_REG_TDCSR 0x00000020
/* [0x24]: REG Calibration register */
#define FD_REG_CALR 0x00000024
/* [0x28]: REG Softpll Register */
#define FD_REG_SPLLR 0x00000028
/* [0x2c]: REG Softpll DAC Register */
#define FD_REG_SDACR 0x0000002c
/* [0x30]: REG Acam to Delay line fractional part Scale Factor Register */
#define FD_REG_ADSFR 0x00000030
/* [0x34]: REG Acam Timestamp Merging Control Register */
#define FD_REG_ATMCR 0x00000034
/* [0x38]: REG Acam Start Offset Register */
#define FD_REG_ASOR 0x00000038
/* [0x3c]: REG Raw Input Events Counter Register */
#define FD_REG_IECRAW 0x0000003c
/* [0x40]: REG Tagged Input Events Counter Register */
#define FD_REG_IECTAG 0x00000040
/* [0x44]: REG Input Event Processing Delay Register */
#define FD_REG_IEPD 0x00000044
/* [0x48]: REG SPI Control Register */
#define FD_REG_SCR 0x00000048
/* [0x4c]: REG Reference Clock Rate Register */
#define FD_REG_RCRR 0x0000004c
/* [0x50]: REG Timestamp Buffer Control Register */
#define FD_REG_TSBCR 0x00000050
/* [0x54]: REG Timestamp Buffer Interrupt Register */
#define FD_REG_TSBIR 0x00000054
/* [0x58]: REG Timestamp Buffer Readout Seconds Register (MSB) */
#define FD_REG_TSBR_SECH 0x00000058
/* [0x5c]: REG Timestamp Buffer Readout Seconds Register (LSB) */
#define FD_REG_TSBR_SECL 0x0000005c
/* [0x60]: REG Timestamp Buffer Readout Cycles Register */
#define FD_REG_TSBR_CYCLES 0x00000060
/* [0x64]: REG Timestamp Buffer Readout Fine / Channel / Seq ID Register */
#define FD_REG_TSBR_FID 0x00000064
/* [0x68]: REG I2C bitbanged IO register */
#define FD_REG_I2CR 0x00000068
/* [0x6c]: REG Test/Debug register 1 */
#define FD_REG_TDER1 0x0000006c
/* [0x70]: REG Test/Debug register 1 */
#define FD_REG_TDER2 0x00000070
/* [0x80]: REG Interrupt disable register */
#define FD_REG_EIC_IDR 0x00000080
/* [0x84]: REG Interrupt enable register */
#define FD_REG_EIC_IER 0x00000084
/* [0x88]: REG Interrupt mask register */
#define FD_REG_EIC_IMR 0x00000088
/* [0x8c]: REG Interrupt status register */
#define FD_REG_EIC_ISR 0x0000008c
#endif
#ifndef __FD_LIB_H
#define __FD_LIB_H
#include <stdint.h>
/* Number of fractional bits in the timestamps/time definitions. Must be consistent with the HDL bitstream. */
#define FDELAY_FRAC_BITS 12
/* fdelay_get_timing_status() return values: */
#define FDELAY_FREE_RUNNING 0x10 /* attached WR core is offline */
#define FDELAY_WR_OFFLINE 0x8 /* attached WR core is offline */
#define FDELAY_WR_READY 0x1 /* attached WR core is synchronized, we can sync the fine delay core anytime */
#define FDELAY_WR_SYNCING 0x2 /* local oscillator is being synchronized with WR clock */
#define FDELAY_WR_SYNCED 0x4 /* we are synced. */
/* fdelay_configure_sync() flags */
#define FDELAY_SYNC_LOCAL 0x1 /* use local oscillator */
#define FDELAY_SYNC_WR 0x2 /* use White Rabbit */
/* Hardware "handle" structure */
typedef struct fdelay_device
{
/* Base address of the FD core */
uint32_t base_addr;
/* Bus-specific readl/writel functions - so the same library can be used both with
RawRabbit, VME and Etherbone backends */
void (*writel)(void *priv, uint32_t data, uint32_t addr);
uint32_t (*readl)(void *priv, uint32_t addr);
void *priv_fd; /* pointer to Fine Delay library private data */
void *priv_io; /* pointer to the I/O routines private data */
} fdelay_device_t;
typedef struct
{
int64_t utc;
int32_t coarse;
int32_t frac;
uint16_t seq_id;
int channel;
} fdelay_time_t;
/*
--------------------
PUBLIC API
--------------------
*/
fdelay_device_t *fdelay_create_rawrabbit(int fd, uint32_t base_addr);
fdelay_device_t *fdelay_create_minibone(char *iface, char *mac_addr, uint32_t base_addr);
fdelay_time_t fdelay_from_picos(const uint64_t ps);
int64_t fdelay_to_picos(const fdelay_time_t t);
int fdelay_init(fdelay_device_t *dev);
int fdelay_release(fdelay_device_t *dev);
int fdelay_read(fdelay_device_t *dev, fdelay_time_t *timestamps, int how_many);
int fdelay_configure_trigger(fdelay_device_t *dev, int enable, int termination);
int fdelay_configure_output(fdelay_device_t *dev, int channel, int enable, int64_t delay_ps, int64_t width_ps, int64_t delta_ps, int rep_count);
int fdelay_configure_sync(fdelay_device_t *dev, int mode);
int fdelay_update_sync_status(fdelay_device_t *dev);
int fdelay_set_time(fdelay_device_t *dev, const fdelay_time_t t);
int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel, int enable, fdelay_time_t t_start, int64_t width_ps, int64_t delta_ps, int rep_count);
int fdelay_channel_triggered(fdelay_device_t *dev, int channel);
int fdelay_get_time(fdelay_device_t *dev, fdelay_time_t *t);
#endif
/*
FmcDelay1ns4Cha (a.k.a. The Fine Delay Card)
User-space driver/library
Private includes
Tomasz Włostowski/BE-CO-HT, 2011
(c) Copyright CERN 2011
Licensed under LGPL 2.1
*/
#ifndef __FDELAY_PRIVATE_H
#define __FDELAY_PRIVATE_H
#include <stdint.h>
/* SPI Bus chip selects */
#define CS_DAC 0 /* AD9516 PLL */
#define CS_PLL 1 /* AD9516 PLL */
#define CS_GPIO 2 /* MCP23S17 GPIO */
/* MCP23S17 GPIO expander pin locations: bit 8 = select bank 2, bits 7..0 = mask of the pin in the selected bank */
#define SGPIO_TERM_EN (1<<0) /* Input termination enable (1 = on) */
#define SGPIO_OUTPUT_EN(x) (1<<(6-x)) /* Output driver enable (1 = on) */
#define SGPIO_TRIG_SEL (1<<6) /* TDC trigger select (0 = trigger input, 1 = FPGA) */
#define SGPIO_CAL_EN (1<<7) /* Calibration mode enable (0 = on) */
/* ACAM TDC operation modes */
#define ACAM_RMODE 0
#define ACAM_IMODE 1
/* MCP23S17 register addresses (only ones which are used by the lib) */
#define MCP_IODIR 0x0
#define MCP_IPOL 0x1
#define MCP_OLAT 0x14
#define MCP_IOCON 0x0a
#define MCP_GPIO 0x12
/* Number of fractional bits in the timestamps/time definitions. Must be consistent with the HDL bitstream. */
#define FDELAY_FRAC_BITS 12
/* Fractional bits shifted away when converting the fine (< 8ns) part to fit the range of SY89295 delay line. */
#define FDELAY_SCALER_SHIFT 12
/* Number of delay line taps */
#define FDELAY_NUM_TAPS 1024
/* How many times each calibration measurement will be averaged */
#define FDELAY_CAL_AVG_STEPS 1024
/* Fine Delay Card Magic ID */
#define FDELAY_MAGIC_ID 0xf19ede1a
/* RSTR Register value which triggers a reset of the FD Core */
#define FDELAY_RSTR_TRIGGER 0xdeadbeef
/* Calibration eeprom I2C address */
#define EEPROM_ADDR 0x50
/* ACAM Calibration parameters */
struct fine_delay_calibration {
uint32_t magic; /* magic ID: 0xf19ede1a */
uint32_t zero_offset[4]; /* Output zero offset, in nsec << FDELAY_FRAC_BITS */
uint32_t adsfr_val; /* ADSFR register value */
uint32_t acam_start_offset; /* ACAM Start offset value */
uint32_t atmcr_val; /* ATMCR register value */
uint32_t tdc_zero_offset; /* Zero offset of the TDC, in picoseconds */
int64_t frr_poly[3]; /* SY89295 delay/temperature polynomial coefficients */
} __attribute__((packed));
/* Internal state of the fine delay card */
struct fine_delay_hw
{
uint32_t base_addr; /* Base address of the core */
uint32_t base_onewire; /* Base address of the core */
uint32_t base_i2c; /* SPI Controller offset */
uint32_t acam_addr; /* Current state of ACAM's address lines */
double acam_bin; /* bin size of the ACAM TDC - calculated for 31.25 MHz reference */
uint32_t frr_offset[4]; /* Offset between the FRR measured at a known temperature at startup and poly-fitted FRR */
uint32_t frr_cur[4]; /* Fine range register for each output, current value (after online temp. compensation) */
int32_t cal_temp; /* SY89295 calibration temperature in 1/16 degC units */
int32_t board_temp; /* Current temperature of the board, unit = 1/16 degC */
int wr_enabled;
int wr_state;
struct fine_delay_calibration calib;
};
/* some useful access/declaration macros */
#define fd_writel(data, addr) dev->writel(dev->priv_io, data, (hw->base_addr + (addr)))
#define fd_readl(addr) dev->readl(dev->priv_io, (hw->base_addr + (addr)))
#define fd_decl_private(dev) struct fine_delay_hw *hw = (struct fine_delay_hw *) dev->priv_fd;
#endif
#ifndef __I2C_MASTER_H
#define __I2C_MASTER_H
#include <stdint.h>
#include "fdelay_lib.h"
void mi2c_init(fdelay_device_t *dev);
int eeprom_read(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size);
int eeprom_write(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size);
#endif
#ifndef ONEWIRE_H_INCLUDED
#define ONEWIRE_H_INCLUDED
#include "fdelay_lib.h"
int ds18x_init(fdelay_device_t *dev);
int ds18x_read_temp(fdelay_device_t *dev, int *temp_r);
#endif // ONEWIRE_H_INCLUDED
const struct {int reg; uint8_t val; } ad9516_regs[] = {
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x05},
{0x0012, 0x00},
{0x0013, 0x0C},
{0x0014, 0x12},
{0x0015, 0x00},
{0x0016, 0x05},
{0x0017, 0xb4}, /* PLL_STATUS = Lock Detect */
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0xE0},
{0x001C, 0x02},
{0x001D, 0x00},
{0x001E, 0x00},
{0x001F, 0x0E},
{0x00A0, 0x01},
{0x00A1, 0x00},
{0x00A2, 0x00},
{0x00A3, 0x01},
{0x00A4, 0x00},
{0x00A5, 0x00},
{0x00A6, 0x01},
{0x00A7, 0x00},
{0x00A8, 0x00},
{0x00A9, 0x01},
{0x00AA, 0x00},
{0x00AB, 0x00},
{0x00F0, 0x08},
{0x00F1, 0x08},
{0x00F2, 0x08},
{0x00F3, 0x18}, /* out3 inverted */
{0x00F4, 0x00},
{0x00F5, 0x08},
{0x0140, 0x5A},
{0x0141, 0x5A},
{0x0142, 0x5B},
{0x0143, 0x42},
{0x0190, 0x00},
{0x0191, 0x80},
{0x0192, 0x00},
{0x0193, 0x00},
{0x0194, 0x80},
{0x0195, 0x00},
{0x0196, 0xFF},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x33},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x20},
{0x019D, 0x00},
{0x019E, 0x00},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x20},
{0x01A2, 0x00},
{0x01A3, 0x00},
{0x01E0, 0x04}, /* VCODIV = 6 */
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
{0x0232, 0x00},
{-1, 0}};
/*
* Public header for the raw I/O interface for PCI or PCI express interfaces
*
* Copyright (C) 2010 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __RAWRABBIT_H__
#define __RAWRABBIT_H__
#include <linux/types.h>
#include <linux/ioctl.h>
#ifdef __KERNEL__ /* The initial part of the file is driver-internal stuff */
#include <linux/pci.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
#include <linux/wait.h>
#include <linux/completion.h>
struct rr_devsel;
struct rr_dev {
struct rr_devsel *devsel;
struct pci_driver *pci_driver;
struct pci_device_id *id_table;
struct pci_dev *pdev; /* non-null after pciprobe */
struct mutex mutex;
wait_queue_head_t q;
void *dmabuf;
char *fwname;
struct timespec irqtime;
unsigned long irqcount;
struct completion complete;
struct resource *area[3]; /* bar 0, 2, 4 */
void *remap[3]; /* ioremap of bar 0, 2, 4 */
unsigned long flags;
struct work_struct work;
const struct firmware *fw;
struct completion fw_load;
void (*load_program)(struct rr_dev *); /* lm32 */
int usecount;
#ifdef IS_SPEC_DEMO
struct miscdevice misc;
char miscname[32]; /* "spec-demo-<bus>-<slot> */
struct list_head list;
#endif
};
extern char *rr_fwname; /* module parameter. If "" then defaults apply */
#define RR_FLAG_REGISTERED 0x00000001
#define RR_FLAG_IRQDISABLE 0x00000002
#define RR_FLAG_IRQREQUEST 0x00000002
#define RR_PROBE_TIMEOUT (HZ) /* for pci_register_drv */
/* These two live in ./loader.c */
extern void rr_ask_firmware(struct rr_dev *dev);
extern void rr_load_firmware(struct work_struct *work);
/* And, for the spec only, this is in ./spec-loader.c */
extern void spec_ask_program(struct rr_dev *dev);
#endif /* __KERNEL__ */
/* By default, the driver registers for this vendor/devid */
#define RR_DEFAULT_VENDOR 0x1a39
#define RR_DEFAULT_DEVICE 0x0004
#define RR_DEFAULT_FWNAME "rrabbit-%P-%p@%b"
#define RR_MAX_FWNAME_SIZE 64
#define RR_DEFAULT_BUFSIZE (1<<20) /* 1MB */
#define RR_PLIST_SIZE 4096 /* no PAGE_SIZE in user space */
#define RR_PLIST_LEN (RR_PLIST_SIZE / sizeof(void *))
#define RR_MAX_BUFSIZE (RR_PLIST_SIZE * RR_PLIST_LEN)
/* This structure is used to select the device to be accessed, via ioctl */
struct rr_devsel {
__u16 vendor;
__u16 device;
__u16 subvendor; /* RR_DEVSEL_UNUSED to ignore subvendor/dev */
__u16 subdevice;
__u16 bus; /* RR_DEVSEL_UNUSED to ignore bus and devfn */
__u16 devfn;
};
#define RR_DEVSEL_UNUSED 0xffff
/* Offsets for BAR areas in llseek() and/or ioctl */
#define RR_BAR_0 0x00000000
#define RR_BAR_2 0x20000000
#define RR_BAR_4 0x40000000
#define RR_BAR_BUF 0xc0000000 /* The DMA buffer */
#define RR_IS_DMABUF(addr) ((addr) >= RR_BAR_BUF)
#define __RR_GET_BAR(x) ((x) >> 28)
#define __RR_SET_BAR(x) ((x) << 28)
#define __RR_GET_OFF(x) ((x) & 0x0fffffff)
static inline int rr_is_valid_bar(unsigned long address)
{
int bar = __RR_GET_BAR(address);
return bar == 0 || bar == 2 || bar == 4 || bar == 0x0c;
}
static inline int rr_is_dmabuf_bar(unsigned long address)
{
int bar = __RR_GET_BAR(address);
return bar == 0x0c;
}
struct rr_iocmd {
__u32 address; /* bar and offset */
__u32 datasize; /* 1 or 2 or 4 or 8 */
union {
__u8 data8;
__u16 data16;
__u32 data32;
__u64 data64;
};
};
/* ioctl commands */
#define __RR_IOC_MAGIC '4' /* random or so */
#define RR_DEVSEL _IOW(__RR_IOC_MAGIC, 0, struct rr_devsel)
#define RR_DEVGET _IOR(__RR_IOC_MAGIC, 1, struct rr_devsel)
#define RR_READ _IOWR(__RR_IOC_MAGIC, 2, struct rr_iocmd)
#define RR_WRITE _IOW(__RR_IOC_MAGIC, 3, struct rr_iocmd)
#define RR_IRQWAIT _IO(__RR_IOC_MAGIC, 4)
#define RR_IRQENA _IO(__RR_IOC_MAGIC, 5)
#define RR_GETDMASIZE _IO(__RR_IOC_MAGIC, 6)
/* #define RR_SETDMASIZE _IO(__RR_IOC_MAGIC, 7, unsigned long) */
#define RR_GETPLIST _IO(__RR_IOC_MAGIC, 8) /* returns a whole page */
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
/* Registers from the gennum header files */
enum {
GNGPIO_BASE = 0xA00,
GNGPIO_DIRECTION_MODE = GNGPIO_BASE + 0x4,
GNGPIO_OUTPUT_ENABLE = GNGPIO_BASE + 0x8,
GNGPIO_OUTPUT_VALUE = GNGPIO_BASE + 0xC,
GNGPIO_INPUT_VALUE = GNGPIO_BASE + 0x10,
FCL_BASE = 0xB00,
FCL_CTRL = FCL_BASE,
FCL_STATUS = FCL_BASE + 0x4,
FCL_IODATA_IN = FCL_BASE + 0x8,
FCL_IODATA_OUT = FCL_BASE + 0xC,
FCL_EN = FCL_BASE + 0x10,
FCL_TIMER_0 = FCL_BASE + 0x14,
FCL_TIMER_1 = FCL_BASE + 0x18,
FCL_CLK_DIV = FCL_BASE + 0x1C,
FCL_IRQ = FCL_BASE + 0x20,
FCL_TIMER_CTRL = FCL_BASE + 0x24,
FCL_IM = FCL_BASE + 0x28,
FCL_TIMER2_0 = FCL_BASE + 0x2C,
FCL_TIMER2_1 = FCL_BASE + 0x30,
FCL_DBG_STS = FCL_BASE + 0x34,
FCL_FIFO = 0xE00,
PCI_SYS_CFG_SYSTEM = 0x800
};
#endif /* __RAWRABBIT_H__ */
#ifndef __RR_IO_H
#define __RR_IO_H
#include <stdint.h>
#include <rawrabbit.h>
int rr_bind(int a_fd);
int rr_init(int bus, int devfn);
int rr_writel(uint32_t data, uint32_t addr);
uint32_t rr_readl(uint32_t addr);
int rr_load_bitstream(const void *data, int size8);
int rr_load_bitstream_from_file(const char *file_name);
#endif
CFLAGS = -I../include -g -Imini_bone -Ispll
#uncomment for extra tests (DAC, output stage INL/DNL)
#CFLAGS += -DPERFORM_LONG_TESTS
OBJS_LIB = fdelay_lib.o fdelay_bus.o rr_io.o i2c_master.o onewire.o mini_bone/minibone_lib.o mini_bone/ptpd_netif.o spec_common.o
all: lib
lib: $(OBJS_LIB)
gcc -shared -o libfinedelay.so $(OBJS_LIB)
testprog: lib fdelay_test.o
gcc -o fdelay_test $(OBJS_LIB) fdelay_test.o -lm
testprog2: lib fdelay_cal.o
gcc -o fdelay_cal $(OBJS_LIB) fdelay_cal.o -lm
testprog3: lib fdelay_pps_demo.o
gcc -o fdelay_pps_demo $(OBJS_LIB) fdelay_pps_demo.o -lm
testprog4: lib fdelay_eeprom.o
gcc -o fdelay_eeprom $(OBJS_LIB) fdelay_eeprom.o -lm
clean:
rm -f libfinedelay.so $(OBJS_LIB)
/*
FmcDelay1ns4Cha (a.k.a. The Fine Delay Card)
User-space driver/library - bus API creation functions
Tomasz Włostowski/BE-CO-HT, 2011
(c) Copyright CERN 2011
Licensed under LGPL 2.1
*/
#include <stdio.h>
#include <stdlib.h>
#include "rr_io.h"
#include "minibone_lib.h"
#include "fdelay_lib.h"
static void my_rr_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
static uint32_t my_rr_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
static void my_mb_writel(void *priv, uint32_t data, uint32_t addr)
{
mbn_writel(priv, data, addr >> 2);
}
static uint32_t my_mb_readl(void *priv, uint32_t addr)
{
uint32_t d = mbn_readl(priv, addr >> 2);
return d;
}
fdelay_device_t *fdelay_create_rawrabbit(int fd, uint32_t base_addr)
{
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
rr_bind(fd);
dev->writel = my_rr_writel;
dev->readl = my_rr_readl;
dev->base_addr = base_addr;
return dev;
}
fdelay_device_t *fdelay_create_minibone(char *iface, char *mac_addr, uint32_t base_addr)
{
void *handle;
uint8_t target_mac[6];
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
sscanf(mac_addr, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &target_mac[0], &target_mac[1], &target_mac[2], &target_mac[3], &target_mac[4], &target_mac[5]);
handle = mbn_open(iface, target_mac);
if(handle == NULL)
return NULL;
// dbg("%s: remote @ %s [%02x:%02x:%02x:%02x:%02x:%02x], base 0x%08x\n",__FUNCTION__, iface,
// target_mac[0], target_mac[1], target_mac[2], target_mac[3], target_mac[4], target_mac[5], base_addr);
dev->writel = my_mb_writel;
dev->readl = my_mb_readl;
dev->base_addr = base_addr;
dev->priv_io = handle;
return dev;
}
#include <stdio.h>
#include <stdint.h>
#include "fdelay_lib.h"
#include "fdelay_private.h"
#include "fd_main_regs.h"
#include "onewire.h"
#include "rr_io.h"
typedef struct {
float kp, ki, err, pwm, setpoint, i, bias;
} pi_t;
pi_t pi_state = {15.0, 5.0, 0, 0, 20, 0, 2048};
void pi_update(fdelay_device_t *dev, float temp)
{
fd_decl_private(dev);
pi_state.err = temp - pi_state.setpoint;
pi_state.i += pi_state.err;
pi_state.pwm = pi_state.bias + pi_state.kp * pi_state.err + pi_state.ki * pi_state.i;
dbg("t %.1f err:%.1f DRIVE: %d\n", temp, pi_state.err, (int)pi_state.pwm);
fd_writel(FD_I2CR_DBGOUT_W((int)pi_state.pwm), FD_REG_I2CR);
}
extern int64_t get_tics();
static int64_t last_tics = 0;
#define TEMP_REG_PERIOD 1000000LL
int pi_set_temp(fdelay_device_t *dev, float new_temp)
{
int temp;
float temp_f;
if(get_tics() - last_tics < TEMP_REG_PERIOD)
return 0;
last_tics = get_tics();
if(ds18x_read_temp(dev, &temp) < 0)
return 0;
temp_f = (float)temp / 16.0;
pi_state.setpoint = new_temp;
pi_update(dev, temp_f);
dbg("Temperature: %.1f degC err %.1f\n", temp_f, pi_state.err);
return fabs(pi_state.err) < 0.1 ? 1: 0;
}
void my_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
uint32_t my_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
main()
{
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
rr_init(RR_DEVSEL_UNUSED, RR_DEVSEL_UNUSED);
dev->writel = my_writel;
dev->readl = my_readl;
dev->base_addr = 0x80000;
if(fdelay_init(dev) < 0)
return -1;
float t_min = 40.0, t_max = 80.0, t_cur;
t_cur = t_min;
for(;;)
{
if(pi_set_temp(dev, t_cur))
{
fd_decl_private(dev);
calibrate_outputs(dev);
fprintf(stderr, "> %.1f %d %d %d %d\n", t_cur, hw->frr_cur[0],
hw->frr_cur[1], hw->frr_cur[2], hw->frr_cur[3]);
t_cur += 1.0;
if(t_cur > t_max)
break;
}
usleep(10000);
}
}
#include <stdio.h>
#include "fdelay_lib.h"
#include "fdelay_private.h"
#include "rr_io.h"
#include "i2c_master.h"
void my_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
uint32_t my_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
main()
{
fdelay_device_t dev;
struct fine_delay_calibration cal;
rr_init(RR_DEVSEL_UNUSED, RR_DEVSEL_UNUSED);
dev.writel = my_writel;
dev.readl = my_readl;
dev.base_addr = 0x84000;
if(fdelay_init(&dev) < 0)
return -1;
cal.magic = 0xf19ede1a;
cal.zero_offset[0] = 63000;
cal.zero_offset[1] = 63000;
cal.zero_offset[2] = 63000;
cal.zero_offset[3] = 63000;
cal.tdc_zero_offset = 35600;
cal.frr_poly[0] = -165202LL;
cal.frr_poly[1] = -29825595LL;
cal.frr_poly[2] = 3801939743082LL;
cal.tdc_zero_offset = 35600;
cal.atmcr_val = 2 | (1000 << 4);
cal.adsfr_val = 56648;
cal.acam_start_offset = 10000;
printf("Writing EEPROM...");
eeprom_write(&dev, EEPROM_ADDR, 0, &cal, sizeof(struct fine_delay_calibration));
printf(" done.\n");
}
/*
FmcDelay1ns4Cha (a.k.a. The Fine Delay Card)
User-space driver/library
Tomasz Włostowski/BE-CO-HT, 2011
(c) Copyright CERN 2011
Licensed under LGPL 2.1
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <math.h>
#include "fd_channel_regs.h"
#include "fd_main_regs.h"
#include "pll_config.h"
#include "acam_gpx.h"
#include "fdelay_lib.h"
#include "fdelay_private.h"
#include "spll_defs.h"
#include "spll_common.h"
#include "spll_helper.h"
#include "onewire.h"
static int acam_test_bus(fdelay_device_t *dev);
#define TEST_PRESENCE 0
#define TEST_FIRMWARE 1
#define TEST_DELAY_LINE 2
#define TEST_SPI 3
#define TEST_SENSORS 4
#define TEST_ACAM_IF 5
/*
----------------------
Some utility functions
----------------------
*/
char fail_test_msg[1024];
int fail_test_id = -1;
static void fail(int test_id, const char *fmt, ...)
{
va_list ap;
fail_test_id = test_id;
va_start(ap, fmt);
vsprintf(fail_test_msg,fmt,ap);
va_end(ap);
}
static int extra_debug = 1;
void fdelay_show_test_results()
{
if(fail_test_id >= 0)
{
fprintf(stderr,"\n\n\n ***** FAILED TEST: %d (%s) ****** \n", fail_test_id, fail_test_msg);
}
}
void dbg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
//if(extra_debug)
//vfprintf(stderr,fmt,ap);
va_end(ap);
}
/* Returns the numer of microsecond timer ticks */
int64_t get_tics()
{
struct timezone tz= {0,0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (int64_t)tv.tv_sec * 1000000LL + (int64_t) tv.tv_usec;
}
/* Microsecond-accurate delay */
void udelay(uint32_t usecs)
{
int64_t ts = get_tics();
while(get_tics() - ts < (int64_t)usecs);
}
/* Card reset. When mode == RESET_HW, resets the FMC hardware by asserting the reset line in the FMC
connector, if mode == RESET_CORE, the FPGA Fine Delay core is reset. Since HW reset operation also
reinitializes the PLL, the HW reset must be followed by a reinitialization of the FD Core. */
#define FD_RESET_HW 1
#define FD_RESET_CORE 0
static void fd_do_reset(fdelay_device_t *dev, int mode)
{
fd_decl_private(dev) ;
if(mode == FD_RESET_HW) {
fd_writel(FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_CORE_MASK, FD_REG_RSTR);
udelay(10000);
fd_writel(FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_CORE_MASK | FD_RSTR_RST_FMC_MASK, FD_REG_RSTR);
udelay(600000); /* Leave the TPS3307 supervisor some time to de-assert the master reset line */
} else if (mode == FD_RESET_CORE)
{
fd_writel(FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_FMC_MASK, FD_REG_RSTR);
udelay(1000);
fd_writel(FD_RSTR_LOCK_W(0xdead) | FD_RSTR_RST_FMC_MASK | FD_RSTR_RST_CORE_MASK, FD_REG_RSTR);
udelay(1000);
}
}
/*
----------------------------------
Simple SPI Master driver
----------------------------------
*/
/* Initializes the SPI Controller */
static void oc_spi_init(fdelay_device_t *dev)
{
fd_decl_private(dev)
}
/* Sends (num_bits) from (in) to slave at CS line (ss), storint the readback data in (*out) */
static void oc_spi_txrx(fdelay_device_t *dev, int ss, int num_bits, uint32_t in, uint32_t *out)
{
fd_decl_private(dev);
uint32_t scr = 0, r;
scr = FD_SCR_DATA_W(in)| FD_SCR_CPOL;
if(ss == CS_PLL)
scr |= FD_SCR_SEL_PLL;
else if(ss == CS_GPIO)
scr |= FD_SCR_SEL_GPIO;
else if(ss == CS_DAC)
scr |= FD_SCR_SEL_DAC;
fd_writel(scr, FD_REG_SCR);
fd_writel(scr | FD_SCR_START, FD_REG_SCR);
while(! (fd_readl(FD_REG_SCR) & FD_SCR_READY));
scr = fd_readl(FD_REG_SCR);
r = FD_SCR_DATA_R(scr);
if(out) *out=r;
udelay(100);
}
/*
-----------------
AD9516 PLL Driver
-----------------
*/
/* Writes an AD9516 register */
static inline void ad9516_write_reg(fdelay_device_t *dev, uint16_t reg, uint8_t val)
{
oc_spi_txrx(dev, CS_PLL, 24, ((uint32_t)(reg & 0xfff) << 8) | val, NULL);
}
/* Reads a register from AD9516 */
static inline uint8_t ad9516_read_reg(fdelay_device_t *dev, uint16_t reg)
{
uint32_t rval;
oc_spi_txrx(dev, CS_PLL, 24, ((uint32_t)(reg & 0xfff) << 8) | (1<<23), &rval);
return rval & 0xff;
}
/* Initializes the AD9516 PLL by loading a pre-defined register set and waiting until the PLL has locked */
static int ad9516_init(fdelay_device_t *dev)
{
fd_decl_private(dev)
int i;
const int64_t lock_timeout = 10000000LL;
int64_t start_tics;
dbg("%s: Initializing AD9516 PLL...\n", __FUNCTION__);
ad9516_write_reg(dev, 0, 0x99);
ad9516_write_reg(dev, 0x232, 1);
/* Check if the chip is present by reading its ID register */
if(ad9516_read_reg(dev, 0x3) != 0xc3)
{
dbg("%s: AD9516 PLL not responding.\n", __FUNCTION__);
fail(TEST_SPI, "Broken SPI connection to AD9516 PLL");
return -1;
}
/* Load the regs */
for(i=0;ad9516_regs[i].reg >=0 ;i++)
ad9516_write_reg (dev, ad9516_regs[i].reg, ad9516_regs[i].val);
ad9516_write_reg(dev, 0x232, 1);
/* Wait until the PLL has locked */
start_tics = get_tics();
for(;;)
{
if(ad9516_read_reg(dev, 0x1f) & 1)
break;
if(get_tics() - start_tics > lock_timeout)
{
dbg("%s: AD9516 PLL does not lock.\n", __FUNCTION__);
return -1;
}
udelay(100);
}
/* Synchronize the phase of all clock outputs (this is critical for the accuracy!) */
ad9516_write_reg(dev, 0x230, 1);
ad9516_write_reg(dev, 0x232, 1);
ad9516_write_reg(dev, 0x230, 0);
ad9516_write_reg(dev, 0x232, 1);
dbg("%s: AD9516 locked.\n", __FUNCTION__);
return 0;
}
static int test_pll_dac(fdelay_device_t *dev)
{
fd_decl_private(dev);
int f_hi, f_lo;
double range;
int i=0;
dbg("Testing DAC/VCXO... ");
oc_spi_txrx(dev, CS_DAC, 24, 0, NULL); /* Drive the DAC to 0 */
udelay(1000000);
f_lo = fd_readl(FD_REG_TDER1) & 0x7fffffff;
oc_spi_txrx(dev, CS_DAC, 24, 0xffff, NULL); /* Drive the DAC to +Vref */
udelay(1000000);
f_hi = fd_readl(FD_REG_TDER1) & 0x7fffffff;
range = (double)abs(f_hi - f_lo) / (double)f_lo * 1e6;
dbg("tuning range: %.1f ppm.\n", range);
if(range < 10.1)
{
fail(TEST_SPI, "Too little VCXO tuning range. Either a broken VCXO or (more likely) broken SPI connection to the DAC.");
return -1;
}
return 0;
}
/*
----------------------------
MCP23S17 SPI I/O Port Driver
----------------------------
*/
/* Writes MCP23S17 register */
static inline void mcp_write(fdelay_device_t *dev, uint8_t reg, uint8_t val)
{
oc_spi_txrx(dev, CS_GPIO, 24, 0x4e0000 | (((uint32_t)reg)<<8) | (uint32_t)val, NULL);
}
/* Reads MCP23S17 register */
static uint8_t mcp_read(fdelay_device_t *dev, uint8_t reg)
{
uint32_t rval;
oc_spi_txrx(dev, CS_GPIO, 24, 0x4f0000 | (((uint32_t)reg)<<8), &rval);
return rval & 0xff;
}
static int sgpio_init(fdelay_device_t *dev)
{
int failed = 0;
mcp_write(dev, MCP_IOCON, 0);
/* try to read and write a register to test the SPI connection */
mcp_write(dev, MCP_IPOL, 0xaa);
if(mcp_read(dev, MCP_IPOL) != 0xaa)
failed = 1;
mcp_write(dev, MCP_IPOL, 0);
if(mcp_read(dev, MCP_IPOL) != 0)
failed = 1;
fail(TEST_SPI, "Failed to access MCP23S17. Broken SPI connection?");
return failed ? - 1: 0;
}
/* Sets the direction (0 = input, non-zero = output) of a particular MCP23S17 GPIO pin */
static void sgpio_set_dir(fdelay_device_t *dev, int pin, int dir)
{
uint8_t iodir = (MCP_IODIR) + (pin & 0x100 ? 1 : 0);
uint8_t x;
x = mcp_read(dev, iodir);
if(dir) x &= ~(pin); else x |= (pin);
mcp_write(dev, iodir, x);
}
/* Sets the value on a given MCP23S17 GPIO pin */
static void sgpio_set_pin(fdelay_device_t *dev, int pin, int val)
{
uint8_t gpio = (MCP_OLAT) + (pin & 0x100 ? 1 : 0);
uint8_t x;
x = mcp_read(dev, gpio);
if(!val) x &= ~(pin); else x |= (pin);
mcp_write(dev, gpio, x);
}
/*
----------------------------------------
ACAM Time To Digital Converter functions
----------------------------------------
*/
/* Sets the address on ACAM's address bus to addr using the SPI GPIO expander */
static inline void acam_set_address(fdelay_device_t *dev, uint8_t addr)
{
fd_decl_private(dev);
/* A hack to speed up calibration - avoid setting the same address several times */
if(addr != hw->acam_addr)
{
mcp_write(dev, MCP_IODIR + 1, 0);
mcp_write(dev, MCP_OLAT + 1, addr & 0xf);
hw->acam_addr = addr;
}
}
/* Reads a register from the ACAM TDC. As for the function above, GCR.BYPASS must be enabled */
static uint32_t acam_read_reg(fdelay_device_t *dev, uint8_t reg)
{
fd_decl_private(dev)
acam_set_address(dev, reg);
fd_writel(FD_TDCSR_READ, FD_REG_TDCSR);
return fd_readl(FD_REG_TDR) & 0xfffffff;
}
/* Writes a particular ACAM register. Works only if (GCR.BYPASS == 1) - i.e. when
the ACAM is controlled from the host instead of the delay core. */
static void acam_write_reg(fdelay_device_t *dev, uint8_t reg, uint32_t data)
{
fd_decl_private(dev)
acam_set_address(dev, reg);
fd_writel(data & 0xfffffff, FD_REG_TDR);
fd_writel(FD_TDCSR_WRITE, FD_REG_TDCSR);
}
/* Calculates the parameters of the ACAM PLL (hsdiv and refdiv)
for a given bin size and reference clock frequency. Returns the closest
achievable bin size. */
static double acam_calc_pll(int *hsdiv, int *refdiv, double bin, double clock_freq)
{
int h;
int r;
double best_err = 100000;
double best_bin;
/* Try all possible divider settings */
for(h=1;h<=255;h++)
for(r=0;r<=7;r++)
{
double b = ((1.0/clock_freq) * 1e12) * pow(2.0, (double) r) / (216.0 * (double)h);
if(fabs(bin - b) < best_err)
{
best_err=fabs(bin-b);
best_bin = b;
*hsdiv= h;
*refdiv = r;
}
}
dbg("%s: requested bin=%.02fps best=%.02fps error=%.02f%%\n", __FUNCTION__, bin, best_bin, (best_err/bin) * 100.0);
dbg("%s: hsdiv=%d refdiv=%d\n", __FUNCTION__, *hsdiv, *refdiv);
return best_bin;
}
/* Returns non-zero if the ACAM's internal PLL is locked */
static inline int acam_pll_locked(fdelay_device_t *dev)
{
uint32_t r12 = acam_read_reg(dev, 12);
return !(r12 & AR12_NotLocked);
}
static int test_addr_bit(fdelay_device_t *dev, int addr1, int addr2, int addr_bit, int data_bit)
{
int failed = 0;
acam_write_reg(dev, addr1, acam_read_reg(dev, addr1) & ~(1<<data_bit)); // set the data bit to 0
acam_write_reg(dev, addr2, acam_read_reg(dev, addr2) | (1<<data_bit)); // set the data bit to 1
if(acam_read_reg(dev, addr1) & (1<<data_bit) || !(acam_read_reg(dev, addr2) & (1<<data_bit)))
failed= 1;
/* the other way around */
acam_write_reg(dev, addr1, acam_read_reg(dev, addr1) | (1<<data_bit));
acam_write_reg(dev, addr2, acam_read_reg(dev, addr2) & ~(1<<data_bit));
if(!(acam_read_reg(dev, addr1) & (1<<data_bit)) || acam_read_reg(dev, addr2) & (1<<data_bit))
failed= 1;
if(failed)
{
dbg("Bit failure on ACAM_A[%d]\n",addr_bit);
fail(TEST_ACAM_IF, "Bit failure on ACAM_A[%d]", addr_bit);
return -1;
}
return 0;
}
static int acam_test_bus(fdelay_device_t *dev)
{
int i, failed = 0;
dbg("Testing ACAM Bus...\n");
for(i=0;i<28;i++)
{
acam_write_reg(dev, 5, (1<<i));
acam_read_reg(dev, 0);
uint32_t rb = acam_read_reg(dev, 5);
acam_write_reg(dev, 5, ~(1<<i));
acam_read_reg(dev, 0);
uint32_t rb2 = acam_read_reg(dev, 5);
if(rb != (1<<i) || rb2 != (~(1<<i) & 0xfffffff))
{
dbg("Bit failure on ACAM_D[%d]: %x shouldbe %x \n", i, rb, (1<<i));
fail(TEST_ACAM_IF, "Bit failure on ACAM_D[%d]: %x shouldbe %x ", i, rb, (1<<i));
return -1;
}
}
failed |= test_addr_bit(dev, 0, 1, 0, 1);
failed |= test_addr_bit(dev, 1, 3, 1, 3);
failed |= test_addr_bit(dev, 0, 4, 2, 1);
failed |= test_addr_bit(dev, 3, 11, 3, 16);
return failed;
}
/* Configures the ACAM TDC to work in a particular mode. Currently there are two modes
supported: R-Mode for the normal operation (delay/timestamper) and I-Mode for the purpose
of calibrating the fine delay lines. */
static int acam_configure(fdelay_device_t *dev, int mode)
{
fd_decl_private(dev)
int hsdiv, refdiv;
int64_t start_tics;
const int64_t lock_timeout = 2000000LL;
hw->acam_bin = acam_calc_pll(&hsdiv, &refdiv, 80.9553, 31.25e6) / 3.0;
/* Disable TDC inputs prior to configuring */
fd_writel(FD_TDCSR_STOP_DIS | FD_TDCSR_START_DIS, FD_REG_TDCSR);
if(mode == ACAM_RMODE)
{
acam_write_reg(dev, 0, AR0_ROsc | AR0_RiseEn0 | AR0_RiseEn1 | AR0_HQSel );
acam_write_reg(dev, 1, AR1_Adj(0, 0) |
AR1_Adj(1, 2) |
AR1_Adj(2, 6) |
AR1_Adj(3, 0) |
AR1_Adj(4, 2) |
AR1_Adj(5, 6) |
AR1_Adj(6, 0));
acam_write_reg(dev, 2, AR2_RMode | AR2_Adj(7, 2) | AR2_Adj(8, 6));
acam_write_reg(dev, 3, 0);
acam_write_reg(dev, 4, AR4_EFlagHiZN);
acam_write_reg(dev, 5, AR5_StartRetrig |AR5_StartOff1(hw->calib.acam_start_offset) | AR5_MasterAluTrig);
acam_write_reg(dev, 6, AR6_Fill(200) | AR6_PowerOnECL);
acam_write_reg(dev, 7, AR7_HSDiv(hsdiv) | AR7_RefClkDiv(refdiv) | AR7_ResAdj | AR7_NegPhase);
acam_write_reg(dev, 11, 0x7ff0000);
acam_write_reg(dev, 12, 0x0000000);
acam_write_reg(dev, 14, 0);
/* Reset the ACAM after the configuration */
acam_write_reg(dev, 4, AR4_EFlagHiZN | AR4_MasterReset | AR4_StartTimer(0));
} else if (mode == ACAM_IMODE)
{
acam_write_reg(dev, 0, AR0_TRiseEn(0) | AR0_HQSel | AR0_ROsc);
acam_write_reg(dev, 2, AR2_IMode);
acam_write_reg(dev, 5, AR5_StartOff1(3000) | AR5_MasterAluTrig);
acam_write_reg(dev, 6, 0);
acam_write_reg(dev, 7, AR7_HSDiv(hsdiv) | AR7_RefClkDiv(refdiv) | AR7_ResAdj | AR7_NegPhase);
acam_write_reg(dev, 11, 0x7ff0000);
acam_write_reg(dev, 12, 0x0000000);
acam_write_reg(dev, 14, 0);
/* Reset the ACAM after the configuration */
acam_write_reg(dev, 4, AR4_EFlagHiZN | AR4_MasterReset | AR4_StartTimer(0));
} else
return -1; /* Unsupported mode? */
int i;
dbg("%s: Waiting for ACAM ring oscillator lock...\n", __FUNCTION__);
start_tics = get_tics();
for(;;)
{
if(acam_pll_locked(dev))
break;
if(get_tics() - start_tics > lock_timeout)
{
dbg("%s: ACAM PLL does not lock.\n", __FUNCTION__);
fail(TEST_ACAM_IF, "ACAM PLL does not lock.");
return -1;
}
usleep(10000);
}
acam_set_address(dev, 8); /* Permamently select FIFO1 register for readout */
return 0;
}
/*
---------------------
Calibration functions
---------------------
*/
#define chan_writel(data, addr) fd_writel((data), channel * 0x100 + (addr))
#define chan_readl(addr) fd_readl(channel * 0x100 + (addr))
/* Measures the the FPGA-generated TDC start and the output of one of the fine delay chips (channel)
at a pre-defined number of taps (fine). Retuns the delay in picoseconds. The measurement is repeated
and averaged (n_avgs) times. Also, the standard deviation of the result can be written to (sdev)
if it's not NULL. */
static double measure_output_delay(fdelay_device_t *dev, int channel, int fine, int n_avgs, double *sdev)
{
fd_decl_private(dev)
double acc = 0.0, std = 0.0;
int i;
/* Mapping between the channel of the delay card and the stop inputs of the ACAM */
int chan_to_acam[5] = {0, 1, 2, 3, 4};
/* Mapping between the channel number and the time tag FIFOs of the ACAM */
int chan_to_fifo[5] = {0, 8, 8, 8, 8};
double rec[1024];
/* Disable the output for the channel being calibrated */
sgpio_set_pin(dev, SGPIO_OUTPUT_EN(channel), 0);
/* Enable the stop input in the ACAM corresponding to the channel being calibrated */
acam_write_reg(dev, 0, AR0_TRiseEn(0) | AR0_TRiseEn(chan_to_acam[channel]) | AR0_HQSel | AR0_ROsc);
/* Program the output delay line setpoint */
chan_writel( fine, FD_REG_FRR);
chan_writel( FD_DCR_ENABLE | FD_DCR_MODE | FD_DCR_UPDATE, FD_REG_DCR);
chan_writel( FD_DCR_FORCE_DLY | FD_DCR_ENABLE, FD_REG_DCR);
/* Set the calibration pulse mask to genrate calibration pulses only on one channel at a time.
This minimizes the crosstalk in the output buffer which can severely decrease the accuracy
of calibration measurements */
fd_writel( FD_CALR_PSEL_W(1<<(channel-1)), FD_REG_CALR);
udelay(1);
/* Do n_avgs single measurements and average */
for(i=0;i<n_avgs;i++)
{
uint32_t fr;
/* Re-arm the ACAM (it's working in a single-shot mode) */
fd_writel( FD_TDCSR_ALUTRIG, FD_REG_TDCSR);
udelay(1);
/* Produce a calibration pulse on the TDC start and the appropriate output channel */
fd_writel( FD_CALR_CAL_PULSE | FD_CALR_PSEL_W((1<<(channel-1))), FD_REG_CALR);
udelay(1);
/* read the tag, convert to picoseconds and average */
fr = acam_read_reg(dev, chan_to_fifo[channel]);
double tag = (double)((fr >> 0) & 0x1ffff) * hw->acam_bin * 3.0;
// dbg("Tag %.1f\n", tag);
acc += tag;
rec[i] = tag;
}
/* Calculate standard dev and average value */
acc /= (double) n_avgs;
for(i=0;i<n_avgs;i++)
std += (rec[i] - acc) * (rec[i] - acc);
if(sdev) *sdev = sqrt(std /(double) n_avgs);
chan_writel( 0, FD_REG_DCR);
return acc;
}
static void measure_linearity(double *x, int n, double *inl, double *dnl)
{
double slope = (x[n-1] - x[0]) / (double)(n-1);
int i;
*inl = 0;
*dnl = 0;
for(i=0;i<n;i++)
{
double d = fabs(x[i] - (((double)i) * slope + x[0]));
if(*inl < d)
*inl = d;
if(i>0)
{
d=fabs(x[i]-x[i-1]-slope);
if(d>*dnl)
*dnl = d;
}
}
}
/* Measures the transfer function of the fine delay line (i.e. delay vs number of taps) and checks
its linearity, performing an indirect check of the delay lines' and TDC signal connections. */
#define MAX_DNL 20
#define MAX_INL 60
static int test_delay_transfer_function(fdelay_device_t *dev)
{
double inl, dnl;
int lin_fail = 0;
fd_decl_private(dev)
int channel, i;
double bias, x, meas[4][FDELAY_NUM_TAPS], sdev[4][FDELAY_NUM_TAPS];
fd_writel( FD_GCR_BYPASS, FD_REG_GCR);
acam_configure(dev, ACAM_IMODE);
fd_writel( FD_TDCSR_START_EN | FD_TDCSR_STOP_EN, FD_REG_TDCSR);
for(channel = 1; channel <= 4; channel++)
{
dbg("calibrating channel %d\n", channel);
bias = measure_output_delay(dev, channel, 0, FDELAY_CAL_AVG_STEPS, &sdev[0][channel-1]);
meas[channel-1][0] = 0.0;
for(i=FDELAY_NUM_TAPS-1;i>=0;i--)
{
x = measure_output_delay(dev, channel, i,
FDELAY_CAL_AVG_STEPS, &sdev[channel-1][i]);
meas[channel-1][i] = x - bias;
}
measure_linearity(meas[channel-1], FDELAY_NUM_TAPS-1, &inl, &dnl);
dbg("Linearity: INL = %.1f ps, DNL = %.1f ps\n", inl, dnl);
if(inl > MAX_INL || dnl > MAX_DNL)
lin_fail=1;
}
if(lin_fail)
{
dbg("Linearity check failed.\n");
fail(TEST_DELAY_LINE, "Maximum INL/DNL exceeded, indicating a wrong connection of the delay chip and/or the TDC calibration signals");
return -1;
}
return 0;
/* FILE *f=fopen("t_func.dat","w");
for(i=0;i<FDELAY_NUM_TAPS;i++)
{
fprintf(f, "%d %.0f %.0f %.0f %.0f %.0f %.0f %.0f %.0f\n", i,
meas[i][0], meas[i][1], meas[i][2], meas[i][3],
sdev[i][0], sdev[i][1], sdev[i][2], sdev[i][3]);
}
fclose(f);*/
}
/* Finds the preset (i.e. the numer of taps) of the output delay line in (channel)
at which it introduces exactly 8 ns more than when it's programmed to 0 taps.
Uses a binary search algorithm to speed up the calibration (assuming that the
line is monotonous). */
static int find_8ns_tap(fdelay_device_t *dev, int channel)
{
int l = 0, r=FDELAY_NUM_TAPS-1;
dbg("Calibrating: %d\n", channel);
/* Measure the delay at zero setting, so it can be further subtracted to get only the
delay part introduced by the delay line (ingoring the TDC, FPGA and routing delays). */
double bias = measure_output_delay(dev, channel, 0, FDELAY_CAL_AVG_STEPS, NULL);
while(abs(l-r)>1)
{
int mid = (l+r) / 2;
double dly = measure_output_delay(dev, channel, mid, FDELAY_CAL_AVG_STEPS, NULL) - bias;
if(dly < 8000.0) l = mid; else r = mid;
}
return l;
}
/* Evaluates 2nd order polynomial. Coefs have 32 fractional bits. */
static int32_t eval_poly(int64_t *coef, int32_t x)
{
int32_t y;
y= (coef[0] * (int64_t)x * (int64_t)x + coef[1] * (int64_t) x + coef[2]) >> 32;
return (int32_t) y;
}
/* Performs the startup calibration of the output delay lines. */
int calibrate_outputs(fdelay_device_t *dev)
{
fd_decl_private(dev)
int i, channel, temp;
#ifdef PERFORM_LONG_TESTS
if(test_delay_transfer_function(dev) < 0)
return -1;
#endif
fd_writel( FD_GCR_BYPASS, FD_REG_GCR);
acam_configure(dev, ACAM_IMODE);
fd_writel( FD_TDCSR_START_EN | FD_TDCSR_STOP_EN, FD_REG_TDCSR);
for(channel = 1; channel <= 4; channel++)
{
while(ds18x_read_temp(dev, &temp) < 0)
usleep(100000);
int cal_measd = find_8ns_tap(dev, channel);
int cal_fitted = eval_poly(hw->calib.frr_poly, temp);
dbg("%s: CH%d: 8ns @ %d (fitted %d, offset %d, temperature %d.%1d)\n", __FUNCTION__, channel, cal_measd, cal_fitted, cal_measd-cal_fitted, temp);
hw->frr_cur[channel-1] = cal_measd;
hw->frr_offset[channel-1] = cal_measd - cal_fitted;
}
return 0;
}
/* TODO: run in a timer context every few seconds instead of the main program loop */
void fdelay_update_calibration(fdelay_device_t *dev)
{
fd_decl_private(dev);
int channel, temp;
ds18x_read_temp(dev, &temp);
for(channel = 1; channel <= 4; channel++)
{
int cal_fitted = eval_poly(hw->calib.frr_poly, temp) + hw->frr_offset[channel-1];
dbg("%s: CH%d: FRR = %d\n", __FUNCTION__, channel, cal_fitted);
hw->frr_cur[channel-1] = cal_fitted;
chan_writel(hw->frr_cur[channel-1], FD_REG_FRR);
}
}
#if 0
void poll_stats()
{
int raw = fd_readl(FD_REG_IECRAW);
int tagged = fd_readl(FD_REG_IECTAG);
int pd = fd_readl(FD_REG_IEPD) & 0xff;
if(events_raw != raw || events_tagged != tagged || pd != tag_delay)
{
events_raw = raw;
events_tagged = tagged;
tag_delay = pd;
// if(events_raw != events_tagged) printf("ERROR: raw %d vs tagged %d\n", raw,tagged);
// printf("NewStats: raw %d tagged %d pdelay %d nsec\n", raw, tagged ,(pd+3)*8);
}
}
#endif
static int read_calibration_eeprom(fdelay_device_t *dev, struct fine_delay_calibration *d_cal)
{
struct fine_delay_calibration cal;
mi2c_init(dev);
if(eeprom_read(dev, EEPROM_ADDR, 0, (uint8_t *) &cal, sizeof(struct fine_delay_calibration)) != sizeof(struct fine_delay_calibration))
{
dbg("Can't read calibration EEPROM.\n");
return -1;
}
if(cal.magic != FDELAY_MAGIC_ID)
{
dbg("EEPROM doesn't contain valid calibration block.\n");
return 0;
}
memcpy(d_cal, &cal, sizeof(cal));
return 1;
}
/*
-------------------------------------
Public API
-------------------------------------
*/
/* Initialize & self-calibrate the Fine Delay card */
int fdelay_init(fdelay_device_t *dev)
{
int i, rv;
struct fine_delay_hw *hw;
fdelay_time_t t_zero;
dbg("Init: dev %x\n", dev);
hw = (struct fine_delay_hw *) malloc(sizeof(struct fine_delay_hw));
if(! hw)
return -1;
dev->priv_fd = (void *) hw;
hw->base_addr = dev->base_addr;
hw->base_i2c = 0x100;
hw->base_onewire = dev->base_addr + 0x500;
hw->wr_enabled = 0;
hw->wr_state = FDELAY_FREE_RUNNING;
hw->acam_addr = 0xff;
dbg("%s: Initializing the Fine Delay Card\n", __FUNCTION__);
/* Read the Identification register and check if we are talking to a proper Fine Delay HDL Core */
if(fd_readl(FD_REG_IDR) != FDELAY_MAGIC_ID)
{
fail(TEST_FIRMWARE, "Core not responding. Firmware loaded incorrectly?");
dbg("%s: invalid core signature. Are you sure you have loaded the FPGA with the Fine Delay firmware?\n", __FUNCTION__);
return -1;
}
if(! (fd_readl(FD_REG_GCR) & FD_GCR_FMC_PRESENT))
{
fail(TEST_PRESENCE, "FMC Card not detected in the slot. Maybe a fault on PRSNT_L line?");
dbg("%s: FMC Presence line not active. Is the FMC correctly inserted into the carrier?\n", __FUNCTION__);
return -1;
}
rv = read_calibration_eeprom(dev, &hw->calib);
if(rv < 0)
{
fail(TEST_SPI, "FMC EEPROM not detected.");
return -1;
} else if(!rv)
{
int i;
dbg("%s: Calibration EEPROM does not contain a valid calibration block. Using default calibration values\n", __FUNCTION__);
hw->calib.frr_poly[0] = -165202LL;
hw->calib.frr_poly[1] = -29825595LL;
hw->calib.frr_poly[2] = 3801939743082LL;
hw->calib.tdc_zero_offset = 35600;
hw->calib.atmcr_val = 2 | (1000 << 4);
hw->calib.adsfr_val = 56648;
hw->calib.acam_start_offset = 10000;
for(i=0;i<4;i++)
hw->calib.zero_offset[i] = 50000;
}
/* Reset the FMC hardware. */
fd_do_reset(dev, FD_RESET_HW);
/* Initialize the clock system - AD9516 PLL */
oc_spi_init(dev);
if(sgpio_init(dev) < 0)
return -1;
if(ad9516_init(dev) < 0)
return -1;
if(ds18x_init(dev) < 0)
{
fail(TEST_SPI, "DS18x sensor not detected.");
dbg("DS18x sensor not detected. Bah!\n");
return -1;
}
int temp;
ds18x_read_temp(dev, &temp);
dbg("Device temperature: %d\n", temp);
/* Configure default states of the SPI GPIO pins */
sgpio_set_dir(dev, SGPIO_TRIG_SEL, 1);
sgpio_set_pin(dev, SGPIO_TRIG_SEL, 1);
for(i=1;i<=4;i++)
{
sgpio_set_pin(dev, SGPIO_OUTPUT_EN(i), 0);
sgpio_set_dir(dev, SGPIO_OUTPUT_EN(i), 1);
}
sgpio_set_dir(dev, SGPIO_TERM_EN, 1);
sgpio_set_pin(dev, SGPIO_TERM_EN, 0);
/* Reset the FD core once we have proper reference/TDC clocks */
fd_do_reset(dev, FD_RESET_CORE);
while(! (fd_readl(FD_REG_GCR) & FD_GCR_DDR_LOCKED))
udelay(1);
fd_do_reset(dev, FD_RESET_CORE);
/* Disable the delay generator core, so we can access the ACAM from the host, both for
initialization and calibration */
fd_writel( FD_GCR_BYPASS, FD_REG_GCR);
#ifdef PERFORM_LONG_TESTS
if(test_pll_dac(dev) < 0)
return -1;
#endif
/* Test if ACAM addr/data lines are OK */
if(acam_test_bus(dev) < 0)
return -1;
/* Calibrate the output delay lines */
if(calibrate_outputs(dev) < 0)
return -1;
/* Switch to the R-MODE (more precise) */
acam_configure(dev, ACAM_RMODE);
/* Switch the ACAM to be driven by the delay core instead of the host */
fd_writel( 0, FD_REG_GCR);
/* Clear and disable the timestamp readout buffer */
fd_writel( FD_TSBCR_PURGE | FD_TSBCR_RST_SEQ, FD_REG_TSBCR);
/* Program the ACAM-specific timestamper registers using pre-defined calibration values:
- bin -> internal timebase scalefactor (ADSFR),
- Start offset (must be consistent with the value written to the ACAM reg 4)
- timestamp merging control register (ATMCR) */
fd_writel( hw->calib.adsfr_val, FD_REG_ADSFR);
fd_writel( 3 * hw->calib.acam_start_offset, FD_REG_ASOR);
fd_writel( hw->calib.atmcr_val, FD_REG_ATMCR);
t_zero.utc = 0;
t_zero.coarse = 0;
fdelay_set_time(dev, t_zero);
/* Enable input */
udelay(1);
fd_writel(FD_GCR_INPUT_EN, FD_REG_GCR);
/* Enable output driver */
// sgpio_set_pin(dev, SGPIO_DRV_OEN, 1);
dbg("FD initialized\n");
return 0;
}
/* Configures the trigger input. Enable enables the input, termination selects the impedance
of the trigger input (0 == 2kohm, 1 = 50 ohm) */
int fdelay_configure_trigger(fdelay_device_t *dev, int enable, int termination)
{
fd_decl_private(dev)
if(termination)
{
dbg("%s: 50-ohm terminated mode\n", __FUNCTION__);
sgpio_set_pin(dev,SGPIO_TERM_EN,1);
} else {
dbg("%s: high impedance mode\n", __FUNCTION__);
sgpio_set_pin(dev,SGPIO_TERM_EN,0);
};
if(enable)
{
fd_writel(fd_readl(FD_REG_GCR) | FD_GCR_INPUT_EN, FD_REG_GCR);
} else
fd_writel(fd_readl(FD_REG_GCR) & (~FD_GCR_INPUT_EN) , FD_REG_GCR);
return 0;
}
/* Converts a positive time interval expressed in picoseconds to the timestamp format used in the Fine Delay core */
fdelay_time_t fdelay_from_picos(const uint64_t ps)
{
fdelay_time_t t;
uint64_t tmp = ps;
t.frac = (tmp % 8000ULL) * (uint64_t)(1<<FDELAY_FRAC_BITS) / 8000ULL;
tmp -= (tmp % 8000ULL);
tmp /= 8000ULL;
t.coarse = tmp % 125000000ULL;
tmp -= (tmp % 125000000ULL);
tmp /= 125000000ULL;
t.utc = tmp;
return t;
}
/* Substract two timestamps */
static fdelay_time_t ts_sub(fdelay_time_t a, fdelay_time_t b)
{
a.frac -= b.frac;
if(a.frac < 0)
{
a.frac += 4096;
a.coarse--;
}
a.coarse -= b.coarse;
if(a.coarse < 0)
{
a.coarse += 125000000;
a.utc --;
}
return a;
}
/* Add two timestamps */
static fdelay_time_t ts_add(fdelay_time_t a, fdelay_time_t b)
{
a.frac += b.frac;
if(a.frac >= (1<<FDELAY_FRAC_BITS))
{
a.frac -= (1<<FDELAY_FRAC_BITS);
a.coarse++;
}
a.coarse += b.coarse;
if(b.coarse >= 125000000)
{
a.coarse -= 125000000;
a.utc ++;
}
return a;
}
/* Converts a Fine Delay time stamp to plain picoseconds */
int64_t fdelay_to_picos(const fdelay_time_t t)
{
int64_t tp = (((int64_t)t.frac * 8000LL) >> FDELAY_FRAC_BITS) + ((int64_t) t.coarse * 8000LL) + ((int64_t)t.utc * 1000000000000LL);
return tp;
}
static int poll_rbuf(fdelay_device_t *dev)
{
fd_decl_private(dev)
if((fd_readl(FD_REG_TSBCR) & FD_TSBCR_EMPTY) == 0)
return 1;
return 0;
}
/* TODO: chan_mask */
int fdelay_configure_readout(fdelay_device_t *dev, int enable)
{
fd_decl_private(dev)
if(enable)
{
fd_writel( FD_TSBCR_PURGE | FD_TSBCR_RST_SEQ, FD_REG_TSBCR);
fd_writel( FD_TSBCR_CHAN_MASK_W(1) | FD_TSBCR_ENABLE, FD_REG_TSBCR);
} else
fd_writel( FD_TSBCR_PURGE | FD_TSBCR_RST_SEQ, FD_REG_TSBCR);
return 0;
}
/* Reads up to (how_many) timestamps from the FD ring buffer and stores them in (timestamps).
Returns the number of read timestamps. */
int fdelay_read(fdelay_device_t *dev, fdelay_time_t *timestamps, int how_many)
{
fd_decl_private(dev)
int n_read = 0;
// dbg("tsbcr %x\n", fd_readl(FD_REG_TSBCR));
while(poll_rbuf(dev))
{
fdelay_time_t ts;
uint32_t seq_frac;
if(!how_many) break;
ts.utc = ((int64_t) (fd_readl(FD_REG_TSBR_SECH) & 0xff) << 32) | fd_readl(FD_REG_TSBR_SECL);
ts.coarse = fd_readl(FD_REG_TSBR_CYCLES) & 0xfffffff;
// dbg("Coarse %d\n", ts.coarse);
seq_frac = fd_readl(FD_REG_TSBR_FID);
ts.frac = FD_TSBR_FID_FINE_R(seq_frac);
ts.seq_id = FD_TSBR_FID_SEQID_R(seq_frac);
ts.channel = FD_TSBR_FID_CHANNEL_R(seq_frac);
*timestamps++ = ts_sub(ts, fdelay_from_picos(hw->calib.tdc_zero_offset));
how_many--;
n_read++;
}
// printf("read %d\n", how_many, n_read);
return n_read;
}
/* Configures the output channel (channel) to produce pulses delayed from the trigger by (delay_ps).
The output pulse width is proviced in (width_ps) parameter. */
int fdelay_configure_output(fdelay_device_t *dev, int channel, int enable, int64_t delay_ps, int64_t width_ps, int64_t delta_ps, int rep_count)
{
fd_decl_private(dev)
uint32_t base = (channel-1) * 0x20;
uint32_t dcr;
fdelay_time_t start, end, delta;
if(channel < 1 || channel > 4)
return -1;
delay_ps -= hw->calib.zero_offset[channel-1];
start = fdelay_from_picos(delay_ps);
end = fdelay_from_picos(delay_ps + width_ps);
delta = fdelay_from_picos(delta_ps);
// printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
chan_writel(hw->frr_cur[channel-1], FD_REG_FRR);
chan_writel(start.utc >> 32, FD_REG_U_STARTH);
chan_writel(start.utc & 0xffffffff, FD_REG_U_STARTL);
chan_writel(start.coarse, FD_REG_C_START);
chan_writel(start.frac, FD_REG_F_START);
chan_writel(end.utc >> 32, FD_REG_U_ENDH);
chan_writel(end.utc & 0xffffffff, FD_REG_U_ENDL);
chan_writel(end.coarse, FD_REG_C_END);
chan_writel(end.frac, FD_REG_F_END);
chan_writel(delta.utc & 0xf, FD_REG_U_DELTA);
chan_writel(delta.coarse, FD_REG_C_DELTA);
chan_writel(delta.frac, FD_REG_F_DELTA);
// chan_writel(0, FD_REG_RCR);
chan_writel(FD_RCR_REP_CNT_W(rep_count) | (rep_count < 0 ? FD_RCR_CONT : 0), FD_REG_RCR);
dcr = 0;
/* For narrowly spaced pulses, we don't have enough time to reload the tap number into the corresponding
SY89295 - therefore, the width/spacing resolution is limited to 4 ns. */
if((delta_ps - width_ps) < 200000 || (width_ps < 200000))
dcr = FD_DCR_NO_FINE;
chan_writel(dcr | FD_DCR_UPDATE, FD_REG_DCR);
chan_writel(dcr | FD_DCR_ENABLE, FD_REG_DCR);
sgpio_set_pin(dev, SGPIO_OUTPUT_EN(channel), enable ? 1 : 0);
return 0;
}
/* Configures the output channel (channel) to produce pulses delayed from the trigger by (delay_ps).
The output pulse width is proviced in (width_ps) parameter. */
int fdelay_configure_pulse_gen(fdelay_device_t *dev, int channel, int enable, fdelay_time_t t_start, int64_t width_ps, int64_t delta_ps, int rep_count)
{
fd_decl_private(dev)
uint32_t base = (channel-1) * 0x20;
uint32_t dcr;
fdelay_time_t start, end, delta;
if(channel < 1 || channel > 4)
return -1;
start = t_start;
end = fdelay_from_picos(fdelay_to_picos(start) + width_ps - 4000);
delta = fdelay_from_picos(delta_ps);
//start = t_start;
//end = ts_add(start, fdelay_from_picos(width_ps));
//delta = fdelay_from_picos(delta_ps);
//printf("Start: %lld: %d:%d\n", start.utc, start.coarse, start.frac);
//printf("width: %lld delta: %lld rep: %d\n", width_ps, delta_ps, rep_count);
chan_writel(hw->frr_cur[channel-1], FD_REG_FRR);
chan_writel(start.utc >> 32, FD_REG_U_STARTH);
chan_writel(start.utc & 0xffffffff, FD_REG_U_STARTL);
chan_writel(start.coarse, FD_REG_C_START);
chan_writel(start.frac, FD_REG_F_START);
chan_writel(end.utc >> 32, FD_REG_U_ENDH);
chan_writel(end.utc & 0xffffffff, FD_REG_U_ENDL);
chan_writel(end.coarse, FD_REG_C_END);
chan_writel(end.frac, FD_REG_F_END);
chan_writel(delta.utc & 0xf, FD_REG_U_DELTA);
chan_writel(delta.coarse, FD_REG_C_DELTA);
chan_writel(delta.frac, FD_REG_F_DELTA);
// chan_writel(0, FD_REG_RCR);
chan_writel(FD_RCR_REP_CNT_W(rep_count < 0 ? 0 :rep_count-1) | (rep_count < 0 ? FD_RCR_CONT : 0), FD_REG_RCR);
dcr = FD_DCR_MODE;
/* For narrowly spaced pulses, we don't have enough time to reload the tap number into the corresponding
SY89295 - therefore, the width/spacing resolution is limited to 4 ns. */
if((delta_ps - width_ps) < 200000 || (width_ps < 200000))
dcr |= FD_DCR_NO_FINE;
chan_writel(dcr | FD_DCR_UPDATE, FD_REG_DCR);
chan_writel(dcr | FD_DCR_ENABLE, FD_REG_DCR);
chan_writel(dcr | FD_DCR_ENABLE | FD_DCR_PG_ARM, FD_REG_DCR);
sgpio_set_pin(dev, SGPIO_OUTPUT_EN(channel), enable ? 1 : 0);
return 0;
}
int fdelay_channel_triggered(fdelay_device_t *dev, int channel)
{
fd_decl_private(dev)
return chan_readl(FD_REG_DCR) & FD_DCR_PG_TRIG ? 1: 0;
}
/* Todo: write get_time() */
int fdelay_set_time(fdelay_device_t *dev, const fdelay_time_t t)
{
fd_decl_private(dev)
uint32_t tcr;
uint32_t gcr;
fd_writel(0, FD_REG_GCR);
fd_writel(t.utc >> 32, FD_REG_TM_SECH);
fd_writel(t.utc & 0xffffffff, FD_REG_TM_SECL);
fd_writel(t.coarse, FD_REG_TM_CYCLES);
tcr = fd_readl(FD_REG_TCR);
fd_writel(tcr | FD_TCR_SET_TIME, FD_REG_TCR);
return 0;
}
/* Todo: write get_time() */
int fdelay_get_time(fdelay_device_t *dev, fdelay_time_t *t)
{
fd_decl_private(dev)
uint32_t tcr;
tcr = fd_readl(FD_REG_TCR);
fd_writel(tcr | FD_TCR_CAP_TIME, FD_REG_TCR);
t->utc = fd_readl(FD_REG_TM_SECL);
t->coarse = fd_readl(FD_REG_TM_CYCLES);
return 0;
}
#if 0
/* To be rewritten to use interrupts and new WR FSM (see TCR register description).
Use the API provided in fdelay_lib.h */
int fdelay_configure_sync(fdelay_device_t *dev, int mode)
{
fd_decl_private(dev)
if(mode == FDELAY_SYNC_LOCAL)
{
fd_writel(0, FD_REG_GCR);
// fd_writel(FD_GCR_CSYNC_INT, FD_REG_GCR);
hw->wr_enabled = 0;
} else {
fd_writel(0, FD_REG_GCR);
hw->wr_enabled = 1;
hw->wr_state = FDELAY_WR_OFFLINE;
}
}
int fdelay_get_sync_status(fdelay_device_t *dev)
{
fd_decl_private(dev)
if(!hw->wr_enabled) return FDELAY_FREE_RUNNING;
switch(hw->wr_state)
{
case FDELAY_WR_OFFLINE:
if(fd_readl(FD_REG_GCR) & FD_GCR_WR_READY)
{
dbg("-> WR Core synced\n");
hw->wr_state = FDELAY_WR_READY;
}
break;
case FDELAY_WR_READY:
fd_writel(FD_GCR_WR_LOCK_EN, FD_REG_GCR);
hw->wr_state = FDELAY_WR_SYNCING;
break;
case FDELAY_WR_SYNCING:
if(fd_readl(FD_REG_GCR) & FD_GCR_WR_LOCKED)
{
fd_writel(FD_GCR_WR_LOCK_EN | FD_GCR_CSYNC_WR, FD_REG_GCR);
fd_writel(FD_GCR_WR_LOCK_EN , FD_REG_GCR);
fd_writel(FD_GCR_WR_LOCK_EN | FD_GCR_INPUT_EN, FD_REG_GCR);
hw->wr_state = FDELAY_WR_SYNCED;
}
break;
case FDELAY_WR_SYNCED:
if((fd_readl(FD_REG_GCR) & FD_GCR_WR_LOCKED) == 0)
hw->wr_state = FDELAY_WR_OFFLINE;
break;
}
return hw->wr_state;
}
#endif
# if 0
/* We might implement SPLL-based DMTD calibration, but not now - don't include in the driver */
int fd_update_spll(fdelay_device_t *dev)
{
struct spll_helper_state pll;
fd_decl_private(dev)
int i =0;
helper_start(dev, &pll);
fd_writel(FD_CALR_CAL_DMTD, FD_REG_CALR);
sgpio_set_pin(dev, SGPIO_TRIG_SEL, 0);
for(;;)
{
helper_update(&pll);
//if(pll.prelock.ld.locked)
// dbg("LOCK!");
}
}
#endif
#include <stdio.h>
#include "fdelay_lib.h"
int spec_fdelay_init(int argc, char *argv[], fdelay_device_t *dev);
main(int argc, char *argv[])
{
fdelay_device_t dev;
fdelay_time_t t_cur, t_start;
if(spec_fdelay_init(argc, argv, &dev) < 0)
return -1;
// Get the current time of the FD core - and program the card to start producing the PPS and 10 MHz one second later */
fdelay_get_time(&dev, &t_cur);
printf("Current Time: %lld:%d\n", t_cur.utc, t_cur.coarse);
t_start.coarse = t_cur.coarse;
t_start.utc = t_cur.utc+1;
t_start.frac = 0;
fdelay_configure_pulse_gen(&dev, 1, 1, t_start, 48000LL, 100000LL, -1); /* Output 1, period = 100 ns, width = 48 ns - a bit asymmetric 10 MHz */
fdelay_configure_pulse_gen(&dev, 2, 1, t_start, 48000LL, 1000000000000LL, -1); /* Output 2: period = 1 second, width = 48 ns - PPS signal */
while(!fdelay_channel_triggered(&dev, 1) || fdelay_channel_triggered(&dev, 2))
usleep(10000); /* wait until both outputs have triggered*/;
return 0;
}
#include <stdio.h>
#include "fdelay_lib.h"
#include "rr_io.h"
void my_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
uint32_t my_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
main()
{
fdelay_device_t dev;
rr_init();
dev.writel = my_writel;
dev.readl = my_readl;
dev.base_addr = 0x84000;
if(fdelay_init(&dev) < 0)
return -1;
fdelay_configure_trigger(&dev, 1,1);
fdelay_configure_output(&dev,1,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,2,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,3,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,4,1,500000, 100000, 100000, 0);
fdelay_configure_readout(&dev, 1);
// fd_update_spll(&dev);
int64_t prev = 0, dp, pmin=10000000000LL,pmax=0;
#if 0
for(;;)
{
fdelay_time_t ts;
if(fdelay_read(&dev, &ts, 1) == 1)
{
int64_t ts_p = fdelay_to_picos(ts), d;
d=ts_p - prev;
if(prev > 0)
{
if(d<pmin) pmin=d;
if(d>pmax) pmax=d;
fprintf(stderr,"Got it %lld:%d:%d delta %lld span %lld\n", ts.utc, ts.coarse, ts.frac, d, pmax-pmin);
}
prev = ts_p;
}
}
#endif
}
#include <stdio.h>
#include "fdelay_lib.h"
#include "rr_io.h"
int spec_fdelay_init(int argc, char *argv[], fdelay_device_t *dev);
main(int argc, char *argv[])
{
fdelay_device_t dev;
fdelay_time_t t_cur, t_start;
if(spec_fdelay_init(argc, argv, &dev) < 0)
{
fdelay_show_test_results();
return -1;
}
fdelay_configure_trigger(&dev, 1,1);
fdelay_configure_output(&dev,1,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,2,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,3,1,500000, 100000, 100000, 0);
fdelay_configure_output(&dev,4,1,500000, 100000, 100000, 0);
fdelay_configure_readout(&dev, 1);
// fd_update_spll(&dev);
int64_t prev = 0, dp, pmin=10000000000LL,pmax=0;
#if 0
for(;;)
{
fdelay_time_t ts;
if(fdelay_read(&dev, &ts, 1) == 1)
{
int64_t ts_p = fdelay_to_picos(ts), d;
d=ts_p - prev;
if(prev > 0)
{
if(d<pmin) pmin=d;
if(d>pmax) pmax=d;
fprintf(stderr,"Got it %lld:%d:%d delta %lld span %lld\n", ts.utc, ts.coarse, ts.frac, d, pmax-pmin);
}
prev = ts_p;
}
}
#endif
for(;;)
{
fdelay_update_calibration(&dev);
sleep(1);
}
}
#include <stdio.h>
#include "fdelay_lib.h"
#include "fdelay_private.h"
#include "fd_main_regs.h"
#define M_SDA_OUT(x) { \
if(x) \
fd_writel(fd_readl(FD_REG_I2CR) | FD_I2CR_SDA_OUT, FD_REG_I2CR); \
else \
fd_writel(fd_readl(FD_REG_I2CR) & (~FD_I2CR_SDA_OUT), FD_REG_I2CR); \
udelay(10);\
}
#define M_SCL_OUT(x) { \
if(x) \
fd_writel(fd_readl(FD_REG_I2CR) | FD_I2CR_SCL_OUT, FD_REG_I2CR); \
else \
fd_writel(fd_readl(FD_REG_I2CR) & (~FD_I2CR_SCL_OUT), FD_REG_I2CR); \
udelay(10); \
}
#define M_SDA_IN ((fd_readl(FD_REG_I2CR) & FD_I2CR_SDA_IN) ? 1 : 0)
static void mi2c_start(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SDA_OUT(0);
M_SCL_OUT(0);
}
static void mi2c_repeat_start(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SDA_OUT(1);
M_SCL_OUT(1);
M_SDA_OUT(0);
M_SCL_OUT(0);
}
static void mi2c_stop(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SDA_OUT(0);
M_SCL_OUT(1);
M_SDA_OUT(1);
}
int mi2c_put_byte(fdelay_device_t *dev, unsigned char data)
{
fd_decl_private(dev);
char i;
unsigned char ack;
for (i=0;i<8;i++, data<<=1)
{
M_SDA_OUT(data&0x80);
M_SCL_OUT(1);
M_SCL_OUT(0);
}
M_SDA_OUT(1);
M_SCL_OUT(1);
ack = M_SDA_IN; /* ack: sda is pulled low ->success. */
M_SCL_OUT(0);
M_SDA_OUT(0);
return ack!=0 ? -1 : 0;
}
void mi2c_get_byte(fdelay_device_t *dev, unsigned char *data, int ack)
{
fd_decl_private(dev)
int i;
unsigned char indata = 0;
/* assert: scl is low */
M_SCL_OUT(0);
M_SDA_OUT(1);
for (i=0;i<8;i++)
{
M_SCL_OUT(1);
indata <<= 1;
if ( M_SDA_IN ) indata |= 0x01;
M_SCL_OUT(0);
}
M_SDA_OUT((ack ? 0 : 1));
M_SCL_OUT(1);
M_SCL_OUT(0);
M_SDA_OUT(0);
*data= indata;
}
void mi2c_init(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SCL_OUT(1);
M_SDA_OUT(1);
}
void mi2c_scan(fdelay_device_t *dev)
{
int i;
for(i=0;i<256;i+=2)
{
mi2c_start(dev);
if(!mi2c_put_byte(dev,i))
printf("Found device at 0x%x\n", i>>1);
mi2c_stop(dev);
}
}
int eeprom_read(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size)
{
int i;
unsigned char c;
for(i=0;i<size;i++)
{
mi2c_start(dev);
if(mi2c_put_byte(dev, i2c_addr << 1) < 0)
{
mi2c_stop(dev);
return -1;
}
mi2c_put_byte(dev, (offset >> 8) & 0xff);
mi2c_put_byte(dev, offset & 0xff);
offset++;
mi2c_stop(dev);
mi2c_start(dev);
mi2c_put_byte(dev, (i2c_addr << 1) | 1);
mi2c_get_byte(dev, &c, 0);
// printf("readback: %x\n", c);
*buf++ = c;
mi2c_stop(dev);
}
return size;
}
int eeprom_write(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size)
{
int i, busy;
for(i=0;i<size;i++)
{
mi2c_start(dev);
if(mi2c_put_byte(dev, i2c_addr << 1) < 0)
{
mi2c_stop(dev);
return -1;
}
mi2c_put_byte(dev, (offset >> 8) & 0xff);
mi2c_put_byte(dev, offset & 0xff);
mi2c_put_byte(dev, *buf++);
offset++;
mi2c_stop(dev);
do /* wait until the chip becomes ready */
{
mi2c_start(dev);
busy = mi2c_put_byte(dev, i2c_addr << 1);
mi2c_stop(dev);
} while(busy);
}
return size;
}
OBJS = minibone_lib.o ptpd_netif.o
all: $(OBJS)
gcc -o m $(OBJS)
\ No newline at end of file
/* MiniBone library. BUGGY CRAP CODE INTENDED FOR TESTING ONLY! */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/time.h>
#include "ptpd_netif.h"
#define F_SEL(x) (x & 0xf)
#define F_ERROR (1<<1)
#define F_READBACK (1<<0)
#define F_WRITE (1<<4)
#define RX_TIMEOUT 10
#define MBN_ETHERTYPE 0xa0a0
struct mbn_packet {
uint16_t flags ;
uint32_t a_d;
uint32_t d;
} __attribute__((packed));
struct mb_device {
mac_addr_t dest;
uint16_t ethertype;
wr_socket_t *sock;
int tx_packets, rx_packets, tx_retries, rx_retries;
};
typedef struct
{
uint64_t start_tics;
uint64_t timeout;
} timeout_t ;
static uint64_t get_tics()
{
struct timezone tz = {0, 0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (uint64_t) tv.tv_sec * 1000000ULL + (uint64_t) tv.tv_usec;
}
static inline int tmo_init(timeout_t *tmo, uint32_t milliseconds)
{
tmo->start_tics = get_tics();
tmo->timeout = (uint64_t) milliseconds * 1000ULL;
return 0;
}
static inline int tmo_restart(timeout_t *tmo)
{
tmo->start_tics = get_tics();
return 0;
}
static inline int tmo_expired(timeout_t *tmo)
{
return (get_tics() - tmo->start_tics > tmo->timeout);
}
void *mbn_open(const char *if_name, mac_addr_t target)
{
struct mb_device *dev = malloc(sizeof(struct mb_device));
wr_sockaddr_t saddr;
if(!dev)
return NULL;
memset(dev, 0, sizeof(struct mb_device));
memcpy(dev->dest, target, 6);
strcpy(saddr.if_name, if_name);
memcpy(saddr.mac, target, 6);
saddr.ethertype = htons(MBN_ETHERTYPE);
saddr.family = PTPD_SOCK_RAW_ETHERNET;
dev->sock = ptpd_netif_create_socket(PTPD_SOCK_RAW_ETHERNET, 0, &saddr);
if(!dev->sock)
{
free(dev);
return NULL;
}
return (void *)dev;
}
static int mbn_send(void *priv, uint8_t *data, int size)
{
struct mb_device *dev = (struct mb_device *)priv;
wr_sockaddr_t to;
memcpy(to.mac, dev->dest, 6);
to.ethertype = MBN_ETHERTYPE;
return ptpd_netif_sendto(dev->sock, &to, (void*)data, size, NULL);
}
static int mbn_recv(void *handle, uint8_t *data, int size, int timeout)
{
struct mb_device *dev = (struct mb_device *)handle;
wr_sockaddr_t from;
timeout_t rx_tmo;
tmo_init(&rx_tmo, timeout);
do {
int n = ptpd_netif_recvfrom(dev->sock, &from, (void*)data, size, NULL);
if(n > 0 && from.ethertype == MBN_ETHERTYPE && !memcmp(from.mac, dev->dest, 6))
{
dev->rx_packets++;
return n;
}
// dev->rx_retries++;
} while(!tmo_expired(&rx_tmo));
return 0;
}
void mbn_writel(void *handle, uint32_t d, uint32_t a)
{
struct mb_device *dev = (struct mb_device *)handle;
int n_retries = 3;
struct mbn_packet pkt;
while(n_retries--)
{
pkt.flags = htons(F_SEL(0xf) | F_WRITE);
pkt.a_d= htonl(a);
pkt.d=htonl(d);
mbn_send(handle, (uint8_t *)&pkt, sizeof(pkt));
int n = mbn_recv(handle, (uint8_t *)&pkt, sizeof(pkt), RX_TIMEOUT);
pkt.flags = ntohs(pkt.flags);
if(n == sizeof(pkt) && ! (!(pkt.flags && F_READBACK) && !(pkt.flags & F_ERROR)))
{
int i;
fprintf(stderr,"\nBadPacket: ");
for(i=0;i<n; i++) fprintf(stderr,"%02x ", *(uint8_t*) (&pkt + i));
fprintf(stderr,"\n");
} if(n == sizeof(pkt) && !(pkt.flags && F_READBACK) && !(pkt.flags & F_ERROR))
{
int i;
// fprintf(stderr,"GoodFlags: %x\n", pkt.flags);
/*fprintf(stderr,"\nGoodPacket: ");
for(i=0;i<n; i++) fprintf(stderr,"%02x ", *(uint8_t*) (&pkt + i));
fprintf(stderr,"\n");*/
dev->tx_packets++;
return ;
}
dev->tx_retries++;
}
fprintf(stderr, "No ack.\n");
}
uint32_t mbn_readl(void *handle, uint32_t a)
{
int n_retries = 3;
struct mb_device *dev = (struct mb_device *)handle;
struct mbn_packet pkt;
pkt.flags = htons(F_SEL(0xf));
pkt.a_d= htonl(a);
while(n_retries--)
{
mbn_send(handle, (uint8_t *)&pkt, sizeof(pkt));
int n = mbn_recv(handle, (uint8_t *)&pkt, sizeof(pkt), RX_TIMEOUT);
pkt.flags = ntohs(pkt.flags);
if(n == sizeof(pkt) && (pkt.flags & F_READBACK) && !(pkt.flags & F_ERROR))
{
return ntohl(pkt.a_d);
}
dev->tx_retries++;
}
fprintf(stderr, "No ack.\n");
}
void mbn_stats(void *handle)
{
struct mb_device *dev = (struct mb_device *)handle;
fprintf(stderr,"Sent: %d [retries: %d], rcvd: %d [retries: %d]\n", dev->tx_packets, dev->tx_retries, dev->rx_packets, dev->rx_retries);
}
void mbn_close(void *handle)
{
struct mb_device *dev = (struct mb_device *)handle;
ptpd_netif_close_socket(dev->sock);
}
\ No newline at end of file
/* MiniBone library. BUGGY CRAP CODE INTENDED FOR TESTING ONLY! */
#ifndef __MINIBONE_LIB_H
#define __MINIBONE_LIB_H
#include <stdint.h>
void *mbn_open(const char *if_name, uint8_t target_mac[]);
void mbn_writel(void *handle, uint32_t d, uint32_t a);
uint32_t mbn_readl(void *handle, uint32_t a);
void mbn_close(void *handle);
#endif
// Supports only raw ethernet now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/errqueue.h>
#include <linux/sockios.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <fcntl.h>
#include <errno.h>
#include <asm/socket.h>
#include "ptpd_netif.h"
#ifdef NETIF_VERBOSE
#define netif_dbg(...) printf(__VA_ARGS__)
#else
#define netif_dbg(...)
#endif
#define ETHER_MTU 1518
#define DMTD_UPDATE_INTERVAL 100
struct scm_timestamping {
struct timespec systime;
struct timespec hwtimetrans;
struct timespec hwtimeraw;
};
PACKED struct etherpacket {
struct ethhdr ether;
char data[ETHER_MTU];
};
struct tx_timestamp {
int valid;
wr_timestamp_t ts;
uint32_t tag;
uint64_t t_acq;
};
struct my_socket {
int fd;
wr_sockaddr_t bind_addr;
mac_addr_t local_mac;
int if_index;
// parameters for linearization of RX timestamps
uint32_t clock_period;
uint32_t phase_transition;
uint32_t dmtd_phase;
};
struct nasty_hack{
char if_name[20];
int clockedAsPrimary;
};
#ifdef MACIEK_HACKs
struct nasty_hack locking_hack;
#endif
wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags,
wr_sockaddr_t *bind_addr)
{
struct my_socket *s;
struct sockaddr_ll sll;
struct ifreq f;
int fd;
// fprintf(stderr,"CreateSocket!\n");
if(sock_type != PTPD_SOCK_RAW_ETHERNET)
return NULL;
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(fd < 0)
{
perror("socket()");
return NULL;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
// Put the controller in promiscious mode, so it receives everything
strcpy(f.ifr_name, bind_addr->if_name);
if(ioctl(fd, SIOCGIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
f.ifr_flags |= IFF_PROMISC;
if(ioctl(fd, SIOCSIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
// Find the inteface index
strcpy(f.ifr_name, bind_addr->if_name);
ioctl(fd, SIOCGIFINDEX, &f);
sll.sll_ifindex = f.ifr_ifindex;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(bind_addr->ethertype);
sll.sll_halen = 6;
memcpy(sll.sll_addr, bind_addr->mac, 6);
if(bind(fd, (struct sockaddr *)&sll, sizeof(struct sockaddr_ll)) < 0)
{
close(fd);
perror("bind()");
return NULL;
}
s=calloc(sizeof(struct my_socket), 1);
s->if_index = f.ifr_ifindex;
// get interface MAC address
if (ioctl(fd, SIOCGIFHWADDR, &f) < 0) {
perror("ioctl()"); return NULL;
}
memcpy(s->local_mac, f.ifr_hwaddr.sa_data, 6);
memcpy(&s->bind_addr, bind_addr, sizeof(wr_sockaddr_t));
s->fd = fd;
return (wr_socket_t*)s;
}
int ptpd_netif_close_socket(wr_socket_t *sock)
{
struct my_socket *s = (struct my_socket *) sock;
if(!s)
return 0;
close(s->fd);
return 0;
}
int ptpd_netif_sendto(wr_socket_t *sock, wr_sockaddr_t *to, void *data,
size_t data_length, wr_timestamp_t *tx_ts)
{
struct etherpacket pkt;
struct my_socket *s = (struct my_socket *)sock;
struct sockaddr_ll sll;
int rval;
wr_timestamp_t ts;
if(s->bind_addr.family != PTPD_SOCK_RAW_ETHERNET)
return -ENOTSUP;
if(data_length > ETHER_MTU-8) return -EINVAL;
memset(&pkt, 0, sizeof(struct etherpacket));
memcpy(pkt.ether.h_dest, to->mac, 6);
memcpy(pkt.ether.h_source, s->local_mac, 6);
pkt.ether.h_proto =htons(to->ethertype);
memcpy(pkt.data, data, data_length);
size_t len = data_length + sizeof(struct ethhdr);
if(len < 72)
len = 72;
memset(&sll, 0, sizeof(struct sockaddr_ll));
sll.sll_ifindex = s->if_index;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(to->ethertype);
sll.sll_halen = 6;
// fprintf(stderr,"fd %d ifi %d ethertype %d\n", s->fd,
// s->if_index, to->ethertype);
rval = sendto(s->fd, &pkt, len, 0, (struct sockaddr *)&sll,
sizeof(struct sockaddr_ll));
return rval;
}
int ptpd_netif_recvfrom(wr_socket_t *sock, wr_sockaddr_t *from, void *data,
size_t data_length, wr_timestamp_t *rx_timestamp)
{
struct my_socket *s = (struct my_socket *)sock;
struct etherpacket pkt;
struct msghdr msg;
struct iovec entry;
struct sockaddr_ll from_addr;
struct {
struct cmsghdr cm;
char control[1024];
} control;
struct cmsghdr *cmsg;
struct scm_timestamping *sts = NULL;
size_t len = data_length + sizeof(struct ethhdr);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &entry;
msg.msg_iovlen = 1;
entry.iov_base = &pkt;
entry.iov_len = len;
msg.msg_name = (caddr_t)&from_addr;
msg.msg_namelen = sizeof(from_addr);
msg.msg_control = &control;
msg.msg_controllen = sizeof(control);
int ret = recvmsg(s->fd, &msg, MSG_DONTWAIT);
if(ret < 0 && errno==EAGAIN) return 0; // would be blocking
if(ret == -EAGAIN) return 0;
if(ret <= 0) return ret;
memcpy(data, pkt.data, ret - sizeof(struct ethhdr));
from->ethertype = ntohs(pkt.ether.h_proto);
memcpy(from->mac, pkt.ether.h_source, 6);
memcpy(from->mac_dest, pkt.ether.h_dest, 6);
return ret - sizeof(struct ethhdr);
}
// Network API for WR-PTPd
#ifndef __PTPD_NETIF_H
#define __PTPD_NETIF_H
#include <stdio.h>
//#include <inttypes.h>
#define PTPD_SOCK_RAW_ETHERNET 1
#define PTPD_SOCK_UDP 2
#define PTPD_FLAGS_MULTICAST 0x1
// error codes (to be extended)
#define PTPD_NETIF_READY 1
#define PTPD_NETIF_OK 0
#define PTPD_NETIF_ERROR -1
#define PTPD_NETIF_NOT_READY -2
#define PTPD_NETIF_NOT_FOUND -3
// GCC-specific
#define PACKED __attribute__((packed))
#define PHYS_PORT_ANY (0xffff)
#define PTPD_NETIF_TX 1
#define PTPD_NETIF_RX 2
#define IFACE_NAME_LEN 16
#define SLAVE_PRIORITY_0 0
#define SLAVE_PRIORITY_1 1
#define SLAVE_PRIORITY_2 2
#define SLAVE_PRIORITY_3 3
#define SLAVE_PRIORITY_4 4
// Some system-independent definitions
typedef uint8_t mac_addr_t[6];
typedef uint32_t ipv4_addr_t;
// WhiteRabbit socket - it's void pointer as the real socket structure is private and probably platform-specific.
typedef void *wr_socket_t;
// Socket address for ptp_netif_ functions
typedef struct {
// Network interface name (eth0, ...)
char if_name[IFACE_NAME_LEN];
// Socket family (RAW ethernet/UDP)
int family;
// MAC address
mac_addr_t mac;
// Destination MASC address, filled by recvfrom() function on interfaces bound to multiple addresses
mac_addr_t mac_dest;
// IP address
ipv4_addr_t ip;
// UDP port
uint16_t port;
// RAW ethertype
uint16_t ethertype;
// physical port to bind socket to
uint16_t physical_port;
} wr_sockaddr_t;
typedef struct {
uint32_t v[4];
} wr_picoseconds_t;
// Precise WhiteRabbit timestamp
// TS[picoseconds] = utc * 1e12 + nsec * 1e3 + phase;
PACKED struct _wr_timestamp {
// UTC time value (seconds)
int64_t utc;
// Nanoseconds
int32_t nsec;
// Phase (in picoseconds), linearized for receive timestamps, zero for send timestamps
int32_t phase; // phase(picoseconds)
int32_t raw_phase;
int32_t raw_nsec;
int32_t raw_ahead;
//int cntr_ahead;
};
typedef struct _wr_timestamp wr_timestamp_t;
/* OK. These functions we'll develop along with network card driver. You can write your own UDP-based stubs for testing purposes. */
// Initialization of network interface:
// - opens devices
// - does necessary ioctls()
// - initializes connection with the mighty HAL daemon
int ptpd_netif_init();
// Creates UDP or Ethernet RAW socket (determined by sock_type) bound to bind_addr. If PTPD_FLAG_MULTICAST is set, the socket is
// automatically added to multicast group. User can specify physical_port field to bind the socket to specific switch port only.
wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags, wr_sockaddr_t *bind_addr);
// Sends a UDP/RAW packet (data, data_length) to address provided in wr_sockaddr_t.
// For raw frames, mac/ethertype needs to be provided, for UDP - ip/port.
// Every transmitted frame has assigned a tag value, stored at tag parameter. This value is later used
// for recovering the precise transmit timestamp. If user doesn't need it, tag parameter can be left NULL.
int ptpd_netif_sendto(wr_socket_t *sock, wr_sockaddr_t *to, void *data, size_t data_length, wr_timestamp_t *tx_ts);
// Receives an UDP/RAW packet. Data is written to (data) and length is returned. Maximum buffer length can be specified
// by data_length parameter. Sender information is stored in structure specified in 'from'. All RXed packets are timestamped and the timestamp
// is stored in rx_timestamp (unless it's NULL).
int ptpd_netif_recvfrom(wr_socket_t *sock, wr_sockaddr_t *from, void *data, size_t data_length, wr_timestamp_t *rx_timestamp);
// Closes the socket.
int ptpd_netif_close_socket(wr_socket_t *sock);
int ptpd_netif_poll(wr_socket_t*);
int ptpd_netif_get_hw_addr(wr_socket_t *sock, mac_addr_t *mac);
/*
* Function start HW locking of freq on WR Slave
* return:
* PTPD_NETIF_ERROR - locking not started
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_locking_enable(int txrx, const char *ifaceName, int priority);
/*
*
* return:
*
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_locking_disable(int txrx, const char *ifaceName, int priority);
int ptpd_netif_locking_poll(int txrx, const char *ifaceName, int priority);
/*
* Function turns on calibration (measurement of delay)
* Tx or Rx depending on the txrx param
* return:
* PTPD_NETIF_NOT_READY - if there is calibratin going on on another port
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibrating_enable(int txrx, const char *ifaceName);
/*
* Function turns off calibration (measurement of delay)
* Tx or Rx depending on the txrx param
* return:
* PTPD_NETIF_ERROR - if there is calibratin going on on another port
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibrating_disable(int txrx, const char *ifaceName);
/*
* Function checks if Rx/Tx (depending on the param) calibration is finished
* if finished, returns measured delay in delta
* return:
*
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_calibrating_poll(int txrx, const char *ifaceName, uint64_t *delta);
/*
* Function turns on calibration pattern.
* return:
* PTPD_NETIF_NOT_READY - if WRSW is busy with calibration on other switch or error occured
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibration_pattern_enable(const char *ifaceName, unsigned int calibrationPeriod, unsigned int calibrationPattern, unsigned int calibrationPatternLen);
/*
* Function turns off calibration pattern
* return:
* PTPD_NETIF_ERROR - turning off not successful
* PTPD_NETIF_OK - turning off successful
*/
int ptpd_netif_calibration_pattern_disable(const char *ifaceName);
/*
* Function read calibration data if it's available, used at the beginning of PTPWRd to check if
* HW knows already the interface's deltax, and therefore no need for calibration
* return:
* PTPD_NETIF_NOT_FOUND - if deltas are not known
* PTPD_NETIF_OK - if deltas are known, in such case, deltaTx and deltaRx have valid data
*/
int ptpd_netif_read_calibration_data(const char *ifaceName, uint64_t *deltaTx, uint64_t *deltaRx);
#define MACIEK_TMP
#ifdef MACIEK_TMP
int ptpd_netif_select(wr_socket_t*);
int ptpd_netif_get_hw_addr(wr_socket_t *sock, mac_addr_t *mac);
#endif
/*
* Function reads state of the given port (interface in our case), if the port is up, everything is OK, otherwise ERROR
* return:
* PTPD_NETIF_ERROR - if the port is down
* PTPD_NETIF_OK - if the port is up
*/
int ptpd_netif_get_port_state(const char *ifaceName);
/*
* Function looks for a port (interface) for the port number 'number'
* it will return in the argument ifname the port name
* return:
* PTPD_NETIF_ERROR - port not found
* PTPD_NETIF_OK - if the port found
*/
int ptpd_netif_get_ifName(char *ifname, int number);
/* Returns the millisecond "tics" counter value */
uint64_t ptpd_netif_get_msec_tics();
/*
* Function detects external source lock,
*
* return:
* HEXP_EXTSRC_STATUS_LOCKED 0
* HEXP_LOCK_STATUS_BUSY 1
* HEXP_EXTSRC_STATUS_NOSRC 2
*/
int ptpd_netif_extsrc_detection();
#endif
#include <stdio.h>
#include <stdint.h>
#include "fdelay_lib.h"
#include "fdelay_private.h"
#define R_CSR 0x0
#define R_CDR 0x4
#define CSR_DAT_MSK (1<<0)
#define CSR_RST_MSK (1<<1)
#define CSR_OVD_MSK (1<<2)
#define CSR_CYC_MSK (1<<3)
#define CSR_PWR_MSK (1<<4)
#define CSR_IRQ_MSK (1<<6)
#define CSR_IEN_MSK (1<<7)
#define CSR_SEL_OFS 8
#define CSR_SEL_MSK (0xF<<8)
#define CSR_POWER_OFS 16
#define CSR_POWER_MSK (0xFFFF<<16)
#define CDR_NOR_MSK (0xFFFF<<0)
#define CDR_OVD_OFS 16
#define CDR_OVD_MSK (0xFFFF<<16)
#define ow_writel(data, addr) dev->writel(dev->priv_io, data, (hw->base_onewire + (addr)))
#define ow_readl(addr) dev->readl(dev->priv_io, (hw->base_onewire + (addr)))
#define CLK_DIV_NOR 624/2
#define CLK_DIV_OVD 124/2
static void ow_init(fdelay_device_t *dev)
{
fd_decl_private(dev);
ow_writel(((CLK_DIV_NOR & CDR_NOR_MSK) | (( CLK_DIV_OVD << CDR_OVD_OFS) & CDR_OVD_MSK)), R_CDR);
}
static int ow_reset(fdelay_device_t *dev, int port)
{
fd_decl_private(dev);
uint32_t data = ((port<<CSR_SEL_OFS) & CSR_SEL_MSK) | CSR_CYC_MSK | CSR_RST_MSK;
ow_writel(data, R_CSR);
while(ow_readl(R_CSR) & CSR_CYC_MSK);
uint32_t reg = ow_readl(R_CSR);
return ~reg & CSR_DAT_MSK;
}
static int slot(fdelay_device_t *dev, int port, int bit)
{
fd_decl_private(dev);
uint32_t data;
data = ((port<<CSR_SEL_OFS) & CSR_SEL_MSK) | CSR_CYC_MSK | (bit & CSR_DAT_MSK);
ow_writel(data, R_CSR);
while(ow_readl(R_CSR) & CSR_CYC_MSK);
uint32_t reg = ow_readl(R_CSR);
return reg & CSR_DAT_MSK;
}
static int read_bit(fdelay_device_t *dev, int port) { return slot(dev, port, 0x1); }
static int write_bit(fdelay_device_t *dev, int port, int bit) { return slot(dev, port, bit); }
int ow_read_byte(fdelay_device_t *dev, int port) {
int data = 0, i;
for(i=0;i<8;i++)
data |= read_bit(dev, port) << i;
return data;
}
int ow_write_byte(fdelay_device_t *dev, int port, int byte)
{
int data = 0;
int byte_old = byte, i;
for (i=0;i<8;i++){
data |= write_bit(dev, port, (byte & 0x1)) << i;
byte >>= 1;
}
return byte_old == data ? 0 : -1;
}
int ow_write_block(fdelay_device_t *dev, int port, uint8_t *block, int len)
{
int i;
for(i=0;i<len;i++)
{
*block++ = ow_write_byte(dev, port, *block);
}
return 0;
}
int ow_read_block(fdelay_device_t *dev, int port, uint8_t *block, int len)
{
int i;
for(i=0;i<len;i++)
{
*block++ = ow_read_byte(dev, port);
}
return 0;
}
#define ROM_SEARCH 0xF0
#define ROM_READ 0x33
#define ROM_MATCH 0x55
#define ROM_SKIP 0xCC
#define ROM_ALARM_SEARCH 0xEC
#define CONVERT_TEMP 0x44
#define WRITE_SCRATCHPAD 0x4E
#define READ_SCRATCHPAD 0xBE
#define COPY_SCRATCHPAD 0x48
#define RECALL_EEPROM 0xB8
#define READ_POWER_SUPPLY 0xB4
static uint8_t ds18x_id [8];
int ds18x_read_serial(fdelay_device_t *dev, uint8_t *id)
{
int i;
if(!ow_reset(dev, 0))
return -1;
ow_write_byte(dev, 0, ROM_READ);
for(i=0;i<8;i++)
{
*id = ow_read_byte(dev, 0);
id++;
}
return 0;
}
static int ds18x_access(fdelay_device_t *dev, uint8_t *id)
{
int i;
if(!ow_reset(dev, 0))
return -1;
if(ow_write_byte(dev, 0, ROM_MATCH) < 0)
return -1;
for(i=0;i<8;i++)
if(ow_write_byte(dev, 0, id[i]) < 0)
return -1;
}
int ds18x_read_temp(fdelay_device_t *dev, int *temp_r)
{
int i;
uint8_t data[9];
if(ds18x_access(dev, ds18x_id) < 0)
return -1;
ow_write_byte(dev, 0, READ_SCRATCHPAD);
for(i=0;i<9;i++) data[i] = ow_read_byte(dev, 0);
int temp = ((int)data[1] << 8) | ((int)data[0]);
if(temp & 0x1000)
temp = -0x10000 + temp;
ds18x_access(dev, ds18x_id);
ow_write_byte(dev, 0, CONVERT_TEMP);
if(temp_r) *temp_r = temp;
return 0;
}
int ds18x_init(fdelay_device_t *dev)
{
ow_init(dev);
if(ds18x_read_serial(dev, ds18x_id) < 0)
return -1;
dbg("Found DS18xx sensor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
ds18x_id[0], ds18x_id[1], ds18x_id[2], ds18x_id[3],
ds18x_id[4], ds18x_id[5], ds18x_id[6], ds18x_id[7]);
return ds18x_read_temp(dev, NULL);
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <rawrabbit.h>
#include "rr_io.h"
#define DEVNAME "/dev/rawrabbit"
static int fd;
int rr_bind(int a_fd)
{
fd = a_fd;
return 0;
}
int rr_init(int bus, int devfn)
{
struct rr_devsel devsel;
int ret = -EINVAL;
devsel.bus = bus;
devsel.devfn = devfn;
devsel.subvendor = RR_DEVSEL_UNUSED;
devsel.vendor = 0x10dc;//RR_DEVSEL_UNUSED;
devsel.device = 0x18d; //RR_DEVSEL_UNUSED;
devsel.subdevice = RR_DEVSEL_UNUSED;
fd = open(DEVNAME, O_RDWR);
if (fd < 0) {
return -1;
}
if (ioctl(fd, RR_DEVSEL, &devsel) < 0) {
return -EIO;
}
return 0;
}
int rr_writel(uint32_t data, uint32_t addr)
{
struct rr_iocmd iocmd;
iocmd.datasize = 4;
iocmd.address = addr;
iocmd.address |= __RR_SET_BAR(0);
iocmd.data32 = data;
ioctl(fd, RR_WRITE, &iocmd);
}
uint32_t rr_readl(uint32_t addr)
{
struct rr_iocmd iocmd;
iocmd.datasize = 4;
iocmd.address = addr;
iocmd.address |= __RR_SET_BAR(0);
ioctl(fd, RR_READ, &iocmd);
return iocmd.data32;
}
static void gennum_writel(uint32_t data, uint32_t addr)
{
struct rr_iocmd iocmd;
iocmd.datasize = 4;
iocmd.address = addr;
iocmd.address |= __RR_SET_BAR(4);
iocmd.data32 = data;
ioctl(fd, RR_WRITE, &iocmd);
}
static uint32_t gennum_readl(uint32_t addr)
{
struct rr_iocmd iocmd;
iocmd.datasize = 4;
iocmd.address = addr;
iocmd.address |= __RR_SET_BAR(4);
ioctl(fd, RR_READ, &iocmd);
return iocmd.data32;
}
static inline int64_t get_tics()
{
struct timezone tz= {0,0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (int64_t)tv.tv_sec * 1000000LL + (int64_t) tv.tv_usec;
}
/* These must be set to choose the FPGA configuration mode */
#define GPIO_BOOTSEL0 15
#define GPIO_BOOTSEL1 14
static inline uint8_t reverse_bits8(uint8_t x)
{
x = ((x >> 1) & 0x55) | ((x & 0x55) << 1);
x = ((x >> 2) & 0x33) | ((x & 0x33) << 2);
x = ((x >> 4) & 0x0f) | ((x & 0x0f) << 4);
return x;
}
static uint32_t unaligned_bitswap_le32(const uint32_t *ptr32)
{
static uint32_t tmp32;
static uint8_t *tmp8 = (uint8_t *) &tmp32;
static uint8_t *ptr8;
ptr8 = (uint8_t *) ptr32;
*(tmp8 + 0) = reverse_bits8(*(ptr8 + 0));
*(tmp8 + 1) = reverse_bits8(*(ptr8 + 1));
*(tmp8 + 2) = reverse_bits8(*(ptr8 + 2));
*(tmp8 + 3) = reverse_bits8(*(ptr8 + 3));
return tmp32;
}
static inline void gpio_out(int fd, const uint32_t addr, const int bit, const int value)
{
uint32_t reg;
reg = gennum_readl(addr);
if(value)
reg |= (1<<bit);
else
reg &= ~(1<<bit);
gennum_writel(reg, addr);
}
/*
* Unfortunately, most of the following is from fcl_gn4124.cpp, for which
* the license terms are at best ambiguous.
*/
int loader_low_level(int fd, const void *data, int size8)
{
int size32 = (size8 + 3) >> 2;
const uint32_t *data32 = data;
int ctrl = 0, i, done = 0, wrote = 0;
/* configure Gennum GPIO to select GN4124->FPGA configuration mode */
gpio_out(fd, GNGPIO_DIRECTION_MODE, GPIO_BOOTSEL0, 0);
gpio_out(fd, GNGPIO_DIRECTION_MODE, GPIO_BOOTSEL1, 0);
gpio_out(fd, GNGPIO_OUTPUT_ENABLE, GPIO_BOOTSEL0, 1);
gpio_out(fd, GNGPIO_OUTPUT_ENABLE, GPIO_BOOTSEL1, 1);
gpio_out(fd, GNGPIO_OUTPUT_VALUE, GPIO_BOOTSEL0, 1);
gpio_out(fd, GNGPIO_OUTPUT_VALUE, GPIO_BOOTSEL1, 0);
gennum_writel( 0x00, FCL_CLK_DIV);
gennum_writel( 0x40, FCL_CTRL); /* Reset */
i = gennum_readl( FCL_CTRL);
if (i != 0x40) {
printf("%s: %i: error\n", __func__, __LINE__);
return -EIO;
}
gennum_writel( 0x00, FCL_CTRL);
gennum_writel( 0x00, FCL_IRQ); /* clear pending irq */
switch(size8 & 3) {
case 3: ctrl = 0x116; break;
case 2: ctrl = 0x126; break;
case 1: ctrl = 0x136; break;
case 0: ctrl = 0x106; break;
}
gennum_writel( ctrl, FCL_CTRL);
gennum_writel( 0x00, FCL_CLK_DIV); /* again? maybe 1 or 2? */
gennum_writel( 0x00, FCL_TIMER_CTRL); /* "disable FCL timr fun" */
gennum_writel( 0x10, FCL_TIMER_0); /* "pulse width" */
gennum_writel( 0x00, FCL_TIMER_1);
/*
* Set delay before data and clock is applied by FCL
* after SPRI_STATUS is detected being assert.
*/
gennum_writel( 0x08, FCL_TIMER2_0); /* "delay before data/clk" */
gennum_writel( 0x00, FCL_TIMER2_1);
gennum_writel( 0x17, FCL_EN); /* "output enable" */
ctrl |= 0x01; /* "start FSM configuration" */
gennum_writel( ctrl, FCL_CTRL);
while(size32 > 0)
{
/* Check to see if FPGA configuation has error */
i = gennum_readl( FCL_IRQ);
if ( (i & 8) && wrote) {
done = 1;
printf("%s: %i: done after %i\n", __func__, __LINE__,
wrote);
} else if ( (i & 0x4) && !done) {
printf("%s: %i: error after %i\n", __func__, __LINE__,
wrote);
return -EIO;
}
/* Wait until at least 1/2 of the fifo is empty */
while (gennum_readl( FCL_IRQ) & (1<<5))
;
/* Write a few dwords into FIFO at a time. */
for (i = 0; size32 && i < 32; i++) {
gennum_writel( unaligned_bitswap_le32(data32),
FCL_FIFO);
data32++; size32--; wrote++;
}
}
gennum_writel( 0x186, FCL_CTRL); /* "last data written" */
/* Checking for the "interrupt" condition is left to the caller */
return wrote;
}
int rr_load_bitstream_from_file(const char *file_name)
{
uint8_t *buf;
FILE *f;
uint32_t size;
f=fopen(file_name,"rb");
if(!f) return -1;
fseek(f, 0, SEEK_END);
size = ftell(f);
buf = malloc(size);
if(!buf)
{
fclose(f);
return -1;
}
fseek(f, 0, SEEK_SET);
fread(buf, 1, size, f);
fclose(f);
int rval = loader_low_level(0, buf, size);
free(buf);
return rval;
}
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "fdelay_lib.h"
#include "rr_io.h"
void spec_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
uint32_t spec_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
int spec_fdelay_init(int argc, char *argv[], fdelay_device_t *dev)
{
int bus = RR_DEVSEL_UNUSED, devfn = RR_DEVSEL_UNUSED;
int opt = 0;
char fw_name[1024];
strcpy(fw_name, "spec_top.bin");
while ((opt = getopt(argc, argv, "hb:d:f:")) != -1) {
switch (opt) {
case 'h':
printf("Usage: %s [-b PCI_bus] [-d PCI dev/func] [-f firmware file]\n", argv[0]);
printf("By default, the first detected SPEC is initialized with 'spec_top.bin' firmware\n");
return 0;
case 'b':
sscanf(optarg, "%x", &bus);
break;
case 'd':
sscanf(optarg, "%x", &devfn);
break;
case 'f':
strcpy(fw_name, optarg);
break;
}
}
if(rr_init(bus, devfn) < 0)
{
fprintf(stderr, "Failed to initialize rawrabbit.\n");
return -1;
}
dev->writel = spec_writel;
dev->readl = spec_readl;
dev->base_addr = 0x84000;
if(rr_load_bitstream_from_file(fw_name) < 0)
{
fprintf(stderr,"Failed to load FPGA bitstream.\n");
return -1;
}
if(fdelay_init(dev) < 0)
return -1;
return 0;
}
#include <stdio.h>
#include "board.h"
#include "hw/softpll_regs.h"
#include "irq.h"
static volatile struct SPLL_WB *SPLL = (volatile struct SPLL_WB *) BASE_SOFTPLL;
/* The includes below contain code (not only declarations) to enable the compiler
to inline functions where necessary and save some CPU cycles */
#include "spll_defs.h"
#include "spll_common.h"
#include "spll_helper.h"
volatile int irq_count = 0,eee,yyy;
struct spll_helper_state helper;
void _irq_entry()
{
volatile uint32_t trr;
int src = -1, tag;
if(! (SPLL->CSR & SPLL_TRR_CSR_EMPTY))
{
trr = SPLL->TRR_R0;
src = SPLL_TRR_R0_CHAN_ID_R(trr);
tag = SPLL_TRR_R0_VALUE_R(trr);
eee = tag;
}
helper_update(&helper, tag, src);
yyy=helper.phase.pi.y;
irq_count++;
clear_irq();
}
void spll_init()
{
volatile int dummy;
disable_irq();
SPLL->CSR= 0 ;
SPLL->OCER = 0;
SPLL->RCER = 0;
SPLL->DEGLITCH_THR = 2000;
while(! (SPLL->TRR_CSR & SPLL_TRR_CSR_EMPTY)) dummy = SPLL->TRR_R0;
dummy = SPLL->PER_HPLL;
SPLL->EIC_IER = 1;
}
void spll_test()
{
int i = 0;
volatile int dummy;
spll_init();
helper_start(&helper, 6);
enable_irq();
for(;;)
{
mprintf("cnt %d serr %d src %d y %d d %d\n", irq_count, eee, serr, yyy, delta);
}
}
\ No newline at end of file
/*
White Rabbit Softcore PLL (SoftPLL) - common definitions
*/
/* PI regulator state */
typedef struct {
int ki, kp; /* integral and proportional gains (1<<PI_FRACBITS == 1.0f) */
int integrator; /* current integrator value */
int bias; /* DC offset always added to the output */
int anti_windup; /* when non-zero, anti-windup is enabled */
int y_min; /* min/max output range, used by claming and antiwindup algorithms */
int y_max;
int x,y; /* Current input and output value */
} spll_pi_t;
/* Processes a single sample (x) using PI controller (pi). Returns the value (y) which should
be used to drive the actuator. */
static inline int pi_update(spll_pi_t *pi, int x)
{
int i_new, y;
pi->x = x;
i_new = pi->integrator + x;
y = ((i_new * pi->ki + x * pi->kp) >> PI_FRACBITS) + pi->bias;
/* clamping (output has to be in <y_min, y_max>) and anti-windup:
stop the integretor if the output is already out of range and the output
is going further away from y_min/y_max. */
if(y < pi->y_min)
{
y = pi->y_min;
if((pi->anti_windup && (i_new > pi->integrator)) || !pi->anti_windup)
pi->integrator = i_new;
} else if (y > pi->y_max) {
y = pi->y_max;
if((pi->anti_windup && (i_new < pi->integrator)) || !pi->anti_windup)
pi->integrator = i_new;
} else
pi->integrator = i_new;
pi->y = y;
return y;
}
/* initializes the PI controller state. Currently almost a stub. */
static inline void pi_init(spll_pi_t *pi)
{
pi->integrator = 0;
}
/* lock detector state */
typedef struct {
int lock_cnt;
int lock_samples;
int delock_samples;
int threshold;
int locked;
} spll_lock_det_t;
/* Lock detector state machine. Takes an error sample (y) and checks if it's withing an acceptable range
(i.e. <-ld.threshold, ld.threshold>. If it has been inside the range for (ld.lock_samples) cyckes, the
FSM assumes the PLL is locked. */
static inline int ld_update(spll_lock_det_t *ld, int y)
{
if (abs(y) <= ld->threshold)
{
if(ld->lock_cnt < ld->lock_samples)
ld->lock_cnt++;
if(ld->lock_cnt == ld->lock_samples)
ld->locked = 1;
} else {
if(ld->lock_cnt > ld->delock_samples)
ld->lock_cnt--;
if(ld->lock_cnt == ld->delock_samples)
{
ld->lock_cnt= 0;
ld->locked = 0;
}
}
return ld->locked;
}
static void ld_init(spll_lock_det_t *ld)
{
ld->locked = 0;
ld->lock_cnt = 0;
}
/*
White Rabbit Softcore PLL (SoftPLL) - common definitions
*/
#include <stdio.h>
/* Reference clock frequency */
#define CLOCK_FREQ 125000000
/* Bit size of phase tags generated by the DMTDs. Used to sign-extend the tags. */
#define TAG_BITS 20
/* Helper PLL N divider (1/2**N is the frequency offset) */
#define HPLL_N 14
/* Fractional bits in PI controller coefficients */
#define PI_FRACBITS 12
/* State of the Helper PLL producing a clock (clk_dmtd_i) which is
slightly offset in frequency from the recovered/reference clock (clk_rx_i or clk_ref_i), so the
Main PLL can use it to perform linear phase measurements. This structure keeps the state of the pre-locking
stage */
struct spll_helper_prelock_state {
spll_pi_t pi;
spll_lock_det_t ld;
int f_setpoint;
int ref_select;
fdelay_device_t *dev;
};
volatile int serr;
void helper_prelock_init(struct spll_helper_prelock_state *s)
{
/* Frequency branch PI controller */
s->pi.y_min = 5;
s->pi.y_max = 65530;
s->pi.anti_windup = 0;
s->pi.kp = 28*32*16;
s->pi.ki = 50*32*16;
s->pi.bias = 32000;
/* Freqency branch lock detection */
s->ld.threshold = 2;
s->ld.lock_samples = 1000;
s->ld.delock_samples = 990;
s->f_setpoint = 131072 / (1<<HPLL_N);
pi_init(&s->pi);
ld_init(&s->ld);
}
void helper_prelock_enable(struct spll_helper_prelock_state *state, int ref_channel, int enable)
{
fdelay_device_t *dev = state->dev;
fd_decl_private(dev);
fd_writel(0, FD_REG_SPLLR);
}
#define SPLL_LOCKED 1
#define SPLL_LOCKING 0
int helper_prelock_update(struct spll_helper_prelock_state *s, int tag)
{
fdelay_device_t *dev = s->dev;
fd_decl_private(dev);
int y;
volatile uint32_t per = fd_readl(FD_REG_SPLLR);
short err = (short) (tag & 0xffff);
serr = (int)err;
err -= s->f_setpoint;
y = pi_update(&s->pi, err);
fd_writel(y, FD_REG_SDACR);
if(ld_update(&s->ld, err))
return SPLL_LOCKED;
return SPLL_LOCKING;
}
struct spll_helper_phase_state {
spll_pi_t pi;
spll_lock_det_t ld;
int p_setpoint, tag_d0;
int ref_src;
fdelay_device_t *dev;
};
void helper_phase_init(struct spll_helper_phase_state *s)
{
/* Phase branch PI controller */
s->pi.y_min = 5;
s->pi.y_max = 65530;
s->pi.kp = (int)(2.0 * 32.0 * 16.0);
s->pi.ki = (int)(0.05 * 32.0 * 3.0);
s->pi.anti_windup = 0;
s->pi.bias = 32000;
/* Phase branch lock detection */
s->ld.threshold = 500;
s->ld.lock_samples = 10000;
s->ld.delock_samples = 9900;
s->ref_src = 6;
s->p_setpoint = -1;
pi_init(&s->pi);
ld_init(&s->ld);
}
void helper_phase_enable(struct spll_helper_phase_state *state, int ref_channel, int enable)
{
fdelay_device_t *dev = state->dev;
fd_decl_private(dev);
fd_writel(FD_SPLLR_MODE, FD_REG_SPLLR);
}
volatile int delta;
int helper_phase_update(struct spll_helper_phase_state *s, int tag, int source)
{
fdelay_device_t *dev = s->dev;
fd_decl_private(dev);
int err, y;
serr = source;
// if(source == s->ref_src)
{
if(s->p_setpoint < 0)
{
s->p_setpoint = tag;
return;
}
err = tag - s->p_setpoint;
delta = tag - s->tag_d0;
s->tag_d0 = tag;
s->p_setpoint += (1<<HPLL_N);
if(s->p_setpoint > (1<<TAG_BITS))
s->p_setpoint -= (1<<TAG_BITS);
y = pi_update(&s->pi, err);
//printf("t %d sp %d\n", tag, s->p_setpoint);
fd_writel(y, FD_REG_SDACR);
if(ld_update(&s->ld, err))
{
return SPLL_LOCKED;
};
}
return SPLL_LOCKING;
}
#define HELPER_PRELOCKING 1
#define HELPER_PHASE 2
#define HELPER_LOCKED 3
struct spll_helper_state {
struct spll_helper_prelock_state prelock;
struct spll_helper_phase_state phase;
int state;
int ref_channel;
};
void helper_start(fdelay_device_t *dev, struct spll_helper_state *s)
{
s->state = HELPER_PRELOCKING;
s->ref_channel = 0;
s->prelock.dev = dev;
s->phase.dev = dev;
helper_prelock_init(&s->prelock);
helper_phase_init(&s->phase);
helper_prelock_enable(&s->prelock, 0, 1);
}
void helper_update(struct spll_helper_state *s)
{
fdelay_device_t *dev = s->prelock.dev;
fd_decl_private(dev);
uint32_t spllr = fd_readl(FD_REG_SPLLR);
if(! (spllr & FD_SPLLR_TAG_RDY))
return;
int tag = FD_SPLLR_TAG_R(spllr);
switch(s->state)
{
case HELPER_PRELOCKING:
if(helper_prelock_update(&s->prelock, tag) == SPLL_LOCKED)
{
s->state = HELPER_PHASE;
helper_prelock_enable(&s->prelock, 0, 0);
s->phase.pi.bias = s->prelock.pi.y;
helper_phase_enable(&s->phase, 0, 1);
}
break;
case HELPER_PHASE:
helper_phase_update(&s->phase, tag, 0);
break;
}
}
#!/usr/bin/python
import sys
import PyQt4
import PyQt4.QtGui
import PyQt4.QtCore
import PyQt4.uic
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from fdelay_lib import FineDelay
FormClass = PyQt4.uic.loadUiType('fd_demo.ui')[0]
class MainWindow(QMainWindow, FormClass):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
# self.setWindowTitle("ion")
def channel_update(channel):
print("UpdateCh: %d" % channel)
en = ch_enable[channel-1].checkState();
dly = int(ch_nsec[channel-1].value() * 1000 + (ch_sec[channel-1].value() * 1000000000000))
w = int(ch_width[channel-1].value() * 1000)
card.conf_output(channel, en, dly, w)
def trigger_update():
card.conf_trigger(m.en_trigger.checkState(), m.en_term.checkState())
def on_ts_enable_disable():
print("ontsen")
card.conf_readout(m.en_ts.checkState())
prev_ts = 0
def on_ts_clear():
print("ontabclear")
poll_timer.stop()
for i in range(0, m.ts_table.rowCount()):
m.ts_table.removeRow(i)
prev_ts = 0
poll_timer.start()
def poll_timer_cb():
buf = card.read_ts()
for ts in buf:
global prev_ts
row = m.ts_table.rowCount()
m.ts_table.insertRow(row)
m.ts_table.setItem(row, 0, QTableWidgetItem("%d"%ts.seq_id))
m.ts_table.setItem(row, 1, QTableWidgetItem("%d"%ts.utc))
m.ts_table.setItem(row, 2, QTableWidgetItem("%.3f"%ts.nsecs()))
m.ts_table.setItem(row, 3, QTableWidgetItem("%.3f"%(ts.nsecs_full()-prev_ts)))
prev_ts = ts.nsecs_full()
# i = QTableWidgetItem()
m.ts_table.scrollToBottom()
m.wr_status.setText(card.get_sync_status())
def on_chk_wr():
if(m.wr_checkbox.checkState()):
card.conf_sync(card.SYNC_WR)
else:
card.conf_sync(card.SYNC_LOCAL)
if __name__ == "__main__":
app = QApplication(sys.argv)
location = "local/0x84000"
m = MainWindow()
m.show()
m.setWindowTitle("Fine Delay Demo @ %s" % location)
card = FineDelay(location)
m.wr_status.setText("")
ch_enable = [m.en_ch1, m.en_ch2, m.en_ch3, m.en_ch4];
ch_nsec = [m.nsec_ch1, m.nsec_ch2, m.nsec_ch3, m.nsec_ch4];
ch_sec = [m.sec_ch1, m.sec_ch2, m.sec_ch3, m.sec_ch4];
ch_width = [m.width_ch1, m.width_ch2, m.width_ch3, m.width_ch4];
for i in range(1,5):
channel_update(i)
ch_enable[0].stateChanged.connect(lambda :channel_update(1))
ch_enable[1].stateChanged.connect(lambda :channel_update(2))
ch_enable[2].stateChanged.connect(lambda :channel_update(3))
ch_enable[3].stateChanged.connect(lambda :channel_update(4))
ch_nsec[0].valueChanged.connect(lambda :channel_update(1))
ch_nsec[1].valueChanged.connect(lambda :channel_update(2))
ch_nsec[2].valueChanged.connect(lambda :channel_update(3))
ch_nsec[3].valueChanged.connect(lambda :channel_update(4))
ch_sec[0].valueChanged.connect(lambda :channel_update(1))
ch_sec[1].valueChanged.connect(lambda :channel_update(2))
ch_sec[2].valueChanged.connect(lambda :channel_update(3))
ch_sec[3].valueChanged.connect(lambda :channel_update(4))
ch_width[0].valueChanged.connect(lambda :channel_update(1))
ch_width[1].valueChanged.connect(lambda :channel_update(2))
ch_width[2].valueChanged.connect(lambda :channel_update(3))
ch_width[3].valueChanged.connect(lambda :channel_update(4))
m.en_trigger.stateChanged.connect(lambda :trigger_update())
m.en_term.stateChanged.connect(lambda :trigger_update())
m.en_ts.stateChanged.connect(on_ts_enable_disable)
m.wr_checkbox.stateChanged.connect(on_chk_wr)
m.btn_clear.clicked.connect(on_ts_clear)
trigger_update();
on_ts_enable_disable()
m.ts_table.clearContents()
# m.ts_table
poll_timer = QTimer()
poll_timer.setInterval(200)
poll_timer.timeout.connect(poll_timer_cb)
poll_timer.start()
app.exec_()
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MyDialog</class>
<widget class="QDialog" name="MyDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>649</width>
<height>352</height>
</rect>
</property>
<property name="windowTitle">
<string>Fine Delay Demo</string>
</property>
<widget class="QTabWidget" name="tabWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>631</width>
<height>331</height>
</rect>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab_delay">
<attribute name="title">
<string>Delay</string>
</attribute>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>591</width>
<height>161</height>
</rect>
</property>
<property name="title">
<string>Outputs</string>
</property>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>470</x>
<y>10</y>
<width>91</width>
<height>16</height>
</rect>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Pulse width</string>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>581</width>
<height>128</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>OUT1:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="en_ch1">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="sec_ch1">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>s</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>120.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="nsec_ch1">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>500.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="width_ch1">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>200.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>200.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>OUT2:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="en_ch2">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="sec_ch2">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>s</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>120.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="nsec_ch2">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>500.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="width_ch2">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>200.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>200.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_5">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>OUT3:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="en_ch3">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="sec_ch3">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>s</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>120.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="nsec_ch3">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>500.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>500.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="width_ch3">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>200.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>200.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_6">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>OUT4:</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="en_ch4">
<property name="text">
<string>Enabled</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="sec_ch4">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>s</string>
</property>
<property name="decimals">
<number>0</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
</property>
<property name="maximum">
<double>120.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="nsec_ch4">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>500.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="width_ch4">
<property name="prefix">
<string/>
</property>
<property name="suffix">
<string>ns</string>
</property>
<property name="decimals">
<number>3</number>
</property>
<property name="minimum">
<double>200.000000000000000</double>
</property>
<property name="maximum">
<double>1000000000.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>200.000000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>260</x>
<y>10</y>
<width>91</width>
<height>16</height>
</rect>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Delay setting</string>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="groupBox_2">
<property name="geometry">
<rect>
<x>10</x>
<y>180</y>
<width>481</width>
<height>51</height>
</rect>
</property>
<property name="title">
<string>Trigger</string>
</property>
<widget class="QCheckBox" name="en_trigger">
<property name="geometry">
<rect>
<x>20</x>
<y>20</y>
<width>111</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>Enabled</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QCheckBox" name="en_term">
<property name="geometry">
<rect>
<x>160</x>
<y>20</y>
<width>191</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>50 Ohm termination</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="groupBox_3">
<property name="geometry">
<rect>
<x>10</x>
<y>240</y>
<width>481</width>
<height>51</height>
</rect>
</property>
<property name="title">
<string>Sync Status</string>
</property>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>20</y>
<width>381</width>
<height>31</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="wr_checkbox">
<property name="text">
<string>Use White Rabbit</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_13">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>WR Status:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="wr_status">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>STATUS</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
<widget class="QWidget" name="tab_ts">
<attribute name="title">
<string>Timestamper</string>
</attribute>
<widget class="QCheckBox" name="en_ts">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>231</width>
<height>19</height>
</rect>
</property>
<property name="text">
<string>Enable timestamping</string>
</property>
</widget>
<widget class="QPushButton" name="btn_clear">
<property name="geometry">
<rect>
<x>520</x>
<y>10</y>
<width>80</width>
<height>24</height>
</rect>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
<widget class="QTableWidget" name="ts_table">
<property name="geometry">
<rect>
<x>10</x>
<y>40</y>
<width>611</width>
<height>251</height>
</rect>
</property>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>150</number>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>150</number>
</attribute>
<column>
<property name="text">
<string>ID</string>
</property>
</column>
<column>
<property name="text">
<string>Seconds</string>
</property>
</column>
<column>
<property name="text">
<string>Nanoseconds</string>
</property>
</column>
<column>
<property name="text">
<string>Delta</string>
</property>
</column>
</widget>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>
#!/usr/bin/python
from ctypes import *
import sys
import re
import os
sys.path.append('../../../common/')
from ptsexcept import *
class fd_timestamp(Structure):
_fields_ = [("utc", c_ulonglong),
("coarse", c_ulong),
("frac", c_ulong),
("seq_id", c_ushort),
("channel", c_int)]
def nsecs(self):
return (float(self.frac) * 8000.0 / 4096.0 + float(self.coarse) * 8000.0) / 1000.0;
def nsecs_full(self):
return (float(self.frac) * 8000.0 / 4096.0 + float(self.coarse) * 8000.0) / 1000.0 + float(self.utc) * 1000000000.0;
def __str__(self):
return "%d:%d" % (self.utc, self.nsecs())
class FineDelay:
GNUM_CSR_ADDR = 0x0
BASE_ADDR = 0x84000
FREE_RUNNING = 0x10
WR_OFFLINE = 0x8
WR_READY = 0x1
WR_SYNCING = 0x2
WR_SYNCED = 0x4
SYNC_LOCAL = 0x1
SYNC_WR = 0x2
def __init__(self, fd):
cwd = os.path.dirname(__file__)
self.fdelay = CDLL(cwd+'/../lib/libfinedelay.so')
self.handle = c_voidp(self.fdelay.fdelay_create_rawrabbit(c_int(fd), c_ulong(self.BASE_ADDR)));
"""
s = re.split("\/", dev_path)
self.fdelay = CDLL('../lib/libfinedelay.so')
if(s[0] == "local"):
print("Initializing local at %x" % int(s[1], 16))
self.handle = c_voidp(self.fdelay.fdelay_create_rawrabbit(int(s[1],16)));
elif(s[0] == "minibone"):
print("Initializing minibone at %s [%s]\n" %( s[1], s[2]))
self.handle = c_voidp(self.fdelay.fdelay_create_minibone(c_char_p(s[1]), c_char_p(s[2]), int(s[3], 16)));
"""
print "Initialising Fine Delay board..."
print self.handle
if(self.fdelay.fdelay_init(self.handle) < 0):
print ("Init failed..");
sys.exit(-1)
def conf_trigger(self, enable, termination):
self.fdelay.fdelay_configure_trigger(self.handle, c_int(enable), c_int(termination))
def conf_output(self, channel, enable, delay, width):
self.fdelay.fdelay_configure_output(self.handle, c_int(channel), c_int(enable), c_ulonglong(delay), c_ulonglong(width))
def conf_readout(self, enable):
self.fdelay.fdelay_configure_readout(self.handle, enable)
def conf_sync(self, mode):
self.fdelay.fdelay_configure_sync(self.handle, mode)
def conf_pulsegen(self, channel, enable, t_start_utc, t_start_coarse, width, delta, count):
t = fd_timestamp(utc=c_ulonglong(t_start_utc), coarse=c_ulong(t_start_coarse))
#print "channel:%d enable:%d start_t:%d width:%d delta:%d count:%d"%(channel, enable, t.utc, width, delta, count)
self.fdelay.fdelay_configure_pulse_gen(self.handle, c_int(channel), c_int(enable), t,
c_ulonglong(width), c_ulonglong(delta), c_int(count))
def set_time(self, utc, coarse):
t = fd_timestamp(utc=c_ulonglong(utc), coarse=c_ulong(coarse))
self.fdelay.fdelay_set_time(self.handle, t)
def get_time(self):
t = fd_timestamp()
self.fdelay.fdelay_get_time(self.handle, byref(t))
return t
def get_sync_status(self):
htab = { self.FREE_RUNNING : "oscillator free-running",
self.WR_OFFLINE : "WR core offline",
self.WR_READY : "WR core ready",
self.WR_SYNCING : "Syncing local clock with WR",
self.WR_SYNCED : "Synced with WR" }
# status = c_int(self.fdelay.fdelay_get_sync_status(self.handle));
# print("GetSyncStatus %x" % status.value);
return "none"; #htab[status.value]
def read_ts(self):
buf = (fd_timestamp * 256)();
ptr = pointer(buf)
n = self.fdelay.fdelay_read(self.handle, ptr, 256)
arr = [];
for i in range(0,n):
arr.append(buf[i])
return arr
#! /usr/bin/env python
# coding: utf8
# Copyright CERN, 2011
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
import sys
import time
import os
def dump_file_to_eeprom(filename):
eeprom_content = []
eeprom_addr = []
print filename
f = open(filename,"r+")
for line in f:
addr,data=line.split()
eeprom_content.append(int(data,2))
eeprom_addr.append(int(addr,2))
return
def main (default_directory = '.'):
in_filename = "eeprom_formatted_data.txt"
f_in = open(in_filename, 'r')
eeprom_content = []
eeprom_addr = []
for line in f_in:
addr,data=line.split()
print "%d 0x%X"%(int(addr,2), int(data,2))
eeprom_content.append(int(data,2))
eeprom_addr.append(int(addr,2))
print "\nCONTENT"
print eeprom_content
print "\nADDR"
print eeprom_addr
if __name__ == '__main__' :
main()
<?xml version="1.0" encoding="UTF-8"?>
<FMC_EPROMDATA memory_size = "2000">
<area number ="1" pos_of_len_field = "2">
<field name= "Board Area Format version" type="binary" content="00000001" description= "Indentifies language used" has_typelen = "no" />
<field name= "Language" type="binary" content= "00000001" description= "Indentifies language used" has_typelen = "no" />
<field name= "Mfg. Date/Time" type="binary" content="00000010 01010101" description="Num of mins from 00:00hrs 1/1/96 - little endian" has_typelen = "no" />
<field name= "Board_manufacturer" type="ascii" content="CERN" description="the manufacturer of the board" has_typelen = "yes" />
<field name= "Board product name" type="ascii" content="ADC 200k 16bit" description="name of the board" has_typelen = "yes" />
<field name= "Board_serial_number" type="binary" content="00000000" description="serial number for board" has_typelen = "yes" />
<field name= "Board_part_number" type="ascii" content="Desired input" description= "Part number for the board" has_typelen = "yes"/>
<field name= "FRU File ID" type="ascii" content="User dependant" description= "User desired - identification of EEPROM info source" has_typelen = "yes"/>
<field name= "Custom Mfg fields" type="ascii" content="Userdependant" description= "Delete if undesired" has_typelen = "yes"/>
</area>
<area number ="5" pos_of_len_field = "0">
<multirecord name= "DC_LOAD" multi_record_num = "1">
<field name= "DC Load number" type="binary" content= "00000001" description= "DC load multirecord number" has_typelen = "no" />
<field name= "Nominal Voltage" type="signed_short" content= "+0.00" description= "Nominal voltage for Vadj" has_typelen = "no" />
<field name="min_v" type="signed_short" content="+0.00" description="Spec'd min voltage for Vadj" has_typelen = "no" />
<field name="max_v" type="signed_short" content="+0.00" description="Spec'd max voltage for Vadj" has_typelen = "no" />
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for vadj" has_typelen = "no" />
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for Vadj" has_typelen = "no" />
<field name="max_current" type="signed_short" content="+0.00" description= "Spec'd min current load for Vadj" has_typelen = "no"/>
</multirecord>
<multirecord name= "DC_LOAD" multi_record_num = "2" >
<field name= "DC load number" type="binary" content="00000001" description= "DC output multirecord number" has_typelen = "no" />
<field name= "Nominal Voltage" type="signed_short" content= "+0.00" description= "Nominal voltage for 3P3V" has_typelen = "no" />
<field name="min_v" type="signed_short" content="+0.00" description="Spec'd min voltage for 3P3V" has_typelen = "no" />
<field name="max_v" type="signed_short" content="+0.00" description="Spec'd max voltage for 3P3V" has_typelen = "no" />
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for 3P3V" has_typelen = "no" />
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for 3P3V" has_typelen = "no" />
<field name="max_current" type="signed_short" content="+0.00" description= "Spec'd min current load for 3P3V" has_typelen = "no" />
</multirecord>
<multirecord name= "DC_LOAD" multi_record_num = "3" >
<field name= "DC load number" type="binary" content= "00000011" description= "DC output multirecord number" has_typelen = "no" />
<field name= "Nominal Voltage" type="signed_short" content= "+0.00" description= "Nominal voltage for 12P0V" has_typelen = "no" />
<field name="min_v" type="signed_short" content = "+0.00" description="Spec'd min voltage for 12P0V" has_typelen = "no" />
<field name="max_v" type="signed_short" content = "+0.00" description="Spec'd max voltage for 12P0V" has_typelen = "no" />
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for 12P0V" has_typelen = "no" />
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for 12P0V" has_typelen = "no" />
<field name="max_current" type="signed_short" content="+0.00" description= "Spec'd min current load for 12P0V" has_typelen = "no" />
</multirecord>
<multirecord name= "DC_OUTPUT" multi_record_num = "1" >
<field name= "DC Output number" type="binary" content= "00000001" description= "DC output multirecord number" has_typelen = "no" />
<field name= "Nominal Voltage" type="signed_short" content= "+0.00" description= "Nominal voltage for VIO_R_M2C" has_typelen = "no" />
<field name="min_v" type="signed_short" content = "+0.00" description="Spec'd min voltage for VIO_R_M2C" has_typelen = "no" />
<field name="max_v" type="signed_short" content = "+0.00" description="Spec'd max voltage for VIO_R_M2C" has_typelen = "no" />
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for VIO_R_M2C" has_typelen = "no" />
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for VIO_R_M2C" has_typelen = "no" />
<field name="max_current" type="signed_short" content="+0.00" description= "Spec'd min current load for VIO_R_M2C" has_typelen = "no" />
</multirecord>
<multirecord name= "DC_OUTPUT" multi_record_num = "2" >
<field name= "DC Output number" type="binary" content= "00000010" description= "DC output multirecord number" has_typelen = "no" />
<field name= "Nominal Voltage" type="signed_short" content= "+0.00" description= "Nominal voltage for VREF_A_M2C" has_typelen = "no" />
<field name="min_v" type="signed_short" content = "+0.00" description="Spec'd min voltage for VREF_A_M2C" has_typelen = "no" />
<field name="max_v" type="signed_short" content = "+0.00" description="Spec'd max voltage for VREF_A_M2C" has_typelen = "no" />
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for VREF_A_M2C" has_typelen = "no" />
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for VREF_A_M2C" has_typelen = "no" />
<field name="max_current" type="signed_short" content="+0.00" description= "Spec'd min current load for VREF_A_M2C" has_typelen = "no" />
</multirecord>
<multirecord name= "DC_OUTPUT" multi_record_num = "3" >
<field name= "DC Output number" type="binary" content= "00000001" description= "DC output multirecord number" has_typelen = "no" />
<field name= "Nominal Voltage" type="signed_short" content= "+0.00" description= "Nominal voltage for VREF_A_M2C" has_typelen = "no" />
<field name="min_v" type="signed_short" content = "+0.00" description="Spec'd min voltage for VREF_A_M2C" has_typelen = "no" />
<field name="max_v" type="signed_short" content = "+0.00" description="Spec'd max voltage for VREF_A_M2C" has_typelen = "no" />
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for VREF_A_M2C" has_typelen = "no" />
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for VREF_A_M2C" has_typelen = "no" />
<field name="max_current" type="signed_short" content="+0.00" description= "Spec'd min current load for VREF_A_M2C" has_typelen = "no" />
</multirecord>
<multirecord name= "OEM_record" multi_record_num = "1" >
<byteField name ="OEM Bytefield 1" >
<field name= "Subtype" type="binary" content= "0000" description= "0 for main definition type" has_typelen = "no" />
<field name= "Version" type="binary" content= "0000" description= "0 for current version" has_typelen = "no" />
</byteField>
<byteField name ="OEM Bytefield 2" >
<field name= "Module Size" type="binary" content= "00" description= "Single width = 00, Double = 01" has_typelen = "no" />
<field name= "P1 Connector Size" type="binary" content= "00" description= "LPC connecter = 01 HPC connecter =00" has_typelen = "no" />
<field name= "P2 Connector Size" type="binary" content= "00" description= "Same as above, or Not fitted =11" has_typelen = "no" />
<field name= "Clock Direction" type="binary" content= "0" description= "Mez to carrier = 0,Carrier to Mez =1" has_typelen = "no" />
<field name= "Reserved" type="binary" content= "0" description= "Reserved, by FMC standard" has_typelen = "no" />
</byteField>
<field name="P1 Bank A number of signals" type="binary" content="00000000" description= "Binary num of size byte" has_typelen = "no" />
<field name="P1 Bank B number of signals" type="binary" content="00000000" description= "Binary num of size byte" has_typelen = "no" />
<field name="P2 Bank A number of signals" type="binary" content="00000000" description= "Binary num of size byte" has_typelen = "no" />
<field name="P2 Bank B number of signals" type="binary" content="00000000" description= "Binary num of size byte" has_typelen = "no" />
<byteField name ="OEM Bytefield 3" >
<field name="P1 GBT Number Transsceivers" type="binary" content="0000" description= "Binary num of size 4 bits" has_typelen = "no" />
<field name="P2 GBT Number Transsceivers" type="binary" content="0000" description= "Binary num of size 4 bits" has_typelen = "no" />
</byteField>
<field name="Max clock for TCK" type="binary" content="00000000" description= "Binary num of size byte" has_typelen = "no" />
</multirecord>
</area>
</FMC_EPROMDATA>
#!/usr/bin/python
from ctypes import *
import array
import struct
import os
lib = cdll.LoadLibrary(os.path.dirname(__file__) + "/libipmi/libipmi.so")
class c_CommonHeader(Structure):
_fields_ = [
("format", c_ubyte),
("internal_use_off", c_ubyte),
("chassis_info_off", c_ubyte),
("board_area_off", c_ubyte),
("product_area_off", c_ubyte),
("multirecord_off", c_ubyte),
("pad", c_ubyte),
("checksum", c_ubyte)
]
class c_BoardInfoArea(Structure):
_fields_ = [
("format", c_ubyte),
("area_len", c_ubyte),
("language", c_ubyte),
("mfg_date0", c_ubyte),
("mfg_date1", c_ubyte),
("mfg_date2", c_ubyte),
("mfgr_typelen", c_ubyte),
("mfgr_data", c_char_p),
("product_typelen", c_ubyte),
("product_data", c_char_p),
("serial_typelen", c_ubyte),
("serial_data", c_char_p),
("partnum_typelen", c_ubyte),
("partnum_data", c_char_p),
("fru_fid_typelen", c_ubyte),
("fru_fid_data", c_char_p),
("typelen_end", c_ubyte),
("pad_len", c_ubyte),
("checksum", c_ubyte)
]
class c_DCLoadRecord(Structure):
_fields_ = [
("voltage_required", c_ubyte),
("nominal_voltage", c_ushort),
("min_voltage", c_ushort),
("max_voltage", c_ushort),
("spec_ripple", c_ushort),
("min_current", c_ushort),
("max_current", c_ushort)
]
class c_DCOutputRecord(Structure):
_fields_ = [
("output_info", c_ubyte),
("nominal_voltage", c_ushort),
("max_neg_voltage_dev", c_ushort),
("max_pos_voltage_dev", c_ushort),
("ripple", c_ushort),
("min_current_draw", c_ushort),
("max_current_draw", c_ushort)
]
class c_InternalUseArea(Structure):
_fields_ = [
("format", c_ubyte),
("len", c_int),
("data", c_char_p)
]
class InternalUseArea:
def __init__(self, data):
self.struct = c_InternalUseArea()
self._as_parameter_ = byref(self.struct)
self.struct.format = 0x1
self.set_data(data)
def set_data(self, data):
self.struct.data = c_char_p(array.array('B', data).tostring())
self.struct.len = c_int(len(data))
class CommonHeader:
def __init__(self):
self.struct = c_CommonHeader()
self._as_parameter_ = byref(self.struct)
self.struct.format = 0x1
self.struct.chassis_info_off = 0
self.struct.product_area_off = 0
self.struct.pad = 0
def set_internal_use_offset(self, off):
self.struct.internal_use_off = off
def set_board_info_area_offset(self, off):
self.struct.board_area_off = off
def set_multirecord_area_offset(self, off):
self.multirecord_off = off
class BoardInfoArea:
def __init__(self, date, mfgr, product, serial, partnum, fru):
self.struct = c_BoardInfoArea()
self._as_parameter_ = byref(self.struct)
self.struct.format = 0x1
self.struct.area_len = 0
self.struct.language = 0 # English
self.set_manufacture_date(date)
self.set_manufacturer(mfgr)
self.set_product_name(product)
self.set_serial_number(serial)
self.set_part_number(partnum)
self.set_fru_file_id(fru)
def set_manufacture_date(self, date):
val = bytearray(struct.pack('>I', date))
self.struct.mfg_date2 = c_ubyte(val[1])
self.struct.mfg_date1 = c_ubyte(val[2])
self.struct.mfg_date0 = c_ubyte(val[3])
def set_manufacturer(self, data):
self.struct.mfgr_data = c_char_p(data)
self.struct.mfgr_typelen = (len(bytearray(data)) & 0x3f) | (0x3 << 6)
def set_product_name(self, data):
self.struct.product_data = c_char_p(data)
self.struct.product_typelen = (len(bytearray(data)) & 0x3f) | (0x3 << 6)
def set_serial_number(self, data):
self.struct.serial_data = c_char_p(data)
self.struct.serial_typelen = (len(bytearray(data)) & 0x3f) | (0x3 << 6)
def set_part_number(self, data):
self.struct.partnum_data = c_char_p(data)
self.struct.partnum_typelen = (len(bytearray(data)) & 0x3f) | (0x3 << 6)
def set_fru_file_id(self, data):
self.struct.fru_fid_data = c_char_p(data)
self.struct.fru_fid_typelen = (len(bytearray(data)) & 0x3f) | (0x3 << 6)
class DCLoadRecord:
def __init__(self, rec_num, nom, vmin, vmax, ripple, imin, imax):
self.struct = c_DCLoadRecord()
self._as_parameter_ = byref(self.struct)
self.struct.voltage_required = 0
self.struct.nominal_voltage = 0
self.struct.min_voltage = 0
self.struct.max_voltage = 0
self.struct.spec_ripple = 0
self.struct.min_current = 0
self.struct.max_current = 0
self.set_record_number(rec_num)
self.set_nominal_voltage(nom*100)
self.set_min_voltage(vmin*100)
self.set_max_voltage(vmax*100)
self.set_spec_ripple(ripple*1000)
self.set_min_current(imin)
self.set_max_current(imax)
def set_record_number(self, val):
self.struct.voltage_required = int(val)
def set_nominal_voltage(self, val):
self.struct.nominal_voltage = int(val)
def set_min_voltage(self, val):
self.struct.min_voltage = int(val)
def set_max_voltage(self, val):
self.struct.max_voltage = int(val)
def set_spec_ripple(self, val):
self.struct.spec_ripple = int(val)
def set_min_current(self, val):
self.struct.min_current = int(val)
def set_max_current(self, val):
self.struct.max_current = int(val)
class DCOutputRecord:
def __init__(self, rec_num, nom, max_neg, max_pos, ripple, imin, imax):
self.struct = c_DCOutputRecord()
self._as_parameter_ = byref(self.struct)
self.struct.output_info = 0
self.struct.nominal_voltage = 0
self.struct.max_net_voltage_dev = 0
self.struct.max_pos_voltage_dev = 0
self.struct.ripple = 0
self.struct.min_current_draw = 0
self.struct.max_current_draw = 0
self.set_record_number(rec_num)
self.set_nominal_voltage(nom*100)
self.set_max_negative_voltage_deviation(max_neg*100)
self.set_max_positive_voltage_deviation(max_pos*100)
self.set_ripple(ripple*1000)
self.set_min_current_draw(imin)
self.set_max_current_draw(imax)
def set_record_number(self, val):
self.struct.output_info = val
def set_nominal_voltage(self, val):
self.struct.nominal_voltage = int(val)
def set_max_negative_voltage_deviation(self, val):
self.struct.max_neg_voltage_dev = int(val)
def set_max_positive_voltage_deviation(self, val):
self.struct.max_pos_voltage_dev = int(val)
def set_ripple(self, val):
self.struct.ripple = int(val)
def set_min_current_draw(self, val):
self.struct.min_current_draw = int(val)
def set_max_current_draw(self, val):
self.struct.max_current_draw = int(val)
class c_FMCOEMData(Structure):
_fields_ = [
("subtype_version", c_ubyte),
("other", c_ubyte),
("p1_a_nsig", c_ubyte),
("p1_b_nsig", c_ubyte),
("p2_a_nsig", c_ubyte),
("p2_b_nsig", c_ubyte),
("p1_p2_gbt_ntran", c_ubyte),
("max_clock", c_ubyte)
]
class c_OEMRecord(Structure):
_fields_ = [
("mfg_id0", c_ubyte),
("mfg_id1", c_ubyte),
("mfg_id2", c_ubyte),
("data", c_FMCOEMData)
]
class OEMRecord:
def __init__(self, msize, p1, p2, clockdir, pa_b1_nsig, pa_b2_nsig, pb_b1_nsig, pb_b2_nsig, pa_ngbt, pb_ngbt, maxclk):
self.struct = c_OEMRecord()
self._as_parameter_ = byref(self.struct)
self.struct.data.subtype_version = 0
self.struct.data.other = 0
self.struct.data.p1_a_nsig = 0
self.struct.data.p1_b_nsig = 0
self.struct.data.p2_a_nsig = 0
self.struct.data.p2_b_nsig = 0
self.struct.data.p1_gbt_ntran = 0
self.struct.data.p2_gbt_ntran = 0
self.struct.data.max_clock = 0
self.set_module_size(msize)
self.set_p1_connector_size(p1)
self.set_p2_connector_size(p2)
self.set_clock_direction(clockdir)
self.set_nsignals(1, 1, pa_b1_nsig)
self.set_nsignals(1, 2, pa_b2_nsig)
self.set_nsignals(2, 1, pb_b1_nsig)
self.set_nsignals(2, 2, pb_b2_nsig)
self.set_num_gbt_transceivers(1, pa_ngbt)
self.set_num_gbt_transceivers(2, pb_ngbt)
self.set_max_clock(maxclk)
def set_module_size(self, val):
self.struct.data.other &= ~(0xc0)
self.struct.data.other |= (val << 6) & 0xc0
def set_p1_connector_size(self, val):
self.struct.data.other &= ~(0x30)
self.struct.data.other |= (val << 4) & 0x30
def set_p2_connector_size(self, val):
self.struct.data.other &= ~(0xc)
self.struct.data.other |= (val << 2) & 0xc
def set_clock_direction(self, val):
self.struct.data.other &= ~(0x2)
self.struct.data.other |= (val << 1) & 0x2
def set_nsignals(self, port, bank, num):
if (port == 1):
if (bank == 1):
self.struct.data.p1_a_nsig = num
elif (bank == 2):
self.struct.data.p1_b_nsig = num
elif (port == 2):
if (bank == 1):
self.struct.data.p2_a_nsig = num
elif (bank == 2):
self.struct.data.p2_b_nsig = num
def set_num_gbt_transceivers(self, port, num):
if (port == 1):
self.struct.data.p1_p2_gbt_ntran &= ~(0xf0)
self.struct.data.p1_p2_gbt_ntran |= (num << 4) & 0xf0
elif (port == 2):
self.struct.data.p1_p2_gbt_ntran &= ~(0xf)
self.struct.data.p1_p2_gbt_ntran |= num & 0xf
def set_max_clock(self, clock):
self.struct.data.max_clock = clock
def ipmi_open_file(name):
lib.ipmi_file_open(c_char_p(name))
def ipmi_close_file():
lib.ipmi_file_close()
def ipmi_set(bia, dcload, dcout, oem, iua=None):
lib.ipmi_set_board_info_area(bia)
for r in dcload:
lib.ipmi_add_dc_load_record(r)
for r in dcout:
lib.ipmi_add_dc_output_record(r)
lib.ipmi_set_oem_record(oem)
if iua != None:
lib.ipmi_set_internal_use_area(iua)
def ipmi_write():
lib.ipmi_write()
def ipmi_get_mfg_date(data):
return lib.ipmi_get_mfg_date(c_char_p(data))
def ipmi_get_internal_use_data(data):
l = c_int()
d = c_void_p(lib.ipmi_get_internal_use_data(c_char_p(data), byref(l)))
q = cast(d, POINTER(l.value*c_ubyte))
return q.contents
def main():
bia = BoardInfoArea(12345678, "CERN", "ADC100M", "1234567890", "ADC100M", "abcde")
dcload0 = DCLoadRecord(0, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload1 = DCLoadRecord(1, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload2 = DCLoadRecord(2, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload3 = DCLoadRecord(3, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload4 = DCLoadRecord(4, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload5 = DCLoadRecord(5, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcload = [ dcload0, dcload1, dcload2, dcload3, dcload4, dcload5 ]
dcout0 = DCOutputRecord(0, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout1 = DCOutputRecord(1, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout2 = DCOutputRecord(2, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout3 = DCOutputRecord(3, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout4 = DCOutputRecord(4, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout5 = DCOutputRecord(5, 2.5, 2.4, 2.6, 0.0, 0, 4000)
dcout = [ dcout0, dcout1, dcout2, dcout3, dcout4, dcout5 ]
# oem = OEMRecord(single width, LPC, not fitted, mezz to carrier, 68, 0, 0, 0, 0, 0, 0)
oem = OEMRecord(0, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0)
iudata = [0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 ]
iua = InternalUseArea(iudata)
# Open, set, write, close!
ipmi_open_file("test.out")
ipmi_set(bia, dcload, dcout, oem, iua)
ipmi_write()
ipmi_close_file()
test = open('test.out', 'r').read()
print ipmi_get_mfg_date(test)
d = ipmi_get_internal_use_data(test)
for v in d:
print hex(v)
if __name__ == "__main__":
main()
#! /usr/bin/env python
# coding: utf8
# Copyright CERN, 2011
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Last modifications: 16/5/2012
# Import system modules
import sys
import time
import datetime
import os
from fmc_eeprom import *
"""
Tests IPMI formatting library.
"""
def main (default_directory='.'):
# Constants declaration
PART_NUMBER = "EDA-02063-V5-0"
SERIAL = "HCCFFIA___-CR000003"
EEPROM_BIN_FILENAME = "eeprom_content.out"
EEPROM_BIN_FILENAME = os.path.join(default_directory, EEPROM_BIN_FILENAME)
EEPROM_SIZE = 8192 # in Bytes
#==================================================
# Serial number
serial = SERIAL
print "Board's serial number: %s\n" % serial
#==================================================
# Calculate number of minutes since 0:00 1/1/96
now_date = datetime.datetime.now()
ref_date = datetime.datetime(1996, 1, 1)
diff_date = now_date - ref_date
total_seconds = diff_date.days * 86400 + diff_date.seconds
current_date = int(total_seconds//60)
print "Current date/time: %d minutes (since 0:00 1/1/96)\n" % current_date
# Manufacturiing date = current date
print "Manufacturing date : %d 0x%06X" % (current_date, current_date)
mfg_date = current_date
#==================================================
# Create Board Info Area
# FRU field is used to store the date of generation of the eeprom content
# This could be used later to determine if the content has to be udated (bug fix, ...)
print "EEPROM content generated: %s\n" % now_date
fru = "%s" % now_date
bia = BoardInfoArea(mfg_date, "CERN", "FmcAdc100m14b4cha", serial, PART_NUMBER, fru)
#==================================================
# Multirecords Area
# output number, vnom, vmin, vmax, ripple, imin, imax
dcload0 = DCLoadRecord(0, 2.5, 2.375, 2.625, 0.0, 0, 4000) # VADJ
dcload1 = DCLoadRecord(1, 3.3, 3.135, 3.465, 0.0, 0, 3000) # P3V3
dcload2 = DCLoadRecord(2, 12.0, 11.4, 12.6, 0.0, 0, 1000) # P12V
dcload = [ dcload0, dcload1, dcload2 ]
# output number, vnom, vmin, vmax, ripple, imin, imax
dcout0 = DCOutputRecord(3, 0.0, 0.0, 0.0, 0.0, 0, 0) # VIO_B_M2C
dcout1 = DCOutputRecord(4, 0.0, 0.0, 0.0, 0.0, 0, 0) # VREF_A_M2C
dcout2 = DCOutputRecord(5, 0.0, 0.0, 0.0, 0.0, 0, 0) # VREF_B_M2C
dcout = [ dcout0, dcout1, dcout2 ]
# module size : 0=single width, 1=double width
# P1 size : 0=LPC, 1=HPC
# P2 size : 0=LPC, 1=HPC, 3=not fitted
# clock dir : 0=M2C, 1=C2M
# nb sig P1 A : number
# nb sig P1 B : number
# nb sig P2 A : number
# nb sig P2 B : number
# nb GBT P1 : number
# nb GBT P2 : number
# max TCK freq : frequency in MHz
oem = OEMRecord(0, 1, 3, 1, 68, 0, 0, 0, 0, 0, 0)
#==================================================
# Internal Use Area
# Takes an array of byte as parameter
iua_data = [0x1,0x2,0x3,0x4]
iua = InternalUseArea(iua_data)
#==================================================
# Write eeprom content to a binary file
ipmi_open_file(EEPROM_BIN_FILENAME)
#ipmi_set(bia, dcload, dcout, oem, iua)
ipmi_set(bia, dcload, dcout, oem)
ipmi_write()
ipmi_close_file()
#==================================================
# Read eeprom content from binary file
f_eeprom = open(EEPROM_BIN_FILENAME, "rb")
eeprom_data = []
byte = f_eeprom.read(1) # reads one byte
while byte:
eeprom_data.append(ord(byte))
byte = f_eeprom.read(1) # reads one byte
f_eeprom.close()
print "Raw EEPROM data:"
i = 0
for data in eeprom_data:
if i%8 == 0:
print "0x%02X (%3d) : %02X" % (i, i, data),
else:
print "%02X" % (data),
i += 1
if i%8 == 0:
print ""
print("\n")
dsum = 0
for data in eeprom_data[158:162]:
dsum += data
print("0x%02X 0x%X" % (data, dsum))
print("\n\nsum: 0x%02X" % dsum)
checksum = (0xff & (1 + ~dsum))
print("calculated checksum: 0x%02X" % checksum)
print("data checksum : 0x%02X" % eeprom_data[162])
print("")
print("check data: 0x%02X" % (dsum + eeprom_data[162]))
print("check data: 0x%02X" % (dsum + checksum))
if __name__ == '__main__' :
main()
import os
import sys
from xml.dom import minidom
from xml.dom.minidom import parse, parseString
import libxml2
import fileinput
import os.path, time
from ctypes import *
import string
import optparse
##COMMENTS:
## Need to change the position of where the calibration data is inserted... should be area 1.
## Need to check all type len bytes
## Need to check the common header generation
## Check that the checksums are correct
## Check that the multirecord headers are correct
## Change things so that calib data file can contain whitespace after comma
default_inputFile = './eeprom_input.xml'
########################################
# Define New Type
########################################
type_list =["yes_no","calib_data"]
type_list_description = [" Takes an input of the form 'yes' or 'no', returns an associated number","This is the type conversation for calibration data,\n should not be used in the XML file"]
########################################
# Functions
########################################
multi_record_options = ["power_supply_information","DC_OUTPUT","DC_LOAD","management_access_record","base_compatibility_record","extended_compatibility_record","OEM_record"]
def yes_no_function(string):
if string.lower() =="yes":
return ["00000001"]
elif string.lower()=="no":
return ["00000000"]
else:
print "Content not as expected for type 'yes_no'"
print "Expected 'yes' or 'no'"
return "error"
def generate_addresses(data_size):
address_list =[]
for i in range(data_size):
address_bytes = convert_to_byte(i,2)
combined_addr = address_bytes[0]+address_bytes[1]
address_list.append([combined_addr])
return address_list
def print_area_nums():
print "\nThe 'number' attribute in 'Area' elements in the XML file must correspond to the type of area"
print "The type options and their corresponding numbers are shown below :"
areas=["internal use" ,"chassis info" ,"board info","product info","multi area"]
print ""
for i in range(len(areas)):
print "%d : %s"%((i+1),areas[i])
print ""
def print_type_options():
print "type options"
print "\nascii : Enter any text\n"
print "binary : Enter in the form \"00000000\" , ie grouped in 8 bis"
print " For more than 8 bits write as 00000000 00000000\n"
print "BCD : Enter an integer\n"
print "Signed_short : Enter in the form +0.00 or -0.00"
print " To be given in 0.01 incriments\n"
if len(type_list)!=0:
for i in range(len(type_list)):
print type_list[i] + " :" + type_list_description[i]+"\n"
def convert_to_byte(number,num=0):
converted=[]
separate_bytes=[]
character = bin(number)[2:]
if num == 0:
required_length = (len(character)/9 +1)*8
else:
required_length = num*8
converted.append(('0' * (required_length-len(character))) + character)
(required_length/8)
for i in range(required_length/8):
separate_bytes.append(converted[0][((i+1)*8)-8:(i+1)*8])
return separate_bytes
def generate_multirecord_header(mh_type,last_multirecord, length):
header=[]
if mh_type==multi_record_options[0] :
type_identifier="00000000"
elif mh_type==multi_record_options[1]:
type_identifier="00000001"
elif mh_type==multi_record_options[2]:
type_identifier="00000010"
elif mh_type==multi_record_options[3]:
type_identifier="00000011"
elif mh_type==multi_record_options[4]:
type_identifier="00000100"
elif mh_type==multi_record_options[5]:
type_identifier="00000101"
elif mh_type==multi_record_options[6]:
type_identifier="11111111"
else:
print "unidentified record type"
type_identifier = "WRONG mh type"
if last_multirecord =='yes':
record_field = convert_to_byte(130)
else:
record_field = convert_to_byte(2)
header.append([type_identifier])
header.append(record_field)
header.append([str(convert_to_byte(length)[0])])
mrchecksum = return_checksum(length)
header.append([str(mrchecksum)])
header.append(["11111011"])
return header
def append_sections(master_data,common_header):
master_binary =[]
for bytes in common_header:
master_binary.append(bytes)
## for i in range(len(master_data)):
## for j in range(len(master_data[i])):
## #print master_data[i]
##
## if len(master_data[i][j])>1:
## for k in range(len(master_data[i][j])):
## master_binary.append([master_data[i][j][k]])
##
## else:
## master_binary.append(master_data[i][j])
for area in range(len(master_data)):
for content in range(len(master_data[area])):
for inside in range(len(master_data[area][content])):
if type(master_data[area][content][inside])==list:
for further in range(len(master_data[area][content][inside])):
master_binary.append([master_data[area][content][inside][further]])
## print master_data[area][content][inside][further]
else:
master_binary.append([master_data[area][content][inside]])
## print master_data[area][content][inside]
return master_binary
def append_common_header(areas_found,area_lengths):
offset = [0,0,0,0,0]
array = [0,0,0,0,0]
for i in range(len(areas_found)):
array[int(areas_found[i])-1]=area_lengths[i]
common_header = []
common_header.append([str(convert_to_byte(1)[0])])
for i in range(len(array)):
if int(array[i])==0:
common_header.append(convert_to_byte(0))
else:
common_header.append(convert_to_byte(sum(array[0:i])+1))
common_header.append(["00000000"])
common_header.append(["11110000"]) # CHECK THIS
return common_header
def gen_common_header_tags():
tags = []
tags.append(["Identifier"])
tags.append(["Offset to area 1"])
tags.append(["Offset to area 2"])
tags.append(["Offset to area 3"])
tags.append(["Offset to area 4"])
tags.append(["Offset to area 5"])
tags.append(["Padding for Common Header"])
tags.append(["Common header checksum"])
return tags
def write_to_file(file_name,data_list,addr_list,tag_bytes,debug):
if file_name ==None:
writing_to_file=open("eeprom_formatted_data.txt","w")
else:
writing_to_file=open(file_name,"w")
if len(data_list)!=len(addr_list):
print "problem with data and addr length"
if debug:
for h in range(len(data_list)):
writing_to_file.write("%s %s %s\n"%(addr_list[h][0],data_list[h][0],tag_bytes[h][0]))
# print ("%s %s %s \n"%(addr_list[h][0],data_list[h][0],tag_bytes[h][0]))
else:
for h in range(len(data_list)):
writing_to_file.write("%s %s \n"%(addr_list[h][0],data_list[h][0]))
#print ("%s %s %s \n"%(addr_list[h][0],data_list[h][0],tag_bytes[h][0]))
if file_name ==None:
print "Formatted data written to 'EEPROM_FORMATTED_DATA.txt' : in current directory"
else:
print "Formatted data written to '",file_name,"' : in current directory"
return 0
def return_checksum(byte):
binary_value=bin(byte%256)[2:]
eight_bit_length=str(('0' * (8- len(binary_value))) + binary_value )
inv_binary_value =[]
for h in eight_bit_length:
if h=='0':
inv_binary_value.append('1')
elif h=='1':
inv_binary_value.append('0')
inverted="".join(element for element in inv_binary_value)
twos_comp_checksum = (bin(int(inverted,2)+1)[2:])
return twos_comp_checksum
def convert_to_ascii(text):
converted_line=[]
for word in text:
for char in word:
character=bin(ord(char))[2:]
converted_line.append(('0' * (8-len(character))) + character)
# print "ascii converted",converted_line
return converted_line
def convert_to_bcd(text):
bcd_conv=[]
if text.isdigit()!=True:
print "Error : BCD value contains a character, ensure the content contains only numbers"
return "error"
if len(text.split())!=1:
print "Error : BCD value not entered correctly"
print "Ensure there is no whitespace between characters"
return "error"
for letter in text:
number=int(letter)
bcd_num=bin(number)[2:]
bcd_conv.append(('0' * (8 - len(bcd_num))) + bcd_num)
# print "BCD", bcd_conv
return bcd_conv
def print_calib_info():
print "\nCalibration data should be stored in a file in the following format:"
print "[hex number],[yes/no]"
print "E.g. 0xABCD,yes"
print "The hex number must start with 0x"
print "If a typelen byte is desired for the data, write yes, else no"
def print_multi_record_options():
print "\nPlease use one of the following MultiRecord names:"
for i in range(len(multi_record_options)):
print multi_record_options[i]
return 0
def convert_to_signed_short(content):
if len(content)<=1:
print " Signed short input not as expected"
print " Please give in the for +0.00 or -0.00"
return "error"
sign = content[0]
fp_value =float(content[1:])
converted_ss=[]
value=int(fp_value*100)
if sign=="+":
binary_value=bin(value)[2:]
sixteen_bits=str(('0' * (16- len(binary_value))) + binary_value)
sixteen_bits,"sixteen"
if sixteen_bits[0]==1:
print "NUMBER IS TOO BIG"
converted_ss.append(sixteen_bits[0:8])
converted_ss.append(sixteen_bits[8:16])
#return converted_ss
elif sign=="-":
converted_ss=[]
inv_binary_value=[]
binary_value=bin(value)[2:]
sixteen_bits=str(('0' * (16- len(binary_value))) + binary_value)
for h in sixteen_bits:
if h=='0':
inv_binary_value.append('1')
elif h=='1':
inv_binary_value.append('0')
inverted="".join(element for element in inv_binary_value)
twos_comp=bin(int(inverted,2)+1)[2:]
converted_ss.append(twos_comp[0:8])
converted_ss.append(twos_comp[8:16])
#print converted_ss,"converted SS"
else:
print"Error : Input for signed short in wrong format"
print"Expected format - +0.00 or -0.00"
print"Give input in 10mV/mA incriments"
return "error"
# print "converted ss", converted_ss
return converted_ss
def convert_to_6bit_ascii(text):
print "6bit packed ascii currently not supported."
return "error"
def check_byte_size(text):
array =[]
bytes_split =text.split()
for i in range(len(bytes_split)):
if len(bytes_split[i])!=8:
print "Binary input not in byte size "
print "If two or more bytes - enter in the form - \"Byte1 Byte2\""
return "error"
else:
array.append(bytes_split[i])
return array
def type_length_byte(type_enc,length): # allows the generation of a type length byte Where is signed short?!
#if type_enc=="ascii":
array =[]
field_size = []
type_len_byte=['0','0','0','0','0','0','0','0']
binary_len=bin(length)[2:]
field_size.append(('0' * (6-len(binary_len))) + binary_len)
if type_enc== "ascii":
type_len_byte[7]='1'
type_len_byte[6]='1'
elif type_enc=="bcd":
type_len_byte[7]='0'
type_len_byte[6]='1'
elif type_enc in type_list or type_enc== "binary" or type_enc == "signed_short":
type_len_byte[7]='0'
type_len_byte[6]='0'
else:
print "Unrecognised conversion type"
print "If necessary... add a function as described in \"fmc_eeprom_gen\" document"
return "error"
type_len_byte[7]='0'
type_len_byte[6]='0'
test_type_len = str(type_len_byte[7]) + str(type_len_byte[6]) + str(field_size[0])
return [test_type_len]
def generate_tags(converted_line, data_type, area_num):
tag_array=[]
for fields in converted_line:
#print fields
#print data_type
tag_array.append("Area Number :" + area_num + " Data Type :" + data_type )
#print tag_array
return tag_array
#print converted_line
def gen_multi_record_header_tags():
tags = []
tags.append(["Multirecord Header : Record ID Type"])
tags.append(["Multirecord Header : Format Version (Bit 7: Last MultiRecord Flag)"])
tags.append(["Multirecord Header : Record Length"])
tags.append(["Multirecord Header : Record Checksum"])
tags.append(["Multirecord Header : Header Checksum"])
return tags
def format_calib_data(hex_calib_data):
#print int(hex_calib_data,16)
#print convert_to_byte(int(hex_calib_data,16))
return convert_to_byte(int(hex_calib_data,16))
def calibration_data(calibration_file):
split_line =[]
area_1_data=[]
area_1_tags=[]
area_1_data.append(["00000001"])
area_1_tags.append(["The start of area 2"])
f = open(calibration_file[0])
for line in f:
split_line = (line.split(','))
converted_line = typeConvFunctionsMap["calib_data"](split_line[0])
tags = generate_tags(converted_line,"calib_data", "2")
has_typelen = split_line[1].strip("\n")
if has_typelen.lower() =="yes":
type_len=type_length_byte("calib_data",len(converted_line))
area_1_data.append(type_len)
area_1_tags.append(["type_len byte"])
area_1_data.append(converted_line)
area_1_tags.append(tags)
byte_count = []
for fields in area_1_data:
for byte in fields:
byte_count.append(byte)
area_len = len(byte_count)
#print (len(byte_count)%8)
while area_len%8!=7:
area_1_data.append(["00000000"])
area_1_tags.append(["Padding - in calibration area"])
area_len = area_len +1
area_1_data.append(["11000001"])
area_1_tags.append(["End of fields identifier in calibration data area"])
byte_count.append("anything")
#print "byte count calib area", len(byte_count)
length_calced = (area_len+1)/8
return_area = [0,0,0]
return_area[0] = area_1_data
return_area[1] = area_1_tags
return_area[2] = length_calced
return return_area
#########################################
# Funtions map
#########################################
typeConvFunctionsMap = {
'ascii' : convert_to_ascii,
'bcd' : convert_to_bcd,
'signed_short' : convert_to_signed_short,
'binary' : check_byte_size,
"yes_no" : yes_no_function,
"calib_data" : format_calib_data
}
#########################################
# Parameters
########################################
##inputFile = './eeprom_input.xml'
#default_inputFile = './test.xml'
def main(file_name,input_name,debug,calibration_file):
if input_name == None:
doc = libxml2.parseFile(default_inputFile)
elif len(input_name.split())==1:
doc = libxml2.parseFile('./' + str(input_name.split()[0]))
else:
print "\n\nunexpected input for input file name"
print "expected : filename.xml\n\n"
error_count = 0
master_data = []
master_tags = []
pos_of_area_len = 2
data=[]
addr=[]
root = doc.getRootElement()
memory_size = int(root.prop('memory_size'))
area = root.children
areas_found = []
area_length =[]
concat=[]
########################################################################################################################
# Loop through XML FILE
########################################################################################################################
while area is not None:
if area.type == "element":
areas_found.append(area.prop('number'))
area_data =[]
area_tags =[]
byte_count=[]
pos_of_len_field = area.prop('pos_of_len_field')
areaContent = area.children
while areaContent is not None:
if areaContent.type == "element":
areaContentName = areaContent.name ########################################
if (areaContentName!='multirecord'): # if fields, then process
field_name = areaContent.prop('name') ########################################
has_typelen = areaContent.prop('has_typelen')
field_content = areaContent.prop('content')
type = areaContent.prop('type')
########################################
# Within Area
########################################
if typeConvFunctionsMap.has_key(type):
converted_line = typeConvFunctionsMap[type](field_content)
tags = generate_tags(converted_line,type, area.prop('number'))
# add descripter
else:
converted_line = "error"
print "Type not contained in function map..."
print "If a new type is required, see \"fmc_eeprom_gen\" for details of how to add a new type"
if converted_line =="error":
print "ERROR Position : Area :",area.prop('number')," \'",areaContent.prop('name'),"\'"
error_count = error_count +1
if has_typelen == "yes":
type_len=type_length_byte(type,len(converted_line))
if type_len =="error":
print "Type len error"
print "ERROR Position : Area :",area.prop('number')," \'",areaContent.prop('name'),"\'"
error_count = error_count +1
area_data.append(type_len)
area_tags.append(["type_len byte"])
area_data.append(converted_line)
area_tags.append(tags)
########################################################### Here
########################################
else: # else, go further to multirecord
# nested loop within areas loop
######################################## ########################################
# Next Child element - MultiRecord
########################################
field = areaContent.children
multi_area_data =[]
multi_area_tags =[]
while field is not None:
if field.type=="element":
fieldContentName = field.name ########################################
if fieldContentName!='byteField': # if fields, then process
field_name = field.prop('name') ########################################
has_typelen = field.prop('has_typelen')
field_content = field.prop('content')
type = field.prop('type')
if typeConvFunctionsMap.has_key(type):
converted_line = typeConvFunctionsMap[type](field_content)
##################################
tags = generate_tags(converted_line,type,area.prop('number'))
##################################
else:
converted_line = "error"
print "Type not contained in function map..."
print "If a new type is required, see \"fmc_eeprom_gen\" for details"
print "on how to add a new type"
if converted_line == "error":
print "ERROR Position :", areaContent.prop('name'),", Multirecord number: ",areaContent.prop('multi_record_num'), " \'",field.prop('name'),"\'"
error_count = error_count +1
if has_typelen == "yes":
type_len=type_length_byte(type,len(converted_line))
if type_len =="error":
print "Type len error"
print "ERROR Position :", areaContent.prop('name'),", Multirecord number: ",areaContent.prop('multi_record_num'), " \'",field.prop('name'),"\'"
error_count = error_count +1
multi_area_data.append(type_len)
multi_area_tags.append(["type_len"])
multi_area_data.append(converted_line)
multi_area_tags.append(tags)
########################################################### Here
########################################
# Next Child Element - ByteField Data
# Process ByteField
# Append to MultiRecord Data
######################################## ########################################
else: # else, go further to bytefield
bytefieldData =[] # nested loop within multirecord loop
bytefield = field.children ########################################
while bytefield is not None:
if bytefield.type=="element":
bytefieldData.append(bytefield.prop('content'))
bytefield = bytefield.next
if len("".join(bytefieldData))!=8:
print "ERROR : fields in byteField \'",field.prop('name'),"\' do not add to 8 bits"
error_count = error_count +1
multi_area_data.append(["".join(bytefieldData)])
multi_area_tags.append(["bytefield"])
bytefieldData=[]
field=field.next
########################################
# Process MultiRecord data
# Append to Area Data
########################################
for fields in multi_area_data:
for byte in fields:
byte_count.append(byte)
multi_record_header = generate_multirecord_header(areaContent.prop('name'),areaContent.prop('last_multirecord'),len(byte_count))
multi_record_header_tags = gen_multi_record_header_tags()
#master_data.append(multi_record_header)
#master_tags.append(multi_record_header_tags)
#area_data.append(multi_record_header)
#master_data.append(multi_area_data)
#area_data.append(multi_area_data)
#master_tags.append(multi_area_tags)
# New system
area_data.append(multi_record_header + multi_area_data)
area_tags.append(multi_record_header_tags + multi_area_tags)
byte_count=[]
########################################
# Process Area fields
# Append to master data
########################################
areaContent = areaContent.next
if (areaContentName!='multirecord'):
area_data.append([convert_to_byte(int("C1",16))[0] ])
area_tags.append(["END OF FIELDS IDENTIFIER"])
for fields in area_data:
for byte in fields:
byte_count.append(byte)
area_size = len(byte_count)
if int(pos_of_len_field) == 0:
pad_size = 7
length_calc_addition = 1
else:
length_calc_addition = 2
pad_size = 6
#while len(byte_count)%8!=pad_size:
while area_size%8!=pad_size:
area_size = area_size +1
area_data.append(["00000000"])
area_tags.append(["Padding to round to multiple of 8 byes"])
# byte_count.append(["00000000"])
# print "pos_of_len_field :",pos_of_len_field
#length_calced = (len(byte_count)+length_calc_addition)/8
length_calced = (area_size+length_calc_addition)/8
if int(pos_of_len_field) !=0:
area_data.insert(int(pos_of_len_field)-1,[convert_to_byte(length_calced)[0]])
area_tags.insert(int(pos_of_len_field)-1,["length of area " + area.prop('number')+" (multiples of 8bytes)"])
area_length.append(length_calced)
checksum = return_checksum(int(length_calced))
string = checksum
area_data.append([string])
area_tags.append(["checksum"])
#byte_count.append("doesnt matter")
#byte_count.append("doesnt matter")
master_data.append(area_data)
master_tags.append(area_tags)
########################################
# If multirecod, just give length as 1
# Not important as offset is to start of
# multi record area.
########################################
else:
master_data.append(area_data)
master_tags.append(area_tags)
area_length.append(1)
area = area.next
### Process calibration data.
if len(calibration_file)!=0:
area_1_info = calibration_data(calibration_file)
area_1_data = area_1_info[0]
area_1_tags = area_1_info[1]
area_1_length = area_1_info[2]
# need to change this to insert calibration data at offset 0
#print areas_found
#print area_length
#print area_1_info[2]
areas_found.insert(0,"1")
area_length.insert(0,area_1_length)
master_data.insert(0,area_1_data)
master_tags.insert(0,area_1_tags)
#print areas_found
#print area_length
#areas_found.insert(1,"1")
#area_length.insert(1,area_1_info[2])
#master_data.insert(1,area_1_data)
#master_tags.insert(1,area_1_tags)
common_header = append_common_header(areas_found,area_length)
common_header_tags = gen_common_header_tags()
tag_bytes = append_sections(master_tags,common_header_tags)
data_bytes = append_sections(master_data,common_header)
if len(data_bytes)>memory_size:
print "Converted data size exceeds size of EEPROM"
error_count=error_count+1
print "\nSize of EEPROM according to XML file is : %d bytes"%memory_size
print "Size of converted data : %d bytes"%len(data_bytes)
if error_count==0:
write_to_file(file_name,data_bytes,generate_addresses(len(data_bytes)),tag_bytes,debug)
else:
print "File not written due to error(s) shown"
########################################################################################################################
# MAIN FUNCTION CALL
########################################################################################################################
if __name__ == "__main__":
########################################
# Options and help functions
########################################
parser = optparse.OptionParser()
parser.add_option("-r", "--run_script", dest="run", action="store_true",
help =("Run the script and generate formatted output file"))
#arser.add_option("-h", "--help", help =("Help Options for GEN_FMC_EEPROM"))
parser.usage = "\n\nusage: python %prog [options] calibration_data_filename.txt \n\n Help Options for fmc_eeprom.py"
parser.add_option("-i", "--file_in", dest="file_in", type="str",
help =("Filename for output file [default:eeprom_formatted_data.txt]"))
parser.add_option("-o", "--file_out", dest="file_out", type="str",
help =("Filename for output file [default:eeprom_data.xml]"))
parser.add_option("-t", "--types", action="store_true", dest="types",
help =("Prints the valid types for fields in eeprom_data.xml"))
parser.add_option("-m", "--multirecords", action="store_true", dest="multirecord",
help =("Prints the valid options for MultiRecord types"))
parser.add_option("-a", "--areas", action="store_true", dest="areas",
help =("Prints the available Areas and their associated numbers"))
parser.add_option("-c", "--calib", action="store_true", dest="calib_info",
help =("Prints the required format for calibration data"))
parser.add_option("-d", "--debug", action="store_true", dest="debug",
help =("Add this option with -r to produce labels on output data"))
opts, args = parser.parse_args()
########################################
# Options process
########################################
if opts.run:
main(opts.file_out,opts.file_in,opts.debug,args)
if opts.multirecord:
print_multi_record_options()
if opts.types:
print_type_options()
if opts.areas:
print_area_nums()
if opts.calib_info:
print_calib_info()
OBJ=ipmi.o
OUT=libipmi.a
OUT_SO=libipmi.so
CFLAGS+=-fPIC -shared -Wall -Wextra -ggdb
all: $(OUT) $(OUT_SO)
$(OUT): $(OBJ)
ar rcs $(OUT) $(OBJ)
$(OUT_SO): $(OBJ)
$(CC) $< $(CFLAGS) -shared -fPIC -L. -Wl,-soname,$@ -o $@
clean:
rm -rf $(OBJ) $(OUT) $(OUT_SO)
#include "ipmi.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static FILE *f = NULL;
struct common_header *ch = NULL;
struct board_info_area *bia = NULL;
struct oem_record *oem = NULL;
struct internal_use_area *iua = NULL;
struct dc_load_list *dcll = NULL;
struct dc_output_list *dcol = NULL;
int ipmi_file_open(const char *name)
{
// if (f)
// fclose(f);
f = fopen(name, "w");
if (!f)
return -1;
ch = NULL;
bia = NULL;
oem = NULL;
iua = NULL;
dcll = NULL;
dcol = NULL;
return 0;
}
void ipmi_file_close(void)
{
if (f)
fclose(f);
}
uint8_t checksum(uint8_t *data, int len)
{
int i;
int sum = 0;
for (i = 0; i < len; i++)
sum += data[i];
return (-sum)&0xff;
}
int board_info_area_get_size(uint8_t *pad)
{
int size = 13 +
(bia->mfgr_typelen & 0x3f) +
(bia->product_typelen & 0x3f) +
(bia->serial_typelen & 0x3f) +
(bia->partnum_typelen & 0x3f) +
(bia->fru_fid_typelen & 0x3f);
if (size & 0x7) {
if (pad) {
*pad = 8 - (size & 0x7);
}
size -= size % 8;
size += 8;
}
return size;
}
int internal_use_area_get_size(void)
{
return 1 + iua->len;
}
int ipmi_common_header_write(void)
{
int ret;
if (!ch || !f)
return -1;
ch->checksum = checksum((uint8_t *)ch, sizeof(struct common_header) - 1);
ret = fwrite(ch, 1, sizeof(struct common_header), f);
return 0;
}
void ipmi_set_board_info_area(struct board_info_area *d)
{
bia = d;
}
void ipmi_add_dc_load_record(struct dc_load_record *d)
{
struct dc_load_list *l = malloc(sizeof(struct dc_load_list));
l->rec = d;
l->next = NULL;
if (!dcll) {
dcll = l;
} else {
l->next = dcll;
dcll = l;
}
}
void ipmi_add_dc_output_record(struct dc_output_record *d)
{
struct dc_output_list *l = malloc(sizeof(struct dc_output_list));
l->rec = d;
l->next = NULL;
if (!dcol) {
dcol = l;
} else {
l->next = dcol;
dcol = l;
}
}
void ipmi_set_oem_record(struct oem_record *d)
{
oem = d;
}
int ipmi_board_info_area_write(void)
{
int i;
int len;
int ret;
uint8_t pad = 0;
uint8_t checksum;
if (!bia || !f)
return -1;
/* Write upto the mfgr_data */
ret = fwrite(bia, 6, 1, f);
len = bia->mfgr_typelen & 0x3f;
ret = fwrite(&bia->mfgr_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->mfgr_data, len, 1, f);
len = bia->product_typelen & 0x3f;
ret = fwrite(&bia->product_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->product_data, len, 1, f);
len = bia->serial_typelen & 0x3f;
ret = fwrite(&bia->serial_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->serial_data, len, 1, f);
len = bia->partnum_typelen & 0x3f;
ret = fwrite(&bia->partnum_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->partnum_data, len, 1, f);
len = bia->fru_fid_typelen & 0x3f;
ret = fwrite(&bia->fru_fid_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->fru_fid_data, len, 1, f);
bia->typelen_end = 0xc1;
ret = fwrite(&bia->typelen_end, 1, sizeof(uint8_t), f);
/* calculate checksum here */
checksum = 0;
checksum +=
bia->format +
bia->area_len +
bia->language +
bia->mfg_date0 +
bia->mfg_date1 +
bia->mfg_date2 +
bia->mfgr_typelen +
bia->product_typelen +
bia->serial_typelen +
bia->partnum_typelen +
bia->fru_fid_typelen +
bia->typelen_end;
for (i = 0; i < (bia->mfgr_typelen & 0x3f); i++)
checksum += bia->mfgr_data[i];
for (i = 0; i < (bia->product_typelen & 0x3f); i++)
checksum += bia->product_data[i];
for (i = 0; i < (bia->serial_typelen & 0x3f); i++)
checksum += bia->serial_data[i];
for (i = 0; i < (bia->partnum_typelen & 0x3f); i++)
checksum += bia->partnum_data[i];
for (i = 0; i < (bia->fru_fid_typelen & 0x3f); i++)
checksum += bia->fru_fid_data[i];
checksum = -checksum;
checksum &= 0xff;
bia->checksum = checksum;
uint8_t nul = 0;
board_info_area_get_size(&pad);
for (i = 0; i < pad; i++)
ret = fwrite(&nul, 1, sizeof(uint8_t), f);
ret = fwrite(&bia->checksum, 1, sizeof(uint8_t), f);
return 0;
}
int ipmi_dc_load_record_write(int end)
{
int ret;
struct dc_load_list *t;
if (!dcll || !f)
return -1;
t = dcll;
while (t) {
struct multirecord_header head;
head.record_typeid = 0x2; /* DC load type */
head.extra = 0x2;
if (end)
head.extra |= (1 << 7);
head.record_len = 13;
head.record_checksum = checksum((uint8_t *)t->rec,
sizeof(struct dc_load_record));
head.header_checksum = checksum((uint8_t *)&head,
sizeof(struct multirecord_header) - 1);
ret = fwrite(&head, 1, sizeof(struct multirecord_header), f);
ret = fwrite(&t->rec->voltage_required, 1, 1, f);
ret = fwrite(&t->rec->nominal_voltage, 1, 12, f);
t = t->next;
}
return 0;
}
int ipmi_dc_output_record_write(int end)
{
int ret;
struct dc_output_list *t;
if (!dcol || !f)
return -1;
t = dcol;
while (t) {
struct multirecord_header head;
head.record_typeid = 0x1; /* DC output type */
head.extra = 0x2;
if (end)
head.extra |= (1 << 7);
head.record_len = 13;
head.record_checksum = checksum((uint8_t *)t->rec,
sizeof(struct dc_output_record));
head.header_checksum = checksum((uint8_t *)&head,
sizeof(struct multirecord_header) - 1);
ret = fwrite(&head, 1, sizeof(struct multirecord_header), f);
ret = fwrite(&t->rec->output_info, 1, 1, f);
ret = fwrite(&t->rec->nominal_voltage, 1, 12, f);
t = t->next;
}
return 0;
}
int ipmi_oem_record_write(int end)
{
int ret;
struct multirecord_header head;
if (!oem || !f)
return -1;
/* VITA ID: 0x0012a2 (LS Byte first) */
oem->mfg_id0 = 0xa2;
oem->mfg_id1 = 0x12;
oem->mfg_id2 = 0x00;
head.record_typeid = 0xfa; /* OEM record type */
head.extra = 0x2;
if (end)
head.extra |= (1 << 7);
head.record_len = sizeof(struct oem_record);
head.record_checksum = checksum((uint8_t *)oem,
sizeof(struct oem_record));
head.header_checksum = checksum((uint8_t *)&head,
sizeof(struct multirecord_header) - 1);
ret = fwrite(&head, 1, sizeof(struct multirecord_header), f);
ret = fwrite(oem, 1, sizeof(struct oem_record), f);
return 0;
}
int multirecord_area_get_size(int *diff)
{
struct dc_load_list *l1 = dcll;
struct dc_output_list *l2 = dcol;
int sum = 0;
while (l1) {
sum += sizeof(struct multirecord_header);
sum += 13;
l1 = l1->next;
}
while (l2) {
sum += sizeof(struct multirecord_header);
sum += 13;
l2 = l2->next;
}
sum += sizeof(struct multirecord_header) + sizeof(struct oem_record);
if (sum % 8) {
if (diff) {
*diff = 8 - (sum % 8);
}
sum += 8;
sum &= ~7;
}
return sum;
}
int ipmi_write(void)
{
int pad = 0;
int padlen = 0;
ch = malloc(sizeof(struct common_header));
memset(ch, 0, sizeof(struct common_header));
ch->format = 1; // Format version
/*
* IPMI areas arrangement in memory
*
* +------------------------------+
* | Common header |
* +------------------------------+
* | Board area |
* +------------------------------+
* | Multi-record area |
* | +------------------------+
* | | 3x DC load records |
* | +------------------------+
* | | 3x DC output records |
* | +------------------------+
* | | OEM record |
* +-----+------------------------+
* | Internal use area (optional) |
* +------------------------------+
*/
// Compute area offsets
ch->board_area_off = sizeof(struct common_header)/8; // always 1
ch->multirecord_off = (sizeof(struct common_header) + board_info_area_get_size(NULL))/8;
if (iua)
ch->internal_use_off = (sizeof(struct common_header) + board_info_area_get_size(NULL) + multirecord_area_get_size(NULL))/8;
else
ch->internal_use_off = 0;
// Write common heade
ipmi_common_header_write();
// Write board info area, padding (to 8 byte multiple) is done inside the write function
bia->area_len = board_info_area_get_size(NULL)/8;
ipmi_board_info_area_write();
// Write multi-record area
ipmi_dc_load_record_write(0);
ipmi_dc_output_record_write(0);
ipmi_oem_record_write(1);
// Padding after multi-record area
multirecord_area_get_size(&padlen);
if (padlen) {
int i;
for (i = 0; i < padlen; i++)
fwrite(&pad, 1, 1, f);
}
// Write Internal Use area, if exists
if (iua)
ipmi_internal_use_area_write();
return 0;
}
void ipmi_set_internal_use_area(struct internal_use_area *d)
{
iua = d;
}
int ipmi_internal_use_area_write(void)
{
if (!iua || !f)
return -1;
fwrite(&iua->format, 1, 1, f);
fwrite(&iua->len, 1, 4, f);
fwrite(iua->data, 1, iua->len, f);
return 0;
}
unsigned char *ipmi_get_internal_use_data(char *data, int *l)
{
unsigned char *buf;
struct common_header *ch = (struct common_header *)data;
unsigned char *d = (unsigned char *)data + ch->internal_use_off*8;
int len = (int)d[1];
buf = malloc(sizeof(uint8_t) * (len + 1));
memcpy(buf, d+5, len);
buf[len] = 0;
*l = len;
return buf;
}
int ipmi_get_mfg_date(char *data)
{
int i;
int ret = 0;
struct common_header *ch = (struct common_header *)data;
unsigned char *date = (unsigned char *)data + ch->board_area_off*8 + 3;
for (i = 0; i < 3; i++)
ret |= (date[i] << (i*8));
return ret;
}
#include "ipmi.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static FILE *f = NULL;
struct common_header *ch = NULL;
struct board_info_area *bia = NULL;
struct oem_record *oem = NULL;
struct internal_use_area *iua = NULL;
struct dc_load_list *dcll = NULL;
struct dc_output_list *dcol = NULL;
int ipmi_file_open(const char *name)
{
// if (f)
// fclose(f);
f = fopen(name, "w");
if (!f)
return -1;
ch = NULL;
bia = NULL;
oem = NULL;
iua = NULL;
dcll = NULL;
dcol = NULL;
return 0;
}
void ipmi_file_close(void)
{
if (f)
fclose(f);
}
uint8_t checksum(uint8_t *data, int len)
{
int i;
int sum = 0;
for (i = 0; i < len; i++)
sum += data[i];
return (-sum)&0xff;
}
int board_info_area_get_size(uint8_t *pad)
{
int size = 13 +
(bia->mfgr_typelen & 0x3f) +
(bia->product_typelen & 0x3f) +
(bia->serial_typelen & 0x3f) +
(bia->partnum_typelen & 0x3f) +
(bia->fru_fid_typelen & 0x3f);
if (size & 0x7) {
if (pad) {
*pad = 8 - (size & 0x7);
}
size -= size % 8;
size += 8;
}
return size;
}
int internal_use_area_get_size(void)
{
return 1 + iua->len;
}
int ipmi_common_header_write(void)
{
int ret;
if (!ch || !f)
return -1;
ch->checksum = checksum((uint8_t *)ch, sizeof(struct common_header) - 1);
ret = fwrite(ch, 1, sizeof(struct common_header), f);
return 0;
}
void ipmi_set_board_info_area(struct board_info_area *d)
{
bia = d;
}
void ipmi_add_dc_load_record(struct dc_load_record *d)
{
struct dc_load_list *l = malloc(sizeof(struct dc_load_list));
l->rec = d;
l->next = NULL;
if (!dcll) {
dcll = l;
} else {
l->next = dcll;
dcll = l;
}
}
void ipmi_add_dc_output_record(struct dc_output_record *d)
{
struct dc_output_list *l = malloc(sizeof(struct dc_output_list));
l->rec = d;
l->next = NULL;
if (!dcol) {
dcol = l;
} else {
l->next = dcol;
dcol = l;
}
}
void ipmi_set_oem_record(struct oem_record *d)
{
oem = d;
}
int ipmi_board_info_area_write(void)
{
int i;
int len;
int ret;
uint8_t pad = 0;
uint8_t checksum;
if (!bia || !f)
return -1;
/* Write upto the mfgr_data */
ret = fwrite(bia, 6, 1, f);
len = bia->mfgr_typelen & 0x3f;
ret = fwrite(&bia->mfgr_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->mfgr_data, len, 1, f);
len = bia->product_typelen & 0x3f;
ret = fwrite(&bia->product_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->product_data, len, 1, f);
len = bia->serial_typelen & 0x3f;
ret = fwrite(&bia->serial_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->serial_data, len, 1, f);
len = bia->partnum_typelen & 0x3f;
ret = fwrite(&bia->partnum_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->partnum_data, len, 1, f);
len = bia->fru_fid_typelen & 0x3f;
ret = fwrite(&bia->fru_fid_typelen, 1, sizeof(uint8_t), f);
ret = fwrite(bia->fru_fid_data, len, 1, f);
bia->typelen_end = 0xc1;
ret = fwrite(&bia->typelen_end, 1, sizeof(uint8_t), f);
/* calculate checksum here */
checksum = 0;
checksum +=
bia->format +
bia->area_len +
bia->language +
bia->mfg_date0 +
bia->mfg_date1 +
bia->mfg_date2 +
bia->mfgr_typelen +
bia->product_typelen +
bia->serial_typelen +
bia->partnum_typelen +
bia->fru_fid_typelen +
bia->typelen_end;
for (i = 0; i < (bia->mfgr_typelen & 0x3f); i++)
checksum += bia->mfgr_data[i];
for (i = 0; i < (bia->product_typelen & 0x3f); i++)
checksum += bia->product_data[i];
for (i = 0; i < (bia->serial_typelen & 0x3f); i++)
checksum += bia->serial_data[i];
for (i = 0; i < (bia->partnum_typelen & 0x3f); i++)
checksum += bia->partnum_data[i];
for (i = 0; i < (bia->fru_fid_typelen & 0x3f); i++)
checksum += bia->fru_fid_data[i];
checksum = -checksum;
checksum &= 0xff;
bia->checksum = checksum;
uint8_t nul = 0;
board_info_area_get_size(&pad);
for (i = 0; i < pad; i++)
ret = fwrite(&nul, 1, sizeof(uint8_t), f);
ret = fwrite(&bia->checksum, 1, sizeof(uint8_t), f);
return 0;
}
int ipmi_dc_load_record_write(int end)
{
int ret,i;
struct dc_load_list *t;
if (!dcll || !f)
return -1;
t = dcll;
i = 0;
while (t) {
printf("loop: %d\n",i);
i++;
struct multirecord_header head;
head.record_typeid = 0x2; /* DC load type */
head.extra = 0x2;
if (end)
head.extra |= (1 << 7);
head.record_len = 13;
head.record_checksum = checksum((uint8_t *)t->rec,
sizeof(struct dc_load_record));
head.header_checksum = checksum((uint8_t *)&head,
sizeof(struct multirecord_header) - 1);
ret = fwrite(&head, 1, sizeof(struct multirecord_header), f);
ret = fwrite(&t->rec->voltage_required, 1, 1, f);
ret = fwrite(&t->rec->nominal_voltage, 1, 12, f);
t = t->next;
}
return 0;
}
int ipmi_dc_output_record_write(int end)
{
int ret, i;
struct dc_output_list *t;
if (!dcol || !f)
return -1;
t = dcol;
i = 0;
while (t) {
printf("loop: %d\n",i);
i++;
struct multirecord_header head;
head.record_typeid = 0x1; /* DC output type */
head.extra = 0x2;
if (end)
head.extra |= (1 << 7);
head.record_len = 13;
head.record_checksum = checksum((uint8_t *)t->rec,
sizeof(struct dc_output_record));
head.header_checksum = checksum((uint8_t *)&head,
sizeof(struct multirecord_header) - 1);
ret = fwrite(&head, 1, sizeof(struct multirecord_header), f);
ret = fwrite(&t->rec->output_info, 1, 1, f);
ret = fwrite(&t->rec->nominal_voltage, 1, 12, f);
t = t->next;
}
return 0;
}
int ipmi_oem_record_write(int end)
{
int ret;
struct multirecord_header head;
if (!oem || !f)
return -1;
/* VITA ID: 0x0012a2 (LS Byte first) */
oem->mfg_id0 = 0xa2;
oem->mfg_id1 = 0x12;
oem->mfg_id2 = 0x00;
head.record_typeid = 0xfa; /* OEM record type */
head.extra = 0x2;
if (end)
head.extra |= (1 << 7);
head.record_len = sizeof(struct oem_record);
head.record_checksum = checksum((uint8_t *)oem,
sizeof(struct oem_record));
head.header_checksum = checksum((uint8_t *)&head,
sizeof(struct multirecord_header) - 1);
ret = fwrite(&head, 1, sizeof(struct multirecord_header), f);
ret = fwrite(oem, 1, sizeof(struct oem_record), f);
return 0;
}
int multirecord_area_get_size(int *diff)
{
struct dc_load_list *l1 = dcll;
struct dc_output_list *l2 = dcol;
int sum = 0;
while (l1) {
sum += sizeof(struct multirecord_header);
sum += 13;
l1 = l1->next;
}
while (l2) {
sum += sizeof(struct multirecord_header);
sum += 13;
l2 = l2->next;
}
sum += sizeof(struct multirecord_header) + sizeof(struct oem_record);
if (sum % 8) {
if (diff) {
*diff = 8 - (sum % 8);
}
sum += 8;
sum &= ~7;
}
return sum;
}
int ipmi_write(void)
{
int pad = 0;
int padlen = 0;
ch = malloc(sizeof(struct common_header));
memset(ch, 0, sizeof(struct common_header));
ch->format = 1; // Format version
/*
* IPMI areas arrangement in memory
*
* +------------------------------+
* | Common header |
* +------------------------------+
* | Board area |
* +------------------------------+
* | Multi-record area |
* | +------------------------+
* | | 3x DC load records |
* | +------------------------+
* | | 3x DC output records |
* | +------------------------+
* | | OEM record |
* +-----+------------------------+
* | Internal use area (optional) |
* +------------------------------+
*/
// Compute area offsets
ch->board_area_off = sizeof(struct common_header)/8; // always 1
ch->multirecord_off = (sizeof(struct common_header) + board_info_area_get_size(NULL))/8;
if (iua)
ch->internal_use_off = (sizeof(struct common_header) + board_info_area_get_size(NULL) + multirecord_area_get_size(NULL))/8;
else
ch->internal_use_off = 0;
// Write common heade
ipmi_common_header_write();
// Write board info area, padding (to 8 byte multiple) is done inside the write function
bia->area_len = board_info_area_get_size(NULL)/8;
ipmi_board_info_area_write();
// Write multi-record area
ipmi_dc_load_record_write(0);
ipmi_dc_output_record_write(0);
ipmi_oem_record_write(1);
// Padding after multi-record area
multirecord_area_get_size(&padlen);
if (padlen) {
int i;
for (i = 0; i < padlen; i++)
fwrite(&pad, 1, 1, f);
}
// Write Internal Use area, if exists
if (iua)
ipmi_internal_use_area_write();
return 0;
}
void ipmi_set_internal_use_area(struct internal_use_area *d)
{
iua = d;
}
int ipmi_internal_use_area_write(void)
{
if (!iua || !f)
return -1;
fwrite(&iua->format, 1, 1, f);
fwrite(&iua->len, 1, 4, f);
fwrite(iua->data, 1, iua->len, f);
return 0;
}
unsigned char *ipmi_get_internal_use_data(char *data, int *l)
{
unsigned char *buf;
struct common_header *ch = (struct common_header *)data;
unsigned char *d = (unsigned char *)data + ch->internal_use_off*8;
int len = (int)d[1];
buf = malloc(sizeof(uint8_t) * (len + 1));
memcpy(buf, d+5, len);
buf[len] = 0;
*l = len;
return buf;
}
int ipmi_get_mfg_date(char *data)
{
int i;
int ret = 0;
struct common_header *ch = (struct common_header *)data;
unsigned char *date = (unsigned char *)data + ch->board_area_off*8 + 3;
for (i = 0; i < 3; i++)
ret |= (date[i] << (i*8));
return ret;
}
#ifndef IPMI_H
#define IPMI_H
#include <stdint.h>
#include <stdio.h>
/* 8 bytes */
struct common_header {
uint8_t format;
uint8_t internal_use_off;
uint8_t chassis_info_off;
uint8_t board_area_off;
uint8_t product_area_off;
uint8_t multirecord_off;
uint8_t pad;
uint8_t checksum;
};
struct board_info_area {
uint8_t format;
uint8_t area_len;
uint8_t language;
uint8_t mfg_date0;
uint8_t mfg_date1;
uint8_t mfg_date2;
uint8_t mfgr_typelen;
uint8_t *mfgr_data;
uint8_t product_typelen;
uint8_t *product_data;
uint8_t serial_typelen;
uint8_t *serial_data;
uint8_t partnum_typelen;
uint8_t *partnum_data;
uint8_t fru_fid_typelen;
uint8_t *fru_fid_data;
/* uint8_t *custom; */
uint8_t typelen_end;
uint8_t pad_len;
uint8_t checksum;
};
/* 5 bytes */
struct multirecord_header {
uint8_t record_typeid;
uint8_t extra;
uint8_t record_len;
uint8_t record_checksum;
uint8_t header_checksum;
};
struct dc_output_list {
struct dc_output_record *rec;
struct dc_output_list *next;
};
/* 13 bytes */
struct dc_load_record {
uint8_t voltage_required;
uint16_t nominal_voltage;
uint16_t min_voltage;
uint16_t max_voltage;
uint16_t spec_ripple;
uint16_t min_current;
uint16_t max_current;
};
struct dc_load_list {
struct dc_load_record *rec;
struct dc_load_list *next;
};
/* 13 bytes */
struct dc_output_record {
uint8_t output_info;
uint16_t nominal_voltage;
uint16_t max_neg_voltage_dev;
uint16_t max_pos_voltage_dev;
uint16_t ripple;
uint16_t min_current_draw;
uint16_t max_current_draw;
};
struct fmc_oem_data {
uint8_t subtype_version;
uint8_t other;
uint8_t p1_a_nsig;
uint8_t p1_b_nsig;
uint8_t p2_a_nsig;
uint8_t p2_b_nsig;
uint8_t p1_p2_gbt_ntran;
uint8_t max_clock;
};
/* 12 bytes */
struct oem_record {
uint8_t mfg_id0;
uint8_t mfg_id1;
uint8_t mfg_id2;
struct fmc_oem_data data;
};
struct internal_use_area {
uint8_t format;
int len;
char *data;
};
int ipmi_file_open(const char *name);
void ipmi_file_close(void);
int ipmi_write(void);
int ipmi_common_header_write(void);
void ipmi_set_board_info_area(struct board_info_area *);
int ipmi_board_info_area_write(void);
void ipmi_set_internal_use_area(struct internal_use_area *);
int ipmi_internal_use_area_write(void);
void ipmi_add_dc_load_record(struct dc_load_record *);
int ipmi_dc_load_record_write(int);
void ipmi_add_dc_output_record(struct dc_output_record *);
int ipmi_dc_output_record_write(int);
void ipmi_set_oem_record(struct oem_record *);
int ipmi_oem_record_write(int);
unsigned char *ipmi_get_internal_use_data(char *data, int *l);
int ipmi_get_mfg_date(char *data);
#endif
<?xml version="1.0" encoding="UTF-8"?>
<FMC_EPROMDATA memory_size="2000">
<area number="1" pos_of_len_field="2">
<field name="Board Area Format version" type="binary" content="00000001" description="Indentifies language used" has_typelen="no"/>
<field name="Language" type="binary" content="00000001" description="Indentifies language used" has_typelen="no"/>
<field name="Mfg. Date/Time" type="binary" content="00000010 01010101" description="Num of mins from 00:00hrs 1/1/96 - little endian" has_typelen="no"/>
<field name="Board_manufacturer" type="ascii" content="CERN" description="the manufacturer of the board" has_typelen="yes"/>
<field name="Board product name" type="ascii" content="ADC 200k 16bit" description="name of the board" has_typelen="yes"/>
<field name="Board_serial_number" type="binary" content="123456" description="serial number for board" has_typelen="yes"/>
<field name="Board_part_number" type="ascii" content="Desired input" description="Part number for the board" has_typelen="yes"/>
<field name="FRU File ID" type="ascii" content="User dependant" description="User desired - identification of EEPROM info source" has_typelen="yes"/>
<field name="Custom Mfg fields" type="ascii" content="Userdependant" description="Delete if undesired" has_typelen="yes"/>
</area>
<area number="5" pos_of_len_field="0">
<multirecord name="DC_LOAD" multi_record_num="1">
<field name="DC Load number" type="binary" content="00000001" description="DC load multirecord number" has_typelen="no"/>
<field name="Nominal Voltage" type="signed_short" content="+0.00" description="Nominal voltage for Vadj" has_typelen="no"/>
<field name="min_v" type="signed_short" content="+0.00" description="Spec'd min voltage for Vadj" has_typelen="no"/>
<field name="max_v" type="signed_short" content="+0.00" description="Spec'd max voltage for Vadj" has_typelen="no"/>
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for vadj" has_typelen="no"/>
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for Vadj" has_typelen="no"/>
<field name="max_current" type="signed_short" content="+0.00" description="Spec'd min current load for Vadj" has_typelen="no"/>
</multirecord>
<multirecord name="DC_LOAD" multi_record_num="2">
<field name="DC load number" type="binary" content="00000001" description="DC output multirecord number" has_typelen="no"/>
<field name="Nominal Voltage" type="signed_short" content="+0.00" description="Nominal voltage for 3P3V" has_typelen="no"/>
<field name="min_v" type="signed_short" content="+0.00" description="Spec'd min voltage for 3P3V" has_typelen="no"/>
<field name="max_v" type="signed_short" content="+0.00" description="Spec'd max voltage for 3P3V" has_typelen="no"/>
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for 3P3V" has_typelen="no"/>
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for 3P3V" has_typelen="no"/>
<field name="max_current" type="signed_short" content="+0.00" description="Spec'd min current load for 3P3V" has_typelen="no"/>
</multirecord>
<multirecord name="DC_LOAD" multi_record_num="3">
<field name="DC load number" type="binary" content="00000011" description="DC output multirecord number" has_typelen="no"/>
<field name="Nominal Voltage" type="signed_short" content="+0.00" description="Nominal voltage for 12P0V" has_typelen="no"/>
<field name="min_v" type="signed_short" content="+0.00" description="Spec'd min voltage for 12P0V" has_typelen="no"/>
<field name="max_v" type="signed_short" content="+0.00" description="Spec'd max voltage for 12P0V" has_typelen="no"/>
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for 12P0V" has_typelen="no"/>
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for 12P0V" has_typelen="no"/>
<field name="max_current" type="signed_short" content="+0.00" description="Spec'd min current load for 12P0V" has_typelen="no"/>
</multirecord>
<multirecord name="DC_OUTPUT" multi_record_num="1">
<field name="DC Output number" type="binary" content="00000001" description="DC output multirecord number" has_typelen="no"/>
<field name="Nominal Voltage" type="signed_short" content="+0.00" description="Nominal voltage for VIO_R_M2C" has_typelen="no"/>
<field name="min_v" type="signed_short" content="+0.00" description="Spec'd min voltage for VIO_R_M2C" has_typelen="no"/>
<field name="max_v" type="signed_short" content="+0.00" description="Spec'd max voltage for VIO_R_M2C" has_typelen="no"/>
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for VIO_R_M2C" has_typelen="no"/>
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for VIO_R_M2C" has_typelen="no"/>
<field name="max_current" type="signed_short" content="+0.00" description="Spec'd min current load for VIO_R_M2C" has_typelen="no"/>
</multirecord>
<multirecord name="DC_OUTPUT" multi_record_num="2">
<field name="DC Output number" type="binary" content="00000010" description="DC output multirecord number" has_typelen="no"/>
<field name="Nominal Voltage" type="signed_short" content="+0.00" description="Nominal voltage for VREF_A_M2C" has_typelen="no"/>
<field name="min_v" type="signed_short" content="+0.00" description="Spec'd min voltage for VREF_A_M2C" has_typelen="no"/>
<field name="max_v" type="signed_short" content="+0.00" description="Spec'd max voltage for VREF_A_M2C" has_typelen="no"/>
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for VREF_A_M2C" has_typelen="no"/>
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for VREF_A_M2C" has_typelen="no"/>
<field name="max_current" type="signed_short" content="+0.00" description="Spec'd min current load for VREF_A_M2C" has_typelen="no"/>
</multirecord>
<multirecord name="DC_OUTPUT" multi_record_num="3">
<field name="DC Output number" type="binary" content="00000001" description="DC output multirecord number" has_typelen="no"/>
<field name="Nominal Voltage" type="signed_short" content="+0.00" description="Nominal voltage for VREF_A_M2C" has_typelen="no"/>
<field name="min_v" type="signed_short" content="+0.00" description="Spec'd min voltage for VREF_A_M2C" has_typelen="no"/>
<field name="max_v" type="signed_short" content="+0.00" description="Spec'd max voltage for VREF_A_M2C" has_typelen="no"/>
<field name="ripple_pk_pk" type="signed_short" content="+0.00" description="Spec'd Ripple and noise pk - pk for VREF_A_M2C" has_typelen="no"/>
<field name="min_current" type="signed_short" content="+0.00" description="Spec'd min current load for VREF_A_M2C" has_typelen="no"/>
<field name="max_current" type="signed_short" content="+0.00" description="Spec'd min current load for VREF_A_M2C" has_typelen="no"/>
</multirecord>
<multirecord name="OEM_record" multi_record_num="1">
<byteField name="OEM Bytefield 1">
<field name="Subtype" type="binary" content="0000" description="0 for main definition type" has_typelen="no"/>
<field name="Version" type="binary" content="0000" description="0 for current version" has_typelen="no"/>
</byteField>
<byteField name="OEM Bytefield 2">
<field name="Module Size" type="binary" content="00" description="Single width = 00, Double = 01" has_typelen="no"/>
<field name="P1 Connector Size" type="binary" content="00" description="LPC connecter = 01 HPC connecter =00" has_typelen="no"/>
<field name="P2 Connector Size" type="binary" content="00" description="Same as above, or Not fitted =11" has_typelen="no"/>
<field name="Clock Direction" type="binary" content="0" description="Mez to carrier = 0,Carrier to Mez =1" has_typelen="no"/>
<field name="Reserved" type="binary" content="0" description="Reserved, by FMC standard" has_typelen="no"/>
</byteField>
<field name="P1 Bank A number of signals" type="binary" content="00000000" description="Binary num of size byte" has_typelen="no"/>
<field name="P1 Bank B number of signals" type="binary" content="00000000" description="Binary num of size byte" has_typelen="no"/>
<field name="P2 Bank A number of signals" type="binary" content="00000000" description="Binary num of size byte" has_typelen="no"/>
<field name="P2 Bank B number of signals" type="binary" content="00000000" description="Binary num of size byte" has_typelen="no"/>
<byteField name="OEM Bytefield 3">
<field name="P1 GBT Number Transsceivers" type="binary" content="0000" description="Binary num of size 4 bits" has_typelen="no"/>
<field name="P2 GBT Number Transsceivers" type="binary" content="0000" description="Binary num of size 4 bits" has_typelen="no"/>
</byteField>
<field name="Max clock for TCK" type="binary" content="00000000" description="Binary num of size byte" has_typelen="no"/>
</multirecord>
</area>
</FMC_EPROMDATA>
#! /usr/bin/env python
# coding: utf8
# Copyright CERN, 2011
# Author: Matthieu Cattin <matthieu.cattin@cern.ch>
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
import sys
import time
import os
import libxml2
def main (default_directory = '.'):
filename = "test.xml"
doc = libxml2.parseFile(filename)
root = doc.getRootElement()
area = root.children
while area is not None:
if area.type == "element":
areaContent = area.children
while areaContent is not None:
if areaContent.type == "element":
if areaContent.prop('name') == "Board_serial_number":
areaContent.setProp('content', '123456')
print "youhou"
areaContent=areaContent.next
area=area.next
f = open(filename, 'w')
doc.saveTo(f)
f.close
if __name__ == '__main__' :
main()
......@@ -109,7 +109,7 @@ BOX_USB_DEVICE_ID = 0xea60 # CP210x Composite Device
TEMPID_FAMILY_CODE = 0x28
TEMP_THRES = 50.0
TEMP_THRES = 46.0
TEMP_RIPPLE = 0.3
FIFO_SIZE = 20
MEAS_SLEEP = 1
......@@ -164,7 +164,7 @@ def main (default_directory='.'):
FPGA_LOADER_PATH = '../../../../gnurabbit/user/fpga_loader'
DAC_CALIBR_FILENAME = "DAC_calibration_data.txt"
DAC_CALIBR_FILENAME = "DAC_calib_data.txt"
DAC_CALIBR_FILENAME = os.path.join(default_directory, DAC_CALIBR_FILENAME)
f_out = open(DAC_CALIBR_FILENAME, 'w')
start_test_time = time.time()
......@@ -260,7 +260,6 @@ def main (default_directory='.'):
box.select_trigger_loopback(0)
"""
print "\n\n________________TDC board temperature stablilization_______________\n"
# Access Temperature-and-Unique-ID chip
try:
......@@ -324,8 +323,8 @@ def main (default_directory='.'):
t2 = time.time()
print "FMC temperature is stable after %10.3fs\n"%(t2-t0)
"""
# Enable timestamps aquisition (TDC_START_FPGA pulse sent at this step)
# Enable channels and start timestamps aquisition (TDC_START_FPGA pulse sent at this step)
print "\n______________________ACAM aquisition start________________________\n"
# Enable channels and terminations of all channels
tdc.enable_channels()
......@@ -334,6 +333,7 @@ def main (default_directory='.'):
tdc.channel_term(3, 1)
tdc.channel_term(4, 1)
tdc.channel_term(5, 1)
tdc.start_acq()
time.sleep(1)
......
......@@ -277,6 +277,12 @@ def main (default_directory='.'):
msg = ("ERROR: Unexpected error with interrupts; expected overflows: %d; received overflows: %d")%((NUM_OF_TSTAMPS*(i+1)),tdc_overflows_now)
print (msg)
raise PtsError (msg)
#timestamps, data = tdc.get_timestamps(0)
#for m in range(len(timestamps)):
# if (timestamps[m][2] == 1) and (timestamps[m][1] == 0): # rising tstamps ch1
# r_edge_timestamps_ch1.append(timestamps[m][0])
# elif (timestamps[m][2] == 1) and (timestamps[m][1] == otherch): # rising tstamps pair channel
# r_edge_timestamps_otherch.append(timestamps[m][0])
print "Ch1 tstamps : %d"%(len(r_edge_timestamps_ch1))
print "Ch%d tstamps : %d"%(i+2, len(r_edge_timestamps_otherch))
......@@ -297,7 +303,7 @@ def main (default_directory='.'):
# allign lists with rising-edge-timestamps for ch1 and the other channel
offset = 0
for l in range(100):
for l in range(10):
if (r_edge_timestamps_ch1[l] - r_edge_timestamps_otherch[0]) < 10000 and (r_edge_timestamps_ch1[l] - r_edge_timestamps_otherch[0]) > -10000:
offset= l
print "offset : %d"%(l)
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -5,7 +5,7 @@
.
vendor = 0x000000000000CE42
device = 0xc5be045e
device = 0x7961274C
position = 0x200
IPMI-FRU
......
......@@ -52,7 +52,6 @@ import os
import math
from numpy import *
from ctypes import *
from pylab import *
from datetime import datetime
# Add common modules location tp path
......@@ -117,11 +116,11 @@ def hex2signed(value):
def main (default_directory='.'):
# Constants declaration
FMC_TDC_ADDR = '1a39:0004/1a39:0004@0001:0000'#'1a39:0004/1a39:0004@000B:0000'
FMC_TDC_ADDR = '1a39:0004/1a39:0004@000B:0000'
FMC_TDC_BITSTREAM_PATH = '../firmwares/tdc.bin'
FPGA_LOADER_PATH = '../../../../gnurabbit/user/fpga_loader'
CALIBR_BIN_FILENAME = "calibration_data.bin"
CALIBR_BIN_FILENAME = "calib_data.bin"
CALIBR_BIN_FILENAME = os.path.join(default_directory, CALIBR_BIN_FILENAME)
EEPROM_BIN_FILENAME = "eeprom_content.out"
EEPROM_BIN_FILENAME = os.path.join(default_directory, EEPROM_BIN_FILENAME)
......@@ -194,14 +193,6 @@ def main (default_directory='.'):
print (msg)
raise PtsError (msg)
# Enable channels and terminations of all channels
tdc.enable_channels()
tdc.channel_term(1, 1)
tdc.channel_term(2, 1)
tdc.channel_term(3, 1)
tdc.channel_term(4, 1)
tdc.channel_term(5, 1)
# Interrupts
print "\n____________________________IRQs_________________________________\n"
print('Set IRQ enable mask: %.4X')%tdc.set_irq_en_mask(0x1F) # was 0xC!!
......@@ -294,8 +285,17 @@ def main (default_directory='.'):
print "TDC Write pointer: %d"%(tdc.get_pointer())
print "TDC Overflows : %d"%(tdc.get_overflow_counter())
# Enable timestamps aquisition (TDC_START_FPGA pulse sent at this step)
# Enable channels and start timestamps aquisition (TDC_START_FPGA pulse sent at this step)
print "\n\n______________________ACAM aquisition start________________________\n"
# Enable channels and terminations of all channels
tdc.enable_channels()
tdc.channel_term(1, 1)
tdc.channel_term(2, 1)
tdc.channel_term(3, 1)
tdc.channel_term(4, 1)
tdc.channel_term(5, 1)
tdc.start_acq()
time.sleep(0.5)
print "\n-----------------------------------------------------------------\n"
......
......@@ -70,9 +70,9 @@ def main (default_directory='.'):
NAME = 'tdc_1ns_5cha'
SERIAL_FILENAME = "../../../../serial.txt"
SERIAL_FILENAME = os.path.join(default_directory, SERIAL_FILENAME)
CH_CALIBR_FILENAME = "ch_calibration_data.txt"
CH_CALIBR_FILENAME = "ch_calib_data.txt"
CH_CALIBR_FILENAME = os.path.join(default_directory, CH_CALIBR_FILENAME)
DAC_CALIBR_FILENAME = "DAC_calibration_data.txt"
DAC_CALIBR_FILENAME = "DAC_calib_data.txt"
DAC_CALIBR_FILENAME = os.path.join(default_directory, DAC_CALIBR_FILENAME)
SDBFS_DIR = "sdbfs/"
SDBFS_DIR = os.path.join(default_directory, SDBFS_DIR)
......@@ -87,7 +87,7 @@ def main (default_directory='.'):
start_test_time = time.time()
# Constants declaration
FMC_TDC_ADDR = '1a39:0004/1a39:0004@0001:0000'#'1a39:0004/1a39:0004@000B:0000'
FMC_TDC_ADDR = '1a39:0004/1a39:0004@000B:0000'
FMC_TDC_BITSTREAM_PATH = '../firmwares/tdc.bin'
FPGA_LOADER_PATH = '../../../../gnurabbit/user/fpga_loader'
......@@ -405,6 +405,7 @@ P1 Bank A nb signal=%d, P1 Bank B nb signal=%d, P2 Bank A nb signal=%d, P2 Bank
#==================================================
# Generate eeprom image with gensdbfs
os.remove(EEPROM_BIN_FILENAME)
cmd = "gensdbfs " + SDBFS_DIR + " " + EEPROM_BIN_FILENAME
print("Generating eeprom image, cmd: %s\n"%(cmd))
os.system(cmd)
......
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