1、分布式EPICS设置
1) 操作界面:包括shell命令行方式(caget, caput, camonitor等)和图形界面方式(medm, edm, css等)。
2)输入输出控制器(IOC)

2、IOC
1) 数据库:数据流,基本上周期运行
2)sequencer:基本上按需的状态机
"硬"IOCs运行vxWorks并且直接连接了A/D, D/A, LLRF等硬件。
"软"IOCs运行在linux等上并且除了串口或网络设备外没有I/O硬件。
3、IOC数据库
1)'IOCcore'软件装载并且执行'记录(records)'-记录配置替代了编写自定义代码。
2)所有控制系统控制箱有:GUI工具; 网络协议;硬件驱动,但基本上没有一个相当的数据库。

4、示例:基本的温度控制
任务:
1)从设备读取温度
2)根据需要接通/断开开关
3)重复
一个温控数据库:
使用VisualDCT设计的由四个记录组成的数据库:
1)模拟输入记录(ai:$(TANK)TEMPERATURE)从设备读取温度值,并且把温度值写入到calcout($(TANK)CHECK)记录。
2)calcout($(TANK)CHECK)记录是通过通道访问从$(TANK)TEMPERATURE获取当前温度和通过数据库访问从模拟输入记录ai($(TANK)SETPOINT)获取了设定温度,并且把二者进行比较,并且把比较结果写入到二进制输出记录bo($(TANK)SWITCH)。
3)二进制输出记录bo($(TANK)SWITCH)根据写入的值是0或1,向设备发出断开或者闭合开关的指令。

以下是文本数据库:
1)$(TANK)TEMPERATURE:模拟输入记录ai用于读取设备的输入。
2)$(TANK)CHECK:calcout记录用于比较输入和设定值,并且在比较结果发生变化时,输出比较结果。
3)$(TANK)SWITCH:二进制输出记录bo,向设备输出向其写入的值。
4)$(TANK)SWITCH_RBV:二进制输入记录bi,用于读取设备的开关状态。
5)$(TANK)SETPOINT:模拟输入记录ai,提供给用户设置温度设定值。
record(ai, "$(TANK)TEMPERATURE") {
  field(DESC, "Read Temperature")
  field(SCAN, "I/O Intr")
  field(DTYP,"asynFloat64")
  field(INP,"@asyn($(PT1), 0,1000)FLOAT32_BE")
  field(PREC, "1")
  field(LINR, "NO CONVERSION")
  field(EGU, "Celsius")
  field(HOPR, "100")
  field(LOPR, "0")
  field(SMOO, "0.5")
  field(HIGH, "15")
  field(HSV, "MINOR")
  field(PINI, "NO")
}
record(calcout, "$(TANK)CHECK") {
  field(DESC, "Control Heater")
  field(CALC, "A<B")
  field(INPA, "$(TANK)TEMPERATURE CP MS")
  field(OUT, "$(TANK)SWITCH PP")
  field(OOPT, "On Change")
  field(DOPT, "Use CALC")
  field(INPB, "$(TANK)SETPOINT")
}
record(bo, "$(TANK)SWITCH") {
  field(DESC, "Heater Switch")
  field(SCAN, "Passive")
  field(DTYP,"asynUInt32Digital")
  field(OUT,"@asynMask($(PT2) 0 0x1)")
  field(OMSL, "supervisory")
  field(ZNAM, "Open")
  field(ONAM, "Closed")
  field(IVOA, "Set output to IVOV")
  field(IVOV, "0")
}
record(bi, "$(TANK)SWITCH_RBV") {
  field(DESC, "Heater Switch Readback")
  field(SCAN, "I/O Intr")
  field(DTYP,"asynUInt32Digital")
  field(INP,"@asynMask($(PT3) 0 0x1)")
  field(ZNAM, "Open")
  field(ONAM, "Closed")
}
record(ai, "$(TANK)SETPOINT") {
  field(DESC, "Temperature Setpoint")
  field(SCAN, "Passive")
  field(INP, "10")
  field(HOPR, "100")
  field(LOPR, "0")
}
 
使用modbus-slave软件模拟设备端:
1)温度定义如下:用两个字组成一个32位大端浮点数


2) 开关定义如下:用一个线圈位模拟一个开关


