id: variable_function_probe
label: Function Probe
flags: [ show_id, python ]

parameters:
-   id: block_id
    label: Block ID
    dtype: name
    default: my_block_0
-   id: function_name
    label: Function Name
    dtype: name
    default: get_number
-   id: function_args
    label: Function Args
    dtype: raw
    hide: ${ ('none' if function_args else 'part') }
-   id: poll_rate
    label: Poll Rate (Hz)
    dtype: real
    default: '10'
-   id: value
    label: Initial Value
    dtype: raw
    default: '0'
    hide: part
value: ${ value }

templates:
    imports: |-
        import time
        import threading
    var_make: self.${id} = ${id} = ${value}
    make: |+
        def _${id}_probe():
          self.flowgraph_started.wait()
          while True:
            <% obj = 'self' + ('.' + block_id if block_id else '') %>
            val = ${obj}.${function_name}(${function_args})
            try:
              try:
                self.doc.add_next_tick_callback(functools.partial(self.set_${id},val))
              except AttributeError:
                self.set_${id}(val)
            except AttributeError:
              pass
            time.sleep(1.0 / (${poll_rate}))
        _${id}_thread = threading.Thread(target=_${id}_probe)
        _${id}_thread.daemon = True
        _${id}_thread.start()
    callbacks:
    - self.set_${id}(${value})

documentation: |-
    Periodically probe a function and set its value to this variable.

    Set the values for block ID, function name, and function args appropriately: Block ID should be the ID of another block in this flow graph. An empty Block ID references the flow graph itself. Function name should be the name of a class method on that block. Function args are the parameters passed into that function. For a function with no arguments, leave function args blank. When passing a string for the function arguments, quote the string literal: '"arg"'.

    The values will used literally, and generated into the following form:
        self.block_id.function_name(function_args)
    or, if the Block ID is empty,
        self.function_name(function_args)

    To poll a stream for a level, use this with the probe signal block.

file_format: 1
