first commit of files

This commit is contained in:
Adrian Zürcher
2025-04-18 10:30:18 +02:00
parent 5595af0add
commit f213f53547
22 changed files with 842 additions and 0 deletions

143
models/bus.go Normal file
View File

@@ -0,0 +1,143 @@
package models
import (
"fmt"
"net"
"time"
"github.com/tatsushid/go-fastping"
)
// Art-Net constants
const (
artPort = 6454
)
// Art-Net Interface
type Bus struct {
ip string `yaml:"ip"`
port int `yaml:"port"`
Devices []*Device `yaml:"devices"`
Data *DMX
}
// adds new Art-Net interface to driver port 0 = 6454 (default art-net)
func NewBus(ip string, port int) *Bus {
if port == 0 {
port = artPort
}
i := Bus{
ip: ip,
port: port,
Data: NewDMXUniverse(),
}
return &i
}
// adds new dmx device to interface
func (i *Bus) AddDevice(address uint, channels uint) (*Device, error) {
d := NewDevice(address, channels, i.Data)
i.Devices = append(i.Devices, d)
return d, nil
}
// start polling dmx data in milliseconds 0 = aprox. 44Hertz
func (i *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(i.ip),
Port: i.port,
})
if err != nil {
return err
}
defer conn.Close()
var errCount int
for {
go func() {
for {
if reached, _ := isUDPReachable(i.ip); !reached {
if errCount > 20 {
break
} else {
errCount += 1
return
}
} else {
errCount = 0
break
}
}
}()
_, err = conn.Write(NewArtNetPackage(i.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 (i *Bus) SendData() error {
// Send packet over UDP
conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
IP: net.ParseIP(i.ip),
Port: i.port,
})
if err != nil {
return err
}
defer conn.Close()
errChan := make(chan error)
go func() {
if reached, _ := isUDPReachable(i.ip); !reached {
errChan <- fmt.Errorf("device not reachable")
return
}
errChan <- nil
}()
err = <-errChan
if err != nil {
return err
}
_, err = conn.Write(NewArtNetPackage(i.Data))
return err
}
const (
protocolICMP = 1
)
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
return
}
p.OnIdle = func() {}
err = p.Run()
return
}

25
models/device.go Normal file
View File

@@ -0,0 +1,25 @@
package models
import "fmt"
type Device struct {
startAddress uint
length uint
channels *DMX
}
func NewDevice(startAddress uint, channels uint, dmx *DMX) *Device {
return &Device{
startAddress: startAddress,
length: channels,
channels: dmx,
}
}
func (d *Device) SetChannelValue(channel uint, value uint8) error {
if d.length == channel {
return fmt.Errorf("channel out of range %d", channel)
}
d.channels.SetValue(d.startAddress+channel, value)
return nil
}

12
models/dmx.go Normal file
View File

@@ -0,0 +1,12 @@
package models
type DMX []byte
func NewDMXUniverse() *DMX {
dmx := make(DMX, 512)
return &dmx
}
func (d *DMX) SetValue(channel uint, value uint8) {
(*d)[channel] = value
}

5
models/get.go Normal file
View File

@@ -0,0 +1,5 @@
package models
type Get struct {
Bus uint `json:"bus"`
}

22
models/jsonData.go Normal file
View File

@@ -0,0 +1,22 @@
package models
type JsonData struct {
Set *[]Set `json:"set,omitempty"`
}
func NewRequest() *JsonData {
return &JsonData{}
}
func (r *JsonData) AddSet(bus, address uint, value uint8) {
if r.Set == nil {
r.Set = &[]Set{}
}
*r.Set = append(*r.Set, Set{
Bus: bus,
Address: address,
Value: value,
})
}

29
models/package.go Normal file
View File

@@ -0,0 +1,29 @@
package models
import (
"bytes"
"encoding/binary"
)
// Art-Net constants
const (
opCode = 0x5000 // OpDmx (low byte first)
protocolID = "Art-Net\x00"
)
type Package []byte
func NewArtNetPackage(data *DMX) Package {
// Build ArtDMX packet
packet := &bytes.Buffer{}
packet.WriteString(protocolID) // Art-Net ID
binary.Write(packet, binary.LittleEndian, uint16(opCode)) // OpCode (OpDmx)
packet.WriteByte(0x00) // Protocol Version High
packet.WriteByte(14) // Protocol Version Low (14 for Art-Net 4)
packet.WriteByte(0x00) // Sequence
packet.WriteByte(0x00) // Physical
binary.Write(packet, binary.BigEndian, uint16(0)) // Universe (net:subuni, usually 0)
binary.Write(packet, binary.BigEndian, uint16(len(*data))) // Length
packet.Write(*data)
return packet.Bytes()
}

7
models/set.go Normal file
View File

@@ -0,0 +1,7 @@
package models
type Set struct {
Bus uint `json:"bus"`
Address uint `json:"address"`
Value uint8 `json:"value"`
}