1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

add Golang example which uses libvillas C-API

This commit is contained in:
Steffen Vogel 2022-03-06 21:13:28 -05:00
parent b207bbf673
commit 82fe40ee1c
7 changed files with 350 additions and 0 deletions

81
go/cmd/test.go Normal file
View file

@ -0,0 +1,81 @@
package main
import (
"fmt"
"log"
"time"
node "git.rwth-aachen.de/acs/public/villas/node/go/pkg"
"git.rwth-aachen.de/acs/public/villas/node/go/pkg/config"
"github.com/google/uuid"
)
func main() {
cfg := &config.LoopbackNode{
Node: config.Node{
Name: "lo1",
Type: "loopback",
},
In: config.NodeLoopbackIn{
Hooks: []interface{}{
&config.PrintHook{
Hook: config.Hook{
Type: "print",
},
},
},
Signals: []config.Signal{
{
Name: "sig1",
},
{
Name: "sig2",
}, {
Name: "sig3",
},
},
},
}
n, err := node.NewNode(cfg, uuid.New())
if err != nil {
log.Fatalf("Failed to create node: %s", err)
}
defer n.Close()
if err := n.Check(); err != nil {
log.Fatalf("Failed to check node: %s", err)
}
if err := n.Prepare(); err != nil {
log.Fatalf("Failed to prepare node: %s", err)
}
if err := n.Start(); err != nil {
log.Fatalf("Failed to start node: %s", err)
}
defer n.Stop()
fmt.Printf("%s\n", n.NameFull())
smps_send := []node.Sample{
{
Sequence: 1234,
TimestampOrigin: time.Now(),
Data: []float64{1.1, 2.2, 3.3},
},
{
Sequence: 1235,
TimestampOrigin: time.Now(),
Data: []float64{4.4, 5.5, 6.6},
},
}
fmt.Printf("Sent: %+#v\n", smps_send)
cnt_written := n.Write(smps_send)
smps_received := n.Read(cnt_written)
fmt.Printf("Received: %+#v\n", smps_received)
}

5
go/go.mod Normal file
View file

@ -0,0 +1,5 @@
module git.rwth-aachen.de/acs/public/villas/node/go
go 1.17
require github.com/google/uuid v1.3.0

2
go/go.sum Normal file
View file

@ -0,0 +1,2 @@
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

10
go/pkg/config/hook.go Normal file
View file

@ -0,0 +1,10 @@
package config
type Hook struct {
Type string `json:"type"`
Priority int `json:"priority,omitempty"`
}
type PrintHook struct {
Hook
}

22
go/pkg/config/node.go Normal file
View file

@ -0,0 +1,22 @@
package config
type Node struct {
Name string `json:"name"`
Type string `json:"type"`
}
type NodeDir struct {
}
type NodeLoopbackIn struct {
NodeDir
Signals []Signal `json:"signals"`
Hooks []interface{} `json:"hooks"`
}
type LoopbackNode struct {
Node
In NodeLoopbackIn `json:"in"`
}

15
go/pkg/config/signal.go Normal file
View file

@ -0,0 +1,15 @@
package config
const (
SignalTypeFloat = "float"
SignalTypeInteger = "integer"
SignalTypeBoolean = "boolean"
SignalTypeComplex = "complex"
)
type Signal struct {
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Unit string `json:"unit,omitempty"`
Init float64 `json:"init,omitempty"`
}

215
go/pkg/node.go Normal file
View file

