Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions xspdApp/Db/ADXSPD.template
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
##################################################################

include "ADBase.template"
include "NDFile.template"

# ADBase record overrides

Expand Down Expand Up @@ -620,6 +621,26 @@ record(ai, "$(P)$(R)BloscNumThreads_RBV"){
field(SCAN, "I/O Intr")
}

# Log files are written to FilePath; stdout is used if FilePath is empty
record(bo, "$(P)$(R)LogRequests"){
field(DESC, "Log HTTP requests sent to XSPD")
field(DTYP, "asynInt32")
field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))XSPD_LOG_REQUESTS")
field(ZNAM, "Disabled")
field(ONAM, "Enabled")
field(VAL, "0")
field(PINI, "NO")
}

record(bi, "$(P)$(R)LogRequests_RBV"){
field(DESC, "Log HTTP requests readback")
field(DTYP, "asynInt32")
field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))XSPD_LOG_REQUESTS")
field(ZNAM, "Disabled")
field(ONAM, "Enabled")
field(SCAN, "I/O Intr")
}

# Disable any ADBase records we don't want to use

record(mbbo, "$(P)$(R)DataType")
Expand Down
1 change: 1 addition & 0 deletions xspdApp/Db/ADXSPD_settings.req
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
file "ADBase_settings.req", P=$(P), R=$(R)
file "NDFile_settings.req", P=$(P), R=$(R)
91 changes: 71 additions & 20 deletions xspdApp/op/bob/ADXSPD.bob
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--Saved on 2026-04-23 15:08:51 by jwlodek-->
<!--Saved on 2026-09-30 09:58:15 by jwlodek-->
<display version="2.0.0">
<name>ADXSPD Control - $(P)</name>
<macros>
Expand All @@ -17,9 +17,9 @@
<widget type="group" version="3.0.0">
<name>Monitor</name>
<x>750</x>
<y>612</y>
<y>602</y>
<width>375</width>
<height>144</height>
<height>120</height>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
</font>
Expand All @@ -36,9 +36,9 @@
<widget type="label" version="2.0.0">
<name>Label_22</name>
<text>Timeout (s)</text>
<x>34</x>
<y>49</y>
<width>110</width>
<x>6</x>
<y>60</y>
<width>125</width>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
</font>
Expand All @@ -52,8 +52,8 @@
<widget type="textupdate" version="2.0.0">
<name>TextUpdate_14</name>
<pv_name>$(P)$(R)MonitorInterval_RBV</pv_name>
<x>229</x>
<y>49</y>
<x>251</x>
<y>60</y>
<width>80</width>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
Expand All @@ -71,9 +71,8 @@
<widget type="textentry" version="3.0.0">
<name>TextEntry_6</name>
<pv_name>$(P)$(R)MonitorInterval</pv_name>
<x>161</x>
<y>49</y>
<width>60</width>
<x>140</x>
<y>60</y>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
</font>
Expand All @@ -87,7 +86,8 @@
<name>Label_45</name>
<text>Monitor mode</text>
<x>6</x>
<y>24</y>
<y>10</y>
<width>125</width>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
</font>
Expand All @@ -101,8 +101,8 @@
<widget type="combo" version="2.0.0">
<name>ComboBox_15</name>
<pv_name>$(P)$(R)MonitorMode</pv_name>
<x>118</x>
<y>24</y>
<x>140</x>
<y>10</y>
<height>20</height>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
Expand All @@ -116,8 +116,59 @@
<widget type="textupdate" version="2.0.0">
<name>TextUpdate_33</name>
<pv_name>$(P)$(R)MonitorMode_RBV</pv_name>
<x>234</x>
<y>24</y>
<x>251</x>
<y>10</y>
<width>80</width>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
</font>
</font>
<foreground_color>
<color red="10" green="0" blue="184">
</color>
</foreground_color>
<background_color>
<color red="187" green="187" blue="187">
</color>
</background_color>
</widget>
<widget type="label" version="2.0.0">
<name>Label_46</name>
<text>Log Requests</text>
<x>6</x>
<y>35</y>
<width>125</width>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
</font>
</font>
<background_color>
<color red="187" green="187" blue="187">
</color>
</background_color>
<horizontal_alignment>2</horizontal_alignment>
</widget>
<widget type="combo" version="2.0.0">
<name>ComboBox_18</name>
<pv_name>$(P)$(R)LogRequests</pv_name>
<x>140</x>
<y>35</y>
<height>20</height>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
</font>
</font>
<background_color>
<color red="115" green="223" blue="255">
</color>
</background_color>
</widget>
<widget type="textupdate" version="2.0.0">
<name>TextUpdate_34</name>
<pv_name>$(P)$(R)LogRequests_RBV</pv_name>
<x>251</x>
<y>35</y>
<width>80</width>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
</font>
Expand Down Expand Up @@ -1080,7 +1131,7 @@
</widget>
<widget type="group" version="3.0.0">
<name>Shutter</name>
<y>675</y>
<y>696</y>
<width>375</width>
<height>166</height>
<font>
Expand Down Expand Up @@ -1337,7 +1388,7 @@
</widget>
<widget type="group" version="3.0.0">
<name>Detector Status</name>
<y>475</y>
<y>485</y>
<width>375</width>
<font>
<font family="Liberation Sans" style="REGULAR" size="16.0">
Expand Down Expand Up @@ -1961,7 +2012,7 @@
</widget>
<widget type="group" version="3.0.0">
<name>Plugins</name>
<y>375</y>
<y>385</y>
<width>375</width>
<height>100</height>
<font>
Expand Down Expand Up @@ -3707,7 +3758,7 @@
<widget type="group" version="3.0.0">
<name>Attributes</name>
<x>750</x>
<y>756</y>
<y>722</y>
<width>375</width>
<height>120</height>
<font>
Expand Down
76 changes: 76 additions & 0 deletions xspdApp/src/ADXSPD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,47 @@ asynStatus ADXSPD::acquireStop() {
return asynSuccess;
}

