Commit 131612ba authored by Alejandro Homs Puron's avatar Alejandro Homs Puron

* Added Frelon::Camera::DeadTimeChangedCallback to notify Lima (Sync)

  about changes in the detector-defined min_lat_time (valid_ranges)
* Added Frelon TimeCalc and Acc. Mode test Python scripts
parent 31fdd944
......@@ -38,6 +38,21 @@ class Camera : public HwMaxImageSizeCallbackGen
DEB_CLASS_NAMESPC(DebModCamera, "Camera", "Frelon");
public:
class DeadTimeChangedCallback {
DEB_CLASS_NAMESPC(DebModCamera, "DeadTimeChangedCallback",
"Frelon::Camera");
public:
DeadTimeChangedCallback();
virtual ~DeadTimeChangedCallback();
protected:
virtual void deadTimeChanged(double dead_time) = 0;
private:
friend class Camera;
Camera *m_cam;
};
Camera(Espia::SerialLine& espia_ser_line);
~Camera();
......@@ -129,6 +144,9 @@ class Camera : public HwMaxImageSizeCallbackGen
void stop();
bool isRunning();
void registerDeadTimeChangedCallback(DeadTimeChangedCallback& cb);
void unregisterDeadTimeChangedCallback(DeadTimeChangedCallback& cb);
protected:
virtual void setMaxImageSizeCallbackActive(bool cb_active);
......@@ -193,6 +211,8 @@ class Camera : public HwMaxImageSizeCallbackGen
bool waitIdleStatus(Status& status, bool use_ser_line=false,
bool read_spb2=false);
void deadTimeChanged();
AutoMutex lock();
SerialLine m_ser_line;
......@@ -205,6 +225,8 @@ class Camera : public HwMaxImageSizeCallbackGen
bool m_mis_cb_act;
Mutex m_lock;
bool m_started;
double m_dead_time;
DeadTimeChangedCallback *m_dead_time_cb;
};
inline bool Camera::isChanActive(InputChan curr, InputChan chan)
......
......@@ -177,8 +177,22 @@ class SyncCtrlObj : public HwSyncCtrlObj
virtual void getValidRanges(ValidRangesType& valid_ranges);
private:
class DeadTimeChangedCallback : public Camera::DeadTimeChangedCallback
{
DEB_CLASS_NAMESPC(DebModCamera, "DeadTimeChangedCallback",
"Frelon::SynCtrlObj");
public:
DeadTimeChangedCallback(SyncCtrlObj *sync);
protected:
virtual void deadTimeChanged(double dead_time);
private:
friend class SyncCtrlObj;
SyncCtrlObj *m_sync;
};
Espia::Acq& m_acq;
Camera& m_cam;
DeadTimeChangedCallback m_dead_time_cb;
};
......
......@@ -32,6 +32,15 @@ class Camera
%End
public:
class DeadTimeChangedCallback {
public:
DeadTimeChangedCallback();
virtual ~DeadTimeChangedCallback();
protected:
virtual void deadTimeChanged(double dead_time) = 0;
};
Camera(Espia::SerialLine& espia_ser_line);
~Camera();
......@@ -125,6 +134,9 @@ class Camera
void stop();
bool isRunning();
void registerDeadTimeChangedCallback(Frelon::Camera::DeadTimeChangedCallback& cb);
void unregisterDeadTimeChangedCallback(Frelon::Camera::DeadTimeChangedCallback& cb);
protected:
virtual void setMaxImageSizeCallbackActive(bool cb_active);
......
......@@ -32,10 +32,24 @@ const double Camera::UpdateCcdStatusTime = 0.1;
const double Camera::MaxIdleWaitTime = 2.5;
const double Camera::MaxBusyRetryTime = 0.2; // 16 Mpixel image Aurora Xfer
Camera::DeadTimeChangedCallback::DeadTimeChangedCallback()
: m_cam(NULL)
{
DEB_CONSTRUCTOR();
}
Camera::DeadTimeChangedCallback::~DeadTimeChangedCallback()
{
DEB_DESTRUCTOR();
if (m_cam)
m_cam->unregisterDeadTimeChangedCallback(*this);
}
Camera::Camera(Espia::SerialLine& espia_ser_line)
: m_ser_line(espia_ser_line), m_timing_ctrl(m_model, m_ser_line),
m_mis_cb_act(false)
m_mis_cb_act(false), m_dead_time(0), m_dead_time_cb(NULL)
{
DEB_CONSTRUCTOR();
......@@ -45,6 +59,9 @@ Camera::Camera(Espia::SerialLine& espia_ser_line)
Camera::~Camera()
{
DEB_DESTRUCTOR();
if (m_dead_time_cb)
unregisterDeadTimeChangedCallback(*m_dead_time_cb);
}
void Camera::sync()
......@@ -120,6 +137,7 @@ void Camera::syncRegs()
Sleep(UpdateCcdStatusTime);
getRoiBinOffset(m_roi_bin_offset);
deadTimeChanged();
}
void Camera::syncRegsGoodHTD()
......@@ -369,6 +387,7 @@ void Camera::setChanMode(int chan_mode)
<< "not supported in " << m_model.getName();
}
writeRegister(ChanMode, chan_mode);
deadTimeChanged();
}
void Camera::getChanMode(int& chan_mode)
......@@ -648,6 +667,8 @@ void Camera::setBin(const Bin& bin)
writeRegister(BinVert, bin.getY());
resetRoiBinOffset();
deadTimeChanged();
}
void Camera::getBin(Bin& bin)
......@@ -676,6 +697,8 @@ void Camera::setRoiMode(RoiMode roi_mode)
if (roi_mode == None)
resetRoiBinOffset();
deadTimeChanged();
}
void Camera::getRoiMode(RoiMode& roi_mode)
......@@ -1007,6 +1030,8 @@ void Camera::writeChanRoi(const Roi& chan_roi)
writeRegister(RoiPixelWidth, size.getWidth());
writeRegister(RoiLineBegin, tl.y);
writeRegister(RoiLineWidth, size.getHeight());
deadTimeChanged();
}
void Camera::readChanRoi(Roi& chan_roi)
......@@ -1135,6 +1160,8 @@ void Camera::resetRoiBinOffset()
DEB_TRACE() << "Forcing alignment " << DEB_VAR2(bin_y,
roi_line_beg);
writeRegister(RoiLineBegin, roi_line_beg);
deadTimeChanged();
}
}
......@@ -1165,6 +1192,7 @@ void Camera::setTimeUnitFactor(TimeUnitFactor time_unit_factor)
DEB_PARAM() << DEB_VAR1(time_unit_factor);
int time_unit = int(time_unit_factor);
writeRegister(TimeUnit, time_unit);
deadTimeChanged();
}
void Camera::getTimeUnitFactor(TimeUnitFactor& time_unit_factor)
......@@ -1335,12 +1363,7 @@ void Camera::setTotalLatTime(double lat_time)
DEB_PARAM() << DEB_VAR1(lat_time);
double dead_time;
getDeadTime(dead_time);
double user_lat_time = lat_time - dead_time;
if (user_lat_time < -1e-6)
THROW_HW_ERROR(InvalidValue) << "Total latency time cannot be "
<< "smaller than dead time";
else if (user_lat_time < 0)
user_lat_time = 0;
double user_lat_time = max(0.0, lat_time - dead_time);
setUserLatTime(user_lat_time);
}
......@@ -1385,6 +1408,7 @@ void Camera::setSPB2Config(SPB2Config spb2_config)
DEB_PARAM() << DEB_VAR1(spb2_config)
<< " [" << getSPB2ConfigName(spb2_config) << "]";
writeRegister(ConfigHD, int(spb2_config));
deadTimeChanged();
}
void Camera::getSPB2Config(SPB2Config& spb2_config)
......@@ -1619,3 +1643,40 @@ double Camera::getMaxIdleWaitTime()
DEB_RETURN() << DEB_VAR1(max_wait_time);
return max_wait_time;
}
void Camera::registerDeadTimeChangedCallback(DeadTimeChangedCallback& cb)
{
DEB_MEMBER_FUNCT();
if (m_dead_time_cb)
THROW_HW_ERROR(InvalidValue) << "a cb is already registered";
cb.m_cam = this;
m_dead_time_cb = &cb;
}
void Camera::unregisterDeadTimeChangedCallback(DeadTimeChangedCallback& cb)
{
DEB_MEMBER_FUNCT();
if (&cb != m_dead_time_cb)
THROW_HW_ERROR(InvalidValue) << "the cb is not registered";
m_dead_time_cb = NULL;
cb.m_cam = NULL;
}
void Camera::deadTimeChanged()
{
DEB_MEMBER_FUNCT();
double dead_time;
getDeadTime(dead_time);
DEB_TRACE() << DEB_VAR2(dead_time, m_dead_time);
if (dead_time == m_dead_time)
return;
m_dead_time = dead_time;
if (m_dead_time_cb)
m_dead_time_cb->deadTimeChanged(dead_time);
}
......@@ -265,15 +265,36 @@ void BufferCtrlObj::unregisterFrameCallback(HwFrameCallback& frame_cb)
* \brief SyncCtrlObj constructor
*******************************************************************/
SyncCtrlObj::DeadTimeChangedCallback::DeadTimeChangedCallback(SyncCtrlObj *sync)
: m_sync(sync)
{
DEB_CONSTRUCTOR();
}
void SyncCtrlObj::DeadTimeChangedCallback::deadTimeChanged(double dead_time)
{
DEB_MEMBER_FUNCT();
DEB_PARAM() << DEB_VAR1(dead_time);
if (!m_sync)
return;
ValidRangesType valid_ranges;
m_sync->getValidRanges(valid_ranges);
m_sync->validRangesChanged(valid_ranges);
}
SyncCtrlObj::SyncCtrlObj(Acq& acq, Camera& cam)
: HwSyncCtrlObj(), m_acq(acq), m_cam(cam)
: HwSyncCtrlObj(), m_acq(acq), m_cam(cam), m_dead_time_cb(this)
{
DEB_CONSTRUCTOR();
m_cam.registerDeadTimeChangedCallback(m_dead_time_cb);
}
SyncCtrlObj::~SyncCtrlObj()
{
DEB_DESTRUCTOR();
m_dead_time_cb.m_sync = NULL;
}
bool SyncCtrlObj::checkTrigMode(TrigMode trig_mode)
......
############################################################################
# This file is part of LImA, a Library for Image Acquisition
#
# Copyright (C) : 2009-2011
# European Synchrotron Radiation Facility
# BP 220, Grenoble 38043
# FRANCE
#
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
############################################################################
import sys
import getopt
from Lima import Core, Frelon
import time
Core.DEB_GLOBAL(Core.DebModTest)
class ImageStatusCallback(Core.CtControl.ImageStatusCallback):
Core.DEB_CLASS(Core.DebModTest, "ImageStatusCallback")
@Core.DEB_MEMBER_FUNCT
def __init__(self, ct, acq_state):
Core.CtControl.ImageStatusCallback.__init__(self)
self.m_ct = ct
self.m_acq_state = acq_state
self.m_nb_frames = 0
@Core.DEB_MEMBER_FUNCT
def start(self):
self.m_acq_state.set(Core.AcqState.Acquiring)
self.m_start_time = time.time()
self.m_stat_acc = [0.0] * 4
ct_acq = self.m_ct.acquisition()
self.m_nb_frames = ct_acq.getAcqNbFrames()
@Core.DEB_MEMBER_FUNCT
def imageStatusChanged(self, cb_img_status):
t = time.time()
global_status = self.m_ct.getStatus()
acq_status = global_status.AcquisitionStatus
img_status = global_status.ImageCounters
last_acq_frame_nb = img_status.LastImageAcquired;
last_base_frame_nb = img_status.LastBaseImageReady;
last_ready_frame_nb = img_status.LastImageReady;
dt = t - self.m_start_time
n = last_acq_frame_nb + 1
acc = self.m_stat_acc
acc[0] += n
acc[1] += n**2
acc[2] += dt
acc[3] += n * dt
acq_state_changed = False
if last_ready_frame_nb == self.m_nb_frames - 1:
self.m_acq_state.set(Core.AcqState.Finished)
acq_state_changed = True
pt = t0 = 0
if n > 1:
pt = (acc[0] * acc[2] - n * acc[3]) / (acc[0]**2 - n * acc[1])
t0 = (acc[2] - pt * acc[0]) / n
if True:
deb.Always("Last Acquired: %8d, Last Base: %8d, " \
"Last Ready: %8d, Status: %s, PT: %.6f, T0: %.6f" %
(last_acq_frame_nb, last_base_frame_nb,
last_ready_frame_nb, acq_status, pt, t0))
@Core.DEB_GLOBAL_FUNCT
def test_frelon_acc(enable_debug, espia_dev_nb, vert_bin, exp_time,
acc_max_exp_time, nb_frames, acc_time_mode):
if enable_debug:
Core.DebParams.enableModuleFlags(Core.DebParams.AllFlags)
Core.DebParams.enableTypeFlags(Core.DebParams.AllFlags)
else:
Core.DebParams.disableModuleFlags(Core.DebParams.AllFlags)
deb.Always("Creating FrelonAcq")
acq = Frelon.FrelonAcq(espia_dev_nb)
deb.Trace("Done!")
cam = acq.getFrelonCamera()
ct = acq.getGlobalControl()
ct_image = ct.image()
ct_acq = ct.acquisition()
acq_state = Core.AcqState()
status_cb = ImageStatusCallback(ct, acq_state)
ct.registerImageStatusCallback(status_cb)
deb.Always("Setting Full Frame Mode - Speed - Chan 3&4")
cam.setSPB2Config(Frelon.SPB2Speed)
cam.setFrameTransferMode(Frelon.FFM)
cam.setInputChan(Frelon.Chan34)
deb.Trace("Done!")
frame_dim = acq.getFrameDim(max_dim=True)
bin = Core.Bin(1, vert_bin)
deb.Always("Setting binning %s" % bin)
ct_image.setBin(bin);
deb.Trace("Done!")
image_size = frame_dim.getSize()
nb_cols = image_size.getWidth()
nb_lines = image_size.getHeight() / vert_bin
roi = Core.Roi(Core.Point(0, nb_lines - 2), Core.Size(nb_cols, 1));
deb.Always("Setting RoI %s" % roi)
ct_image.setRoi(roi);
deb.Trace("Done!")
deb.Always("Setting Kinetic RoI mode")
cam.setRoiMode(Frelon.Kinetic);
deb.Trace("Done!")
deb.Always("Setting Acc. mode")
ct_acq.setAcqMode(Core.Accumulation)
deb.Trace("Done!")
deb.Always("Setting %s Acc. Time mode" % acc_time_mode)
acc_mode = Core.CtAcquisition.Live \
if acc_time_mode == 'Live' \
else Core.CtAcquisition.Real
ct_acq.setAccTimeMode(acc_mode)
deb.Trace("Done!")
deb.Always("Setting Acc. max. exp. time %s" % acc_max_exp_time)
ct_acq.setAccMaxExpoTime(acc_max_exp_time)
deb.Trace("Done!")
deb.Always("Setting exp. time %s" % exp_time)
ct_acq.setAcqExpoTime(exp_time)
deb.Trace("Done!")
deb.Always("Setting nb. frames %s" % nb_frames)
ct_acq.setAcqNbFrames(nb_frames)
deb.Trace("Done!")
acc_nb_frames = ct_acq.getAccNbFrames()
acc_dead_time = ct_acq.getAccDeadTime()
acc_live_time = ct_acq.getAccLiveTime()
deb.Always("AccNbFrames: %d, AccDeadTime: %.6f, AccLiveTime: %.6f" %
(acc_nb_frames, acc_dead_time, acc_live_time))
deb.Always("Preparing acq.")
ct.prepareAcq()
deb.Trace("Done!")
deb.Always("Starting acq.")
status_cb.start()
ct.startAcq()
deb.Trace("Done!")
state_mask = Core.AcqState.Acquiring
acq_state.waitNot(state_mask)
deb.Always("Finished!")
dead_time = cam.getDeadTime()
read_time = cam.getReadoutTime()
xfer_time = cam.getTransferTime()
deb.Always("Dead Time: %.6f, Readout Time: %.6f, Transfer Time: %.6f" %
(dead_time, read_time, xfer_time))
def main(argv):
enable_debug = False
espia_dev_nb = 0
vert_bin = 64
exp_time = 20e-3
acc_max_exp_time = 2e-3
nb_frames = 10
acc_time_mode = 'Live'
opts, args = getopt.getopt(argv[1:], 'de:v:t:m:n:r')
for opt, val in opts:
if opt == '-d':
enable_debug = True
if opt == '-e':
espia_dev_nb = int(val)
if opt == '-v':
vert_bin = int(val)
if opt == '-t':
exp_time = float(val)
if opt == '-m':
acc_max_exp_time = float(val)
if opt == '-n':
nb_frames = int(val)
if opt == '-r':
acc_time_mode = 'Real'
test_frelon_acc(enable_debug, espia_dev_nb, vert_bin, exp_time,
acc_max_exp_time, nb_frames, acc_time_mode)
if __name__ == '__main__':
main(sys.argv)
############################################################################
# This file is part of LImA, a Library for Image Acquisition
#
# Copyright (C) : 2009-2011
# European Synchrotron Radiation Facility
# BP 220, Grenoble 38043
# FRANCE
#
# This is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
############################################################################
import sys
from Lima import Core, Espia, Frelon
Core.DEB_GLOBAL(Core.DebModTest)
class DeadTimeChangedCallback(Frelon.Camera.DeadTimeChangedCallback):
Core.DEB_CLASS(Core.DebModTest, "DeadTimeChangedCallback")
@Core.DEB_MEMBER_FUNCT
def __init__(self, cam):
Frelon.Camera.DeadTimeChangedCallback.__init__(self)
self.m_cam = cam
@Core.DEB_MEMBER_FUNCT
def deadTimeChanged(self, dead_time):
cam = self.m_cam
deb.Always("dead_time=%.6f, readout_time=%.6f, xfer_time=%.6f" %
(dead_time, cam.getReadoutTime(), cam.getTransferTime()))
def main():
edev_nr = 0
enable_debug = False
if len(sys.argv) > 1:
edev_nr = int(sys.argv[1])
if enable_debug:
Core.DebParams.enableModuleFlags(Core.DebParams.AllFlags)
Core.DebParams.enableTypeFlags(Core.DebParams.AllFlags)
else:
Core.DebParams.disableModuleFlags(Core.DebParams.AllFlags)
edev = Espia.Dev(edev_nr)
eserline = Espia.SerialLine(edev)
cam = Frelon.Camera(eserline)
dt_cb = DeadTimeChangedCallback(cam)
cam.registerDeadTimeChangedCallback(dt_cb)
cam.setFrameTransferMode(Frelon.FTM)
cam.setFrameTransferMode(Frelon.FFM)
if __name__ == '__main__':
main()
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