140 lines
2.3 KiB
Go
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
|
|
}
|