ControlSystemStudio / phoebus

A framework and set of tools to monitor and operate large scale control systems, such as the ones in the accelerator community.
http://phoebus.org/
Eclipse Public License 1.0
92 stars 89 forks source link

PVA Booleans do not appear to be supported #1108

Closed jjaraalm closed 4 years ago

jjaraalm commented 4 years ago

I've created a simple boolean:

import pvaccess as pva
s = pva.PvaServer('bool', pva.PvBoolean())

but it shows up as a structure in phoebus and I cannot interact with it controls

pva://bool -> structure boolean value false

kasemir commented 4 years ago

Right, we only tested with qsrv PVs, and on IOCs there is no boolean. You get an enum with 2 options instead.

kasemir commented 4 years ago

So same argument as with custom structures in general: For the UI, we support the NT types. An IOC with a binary input, binary output record creates an NT enum type with the value 0/1 and the labels determined by ZNAM/ONAM. If you create your own custom structure with an boolean, the underlying PVA library can read/write that in case you want to create your own java client. Or you can create your own python or C++ client. But you very likely have to create your own client for your custom PVA server. Generic clients cannot magically understand your custom data. They only try to support the normative types.

jjaraalm commented 4 years ago

Understood. I've updated my code and now it works using enums.

enum = pva.PvObject(dict(index=pva.INT, choices=[pva.STRING]), dict(index=0, choices=['false', 'true']))
x = pva.PvObject(dict(value=enum), dict(value=enum), 'epics:nt/NTEnum:1.0')
s.addRecord('enum_bool', x)

I understand that phoebus is designed mostly to support existing systems and so is not feature complete, so I appreciate you answering my questions. It is a little confusing since there is little documentation and things that I would expect to "just work" (like basic data types) do not, but higher-level components like NTEnum do.

Regarding IOCs, the issue is that in developing new systems the overhead and maintenance cost of creating a full IOC greatly outweighs simple pvapy serves, at least in my use cases. For example, developing an IOC from scratch to interface with an NI FPGA system (of which I have many) is a significant undertaking and may need to be customized to each FPGA system. In contrast, a pvapy based interface layer is < 50 lines of python code and the same code can be deployed on all systems.

jjaraalm commented 4 years ago

Hmm nevermind, it's reading correctly but interaction still does not work. Maybe I haven't set it up correctly? The error I'm getting is

2020-02-05 10:56:38 WARNING [org.epics.pva] TCP sender /127.0.0.1:5075 request encoding error
java.lang.Exception: Cannot set  value to 1
    at org.epics.pva.data.PVAStructure.setValue(PVAStructure.java:114)
    at org.epics.pva.client.PutRequest.encodeRequest(PutRequest.java:124)
    at org.epics.pva.common.TCPHandler.sender(TCPHandler.java:179)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:830)

With a Boolean Button linked to pva://enum_bool which is reading correctly on an LED monitor and in the PV Table. Structure looks like

epics:nt/NTEnum:1.0 
    structure value
        int index 0
        string[] choices ["false", "true"]
kasemir commented 4 years ago

For what it's worth, I added support for the 'bool', but again we won't be able to support any custom structure. This is mostly meant to allow looking at pva://some_struct/sub/sub/bool_value when debugging a custom struct, we don't otherwise have any understanding of what the elements in the custom structure mean.

As for NTEnum, works OK when I create a 'bool' PV with an IOC:

# softIocPVA -m N='' -d demo.db

record(bi, "bool$(N)")
{
  field(ZNAM, "false")
  field(ONAM, "true")
  field(PINI, "YES")
}
pvinfo bool
...
    epics:nt/NTEnum:1.0
        enum_t value
            int index
            string[] choices
        alarm_t alarm
            int severity
            int status
            string message
        time_t timeStamp
            long secondsPastEpoch
            int nanoseconds
            int userTag

When using that with Phoebus 'probe', you can enter 0, 1, true or false. Any of those are written as strings. When used with a 'checkbox' widget in a display, that writes an integer 0/1.

kasemir commented 4 years ago
pvget -v bool
bool epics:nt/NTEnum:1.0 
    enum_t value (0) false
        int index 0
        string[] choices ["false", "true"]
    alarm_t alarm 
        int severity 0
        int status 0
        string message NO_ALARM
    time_t timeStamp 2020-02-05 11:18:30.262  
        long secondsPastEpoch 1580919510
        int nanoseconds 262235982
        int userTag 0
kasemir commented 4 years ago

I guess in the NTEnum it needs to be an enum_t value, not a structure value.

jjaraalm commented 4 years ago

Ah got it. Added the enum_t type and it works now. Thanks so much for the help and for adding boolean support anyways!