C++ 节点 API
C++ 节点 API
本文档描述 C++ 节点中可能会用到的各种数据类型和操作函数。
基本类型
Number
表示一个普通数值。该类型的底层实现为符合 IEEE 754 的 32 位浮点数。
TimeMs
以毫秒表示的时间数值。底层实现为一个 32 位无符号整型数。
XString
表示一个字符串。底层实现为 List<char>
,因此也可以使用 List<char>
的对应方法和函数进行操作。
node {}
代码块
每一个 C++ 节点的代码都被包围在 node
块中。每一个 node
块都会被转换为一个 C++ 语言中的结构体(struct
)。开发者可以往这个结构体添加属性和方法。
meta {}
使用 meta {}
代码块来封装一些需要被放到一个结构体中的代码。
Context
每一个节点实例的上下文。同一个节点类型的不同实例会对应不同的上下文。每一个 C++ 节点都带这个参数。我们在可视化开发界面看到的输入输出端口对应的参数都会通过 Context
传递。
typeof_$$$
对应到每一个端口的类型。在实现中经常需要使用该方式来进行必要的类型转换。
端口描述
系统会节点的每一个端口都自动生成对应的描述。这种描述不应该被当做类型来实例化变化,而只应该作为模板参数来获取输入输出参数。
以下提到的 $$$
都会在实际中被替换为端口标签,比如 input_IN1
、output_FOO
等。
input_$$$
如果一个节点拥有唯一一个没有设置标签的输入端口,那么这个端口会被自动命名为 input_IN
。而如果有多个输入端口,则会被命名为 input_IN1
、input_IN2
、input_IN3
等等。
output_$$$
每一个 C++ 节点支持不超过 7 个输出端口。
输出端口的命名方式跟输入端口类似,即只有一个输出端口时名称为 output_OUT
,多个输出时会被依次命名为 output_OUT1
、output_OUT2
等,最高到 output_OUT7
。
端口常量
通常用于静态断言以确认代码的正确性。
constant_input_$$$
常量输入。
constant_output_$$$
节点的常量输出。
通常为手动定义为如下形态:
static constexpr typeof_OUT constant_output_OUT = $$$;
代码里的 $$$
需要被替换为一个有效的输出值。
如果需要使用到一个结构体中包含的常量,可以定义为如下形态:
static constexpr typeof_OUT constant_output_OUT = typeof_DEV::port;
nodespace {}
代码块
这个代码块用于放置一些不在 struct Node {}
内但又属于节点的代码,因此这些代码只可能被这个节点所访问。
此位置比较适合放置一些 PROGMEM
常量。使用案例可以参考 heart-16x16-rgba
节点。
节点函数
void evaluate(Context ctx)
这是所有 C++ 节点的入口函数。每一个 C++ 节点都需要实现该函数。该函数通常在这类情况下被调用:输入参数变化,超时等等。
ValueT getValue<input_$$$ | output_$$$>(Context ctx)
从输入和输出端口获取相应的最新值。返回的数值类型 ValueT
依赖于该端口的数据类型,可能会为 Number
、bool
等等。
需要注意的是,pulse 类型是没有值的,因此没有必要针对 pulse 端口调用此取值函数。如果要知道是否触发了 pulse,应该使用 isInputDirty
方法。
每一个节点掌握输出值的生命周期。因此节点的输出值即可以作为下游节点的输入,也同时可以作为本节点的状态存储。所以,我们在必要时可以使用 getValue<output_$$$>(ctx)
来获取本节点的上一次输出值。
void emitValue<output_$$$>(Context ctx, ValueT value)
设置本节点的输出值。同理,参数类型 ValueT
取决于对应输出端口的数据类型。
对于 emitValue
的调用会导致该节点的下游节点都重新执行求值过程(调用 evaluate()
函数)。需要注意的是,即使本次的输出跟上次输出的值相同,下游节点的求值过程同样会被触发。如果可以的话,建议增加一个检查环节以避免输出同样的值。
如果要触发一个脉冲信号(pulse),请将 value
赋值为 true
。
bool isInputDirty<input_$$$>(Context ctx)
判断在当前执行周期中某个输入端口是否获取到一个不同的值。是的话返回 true
。
bool isSettingUp()
只在求值过程第一次被调用时这个函数会返回 true
。比较适合在当需要执行一些设备启动时才需要执行的代码时,作为检查手段。
TimeMs transactionTime()
返回自程序启动以来过去的时间长度,单位为毫秒。该函数的返回值在任一求值过程中会保持不变。
void setTimeout(Context ctx, TimeMs timeout)
设置在多长时间后触发一个强制的重新求值过程。
每个节点在同一时刻只能存在一个求值过程。因此后一个求值过程的触发会导致前一个过程被中止。如果我们希望这个新的求值过程紧跟于当前过程之后(而不是中止当前求值过程),那么建议使用 setImmediate
函数。
void clearTimeout(Context ctx)
清理已计划的求值过程。
bool isTimeout(Context ctx)
如果当前求值过程已经超时,则返回 true
。从下一次求值过程开始会返回 false
。
void setImmediate()
强制在本次求值之后马上重启求值。参见 setTimeout
。
void raiseError<output_$$$>(Context ctx)
往输出端口触发一个错误。对于值类型的端口(非 pulse),这个错误会被一直存储直到输出正常值。而对于 pulse 类型,输出的错误会在下一次求值前就被清理。
bool getError<input_$$$>(Context ctx)
如果该输入端口的上游节点输出了错误,则返回 true
,否则返回 false
。
列表
系统里的列表对象既不是链表也不是向量(vector),而只是对现有数据的一种视图。列表只是创建一个迭代子 Iterator<T>
来遍历整个列表。
使用示例:
Number sum(List<Number> numbers) {
Number result = 0;
for (Iterator<Number> it = numbers.iterate(); it; ++it)
result += *it;
return result;
}
List<T>
一个类型为 T
的列表。
List<T>
是对 ListView<T>
的一种浅封装。内部实现只是一个指向真实列表数据的指针,因此传值的成本很低。
List<T>::List()
构建一个新的空列表。
List<T>::List(const ListView<T>* view)
将一个 ListView<T>
对象封装为列表对象。
需要注意的是,开发者需要保证 view
对象的生命周期不早于本列表结束,否则会导致程序崩溃。
Iterator<T> List<T>::iterator() const
创建一个新的迭代器,指向第一个元素。
Iterator<T>
迭代器类型。迭代器可以指向一个合格的元素或者指向边界之外,后者用于判断迭代是否结束。
Iterator<T>::operator bool() const
如果指向一个有效元素则返回 true
。
T Iterator<T>::operator*() const
返回指向的元素。
bool Iterator<T>::value(T* out) const
检测指向的有效性,同时返回指向的元素。
Iterator<T>::operator++()
将当前迭代指向下一个元素。
列表函数
size_t length(List<T> xs)
返回列表长度。这会导致遍历所有元素,因此调用成本较高。
size_t dump(List<T> xs, T* outBuff)
将列表 xs
中的所有元素全部拷贝到 outBuff
。使用者需要自行保证缓存的大小足以放下所有的元素,否则会导致程序崩溃。
TR foldl(List<T> xs, TR (*func)(TR, T), TR acc)
对列表使用函数 func
进行 reduce 操作,且以 acc
为初始的累加器。
类型转换
size_t formatNumber(Number value, int prec, char* str)
将一个数值转换为字符串。功能类似于标准库里的 dtostrf
/ sprintf
/ to_string
,不过性能足够在单片机上运行。
返回转换的字符串长度,未包含结束符。
示例:
value | prec | str |
---|---|---|
-0.321 | 0 | "0" |
-0.321 | 2 | "-0.32" |
-0.64 | 0 | "-1" |
123.456 | 0 | "123" |
123.456 | 2 | "123.46" |
NaN | any | "NaN" |
Inf | any | "Inf" |
-Inf | any | "-Inf" |
99000000000 | any | "OVF" |
-99000000000 | any | "-OVF" |