/**
* @brief Enables or disables logging of HTTP requests sent to XSPD.
*
* Logs are written to <FilePath>/<FileName>, or <FilePath>/xspd_requests.log if FileName is empty.
* If FilePath is empty, logs are written to stdout.
*
* @param enable Whether to enable request logging
* @throws runtime_error if the file path does not exist or the log file cannot be opened
*/
void ADXSPD::setRequestLogging(bool enable) {
if (!enable) {
this->pApi->DisableRequestLogging();
setStringParam(NDFullFileName, "");
return;
}

char filePath[MAX_FILENAME_LEN];
char fileName[MAX_FILENAME_LEN];
getStringParam(NDFilePath, sizeof(filePath), filePath);

if (strlen(filePath) == 0) {
this->pApi->EnableRequestLogging();
setStringParam(NDFullFileName, "");
INFO("Logging XSPD requests to stdout");
return;
}

if (this->checkPath() != asynSuccess)
throw runtime_error("File path " + string(filePath) + " does not exist");

// checkPath() normalizes the path to include a trailing delimiter
getStringParam(NDFilePath, sizeof(filePath), filePath);
getStringParam(NDFileName, sizeof(fileName), fileName);
string logFilePath =
string(filePath) + (strlen(fileName) > 0 ? string(fileName) : "xspd_requests.log");

this->pApi->EnableRequestLogging(logFilePath);
setStringParam(NDFullFileName, logFilePath.c_str());
INFO_ARGS("Logging XSPD requests to %s", logFilePath.c_str());
}

