Files
tecamino-driver-artNet/models/bus.go
2025-04-21 09:56:30 +02:00

140 lines
2.3 KiB
Go

package models
import (
"fmt"
"log"
"net"
"time"
"github.com/tatsushid/go-fastping"
)
// Art-Net constants
const (
artPort = 6454
)
// Art-Net Interface
type Bus struct {
Name string `yaml:"name" json:"name"`
Ip string `yaml:"ip" json:"ip"`
Port *int `yaml:"port" json:"port,omitempty"`
Data *DMX `yaml:"-" json:"-"`
}
// adds new Art-Net interface to driver port 0 = 6454 (default art-net)
func NewBus(name, ip string, port int) *Bus {
if port == 0 {
port = artPort
}
i := Bus{
Name: name,
Ip: ip,
Port: &port,
Data: NewDMXUniverse(),
}
return &i
}
// get bus port from pointer
func (b *Bus) GetPort() int {
if b.Port == nil {
return artPort
}
return *b.Port
}
// start polling dmx data in milliseconds 0 = aprox. 44Hertz
func (b *Bus) Poll(interval time.Duration) error {
if interval == 0 {
interval = 23
}
// Send packet over UDP
conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: net.ParseIP(b.Ip),
Port: *b.Port,
})
if err != nil {
return err
}
defer conn.Close()
var errCount int
for {
go func() {
for {
if reached, _ := isUDPReachable(b.Ip); !reached {
if errCount > 20 {
break
} else {
errCount += 1
return
}
} else {
errCount = 0
break
}
}
}()
_, err = conn.Write(NewArtNetPackage(b.Data))
if err != nil {
return err
}
if errCount > 5 {
return fmt.Errorf("device not reachable")
}
time.Sleep(23 * time.Millisecond)
}
}
// start polling dmx data in milliseconds 0 = aprox. 44Hertz
func (b *Bus) SendData() error {
// Send packet over UDP
conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: net.ParseIP(b.Ip),
Port: *b.Port,
})
if err != nil {
return err
}
defer conn.Close()
go func() {
if reached, err := isUDPReachable(b.Ip); err != nil {
log.Println(err)
return
} else if !reached {
log.Println("device not reachable")
return
}
}()
_, err = conn.Write(NewArtNetPackage(b.Data))
return err
}
func isUDPReachable(ip string) (recieved bool, err error) {
p := fastping.NewPinger()
ra, err := net.ResolveIPAddr("ip4:icmp", ip)
if err != nil {
return
}
p.AddIPAddr(ra)
p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) {
recieved = true
}
p.OnIdle = func() {}
err = p.Run()
return
}