12 Commits
1.1.0 ... 1.1.3

Author SHA1 Message Date
Marco Filho
def770e2f8 Merge branch 'improve-timestamp' into 'master'
Pass timestamp to epicsTS instead of timeStamp

See merge request epics-modules/adorca!29
2025-10-15 13:03:58 +02:00
marcofilho
cceb18989b Make epicsTS carry the proper EVR timestamp
epicsTS is the one passed to kafka: https://gitlab.esss.lu.se/epics-modules/ADPluginKafka/-/blob/2.0.2/adpluginkafkaApp/src/KafkaPlugin.cpp?ref_type=tags#L40
The documentation is a bit confusing on what is the difference between
epicsTS and timeStamp, but apparently both can be modified with no
problems.

After [this discussion](github.com/areaDetector/ADCore/issues?q=is%3Aissue%20state%3Aclosed)
I decided it was fine to keep the epicsTS in nanoseconds with the EVR
values.
2025-10-15 13:00:16 +02:00
marcofilho
e2d6d48cde Decrease image-timestamp latency.
The timestamp buffer is now filled unconditionally, always after
dcamcap_transferinfo is called. It is only used, however, if trigger
mode is external.

This reduces time between detecting an image and getting the timestamp
from around 1.6 ms to around 200 ns.
2025-10-10 16:48:07 +02:00
Jim Larsson
62065f7f44 Merge branch 'v1.1.2_fix' into 'master'
uncomment line

See merge request epics-modules/adorca!28
2024-12-19 10:49:18 +00:00
Jim Larsson
00cb454e8c uncomment line 2024-12-19 11:24:08 +01:00
Jim Larsson
66cbff0ca4 Merge branch '1.1.2_bugfixes' into 'master'
fix compilation errors and warnings

See merge request epics-modules/adorca!27
2024-12-18 13:17:23 +00:00
Jim Larsson
934ce7afd0 fix compilation errors and warnings 2024-12-18 13:16:44 +00:00
Jim Larsson
47a2b8435f Merge branch 'ICSHWI_19722_orca_acq_modes' into 'master'
Icshwi 19722 orca acq modes

See merge request epics-modules/adorca!26
2024-12-18 13:04:13 +00:00
Jim Larsson
eaebcece9d added placeholder for LEVEL and sync triggers 2024-12-05 16:21:56 +01:00
Jim Larsson
994242e524 seperate timeout from syncreadout 2024-12-03 14:47:06 +01:00
Douglas Araujo
ca22a8166c Fix initial value for SensorCooler 2024-10-29 10:57:26 +01:00
Douglas Araujo
6f0f6357be Fix mbbi item string length 2024-10-29 10:55:30 +01:00
4 changed files with 61 additions and 34 deletions

3
.gitignore vendored
View File

@@ -14,3 +14,6 @@ ecdc-kafka-ca.crt
.pre-commit-config.yaml
.clang-format
.iocsh_history
build
build.sh

View File