启动脚本设定如下:
#!../../bin/linux-aarch64/tank
#- You may have to change tank to something else
#- everywhere it appears in this file
< envPaths
cd "${TOP}"
## Register all support components
dbLoadDatabase "dbd/tank.dbd"
tank_registerRecordDeviceDriver pdbbase
drvAsynIPPortConfigure("TANK","192.168.50.252:502",0,0,1)
#modbusInterposeConfig(const char *portName,
#                      modbusLinkType linkType,
#                      int timeoutMsec,
#                      int writeDelayMsec)
modbusInterposeConfig("TANK",0, 5000,0)
# one float32 input read
drvModbusAsynConfigure("PT1", "TANK", 1, 4,  0, 2, 0, 500,  "Tank")
# one bit write
drvModbusAsynConfigure("PT2", "TANK", 1, 5,  0, 1, 0, 1000, "Tank")
# one bit read
drvModbusAsynConfigure("PT3", "TANK", 1, 1,  0, 1, 0, 500,  "Tank")
## Load record instances
dbLoadRecords("db/tank.db","TANK=TANK:, PT1=PT1,PT2=PT2,PT3=PT3")
cd "${TOP}/iocBoot/${IOC}"
iocInit 
运行这个IOC,并且查看IOC中加载的记录:
../../bin/linux-aarch64/tank st.cmd
#!../../bin/linux-aarch64/tank
< envPaths
...
############################################################################
## EPICS R7.0.7
## Rev. 2023-05-18T10:40+0800
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
## Start any sequence programs
epics> dbl
TANK:TEMPERATURE
TANK:SETPOINT
TANK:SWITCH_RBV
TANK:SWITCH
TANK:CHECK 
CSS界面:
1) 当在modbus-slave中设置环境温度大于Set Point的温度时,开关会自动打开。


2)当在modbus-slave中设置环境温度小于Set Point的温度时,开关会自动闭合。

 
5、Database = Records + Fields + Links
1)IOC装载并且执行一个或多个数据库。
2)每个数据库有若干记录。
3)每个记录有以下字段:
- 名称(在整个网络上唯一)
 - 类型(确定字段和它们的功能)
 - 字段(属性,可以运行时被读取,绝大部分也能被写入)。
 - 经常有与硬件连接的设备支持。
 - 指向其他记录的链接。
 
6、记录是活动的
1)记录做事情的
- 从其他记录或者硬件获取数据
 - 执行计算
 - 检查值范围,产生警报
 - 写入其他记录或硬件
 
记录做什么取决于记录类型,字段值,设备支持
2) 何时运行记录
记录周期性运行或者被事件或者其他记录触发运行。
除非一个记录被运行了,否则不发生操作。
7、第一个记录"first.db"
这是最简单的记录,它每秒产生一个随机数。
record(calc, $(P)Random)
{
  field(SCAN, "1 second")
  field(INPA,  "10")
  field(CALC,  "RNDM*A")
} 
1)执行:softIoc -m P=FIRST: -d first.db
root@orangepi5:/usr/local/EPICS/program/softdb# softIoc -m P=FIRST: -d first.db
Starting iocInit
############################################################################
## EPICS R7.0.7
## Rev. 2023-05-18T10:40+0800
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
epics> 
2) 在另一个终端中:camonitor FIRST:Random
(base) [blctrl@localhost EPICS]$ camonitor FIRST:Random
FIRST:Random                   2024-05-01 03:34:42.839417 3.26696
FIRST:Random                   2024-05-01 03:34:43.839276 0.0920119
FIRST:Random                   2024-05-01 03:34:44.839298 2.97612
FIRST:Random                   2024-05-01 03:34:45.839343 4.24582
^C 
3) 尝试dbl,dbpr, dbpf命令:
epics> dbl
FIRST:Random
epics> dbpf FIRST:Random 10
DBF_DOUBLE:         10
epics> dbpr FIRST:Random
A   : 10            AMSG:               ASG :               B   : 0
C   : 0             CALC: RNDM*A        D   : 0             DESC:
DISA: 0             DISV: 1             E   : 0             F   : 0
G   : 0             H   : 0             I   : 0             J   : 0
K   : 0             L   : 0             NAME: FIRST:Random  NAMSG:
SEVR: NO_ALARM      STAT: NO_ALARM      TPRO: 0
VAL : 3.27107652399481
 