@ -0,0 +1,215 @@
package pkg
// #cgo LDFLAGS: -lvillas
// #cgo CFLAGS: -DCGO
// #include <villas/node.h>
import "C"
import (
"encoding/json"
"fmt"
"log"
"time"
"unsafe"
"github.com/google/uuid"
)
const MAX_SIGNALS = 64
const NUM_HUGEPAGES = 100
func ret2err(ret C.int) error {
if ret == 0 {
return nil
} else {
return fmt.Errorf("ret=%d", ret)
}
}
type Sample struct {
TimestampOrigin time.Time
TimestampReceived time.Time
Sequence uint
Flags int
Data []float64
}
func (s *Sample) ToC() *C.vsample {
return C.sample_pack(
C.uint(s.Sequence),
&C.struct_timespec{
tv_sec: C.long(s.TimestampOrigin.Unix()),
tv_nsec: C.long(s.TimestampOrigin.Nanosecond()),
},
&C.struct_timespec{
tv_sec: C.long(s.TimestampReceived.Unix()),
tv_nsec: C.long(s.TimestampReceived.Nanosecond()),
},
C.uint(len(s.Data)),
(*C.double)(unsafe.Pointer(&s.Data[0])),
)
}
func (s *Sample) FromC(c *C.vsample) {
var tsOrigin C.struct_timespec
var tsReceived C.struct_timespec
len := C.sample_length(c)
s.Data = make([]float64, uint(len))
C.sample_unpack(c,
(*C.uint)(unsafe.Pointer(&s.Sequence)),
&tsOrigin,
&tsReceived,
(*C.int)(unsafe.Pointer(&s.Flags)),
&len,
(*C.double)(unsafe.Pointer(&s.Data[0])),
)
s.TimestampOrigin = time.Unix(int64(tsOrigin.tv_sec), int64(tsOrigin.tv_nsec))
s.TimestampReceived = time.Unix(int64(tsReceived.tv_sec), int64(tsReceived.tv_nsec))
}
type Node struct {
inst *C.vnode
}
func IsValidNodeNname(name string) bool {
return bool(C.node_is_valid_name(C.CString(name)))
}
func NewNode(cfg interface{}, sn_uuid uuid.UUID) (*Node, error) {
if js, err := json.Marshal(cfg); err != nil {
return nil, fmt.Errorf("failed to serialize config: %w", err)
} else {
log.Printf("Config = %s\n", js)
n := C.node_new(C.CString(string(js)), C.CString(sn_uuid.String()))
return &Node{n}, nil
}
}
func (n *Node) Prepare() error {
return ret2err(C.node_prepare(n.inst))
}
func (n *Node) Check() error {
return ret2err(C.node_check(n.inst))
}
func (n *Node) Start() error {
return ret2err(C.node_start(n.inst))
}
func (n *Node) Stop() error {
return ret2err(C.node_stop(n.inst))
}
func (n *Node) Pause() error {
return ret2err(C.node_pause(n.inst))
}
func (n *Node) Resume() error {
return ret2err(C.node_resume(n.inst))
}
func (n *Node) Restart() error {
return ret2err(C.node_restart(n.inst))
}
func (n *Node) Close() error {
return ret2err(C.node_destroy(n.inst))
}
func (n *Node) Reverse() error {
return ret2err(C.node_reverse(n.inst))
}
func (n *Node) Read(cnt int) []Sample {
var csmps = make([]*C.vsample, cnt)
for i := 0; i < cnt; i++ {
csmps[i] = C.sample_alloc(MAX_SIGNALS)
}
read := int(C.node_read(n.inst, (**C.vsample)(unsafe.Pointer(&csmps[0])), C.uint(cnt)))
var smps = make([]Sample, read)
for i := 0; i < read; i++ {
smps[i].FromC(csmps[i])
C.sample_decref(csmps[i])
}
return smps
}
func (n *Node) Write(smps []Sample) int {
cnt := len(smps)
var csmps = make([]*C.vsample, cnt)
for i := 0; i < cnt; i++ {
csmps[i] = smps[i].ToC()
}
return int(C.node_write(n.inst, (**C.vsample)(unsafe.Pointer(&csmps[0])), C.uint(cnt)))
}
func (n *Node) PollFDs() []int {
var cfds [16]C.int
cnt := int(C.node_poll_fds(n.inst, (*C.int)(unsafe.Pointer(&cfds))))
var fds = make([]int, cnt)
for i := 0; i < cnt; i++ {
fds[i] = int(cfds[i])
}
return fds
}
func (n *Node) NetemFDs() []int {
var cfds [16]C.int
cnt := int(C.node_netem_fds(n.inst, (*C.int)(unsafe.Pointer(&cfds))))
var fds = make([]int, cnt)
for i := 0; i < cnt; i++ {
fds[i] = int(cfds[i])
}
return fds
}
func (n *Node) IsEnabled() bool {
return bool(C.node_is_enabled(n.inst))
}
func (n *Node) Name() string {
return C.GoString(C.node_name(n.inst))
}
func (n *Node) NameShort() string {
return C.GoString(C.node_name_short(n.inst))
}
func (n *Node) NameFull() string {
return C.GoString(C.node_name_full(n.inst))
}
func (n *Node) Details() string {
return C.GoString(C.node_details(n.inst))
}
func (n *Node) InputSignalsMaxCount() uint {
return uint(C.node_input_signals_max_cnt(n.inst))
}
func (n *Node) OutputSignalsMaxCount() uint {
return uint(C.node_output_signals_max_cnt(n.inst))
}
func (n *Node) ToJSON() string {
json_str := C.node_to_json_str(n.inst)
return C.GoString(json_str)
}
func init() {
C.memory_init(NUM_HUGEPAGES)
}