@@ -1676,9 +1676,9 @@ record(mbbi, "$(P)$(R)FrameStampProd-R") {
field(DESC, "Timestamp produced source")
field(DTYP, "asynInt32")
field(ZRVL, "2")
field(ZRST, "Frame timestamp DCAM module")
field(ZRST, "DCAM module")
field(ONVL, "5")
field(ONST, "Frame timestamp image device")
field(ONST, "Image device")
field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))H_FRAMESTAMP_PRODUCER")
field(SCAN, "I/O Intr")
}
@@ -1694,7 +1694,7 @@ record(mbbo, "$(P)$(R)SensorCooler-S") {
field(TWVL, "4")
field(TWST, "Max")
field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))H_SENSOR_COOLER")
field(VAL, "Off")
field(VAL, "0")
}
record(mbbi, "$(P)$(R)SensorCooler-RB") {

View File

@@ -834,12 +834,15 @@ void Orca::imageTask() {
uint64_t prevAcquisitionCount = 0;
DCAMCAP_TRANSFERINFO captransferinfo;
epicsTimeStamp prevAcqTime, currentAcqTime;
epicsTimeStamp acqTimestamp;
epicsTimeStamp prev_trigger_time, current_trigger_time;
double elapsedTime;
int evr_counts = 0;
double exposure_time, readout_time;
double maxAcqusitionTime, acqusitionRate;
int triggerMode = DCAMPROP_TRIGGERSOURCE__INTERNAL;
int triggerActive;
char buf[256];
lock();
while (1) {
@@ -874,7 +877,7 @@ void Orca::imageTask() {
// get image transfer status.
unlock();
imageTransferStatus(m_hdcam, captransferinfo);
imageTransferStatus(m_hdcam, captransferinfo, buf);
lock();
if (prevAcquisitionCount < (uint64_t)captransferinfo.nFrameCount) {
@@ -910,39 +913,48 @@ void Orca::imageTask() {
double timestamp;
getIntegerParam(hTriggerSource, &triggerMode);
if (triggerMode == DCAMPROP_TRIGGERSOURCE__EXTERNAL) {
getIntegerParam(evrCounts, &evr_counts);
// Count events
evr_counts_since_last_start = evr_counts - initial_evr_counters;
evr_trigger_dropped =
evr_counts_since_last_start - captransferinfo.nFrameCount;
FLOW_ARGS("EVR event count: %d\n", evr_counts);
FLOW_ARGS("evr_counts_since_last_start: %d\n",
evr_counts_since_last_start);
// Update asyn parameters
setIntegerParam(evrCountsSinceAcqStart, evr_counts_since_last_start);
setIntegerParam(evrTriggerDropped, evr_trigger_dropped);
char buf[256];
getStringParam(evrTimeStamp, 256, buf);
// remember parsed timestamp values
sscanf(buf, "%u.%u", &mTimeStampSec, &mTimeStampNsec);
timestamp = mTimeStampSec + mTimeStampNsec / 1.e9;
FLOW_ARGS("mTimeStampSec: %u - mTimeStampNsec: %u\n", mTimeStampSec,
mTimeStampNsec);
sscanf(buf, "%u.%u", &acqTimestamp.secPastEpoch, &acqTimestamp.nsec);
acqTimestamp.secPastEpoch -= POSIX_TIME_AT_EPICS_EPOCH;
timestamp = acqTimestamp.secPastEpoch + acqTimestamp.nsec / 1.e9;
FLOW_ARGS("acqTimestamp.secPastEpoch: %u - acqTimestamp.nsec: %u\n", acqTimestamp.secPastEpoch,
acqTimestamp.nsec);
FLOW_ARGS("Timestamp from evr: %f\n", timestamp);
} else {
updateTimeStamp(&acqTimestamp);
timestamp =
(ts_sec + ts_microsec / 1.0e6) - (exposure_time + readout_time);
FLOW_ARGS("Timestamp from camera: %f\n", timestamp);
}
}
FLOW_ARGS("readout_time: %f - exposure_time: %f\n", readout_time,
exposure_time);
// calculate time since previous frame and update framerate.
epicsTimeGetCurrent(&currentAcqTime);
elapsedTime = epicsTimeDiffInSeconds(&currentAcqTime, &prevAcqTime);
prevAcqTime = currentAcqTime;
status = setDoubleParam(hFrameRate, (double)(1 / elapsedTime));
getIntegerParam(NDArrayCallbacks, &callback);
if (callback) {
NDArray* pImage;
@@ -958,7 +970,7 @@ void Orca::imageTask() {
if (pImage) {
pImage->uniqueId = count;
pImage->timeStamp = timestamp;
updateTimeStamp(&pImage->epicsTS);
pImage->epicsTS = acqTimestamp;
memcpy(pImage->pData, (epicsUInt16*)image, pImage->dataSize);
@@ -973,6 +985,7 @@ void Orca::imageTask() {
setIntegerParam(ADNumImagesCounter, captransferinfo.nFrameCount);
// Check if evr count number has been updated and update parameters.
getIntegerParam(evrCounts, &evr_counts);
evr_counts_since_last_start = evr_counts - initial_evr_counters;
if (evr_counts_since_last_start != evr_counts_since_last_start_previous) {
@@ -980,23 +993,35 @@ void Orca::imageTask() {
epicsTimeGetCurrent(&prev_trigger_time);
evr_counts_since_last_start_previous = evr_counts_since_last_start;
}
getIntegerParam(hTriggerActive, &triggerActive);
getDoubleParam(ADAcquirePeriod, &acqusitionRate);
getIntegerParam(ADStatus, &acqStatus);
maxAcqusitionTime = acqusitionRate * 2;
epicsTimeGetCurrent(&currentAcqTime);
if ((epicsTimeDiffInSeconds(&currentAcqTime, &prevAcqTime) >
maxAcqusitionTime) &&
acqStatus != ADStatusAborted) {
FLOW_ARGS("maxAcqusitionTime %f\n", maxAcqusitionTime);
setShutter(0);
stopAcquire();
setIntegerParam(ADAcquire, 0);
setIntegerParam(hAcqControl, 0);
setIntegerParam(ADStatus, ADStatusError);
setStringParam(ADStatusMessage, "Acquisition timeout");
if (triggerActive == DCAMPROP_TRIGGERACTIVE__SYNCREADOUT) {
} else if (triggerActive == DCAMPROP_TRIGGERACTIVE__LEVEL) {
} else {
// Checks if the elapsed time since last frame is longer than the exposure,
// stop waiting for image and put in timeout status.
getDoubleParam(ADAcquirePeriod, &acqusitionRate);
getIntegerParam(ADStatus, &acqStatus);
maxAcqusitionTime = acqusitionRate * 2; // arbitrary time longer than the acqusiontime.
epicsTimeGetCurrent(&currentAcqTime);
if ((epicsTimeDiffInSeconds(&currentAcqTime, &prevAcqTime) >
maxAcqusitionTime) &&
acqStatus != ADStatusAborted) {
FLOW_ARGS("maxAcqusitionTime %f\n", maxAcqusitionTime);
setShutter(0);
stopAcquire();
setIntegerParam(ADAcquire, 0);
setIntegerParam(hAcqControl, 0);
setIntegerParam(ADStatus, ADStatusError);
setStringParam(ADStatusMessage, "Acquisition timeout");
}
}
// Check if the camera has failed a trigger from the evr. Updates the
// amount dropped evr triggers.
epicsTimeGetCurrent(&current_trigger_time);
if (epicsTimeDiffInSeconds(&current_trigger_time, &prev_trigger_time) >
(exposure_time + readout_time)) {
@@ -1007,6 +1032,7 @@ void Orca::imageTask() {
}
}
// Check if the acqusition is done (support single and multiple exposure)
if ((imageMode == ADImageMultiple &&
totalImages == captransferinfo.nFrameCount) ||
(imageMode == ADImageSingle && captransferinfo.nFrameCount == 1)) {
@@ -1078,7 +1104,7 @@ asynStatus Orca::writeInt32(asynUser* pasynUser, epicsInt32 value) {
} else if (!value &&
(adstatus == ADStatusAcquire || adstatus == ADStatusError ||
adstatus == ADStatusWaiting)) {
/* This was a command to stop acquisition */
/* This was a command to stop acquisition */ //But not anymore?
setIntegerParam(ADStatus, ADStatusAborted);
setIntegerParam(hAcqControl, 0);
setStringParam(ADStatusMessage, "Acquisition aborted by user");
@@ -1719,7 +1745,7 @@ void Orca::getImageInformation(HDCAM hdcam, int32& pixeltype, int32& width,
}
asynStatus Orca::imageTransferStatus(HDCAM hdcam,
DCAMCAP_TRANSFERINFO& captransferinfo) {
DCAMCAP_TRANSFERINFO& captransferinfo, char *buf) {
DCAMERR err;
const char* functionName = "imageTransferStatus";
memset(&captransferinfo, 0, sizeof(captransferinfo));
@@ -1727,6 +1753,7 @@ asynStatus Orca::imageTransferStatus(HDCAM hdcam,
// get number of captured image
err = dcamcap_transferinfo(m_hdcam, &captransferinfo);
getStringParam(evrTimeStamp, 256, buf);
if (failed(err)) {
ERR_ARGS("DCAMERR: 0x%08X [%s]", m_err, "dcamcap_transferinfo");
return asynError;

View File

@@ -189,9 +189,6 @@ class epicsShareClass Orca : public ADDriver {
int readParameter(int propertyID, bool processPV = true);
int readParameterStr(int paramIndex);
epicsUInt32 mTimeStampSec;
epicsUInt32 mTimeStampNsec;
void imageTask();
void temperatureTask();
@@ -333,7 +330,7 @@ class epicsShareClass Orca : public ADDriver {
int32 rowbytes, int32 cx, int32 cy,
epicsUInt32& ts_sec, epicsUInt32& ts_microsec);
asynStatus imageTransferStatus(HDCAM hdcam,
DCAMCAP_TRANSFERINFO& captransferinfo);
DCAMCAP_TRANSFERINFO& captransferinfo, char *buf);
// wrapper functions for dcamapi
int allocateBuffers(unsigned int);