---
#CPU: AS1           # 指示属于哪一个CPU
#feature: modbusTCP # 指示本配置为生成 modbusTCP 文档
#feature: MT        # MT 等同于 modbusTCP

name: AS1-modbusTCP # 相当于上面2条被注释的指令

description: |
  使用 modbusTCP 通信，必须在step7工程中加入以下库
  * FB63 TSEND
  * FB64 TRCV
  * FB65 TCON
  * FB66 TDISCON

symbols:
# 系统已有3个内置符号，其内容自动生成：
# - [MT_Poll, FB344]      modbusTCP通信主处理函数
# - [MT_Loop, FC344]      主循环调用FC，将这个加入OB1中
# - [MT_polls_DB, DB881]  用于保存轮询命令数据
# 可以在对上述内置符号的地址进行更改，只要重新定义就可以了，注意保持名称一致
- [MT_polls_DB, DB901] # 修改内置DB块 MT_polls_DB 的地址
- [FB_write, FB812]    # 处理流量计1的写入操作
- [FB_IO, FB813]       # 处理远程IO的写入操作

# 本配置用的 JS_Flow 已在 CPU 文档中定义

list : # modbus TCP 连接列表

# 第1个连接
- comment: 192.168.10.10:502 智能流量计 # 本连接的注释，可省略

  # 十进制连接号，自行指定，但不可重复。省略时，程序会自动生成一个从1开始且不重复的ID。
  # 类型: 正整数
  ID: 1

  # 轮询间隔时间初始值，可省略，默认200
  # 类型: null | 整数字面量 | TIME字面量
  # 该设置用于过滤过程值的突变，当为整数值时代表单位毫秒
  $interval_time: 1000

  # 运行期间指定轮询间隔时间，可省略
  # 类型: null | S7表达式 | S7符号定义 | S7符号引用
  # 值类型: 整数 (注意不能是TIME字面量)
  interval_time: [flow_interval, md200]

  # 背景块，必填项。注意每个连接的背景块必须不同。
  # 可以不必填写type，会自动指定为 MT_Poll
  # 类型: S7符号定义 | S7符号引用
  # 注意，连接 DB 的名称必须是一个标识符，因为要在轮询块中用相同名称作字段。
  # 即，必须是下划线或字母开头，后面跟字母、数字或下划线。
  # 例如：conn_flow 是合法的，conn-flow 不合法
  DB: [conn_flow, DB891]

  # modbusTCP 远程IP 必填
  # 类型: 字符串 | 整数数组
  host: 192.168.10.10 # 也可以用数组 `[192, 168, 10, 10]`

  # modbusTCP 远程端口，必填，注意host:port组合不得重复，否则报错
  # 类型: 正整数
  port: 502

  # 用于通信的设备号，见 https://support.industry.siemens.com/cs/document/51339682/使用fb65-tcon-建立以太网的开放式用户通信连接时，如何参数化-loc
  # 本参数优先级最高，会忽略 local_device rack XSlot 3个参数
  # 建议不要填写本参数，采用直观的 local_device rack XSlot 参数
  #local_device_id: B#16#02

  # 由于local_device_id不直观，建议用下面三个参数进行直观配置，同时程序自动检验
  # 如果已经设置了local_device_id，则忽略下方参数。
  #   device  设备名称            见 CPU 文档中的定义
  #           类型: 字符串        如果在CPU文档已设置了device，可以省略本参数
  #   rack    机架号              可以在Step7硬件配置里看到，通常为0或1，除了冗余机型外，大多情况下本参数可省略
  #           类型: 正整数        仅 CPU412-5H_PN/DP CPU414-5H_PN/DP CPU416-5H_PN/DP CPU417-5H_PN/DP CPU410-5H 需要设置本参数值
  #   XSlot   通信接号扩展插槽号   可以在Step7硬件配置里的通信接口名称中看到，比如"X2"则XSlot值就是2
  #           类型: 正整数         仅 CPU319-3 PN/DP CPU317-2 PN/DP CPU410-5H 需要设置本参数值
  device: ~                       # 设备名称 省略时采用CPU文档中的定义，如果CPU文档也无定义，则local_device_id会默认为B#16#02
  rack: 1                         # 机架号  部分CPU可省略
  XSlot: 8                        # 插槽号  非多IF可省略


  polls:  # 该连接下的轮询定义，至少要有一个查询

  # 为了在SCL中对查询进行控制，可以使用符号引用，轮询块具体一个查询的引用为：
  #   MT_polls_DB.{conn_DB_name}[{序号}].{控制项}
  # 以下方查询0为例，自动产生以下字段用于控制轮询：
  # - MT_polls_DB.conn_flow[0].enable         允许该查询，默认为 true
  # - MT_polls_DB.conn_flow[0].timeout        是否超时，只读
  # - MT_polls_DB.conn_flow[0].periodicity      指示自动周期性发送请求，只读，默认为true
  #                                            以 interval_time 为同期触发
  # - MT_polls_DB.conn_flow[0].custom_trigger 自定义发送请求，在上升沿发送查询
  # - MT_polls_DB.conn_flow[0].try_times      最多询问失败间隔次数
  # - MT_polls_DB.conn_flow[0].send_DB        发送块的块号，默认为 MT_polls_DB 的块号
  # - MT_polls_DB.conn_flow[0].send_start     发送块的起始地址
  # - MT_polls_DB.conn_flow[0].recv_DB        接收块的块号，必须由用户指定
  # - MT_polls_DB.conn_flow[0].recv_start     接收块的起始地址

  # 注意：以下在 poll 中的配置项为发送 PDU 中的数据
  #   - unit_ID
  #   - func_code
  #   - address
  #   - data | length
  #   - count
  #   - extra_data
  # 并不能通过 MT_polls_DB.conn_flow[0] 去引用发送 PDU 数据本身
  # 如果想在运行中动态改变发送数据，请使用外部发送块，即指定的 send_DB

  # unit_ID func_code address data|length 配置项允许16进制字符串，写法为 `0x` 开头

  - # 查询0 可通过 MT_polls_DB.conn_flow[0] 访问控制项，见上方说明
    comment: 读取过程值                # 本查询的注释，可省略。 类型: 字符串
    unit_ID: 1                        # 设备号，即RTU从站地址。 类型: 正整数
    func_code: 4                      # modbus 功能号。 类型: 正整数
    address: 0                        # 查询起始地址。 类型: 正整数
    length: 28                        # 查询长度。 类型: 正整数
    recv_DB: [Flow01, DB802, JS_flow] # 接收块。 类型: S7符号定义 | S7符号引用
    recv_start: 0                     # 接收开始位置。 类型: 正整数

    # 本 pool 的额外处理代码
    # 可以自由书写 SCL
    # 当内容仅仅是 FB 时，转换程序会自动对发送块和接收块进行背景调用。
    extra_code: FB                    # 将自动产生 `JS_flow.Flow01();`

  - # 查询1 本查询对应的地址为 MT_polls_DB.conn_flow[1]
    comment: 循环写1个参数值

    # enable 属性指示是否使能该查询，默认为 true
    # 为 true 时，恢复正常轮询，轮询时机或频率由后面 periodicity  或 custom_trigger 决定
    # 配置项 enable 指示其初始值，运行时如需更改，外部代码直接操作 MT_polls_DB.conn_flow[1].enable
    enable: false                     # 初始禁用该查询

    unit_ID: 0x6                      # 16进制数形式 6 号功能码写寄存器
    func_code: 0x6                    # 16进制数形式
    address: 0x10                     # 16进制数形式
    data: 0x28                        # data 配置项和 length 配置项等效，用此名称是为了语义。
    recv_DB: [Flow01_paras, DB+, FB_write]
    recv_start: 0

    # 轮询计次，可省略，默认10次
    # 类型: null | 正整数字面量
    # 用于设置未返回数据的计次，单位次，超过该次数标记该设备数据无效
    # 1次时间即轮询间隔时间
    # try_times 配置项指示初始值
    try_times: 20

    extra_code: FB

  - # 查询2 本查询对应的地址为 MT_polls_DB.conn_flow[2]
    comment: 非循环写多个参数值

    # 为了避免循环写入操作，可以用 custom_trigger 控制发送请求
    # 使用 custom_trigger 配置项与 enable 是不同的，它在查询成功一次后自动复位
    # 外部代码通过对其置位来实现定制本查询的发送时机。
    # custom_trigger 配置项指示初值值：
    #    MT_polls_DB.conn_flow[2].custom_trigger := 初值值
    # 只要设置了 $custom_trigger ，无论初始值是 true 还是 false，
    # 转换程序都会将 periodicity  初始值设为false
    #    MT_polls_DB.conn_flow[2].periodicity  := false
    custom_trigger: false             # 设置 custom_trigger 初值值为 false

    unit_ID: 1
    func_code: 16                     # 16 号功能码写寄存器
    address: 17
    length: 2                         # 写入个数，单位依赖于功能码，这里是2个字，写一个浮点数
    recv_DB: Flow01_paras             # 同一接收块不可再使用 `extra_code: FB`
    recv_start: 8
    # 以下1项仅用于 15 16 功能码，为 PDU 中的数据
    # 使用外部发送块时，也不需要这一项
    # 转换程序会自动生成 MBAP_length 和 extra_data_length
    # 下面示例中，自动计算出的 MBAP_length:17 extra_data_length:4
    extra_data: 42 FF 33 33           # 15 16 功能码的额外数据，使用空格分隔的16进制字符串

  - # 查询3 本查询对应的地址为 MT_polls_DB.conn_flow[3]
    comment: 非循环写布尔值，用于控制

    custom_trigger: false
    unit_ID: 1
    func_code: 15
    address: 66
    length: 20                        # 写入个数，单位依赖于功能码，这里是比特
    recv_DB: Flow01_paras             # 同一接收块不可再使用 `extra_code: FB`
    recv_start: 7
    extra_data: 3A 5B 80              # 15 16 功能码的额外数据，使用空格分隔的16进制字符串

  - # 查询4 本查询对应的地址为 MT_polls_DB.conn_flow[4]
    comment: 通过 modbutTCP 的远程 IO
    # 15 16 功能码查询的 PDU 是变长的，必须指定整个 PDU 的长度
    # 同时为了能动态改变写入数据的个数和数值，这里指定使用外部发送块
    custom_trigger: true              # 指示自定义发送请求，初始值为 true
    send_DB: [remote_IO, DB+, FB_IO]  # 指定外部发送块，这样不必指定具体的发送数据了
    send_start: 26                    # 发送开始位置
    recv_DB: remote_IO                # 接收块
    recv_start: 0                     # 接收开始位置
    # extra_code 用于额外的代码，比如用于控制发送数据
    # 当有 extra_code 时，不再自动调用 "FB_IO"."remote_IO"();
    extra_code: |- # 本 pool 的额外处理代码
      // 远程 IO 的控制
      "FB_IO"."remote_IO"(enable := "reading");

# 更多的连接设置，可以依照上方书写，注意对齐，以对齐表示层级

# 用户自写SCL代码，放在循环的开始和结束处。
loop_begin: |-
  // 这里的代码将在 MT_Loop 循环开始时执行

loop_end: |-
  // 这里的代码将在 MT_Loop 循环结束时执行

options : # 选项，非必需，无需要时可以全部删除或注释掉。
  # output_file : 'example.scl'

...
