diff --git a/config.go b/config.go index f8d9aaa..c9bcb3e 100644 --- a/config.go +++ b/config.go @@ -78,6 +78,8 @@ func ArtPollReplyFromConfig(c NodeConfig) *packet.ArtPollReplyPacket { Status2: c.Status2, NetSwitch: c.BaseAddress.Net, SubSwitch: c.BaseAddress.SubUni, + NumPorts: c.NumberOfPorts(), + PortTypes: c.PortTypes(), } copy(p.IPAddress[0:4], c.IP.To4()) @@ -91,6 +93,64 @@ func ArtPollReplyFromConfig(c NodeConfig) *packet.ArtPollReplyPacket { return p } +// NumberOfPorts returns the count of node ports. This method assumes that +// NodeConfig is validated. +func (c NodeConfig) NumberOfPorts() uint16 { + if len(c.InputPorts) > len(c.OutputPorts) { + return uint16(len(c.InputPorts)) + } + return uint16(len(c.OutputPorts)) +} + +// PortType merges the InputPorts and OutputPorts config into a single PortTypes +// definition. This method assumes that NodeConfig is validated. +func (c NodeConfig) PortTypes() [4]code.PortType { + rsl := [4]code.PortType{} + for i := 0; i < 4; i++ { + tmp := code.PortType(0) + if len(c.InputPorts) > i { + tmp = tmp.WithInput(true) + rsl[i] = tmp.WithType(c.InputPorts[i].Type.Type()) + } + if len(c.OutputPorts) > i { + tmp = tmp.WithOutput(true) + rsl[i] = tmp.WithType(c.OutputPorts[i].Type.Type()) + } + } + return rsl +} + +// validate will check the config and return an error if something is not valid. +// The main objective of this method is to check if the in- and output-ports configured +// by the user can be announced on the Art-Net network. It checks: +// +// - At max 4 in- and/or outputs are supported per node. +// - If a port supports in- and output at the same time the protocol type has to be +// the same for the input port of the same index as the output port. +func (c NodeConfig) validate() error { + if len(c.InputPorts) > 4 { + return fmt.Errorf("validation error: more than 4 input ports configured (%d) for the node, this isn't supported by the library", len(c.InputPorts)) + } + if len(c.OutputPorts) > 4 { + return fmt.Errorf("validation error: more than 4 output ports configured (%d) for the node, this isn't supported by the library", len(c.InputPorts)) + } + for i := 0; i < 4; i++ { + if len(c.InputPorts) <= i || len(c.OutputPorts) <= i { + continue + } + if c.InputPorts[i].Type.Type() != c.OutputPorts[i].Type.Type() { + return fmt.Errorf( + "validation error: the type (%s) of input port %d has a different type (%s) than output port %d, input and output ports with the same index must have the same type", + c.InputPorts[i].Type.Type(), + i+1, + c.OutputPorts[i].Type.Type(), + i+1, + ) + } + } + return nil +} + // ConfigFromArtPollReply will return a Config from the information in the ArtPollReplyPacket func ConfigFromArtPollReply(p packet.ArtPollReplyPacket) NodeConfig { nodeConfig := NodeConfig{ diff --git a/node.go b/node.go index 31f2771..6ce87a3 100644 --- a/node.go +++ b/node.go @@ -108,6 +108,9 @@ func (n *Node) isShutdown() bool { // Start will start the controller func (n *Node) Start() error { + if err := n.Config.validate(); err != nil { + return err + } n.log.With(Fields{"ip": n.Config.IP.String(), "type": n.Config.Type.String()}).Debug("node started") n.sendCh = make(chan netPayload, 10)