mdavidsaver / pyDevSup

EPICS Device Support in Python
GNU General Public License v2.0
13 stars 16 forks source link

ai record not working #22

Closed whit2333 closed 4 years ago

whit2333 commented 4 years ago

I have to use longin plus a calc as a work around. Perhaps I am not doing something correct. Have you seen this problem?

mdavidsaver commented 4 years ago

Can you be specific about what you are trying to do?

whit2333 commented 4 years ago

Yes. I want a float database record but the ai record seems to truncate float values. My work around is this:

#
record(longin, "$(dev):$(num):IntField") {
  field(DTYP, "Python Device")
  field(DESC, "work around")
  field(INP , "@fieldprobe 0")
  field(SCAN, "Passive")
}

record(calc, "$(dev):$(num):Field") 
{
  field(DESC, "ai work around")
  field(INPA, "$(dev):$(num):IntField PP")
  field(CALC,  "A/1000000.0")
  field(SCAN, "1 second")
  field(PREC, "9")
  field(EGU,  "Gauss")
}

and my simplified fieldprobe.py is

class MySupport:
    def __init__(self, rec, args):
        """ integer to field component (0,1,2,3) = (|B|,Bx,By,Bz)"""
        self.field_comp = int(args)
        self.teslameter = Teslameter()

    def process(self, rec, reason):
        if self.field_comp is 0:
            field = self.teslameter.get_dc_field()
            rec.VAL = int(field*1000000)
        else :
            field = self.teslameter.get_dc_field()
            rec.VAL = int(field*1000000)

build = MySupport

I want to do this

record(ai, "$(dev):$(num):Field") {
  field(DTYP, "Python Device")
  field(DESC, "work around")
  field(INP , "@fieldprobe 0")
  field(SCAN, "1 second")
}

with fieldprobe.py ...

class MySupport:
...
    def process(self, rec, reason):
        rec.VAL = float( self.teslameter.get_dc_field() )

build = MySupport

But the ai value seems to be truncated to an int no matter what I do.

mdavidsaver commented 4 years ago

The default behavior of aiRecord is the assume that device support has updated the integer RVAL field, and update VAL based on this. If the value you're reading is actually an integer, then just assign to RVAL instead. If your device has given you a floating point, then add raw=True to skip the RVAL to VAL conversion logic.

http://mdavidsaver.github.io/pyDevSup/interfaces.html#DeviceSupport.raw

class MySupport:
     raw = True   # <---- Required for records with RVAL when VAL written directly
...
    def process(self, rec, reason):
        rec.VAL = float( self.teslameter.get_dc_field() )

build = MySupport
mdavidsaver commented 4 years ago

Details for future reference. The C device support read/write function uses the raw attribute to decide to return the magic code 2 (yes really).

https://github.com/mdavidsaver/pyDevSup/blob/849fa492f06258d7b0895f2886996198c9583f64/devsupApp/src/dbdset.c#L349-L356

This magic code is returned to the aiRecord.c support code in Base, and is used to decide whether to call convert() (in the same file), which overwrites VAL.

https://github.com/epics-base/epics-base/blob/6d8bf7c8ef02e9dfe024f2632ea27de11f583f46/modules/database/src/std/rec/aiRecord.c#L161-L169

whit2333 commented 4 years ago

Thank you for the very detailed reply! This fixes it.