109 lines
2.4 KiB
Go
109 lines
2.4 KiB
Go
package remap
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/gopatchy/artmap/config"
|
|
)
|
|
|
|
// Output represents a remapped DMX output
|
|
type Output struct {
|
|
Universe config.Universe
|
|
Data [512]byte
|
|
}
|
|
|
|
// Engine handles DMX channel remapping
|
|
type Engine struct {
|
|
mappings []config.NormalizedMapping
|
|
bySource map[config.Universe][]config.NormalizedMapping
|
|
state map[config.Universe]*[512]byte
|
|
stateMu sync.Mutex
|
|
}
|
|
|
|
// NewEngine creates a new remapping engine
|
|
func NewEngine(mappings []config.NormalizedMapping) *Engine {
|
|
bySource := make(map[config.Universe][]config.NormalizedMapping)
|
|
for _, m := range mappings {
|
|
bySource[m.From] = append(bySource[m.From], m)
|
|
}
|
|
|
|
state := make(map[config.Universe]*[512]byte)
|
|
for _, m := range mappings {
|
|
if _, ok := state[m.To]; !ok {
|
|
state[m.To] = &[512]byte{}
|
|
}
|
|
}
|
|
|
|
return &Engine{
|
|
mappings: mappings,
|
|
bySource: bySource,
|
|
state: state,
|
|
}
|
|
}
|
|
|
|
// Remap applies mappings to incoming DMX data and returns outputs
|
|
func (e *Engine) Remap(src config.Universe, srcData [512]byte) []Output {
|
|
mappings, ok := e.bySource[src]
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
e.stateMu.Lock()
|
|
defer e.stateMu.Unlock()
|
|
|
|
affected := make(map[config.Universe]bool)
|
|
|
|
for _, m := range mappings {
|
|
affected[m.To] = true
|
|
outState := e.state[m.To]
|
|
|
|
for i := 0; i < m.Count; i++ {
|
|
srcChan := m.FromChan + i
|
|
dstChan := m.ToChan + i
|
|
if srcChan < 512 && dstChan < 512 {
|
|
outState[dstChan] = srcData[srcChan]
|
|
}
|
|
}
|
|
}
|
|
|
|
result := make([]Output, 0, len(affected))
|
|
for u := range affected {
|
|
result = append(result, Output{
|
|
Universe: u,
|
|
Data: *e.state[u],
|
|
})
|
|
}
|
|
|
|
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)
|
|
func (e *Engine) DestArtNetUniverses() []uint16 {
|
|
seen := make(map[uint16]bool)
|
|
for _, m := range e.mappings {
|
|
if m.To.Protocol == config.ProtocolArtNet {
|
|
seen[m.To.Number] = true
|
|
}
|
|
}
|
|
result := make([]uint16, 0, len(seen))
|
|
for u := range seen {
|
|
result = append(result, u)
|
|
}
|
|
return result
|
|
}
|