Fix ArtPollReply to advertise both input and output universes
This commit is contained in:
@@ -20,25 +20,27 @@ type Node struct {
|
|||||||
|
|
||||||
// Discovery handles ArtNet node discovery
|
// Discovery handles ArtNet node discovery
|
||||||
type Discovery struct {
|
type Discovery struct {
|
||||||
sender *Sender
|
sender *Sender
|
||||||
nodes map[string]*Node // keyed by IP string
|
nodes map[string]*Node // keyed by IP string
|
||||||
nodesMu sync.RWMutex
|
nodesMu sync.RWMutex
|
||||||
localIP [4]byte
|
localIP [4]byte
|
||||||
shortName string
|
shortName string
|
||||||
longName string
|
longName string
|
||||||
universes []Universe
|
inputUnivs []Universe // universes we transmit TO (SwIn)
|
||||||
pollTargets []*net.UDPAddr
|
outputUnivs []Universe // universes we receive FROM (SwOut)
|
||||||
done chan struct{}
|
pollTargets []*net.UDPAddr
|
||||||
|
done chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDiscovery creates a new discovery handler
|
// NewDiscovery creates a new discovery handler
|
||||||
func NewDiscovery(sender *Sender, shortName, longName string, universes []Universe, pollTargets []*net.UDPAddr) *Discovery {
|
func NewDiscovery(sender *Sender, shortName, longName string, inputUnivs, outputUnivs []Universe, pollTargets []*net.UDPAddr) *Discovery {
|
||||||
return &Discovery{
|
return &Discovery{
|
||||||
sender: sender,
|
sender: sender,
|
||||||
nodes: make(map[string]*Node),
|
nodes: make(map[string]*Node),
|
||||||
shortName: shortName,
|
shortName: shortName,
|
||||||
longName: longName,
|
longName: longName,
|
||||||
universes: universes,
|
inputUnivs: inputUnivs,
|
||||||
|
outputUnivs: outputUnivs,
|
||||||
pollTargets: pollTargets,
|
pollTargets: pollTargets,
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
}
|
}
|
||||||
@@ -185,10 +187,29 @@ func (d *Discovery) HandlePollReply(src *net.UDPAddr, pkt *PollReplyPacket) {
|
|||||||
|
|
||||||
// HandlePoll processes an incoming ArtPoll and responds
|
// HandlePoll processes an incoming ArtPoll and responds
|
||||||
func (d *Discovery) HandlePoll(src *net.UDPAddr) {
|
func (d *Discovery) HandlePoll(src *net.UDPAddr) {
|
||||||
// Respond with our info
|
d.sendPollReplies(src, d.inputUnivs, true)
|
||||||
err := d.sender.SendPollReply(src, d.localIP, d.shortName, d.longName, d.universes)
|
d.sendPollReplies(src, d.outputUnivs, false)
|
||||||
if err != nil {
|
}
|
||||||
log.Printf("[->artnet] pollreply error: dst=%s err=%v", src.IP, err)
|
|
||||||
|
func (d *Discovery) sendPollReplies(dst *net.UDPAddr, universes []Universe, isInput bool) {
|
||||||
|
groups := make(map[uint16][]Universe)
|
||||||
|
for _, u := range universes {
|
||||||
|
key := uint16(u.Net())<<8 | uint16(u.SubNet())<<4
|
||||||
|
groups[key] = append(groups[key], u)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, univs := range groups {
|
||||||
|
for i := 0; i < len(univs); i += 4 {
|
||||||
|
end := i + 4
|
||||||
|
if end > len(univs) {
|
||||||
|
end = len(univs)
|
||||||
|
}
|
||||||
|
chunk := univs[i:end]
|
||||||
|
err := d.sender.SendPollReply(dst, d.localIP, d.shortName, d.longName, chunk, isInput)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[->artnet] pollreply error: dst=%s err=%v", dst.IP, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -254,7 +254,8 @@ func BuildPollPacket() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildPollReplyPacket creates an ArtPollReply packet
|
// BuildPollReplyPacket creates an ArtPollReply packet
|
||||||
func BuildPollReplyPacket(ip [4]byte, shortName, longName string, universes []Universe) []byte {
|
// isInput: true = we transmit to network (SwIn), false = we receive from network (SwOut)
|
||||||
|
func BuildPollReplyPacket(ip [4]byte, shortName, longName string, universes []Universe, isInput bool) []byte {
|
||||||
buf := make([]byte, 239)
|
buf := make([]byte, 239)
|
||||||
|
|
||||||
copy(buf[0:8], ArtNetID[:])
|
copy(buf[0:8], ArtNetID[:])
|
||||||
@@ -263,17 +264,14 @@ func BuildPollReplyPacket(ip [4]byte, shortName, longName string, universes []Un
|
|||||||
binary.LittleEndian.PutUint16(buf[14:16], Port)
|
binary.LittleEndian.PutUint16(buf[14:16], Port)
|
||||||
binary.BigEndian.PutUint16(buf[16:18], ProtocolVersion)
|
binary.BigEndian.PutUint16(buf[16:18], ProtocolVersion)
|
||||||
|
|
||||||
// Net/Subnet from first universe if available
|
|
||||||
if len(universes) > 0 {
|
if len(universes) > 0 {
|
||||||
buf[18] = universes[0].Net()
|
buf[18] = universes[0].Net()
|
||||||
buf[19] = universes[0].SubNet()
|
buf[19] = universes[0].SubNet()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Names
|
|
||||||
copy(buf[26:44], shortName)
|
copy(buf[26:44], shortName)
|
||||||
copy(buf[44:108], longName)
|
copy(buf[44:108], longName)
|
||||||
|
|
||||||
// Ports
|
|
||||||
numPorts := len(universes)
|
numPorts := len(universes)
|
||||||
if numPorts > 4 {
|
if numPorts > 4 {
|
||||||
numPorts = 4
|
numPorts = 4
|
||||||
@@ -281,9 +279,15 @@ func BuildPollReplyPacket(ip [4]byte, shortName, longName string, universes []Un
|
|||||||
buf[173] = byte(numPorts)
|
buf[173] = byte(numPorts)
|
||||||
|
|
||||||
for i := 0; i < numPorts; i++ {
|
for i := 0; i < numPorts; i++ {
|
||||||
buf[174+i] = 0xC0 // Output, can output DMX
|
if isInput {
|
||||||
buf[182+i] = 0x80 // Data transmitted
|
buf[174+i] = 0x40 // Can input to Art-Net (we transmit)
|
||||||
buf[190+i] = universes[i].Universe()
|
buf[178+i] = 0x80 // Data received
|
||||||
|
buf[186+i] = universes[i].Universe()
|
||||||
|
} else {
|
||||||
|
buf[174+i] = 0x80 // Can output from Art-Net (we receive)
|
||||||
|
buf[182+i] = 0x80 // Data transmitted
|
||||||
|
buf[190+i] = universes[i].Universe()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[200] = 0x00 // StNode
|
buf[200] = 0x00 // StNode
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ func (s *Sender) SendPoll(addr *net.UDPAddr) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SendPollReply sends an ArtPollReply to a specific address
|
// SendPollReply sends an ArtPollReply to a specific address
|
||||||
func (s *Sender) SendPollReply(addr *net.UDPAddr, localIP [4]byte, shortName, longName string, universes []Universe) error {
|
func (s *Sender) SendPollReply(addr *net.UDPAddr, localIP [4]byte, shortName, longName string, universes []Universe, isInput bool) error {
|
||||||
pkt := BuildPollReplyPacket(localIP, shortName, longName, universes)
|
pkt := BuildPollReplyPacket(localIP, shortName, longName, universes, isInput)
|
||||||
_, err := s.conn.WriteToUDP(pkt, addr)
|
_, err := s.conn.WriteToUDP(pkt, addr)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
from = "artnet:32.0.0"
|
from = "artnet:32.0.0"
|
||||||
to = "sacn:32"
|
to = "sacn:32"
|
||||||
|
|
||||||
|
[[mapping]]
|
||||||
|
from = "artnet:34.0.0"
|
||||||
|
to = "sacn:34"
|
||||||
|
|
||||||
# lighting-1 port 1
|
# lighting-1 port 1
|
||||||
[[target]]
|
[[target]]
|
||||||
universe = "artnet:0.0.0"
|
universe = "artnet:0.0.0"
|
||||||
|
|||||||
11
main.go
11
main.go
@@ -115,11 +115,16 @@ func main() {
|
|||||||
|
|
||||||
// Create discovery
|
// Create discovery
|
||||||
destNums := engine.DestArtNetUniverses()
|
destNums := engine.DestArtNetUniverses()
|
||||||
destUniverses := make([]artnet.Universe, len(destNums))
|
inputUnivs := make([]artnet.Universe, len(destNums))
|
||||||
for i, n := range destNums {
|
for i, n := range destNums {
|
||||||
destUniverses[i] = artnet.Universe(n)
|
inputUnivs[i] = artnet.Universe(n)
|
||||||
}
|
}
|
||||||
discovery := artnet.NewDiscovery(artSender, "artmap", "ArtNet Remapping Proxy", destUniverses, pollTargetSlice)
|
srcNums := engine.SourceArtNetUniverses()
|
||||||
|
outputUnivs := make([]artnet.Universe, len(srcNums))
|
||||||
|
for i, n := range srcNums {
|
||||||
|
outputUnivs[i] = artnet.Universe(n)
|
||||||
|
}
|
||||||
|
discovery := artnet.NewDiscovery(artSender, "artmap", "artmap", inputUnivs, outputUnivs, pollTargetSlice)
|
||||||
|
|
||||||
// Create app
|
// Create app
|
||||||
app := &App{
|
app := &App{
|
||||||
|
|||||||
@@ -77,6 +77,21 @@ func (e *Engine) Remap(src config.Universe, srcData [512]byte) []Output {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SourceArtNetUniverses returns source ArtNet universe numbers (for discovery)
|
||||||
|
func (e *Engine) SourceArtNetUniverses() []uint16 {
|
||||||
|
seen := make(map[uint16]bool)
|
||||||
|
for _, m := range e.mappings {
|
||||||
|
if m.From.Protocol == config.ProtocolArtNet {
|
||||||
|
seen[m.From.Number] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result := make([]uint16, 0, len(seen))
|
||||||
|
for u := range seen {
|
||||||
|
result = append(result, u)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// DestArtNetUniverses returns destination ArtNet universe numbers (for discovery)
|
// DestArtNetUniverses returns destination ArtNet universe numbers (for discovery)
|
||||||
func (e *Engine) DestArtNetUniverses() []uint16 {
|
func (e *Engine) DestArtNetUniverses() []uint16 {
|
||||||
seen := make(map[uint16]bool)
|
seen := make(map[uint16]bool)
|
||||||
|
|||||||
Reference in New Issue
Block a user