Commit 3b521e98 authored by Alejandro Homs Puron's avatar Alejandro Homs Puron

* Implemented Frelon::Camera::waitIdleStatus, to be called

  after a Stop command is sent, using getMaxIdleWaitTime,
  which includes in the internal exposure time if 2.x <= FW < 3.0
* Added Frelon::Camera::syncRegsBadHTD to improve
  initialisation sequence if 2.x <= FW < 3.0:
  + If camera is not idle and not in ExtGate, send a Stop command
  + Always attempt to wait for idle status
  + Force an Aurora link reset on startup to trigger
    FPGA reconfiguration, solving blocking problems
  + Added Frelon::Model::hasHTDCmd (from v2.0c on), used to force
    hardware trigger enabled
* Improved Frelon::Camera::setExpTime:
  + Better error detection and simpler sequence
  + Round to MinExp (1 us) if positive but less than that
  + Only use Microseconds TimeUnit if Milliseconds is not precise enough
* Do not start Frelon::Camera if already started
* Better debug around waitIdleStatus in Frelon::Camera::stop,
  printing real time spent waiting
* Activate Espia SG Roi in Frelon::RoiCtrlObj::checkEspiaRoi only
  if Camera Roi is different than requested one
* Export CtSaving feature allowing to manually save multiple
  concatenated frames (stripes) as a single image
