Execute evaluates the value expression and writes it through the linked channel. Digital coerces to bool; PWM expects a duty in [0,1]; DAC expects millivolts.
(_ context.Context, scope *engine.Scope)
| 64 | } |
| 65 | |
| 66 | // NewWritePinDAC builds a WritePin bound to a DAC output channel. |
| 67 | func NewWritePinDAC(id string, value *workflowapi.Expression, toolDescription string, dac *channel.DAC) *WritePin { |
| 68 | return &WritePin{ |
| 69 | LinearNode: engine.NewLinearNode(id), |
| 70 | value: value, |
| 71 | toolDescription: toolDescription, |
| 72 | dac: dac, |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | // writePinArgs is the tool-call payload. Value is `any` because the JSON type |
| 77 | // the channel accepts is only known per instance — Tools() constrains it in the |
| 78 | // schema and writePin coerces it. |
| 79 | type writePinArgs struct { |
| 80 | Value any `json:"value"` |
| 81 | } |
| 82 | |
| 83 | // Execute evaluates the value expression and writes it through the linked |
| 84 | // channel. The cast to the channel's type happens here so the author-supplied |
| 85 | // expression keeps its lenient conversion; writePin's Coerce is then a no-op. |
| 86 | func (w *WritePin) Execute(ctx context.Context, scope *engine.Scope) (string, error) { |
| 87 | if w.value == nil { |
| 88 | return "", fmt.Errorf("writePin %s: no value expression", w.ID()) |
| 89 | } |
| 90 | v, err := expr.Eval(*w.value, scope) |
| 91 | if err != nil { |