数据库可以分开,用以下方法在一个IOC中加载若干数据库文件:
first_a.db:
# first_a.db
record(ai, "$(P)Range")
{
  info(autosaveFields, "VAL")
  field(INP,  "10")
  field(PINI, "YES")
}
 
first_b.db:
# first_b.db
record(calc, "$(P)Random")
{
  field(SCAN, "1 second")
  field(INPA, "$(P)Range")
  field(CALC, "RNDM*A")
}
 
#softIoc -m P=FIRST: -d first_a.db -d first_b.db
root@orangepi5:/usr/local/EPICS/program/softdb# softIoc -m P=FIRST: -d first_a.db -d first_b.db         
Starting iocInit
############################################################################
## EPICS R7.0.7
## Rev. 2023-05-18T10:40+0800
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
epics> dbl
FIRST:Range
FIRST:Random
epics>
 
 
8、记录类型
1)ai/ao:模拟输入/输出:-读取/写入数值,映射成工程单位
2)bi/bo:二进制输入/输出:-读取/写入位,映射成字符串
3)calc:公式
4)mbbi/mbbo:多位二进制输入/输出:-读取/写入16位数值,映射位模式到字符串。
5)stringin/stringout:longin/longout, seq, compress, histogram, waveform, sub, ..
9、公共字段
1)设计时间
- -NAME:记录明,网上唯一。
 - -DESC:描述。
 - -SCAN:扫描机制。
 - -PHAS:扫描阶段。
 - -PINI:初始化时运行一次。
 - -FLNK:转发链接。
 
2)运行时
- -TIME:时间戳。
 - -SEVR,STAT:警报严重性,状态。
 - -PACT:运行活动的。
 - -UDF:未定义?从未运行?
 - -PROC:强制运行。
 
3)还有
-TPRO:跟踪运行,设为1来调试记录运行。
10、记录扫描
1)SCAN字段
- 当被其它记录运行时:"Passive"(默认)
-周期地:".1 second", ".2 second", ".5 second", "1 second", "2 second", "5 second", "10 second"。
-事件触发:
- "Event":(EVNT字段选择事件)
 - "I/O Intr":(如果设备支持允许这个)。
 
2)PHAS字段
对处于相同周期扫描地记录添加顺序。首先PHAS=0, 接着PHAS=1, ...
3)PINI字段
设置成"YES"使得记录启动时运行一次。对基本不再更改的"操作输入"记录有用,因此它们有一个初始值。
4)PROC字段
写入这个字段将运行一个记录。
11、数据库和IOC其它部分
1)记录扫描运行优先级高于通道访问或PV访问
在高CPU负载,PVs在记录仍然在运行时可能没有连接。
2)0.1秒扫描运行优先级高于10秒扫描。
3)PRIO字段为异步完成和事件扫描的记录选择优先级。
12、公有的输入/输出记录字段
- DYTP:设备类型。
 - INP/OUT:如何读取/写入,格式取决于DTYP。
 - RVAL:原始值(例如:16位整数)
 - VAL:工程单位值(例如:64位float)
 
仅限输出:
- DOL:所需输出链接。输出记录读取这个链接获取VAL,接着写入OUT。
 - OSML:输入模式选择,closed_loop, supervisory。
 - IVOA:无效时,输出操作。
 - DRVL,DRVH:驱动限制。
 
13、扩展"first.db"
一个从0到上限的渐变,通过一个单独的记录可以设置这个上限。
ramp.db:两个记录组成的数据库文件。
1)$(P)Limit是模拟输出记录,用它设置渐变的上限。使用输出。输入也有效,由于没有要读或要写的硬件,但仅输出有DRVH。
2)$(P)Ramp是calc记录,它每秒运行一次,如果计算结果小于上限,则其值每次加1,否则,其只被设为0。读取输入:A=我自己的当前值;B=$(P)Limit激烈的值。
record(ao, "$(P)Limit")
{
  field(DRVH, "100")
  field(DOL,  "9")
  field(PINI, "YES")
}
record(calc, "$(P)Ramp")
{
  field(SCAN, "1 second")
  field(INPA, "$(P)Ramp")
  field(INPB, "$(P)Limit")
  field(CALC, "A<B?A+1:0")
} 
使用softIoc -m P=SECOND: -d ramp.db
root@orangepi5:/usr/local/EPICS/program/softdb# softIoc -m P=SECOND: -d ramp.db
Starting iocInit
############################################################################
## EPICS R7.0.7
## Rev. 2023-05-18T10:40+0800
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
epics> dbl
SECOND:Limit
SECOND:Ramp 
从CSS软件中查看calc记录随时间的变化:

14、模拟记录字段
1)EGU:工程单位名称。
2)SMOO:平滑。
- -VAL:(1-SMOO) * new_value + SMOO*last_value
 - -SMOO=0:VAL=new_value, 默认行为
 - -SMOO=1:VAL=last_value, 失效行为
 - -0<SMOO<1:VAL ‘平滑地’跟随最新地读数。
 
3)LINR:线性化(None, Slope, 断点表):-EGUL,EGUF,ESLO,EOFF:用于LINR的参数。
4)LOLO,LOW,HIGH,HIHI:警报限制:-LLSV,LSV,HSV,HHSV:相关联的警报严重性。
15、二进制记录字段
1) ZNAM, ONAM:对应"0", "1"的状态名称。
2)ZSV,OSV:警报严重性。
16、记录链接
1)输入或输出记录可以是
-其他记录的字段名称:“other”, “other.VAL”,"other.A"
- 如果其他记录是在相同IOC中,"数据库链接"
 - 如果没有找到名称:"通道访问链接"
 
-硬件链接
- 具体取决于设备支持
 - DTYP字段选择设备支持
 - 格式示例:"field(OUT,"@asynMask($(PT2) 0 0x1)")"
 
2) 输入链接可以是
-常数数值:"0", "3.14", "1.6e-19"。
3) 一个记录的FLNK记录在当前记录结束后运行另一个记录。
17、数据库链接
1) 格式:"record.field {flags}"
-VAL是字段的默认。
2)Flags:
-PP:运行一个被动目标记录。
- INP,DOL:在读取前。
 - OUT:在写入后。
 
-NPP:非运行被动(默认)。
-MS:最大化严重性
-NMS:非MS(默认)
-MSS:最大化严重性和状态。
-MSI:当severity=INVALID时。
3)示例:
field("INP", "other_rec.VAL PP MS")
18、通道访问链接
当被链接的记录不是在这个IOC中时,自动使用通道访问链接。
flags:
-PP:被忽略。不触发另一个IOC上运行。
-MS,MSI:(INVALID时)最大化严重性。
通道访问链接flags:
1)CA:强制CA链接,即使目标记录在相同IOC中,可以用于打破'锁集'。
2)CP:用于INP链接,对收到的CA monitor时运行。一般在链接的值变化时引起运行。具体取决于源的MDEL。
3)CPP:CP,但仅限SCAN=Passive。
19、转发链接(Forward links)
1) 触发运行,但不传递数据。
2)如果SCAN=Passive,目标记录被运行。
3)可以使用CA链接:
-必须使用
- FLNK=“other.PROC”(其他IOC)
 - FLNK=“ohter.PROC CA”(相同IOC)
 
-即使SCAN!=Passive,总是触发运行。
20、运行链
1) 运行链1

以上记录都是每0.1秒执行一次,执行顺序由PHAS=0,1,2指定;Calculation_1通过INPA字段从Input_1获取输入,Output_1通常DOL从Calculation_1获取输入。
2)运行链2

Input_2记录每0.1秒运行一次,在其运行结束时,通过FLNK链接,使得Calculation_2运行,在Calculation_2运行期间,通过INPA从Input_2获取输入,并进行计算,在其运行结束时,通过FLNK链接,使得Output_2运行,在Calculation_2运行期间,通过DOL从Calculation_2获取输入。
3)运行链3

Output_3记录每0.1秒记录运行一次,在其运行期间,通过DOL从Calculation_3获取输入,由于其链接属性是PP,此时Calculation_3开始运行,其运行期间通过INPA从Input_3获取输入,由于其输入链接是PP,此时Input_3开始运行,其运行结束后,Calculation_3获取了输入值,并进行计算并得到结果,此时Calculation_3运行结束,Output_3开始运行,从Calculation_3获取了输入,并完成之后的运行。
21、变化率示例
计算一个输入的变化率:

