Hello everyone,
I have an application (saving postmortem data after beam dump) which uses simplified records as below:
record(bi, "PMStatus-I") {
field(DESC,"Post-Mortem status")
field(ZNAM,"PM Ready")
field(ONAM,"PM Detected")
}
record(calcout,"PM-Calc_") {
field(INPA,"PMStatus-I CP")
field(CALC,"A")
field(OOPT,"Transition To Non-zero")
field(OUT, "PM-Cmd PP")
field(ODLY, "15")
field(RPRO,"1")
field(MDEL,"-1")
}
record(bo, "PM-Cmd") {
#field(DTYP,"Launcher")
#field(OUT, "@python /epics/iocs/postmortem/save_pmdata.py")
field(ZNAM,"Idle")
field(ONAM,"Setting")
field(HIGH,"1")
}
The logic in the records above: whenever “PMStatus-I” is changed from 0 to 1 meaning the beam is dumped, the calcout record waits for ODLY seconds, then it writes to "PM-Cmd", which in turn executes a Python
script. For the purpose of simple and easy tests (you can try it by yourself), ODLY is set to 15 and DTYP and OUT are commented out in the bo record. The actual ODLY in my application is 180-second. After beam dump, “PMStatus-I” becomes 1. Then after the machine
is ready for injection again, our operators manually reset “PMStatus-I” to 0. My application works most of the time, but occasionally it fails to execute the Python script after beam dump. After a deep investigation, it turns out the problem occurs whenever
our operators reset “PMStatus-I” to 0 too quickly (before the 180-second ODLY expires).
Sorry for the long story. Let’s back to the simplified records above. I use this simple Python script to test it out:
$ cat test1.py
#!/usr/bin/python
import cothread
from cothread.catools import caput
caput('PMStatus-I', 1)
cothread.Sleep(2)
caput('PMStatus-I', 0)
cothread.Sleep(17)
caput('PMStatus-I', 1)
cothread.Sleep(17)
caput('PMStatus-I', 0)
Basically, the script performs this:
- Simulate beam dump: caput PMStatus-I 1;
- 2-second later, reset PM Status (the reset is too early): caput PMStatus-I 0;
- 17-second later, simulate beam dump again: caput PMStatus-I 1;
- 17-second later, reset PM Status: caput PMStatus-I 0;
This is the result, which reproduces the problem: two beam dumps, but the record “PM-Cmd” only gets processed once.
camonitor -n PM-Cmd PM-Calc_ PMStatus-I PM-Calc_.DLYA PM-Calc_.RPRO PM-Calc_.MDEL PM-Calc_.PACT
PM-Cmd <undefined> 0 UDF INVALID
PM-Calc_ 2020-11-20 11:32:41.850265 0
PMStatus-I <undefined> 0 UDF INVALID
PM-Calc_.DLYA 2020-11-20 11:32:41.850265 0
PM-Calc_.RPRO 2020-11-20 11:32:41.850265 0
PM-Calc_.MDEL 2020-11-20 11:32:41.850265 -1
PM-Calc_.PACT 2020-11-20 12:17:15.011557 0
PMStatus-I 2020-11-20 11:39:44.310406 1
PM-Calc_.DLYA 2020-11-20 11:39:44.310465 1
PMStatus-I 2020-11-20 11:39:46.311319 0
PM-Calc_.DLYA 2020-11-20 11:39:59.305587 0
PM-Cmd 2020-11-20 11:39:59.305599 1
PM-Calc_ 2020-11-20 11:39:59.305587 1
PM-Cmd 2020-11-20 11:40:00.300696 0
PMStatus-I 2020-11-20 11:40:03.325023 1
PM-Calc_ 2020-11-20 11:40:03.325097 1
PMStatus-I 2020-11-20 11:40:20.336303 0
PM-Calc_ 2020-11-20 11:40:20.336354 0
In the document AppDevGuide, it says: CP - Forces the link to be a channel access link and also requests that the record containing the link be processed whenever a monitor occurs. In the step #2, “PMStatus-I”
is changed from 1 to 0, which I thought will cause the calcout record “PM-Calc_” to be processed again later on although the PACT of “PM-Calc_” is still TRUE right now. However, it does not happen as I thought: “PM-Calc_” does not change to 0 after “PM-Cmd”
gets processed.
If I add “caput PM-Calc_.PROC 1” in step #2 after “caput PMStatus-I 0”, then everything works: the record “PM-Cmd” gets processed twice after two simulated beam dumps.
So, “caput PM-Calc_.PROC 1” seems to be “Cached Puts” as said in the AppDevGuide. My questions:
- Should the CA input link CP/CPP have the function of “Cached Puts”?
- Is it a good idea to have “Queued Puts” for EPICS records? AreaDetector is using “queue” for plugins although its queue is for keeping input data.
Thank you for taking your time to read such a long message. Wish you a safe and Happy Thanksgiving.
Yong
NSLS-II Controls Group