/**
* @brief Subtracts two frames element-wise with floor at 0
*
Expand Down Expand Up @@ -788,6 +829,8 @@ asynStatus ADXSPD::writeInt32(asynUser* pasynUser, epicsInt32 value) {
if (value < ADXSPD_MIN_STATUS_POLL_INTERVAL) {
actualValue = ADXSPD_MIN_STATUS_POLL_INTERVAL;
}
} else if (function == ADXSPD_LogRequests) {
this->setRequestLogging(value != 0);
}

setIntegerParam(function, actualValue);
Expand Down Expand Up @@ -890,6 +933,39 @@ asynStatus ADXSPD::writeFloat64(asynUser* pasynUser, epicsFloat64 value) {
}
}

/**
* @brief Override of asynNDArrayDriver::writeOctet. Re-opens the request log if the file
* path or name changes while request logging is enabled.
*
* @param pasynUser asyn client who requests a write
* @param value string value to write
* @param nChars number of characters to write
* @param nActual number of characters actually written
* @return asynStatus success if write was successful, else failure
*/
asynStatus ADXSPD::writeOctet(asynUser* pasynUser, const char* value, size_t nChars,
size_t* nActual) {
int function = pasynUser->reason;
asynStatus status = ADDriver::writeOctet(pasynUser, value, nChars, nActual);

int logRequests;
getIntegerParam(ADXSPD_LogRequests, &logRequests);
if (status == asynSuccess && logRequests &&
(function == NDFilePath || function == NDFileName)) {
try {
this->setRequestLogging(true);
} catch (std::runtime_error& e) {
this->pApi->DisableRequestLogging();
setIntegerParam(ADXSPD_LogRequests, 0);
ERR_TO_STATUS_ARGS("Failed to update request log file, disabling logging: %s",
e.what());
status = asynError;
}
callParamCallbacks();
}
return status;
}

/**
* @brief Override of ADDriver base function - reports driver status
*
Expand Down
3 changes: 3 additions & 0 deletions xspdApp/src/ADXSPD.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ class ADXSPD : ADDriver {
// ADDriver overrides
virtual asynStatus writeInt32(asynUser* pasynUser, epicsInt32 value);
virtual asynStatus writeFloat64(asynUser* pasynUser, epicsFloat64 value);
virtual asynStatus writeOctet(asynUser* pasynUser, const char* value, size_t nChars,
size_t* nActual);
virtual void report(FILE* fp, int details);

// Destructor. Disconnects from the detector and performs cleanup
Expand All @@ -189,6 +191,7 @@ class ADXSPD : ADDriver {
asynStatus refreshFrameSize();
asynStatus acquireStart();
asynStatus acquireStop();
void setRequestLogging(bool enable);

template <typename T>
void subtractFrames(void* currentFrame, void* previousFrame, void* outputFrame,
Expand Down
1 change: 1 addition & 0 deletions xspdApp/src/ADXSPDParamDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ void ADXSPD::createAllParams() {
createParam(ADXSPD_MonitorIntervalString, asynParamFloat64, &ADXSPD_MonitorInterval);
createParam(ADXSPD_DecompressString, asynParamInt32, &ADXSPD_Decompress);
createParam(ADXSPD_BloscNumThreadsString, asynParamInt32, &ADXSPD_BloscNumThreads);
createParam(ADXSPD_LogRequestsString, asynParamInt32, &ADXSPD_LogRequests);
}
6 changes: 4 additions & 2 deletions xspdApp/src/ADXSPDParamDefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#define ADXSPD_MonitorIntervalString "XSPD_MONITOR_INTERVAL"
#define ADXSPD_DecompressString "XSPD_DECOMPRESS"
#define ADXSPD_BloscNumThreadsString "XSPD_BLOSC_NUM_THREADS"
#define ADXSPD_LogRequestsString "XSPD_LOG_REQUESTS"

// Parameter index definitions
int ADXSPD_ApiVersion;
Expand Down Expand Up @@ -69,10 +70,11 @@ int ADXSPD_MonitorMode;
int ADXSPD_MonitorInterval;
int ADXSPD_Decompress;
int ADXSPD_BloscNumThreads;
int ADXSPD_LogRequests;

#define ADXSPD_FIRST_PARAM ADXSPD_ApiVersion
#define ADXSPD_LAST_PARAM ADXSPD_BloscNumThreads
#define ADXSPD_LAST_PARAM ADXSPD_LogRequests

#define NUM_ADXSPD_PARAMS 31
#define NUM_ADXSPD_PARAMS 32

#endif
Loading
Loading