Rate记录的类型是calc,它每1秒钟运行一次,当其运行时,首先通过INPA从Input记录获取输入,并且存入其A字段,然后通过INPB记录从Input记录获取输入,由于此输入链接是PP属性,此时会将运行权交给Input记录使得Input记录运行,当其运行结束时,将运行全交给Rate记录,INPB获取了Input新产生的值,并且将其放入字段B,然后根据CALC中指定的A-B进行计算,计算结果便是Input记录一秒间隔的变化值。
22、仿真模式

当在仿真模式时,AO记录不调用设备支持并且AI记录从AO记录获取其输入。
23、多扫描触发
慢周期扫描和快变化响应

每5秒钟以及在AO记录被更改时,AI记录被运行。即使正常扫描速率非常满,这也提供了对操作人员更改的立即响应。对电源设置的更改被代表一个本地/远程切换开关的BO记录禁止。
24、设备支持
1)记录(AI, AO,..)靠它们自己仅读写其它记录。
2)设备支持链接它们到硬件
3)硬件设备支持是EPICS ‘base’之外的。根据需要被添加到IOC中。
4)DTYP选择了一个设备支持模块。
5)INP/OUT提供细节。
25、同步与异步
1)”快“:在记录被运行时,同步设备支持读或写一个记录的VAL。
2)"慢“:当记录被运行时,异步支持开始读取或写入。记录保持在PACT=true状态,并且在数据已经被读/写时,设备支持触发运行结束。
3)无论记录是否正在运行,通道访问'get/put'读/写当前VAL。
4) 通道访问'get/put callback'在运行结束时将结束。
26、'软'设备支持
1)用于AI,AO,BI,BO,...的"软通道"
读/写这个VAL字段
2)用于AI,AO,BI,BO,...的"原始软通道"
读写RVAL字段,转成/或从VAL转换
3)用于AI,AO,BI,BO,...的”异步软通道“
执行一个get/put回调,等待结束。
27、锁集
1)由链接连接起来的记录组。
2)运行一个记录锁定了它的锁集。
- -防止由多个线程运行。
 - 类似,但技术上与PACT分开
 
常能透明地避免问题,使用"CA"标记打破锁集。
28、记录锁定 VS PACT
取决于记录地设备支持,一个记录可以运行很长时间:
-运行置位PACT并且触发驱动程序获取数据。
-一段时间后,驱动程序再次运行这个记录,并且复位PACT。
当以下情况,在锁集中的记录被锁定:
1)运行开始,在其结束时,再次,但不在两个时段之间。
2)读取一个字段。
3)写一个字段。
29、警报
1)公共字段:
- SEVR:警报严重性。NONE,MINOR, MAJOR, INVALID
 - STAT:警报状态。UDF, READ, WRITE, CALC, HIGH, STATE, ...
 
2) 二进制字段
-ZSV, OSV:对应'zero'和'one'状态的严重性。
3)模拟字段
- -LOLO, LOW, HIGH, HIHI:阈值
 - -LLSV, LSV, HSV, HHSV:相关的严重性。
 - HYST:回滞。
 
警报示例
当温度接近沸点时,产生警报:
record(ai, "$(P)TANK")
{
  field(DESC,  "Water Temperature")
  field(SCAN,  "xxx")
  field(INP,   "xxx")
  field(EGU,   "C")
  field(PREC,  "1")
  field(HIGH,  "90")
  field(HSV,   "MINOR")
  field(HIHI,  "100")
  field(HHSV,  "MAJOR")
} 

30、监视死区
模拟记录发送更新给CA客户端
-MDEL:用于大部分客户端的变化yu'zhi
-ADEL:用于存档的客户端。
31、记录小提示
1)对用户输入使用AO,模拟输出
-DRVL,DRVH可以限制值范围。
2)BO记录可以用作计时器:
-HIGH字段:当写VAL=1时,保持1 HIGH秒。
-对操作接口按钮有用:按钮西1,记录在HIGH=1后恢复为0。
3)MBBI,MBBO记录映射状态:
- 通过ZRVL/ZRST,ONVL/ONST,TWVL/TWST,...定义值和状态。
 - 可以像BI/BO一样使用:ZRVL=0, ONVL=1, ZRST<=>ZNAM, ONST<=>ONAM
 - 对于除了0,1外的值,ZRVL=0, ONVL=255
 - 从位解码限位开关状态: 
  