parent eb40b17b
......@@ -137,6 +137,7 @@ class Camera : public HwMaxImageSizeCallbackGen
void sync();
void syncRegs();
void syncRegsGoodHTD();
void syncRegsBadHTD();
void sendCmd(Cmd cmd);
......@@ -181,6 +182,10 @@ class Camera : public HwMaxImageSizeCallbackGen
void setTimeUnitFactor(TimeUnitFactor time_unit_factor);
void getTimeUnitFactor(TimeUnitFactor& time_unit_factor);
double getMaxIdleWaitTime();
bool waitIdleStatus(Status& status, bool use_ser_line=false,
bool read_spb2=false);
AutoMutex lock();
SerialLine m_ser_line;
......@@ -205,6 +210,14 @@ inline AutoMutex Camera::lock()
return AutoMutex(m_lock);
}
inline bool Camera::waitIdleStatus(Status& status, bool use_ser_line,
bool read_spb2)
{
status = Wait;
return waitStatus(status, StatusMask, getMaxIdleWaitTime(),
use_ser_line, read_spb2);
}
} // namespace Frelon
......
......@@ -49,6 +49,7 @@ class Firmware
int getMinor() const;
std::string getRelease() const;
static const Firmware v2_0c;
static const Firmware v2_1b;
static const Firmware v3_0i;
static const Firmware v3_1c;
......@@ -127,6 +128,7 @@ class Model
bool hasTaper();
bool hasModesAvail();
bool hasTimeCalc();
bool hasHTDCmd();
bool hasGoodHTD();
bool hasImagesPerEOF();
......@@ -146,6 +148,7 @@ class Model
ChipType m_chip_type;
bool m_modes_avail;
bool m_time_calc;
bool m_htd_cmd;
bool m_good_htd;
bool m_images_per_eof;
};
......
......@@ -504,9 +504,10 @@ class FrelonAcq:
self.m_ct_saving.setCommonHeader(header_map)
@DEB_MEMBER_FUNCT
def writeFile(self, frame_nb):
deb.Param('Writing frame %s to file' % frame_nb)
self.m_ct_saving.writeFrame(frame_nb)
def writeFile(self, frame_nb, nb_frames=1):
deb.Param('Writing %d frame(s) starting from %s to file' %
(nb_frames, frame_nb))
self.m_ct_saving.writeFrame(frame_nb, nb_frames)
@DEB_MEMBER_FUNCT
def setAutosave(self, autosave_act):
......
......@@ -44,6 +44,7 @@ class Firmware
int getMinor() const;
std::string getRelease() const;
static const Frelon::Firmware v2_0c;
static const Frelon::Firmware v2_1b;
static const Frelon::Firmware v3_0i;
static const Frelon::Firmware v3_1c;
......@@ -78,6 +79,7 @@ class Model
bool hasTaper();
bool hasModesAvail();
bool hasTimeCalc();
bool hasHTDCmd();
bool hasGoodHTD();
bool hasImagesPerEOF();
......
......@@ -104,6 +104,9 @@ void Camera::syncRegs()
if (m_model.hasGoodHTD())
syncRegsGoodHTD();
else
syncRegsBadHTD();
double exp_time;
getExpTime(exp_time);
......@@ -134,10 +137,8 @@ void Camera::syncRegsGoodHTD()
do {
setExtSyncEnable(ExtSyncNone);
sendCmd(Stop);
status = Wait;
waitStatus(status, StatusMask, MaxIdleWaitTime,
use_ser_line, read_spb2);
if (status == Wait) {
bool ok = waitIdleStatus(status, use_ser_line, read_spb2);
if (ok) {
if (retry > 0)
DEB_TRACE() << "Succeeded after " << retry
<< " retries";
......@@ -153,6 +154,42 @@ void Camera::syncRegsGoodHTD()
<< DEB_VAR1(DEB_HEX(status));
}
void Camera::syncRegsBadHTD()
{
DEB_MEMBER_FUNCT();
Status status;
getStatus(status);
if ((status != 0) && (status != Wait)) {
DEB_WARNING() << "Camera not IDLE: "
<< DEB_VAR1(DEB_HEX(status));
double exp_time;
getExpTime(exp_time);
if (exp_time > 0) {
DEB_TRACE() << "Sending software STOP ...";
sendCmd(Stop);
}
if (waitIdleStatus(status))
DEB_TRACE() << "Succeeded";
else
DEB_WARNING() << "Camera still not IDLE: "
<< DEB_VAR1(DEB_HEX(status));
}
Espia::Dev& dev = getEspiaDev();
DEB_TRACE() << "Forcing Aurora link reset on old firmware!";
dev.resetLink();
DEB_TRACE() << "Sleeping additional "
<< DEB_VAR1(Frelon::Camera::ResetLinkWaitTime);
Sleep(ResetLinkWaitTime);
if (m_model.hasHTDCmd())
setExtSyncEnable(ExtSyncBoth);
}
SerialLine& Camera::getSerialLine()
{
return m_ser_line;
......@@ -1136,25 +1173,34 @@ void Camera::setExpTime(double exp_time)
DEB_TRACE() << "Ignoring " << DEB_VAR1(exp_time)
<< " in ExtGate trigger mode";
return;
} else if (exp_time < 0)
THROW_HW_ERROR(InvalidValue) << "Invalid negative "
<< DEB_VAR1(exp_time);
double MaxExp = MaxRegVal * TimeUnitFactorMap[Milliseconds];
if (exp_time > MaxExp)
THROW_HW_ERROR(InvalidValue) << "Exp. time too high: "
<< DEB_VAR2(exp_time, MaxExp);
double MinExp = 1 * TimeUnitFactorMap[Microseconds];
if ((exp_time > 0) && (exp_time < MinExp)) {
DEB_WARNING() << "Rounding non-null " << DEB_VAR1(exp_time)
<< " to " << DEB_VAR1(MinExp);
exp_time = MinExp;
}
bool ok = false;
int exp_us = int(exp_time / TimeUnitFactorMap[Microseconds] + 0.1);
int exp_ms = int(exp_time / TimeUnitFactorMap[Milliseconds] + 0.1);
int exp_val;
TimeUnitFactor seq_clist[] = { Microseconds, Milliseconds };
TimeUnitFactor *it, *end = C_LIST_END(seq_clist);
for (it = seq_clist; it != end; ++it) {
double factor = TimeUnitFactorMap[*it];
exp_val = int(exp_time / factor + 0.1);
ok = (exp_val <= MaxRegVal);
if (ok)
break;
TimeUnitFactor time_unit;
if ((exp_us <= MaxRegVal) && (exp_us != exp_ms * 1000)) {
exp_val = exp_us;
time_unit = Microseconds;
} else {
exp_val = exp_ms;
time_unit = Milliseconds;
}
if (!ok)
THROW_HW_ERROR(InvalidValue) << "Exp. time too high: "
<< DEB_VAR1(exp_time);
TimeUnitFactor time_unit_factor = (exp_val == 0) ? Milliseconds : *it;
setTimeUnitFactor(time_unit_factor);
setTimeUnitFactor(time_unit);
writeRegister(ExpTime, exp_val);
}
......@@ -1376,6 +1422,9 @@ void Camera::start()
AutoMutex l = lock();
if (m_started)
THROW_HW_ERROR(InvalidValue) << "Camera already running!";
TrigMode trig_mode;
getTrigMode(trig_mode);
if (trig_mode == IntTrig) {
......@@ -1431,9 +1480,13 @@ void Camera::stop()
}
DEB_TRACE() << "Waiting for camera to become idle";
status = Wait;
waitStatus(status, StatusMask, MaxIdleWaitTime);
Timestamp t0 = Timestamp::now();
bool idle = waitIdleStatus(status);
double wait_time = Timestamp::now() - t0;
DEB_TRACE() << "Waited " << DEB_VAR2(wait_time, idle);
if (!idle)
DEB_WARNING() << "Camera not idle after "
<< DEB_VAR1(wait_time);
m_started = false;
}
......@@ -1449,3 +1502,21 @@ void Camera::setMaxImageSizeCallbackActive(bool cb_active)
{
m_mis_cb_act = cb_active;
}
double Camera::getMaxIdleWaitTime()
{
DEB_MEMBER_FUNCT();
double max_wait_time = MaxIdleWaitTime;
if (!m_model.hasGoodHTD()) {
double exp_time;
getExpTime(exp_time);
if (exp_time > 0) {
max_wait_time += exp_time;
DEB_TRACE() << "Adjusted " << DEB_VAR1(max_wait_time);
}
}
DEB_RETURN() << DEB_VAR1(max_wait_time);
return max_wait_time;
}
......@@ -32,7 +32,7 @@ using namespace std;
*******************************************************************/
Frelon::AcqEndCallback::AcqEndCallback(Camera& cam)
: m_cam(cam)
: m_cam(cam)
{
DEB_CONSTRUCTOR();
}
......@@ -531,7 +531,7 @@ void RoiCtrlObj::checkEspiaRoi(const Roi& set_roi, Roi& hw_roi,
det_frame_size = hw_roi.getSize();
bool sg_roi = !set_roi.isEmpty();
bool sg_roi = (!set_roi.isEmpty() && (hw_roi != set_roi));
if (sg_roi) {
espia_roi = hw_roi.subRoiAbs2Rel(set_roi);
int width = set_roi.getSize().getWidth();
......
......@@ -26,6 +26,7 @@ using namespace lima;
using namespace lima::Frelon;
using namespace std;
const Firmware Firmware::v2_0c("2.0c");
const Firmware Firmware::v2_1b("2.1b");
const Firmware Firmware::v3_0i("3.0i");
const Firmware Firmware::v3_1c("3.1c");
......@@ -164,7 +165,7 @@ const Firmware& Model::getFirmware()
void Model::setComplexSerialNb(int complex_ser_nb)
{
DEB_MEMBER_FUNCT();
DEB_PARAM() << DEB_VAR1(complex_ser_nb);
DEB_PARAM() << DEB_VAR1(DEB_HEX(complex_ser_nb));
m_complex_ser_nb = complex_ser_nb;
update();
......@@ -174,7 +175,7 @@ void Model::getComplexSerialNb(int& complex_ser_nb)
{
DEB_MEMBER_FUNCT();
complex_ser_nb = m_complex_ser_nb;
DEB_RETURN() << DEB_VAR1(complex_ser_nb);
DEB_RETURN() << DEB_VAR1(DEB_HEX(complex_ser_nb));
}
void Model::reset()
......@@ -201,6 +202,9 @@ void Model::update()
else
m_chip_type = bool(getSerialNbParam(SPB1Kodak)) ? Kodak : Atmel;
bool firm_v2_0c = (is_spb2 && (m_firmware >= Firmware::v2_0c));
m_htd_cmd = firm_v2_0c;
bool firm_v2_1b = (is_spb2 && (m_firmware >= Firmware::v2_1b));
m_modes_avail = m_time_calc = firm_v2_1b;
......@@ -321,6 +325,16 @@ bool Model::hasTimeCalc()
return m_time_calc;
}
bool Model::hasHTDCmd()
{
DEB_MEMBER_FUNCT();
checkValid();
DEB_RETURN() << DEB_VAR1(m_htd_cmd);
return m_htd_cmd;
}
bool Model::hasGoodHTD()
{
DEB_MEMBER_FUNCT();
......
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