- ZRVL=0,ZRST=‘Moving’
 - ONVL=1,ONST='At Left limit'
 - TWVL=2,TWST='At Right Limt'
 - THVL=3,THST='Broken', THSV=MAJOR
 
 
4) 对if-then-else逻辑使用CALCOUT
- INP*和CALC如CALC记录中的INP*和CALC。
 - OOPT "On Change", "When Zero", "Transition to Zero"等。
 - 输出可以使用CALC或者一个单独的OCAL。
 
5) SEQ, FANOUT, DFANOUT可以运行一个记录列表
- 只是运行或者写值。
 - SEL可以从运行所有更改到运行选取的记录。
 
6)COMPRESS记录可以
- 在一个环形缓存中保持最新的N个值。
 - 计算数组的平均,最大或最小。
 
7)ASUB记录可以调用C代码
- INAM,SNAM:initial()和sub()的名称。
 - 很多INP*和VAL*字段。
 
8)EVENT记录可以提交数据库事件
-触发SCAN=Event并且EVNT=那个事件的记录。
32、Calcout记录详解
1)结合了calc记录和模拟输出功能。
- -INPA,INPB,..., INPL和CALC计算VAL。
 - OUT指向要写VAL的位置。
 
2)OOPT确定了OUT是否/何时输出OUT。
-”Every time“, ”On Change“, ”When None-zero“, ”Transition to Zero“, ...
3)默认,VAL被输出,但也可以配置:
- -field(OCAL, "A/B+..."):计算另外的OVAL
 - -field(DOPT, "Use OCAL"):选择输出OVAL而不是VAL到OUT。
 
4) 在一个记录内两个计算和一个"if"类型选择器。
record(calcout, “Corrector”)
{
  field(SCAN, “.1 second”)
  field(INPA, “Enable”)
  field(INPB, “Setpoint”)
  field(INPC, “Readback”)
  field(INPD, “17.54”)
  field(CALC, “A”)
  field(OOPT, “When Non-zero”)
  field(DOPT, “Use OCAL”)
  field(OCAL, “D*(B-C)”)
  field(OUT, ”SteeringMagnet PP”)
} 
CALC确定我们是否应该做任何事情,OCAL用于实际计算,OVAL值用于实际输出到OUT。
33、EPICS base之外的'synApps'记录
1) MOTOR记录
用于控制电机的整个生态系统。
2)BUSY记录可以用于支持put-回调:
- 某些设置点记录FLNKs指向设置BUSY记录=1的逻辑。
 - 当设备支持到达设置点,设置BUSY记录VAL=0
 - 在设置达到设置点后,指向设置点的CA 'put-callback'将结束。
 
34、Motor记录详解
1)这个记录有超过100个字段。
2)基本控制
- VAL:电机需要的位置。支持put-calback
 - RBV:回读值,实际电机位置
 - DONE:结束移动电机了吗?
 - HLS,LLS:电机在上限位或下限位吗?
 - STOP:停止移动。
 
3) 分辨率:
-MRES,DIR,OFF,EGU:将电机脉冲数转成了"mm"或"degrees"工程单位。
-它时步进电机或伺服电机?我们有编码器吗,如果标定它。
4)移动
- VBAS, VMAX,ACCL,HVEL,JVEL, ... 速度,加速度
 - HLM,LLM,移动范围的限制。
 - BDST,BACC,RTRY,...齿隙补偿,重试。
 
5)其它:Homing, "Jog", "tweak", status
35、时间戳
1)TIME一般设置成记录上次被运行的时间。
2)TSE=-2:例如,设备支持已经设置TIME为从硬件获取的准确触发时间。
3)TSE=1...255:设置TIME为从定时系统获取的事件1..255的上次发生。
4)TSEL:允许从另一个记录获取时间戳。
36、线性转换
模拟记录转换RVAL<=>VAL
1) LINR=NO CONVERSION,VAL=RVAL
2) LINR=SLOPE:VAL=(RVAL)*ESLO+EOFF。
这假设设备支持填充整数RVAL字段。如果设备支持已经有了一个浮点值,它放置这个值到浮点VAL字段。需要进一步转换,则使用一个CALC记录。



















