sacn

package module
v0.0.0-...-00e6fbe Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2022 License: MIT Imports: 6 Imported by: 13

Documentation

Overview

Package sacn is a simple sACN implementation. The standard can be obtained here: http://tsp.esta.org/tsp/documents/docs/E1-31-2016.pdf

This is by no means a full implementation yet, but may be in the future. If you want to see a full DMX package, see the http://opendmx.net/index.php/Open_Lighting_Architecture project.

Receiving

The simplest way to receive sACN packets is to use `sacn.NewReceiverSocket`.

The receiver checks for out-of-order packets (inspecting the sequence number) and sorts for priority. Synchronization must be implemented in the callers program, but currently there is no way to receive the sACN sync-packets. This feature may come in a future version.

This `sacn.ReceiverSocket` can use multicast groups to receive its data. Unicast packets that are received are also processed like the normal unicast receiver. Depending on your operating system, you might can provide `nil` as an interface, sometimes you have to use a dedicated interface, to get multicast working. Windows needs an interface and Linux generally not.

Note that the network infrastructure has to be multicast ready and that on some networks the delay of packets will increase. Also the packet loss can be higher if multicast is chosen (This is often a problem when WLAN is used). This can cause unintentional timeouts, if the sources are only transmitting every 2 seconds (like grandMA2 consoles).

Transmitting

To transmit DMX data, you have to initialize a `Transmitter` object. This handles all the protocol specific actions (currently not all). You can activate universes, if you wish to send out data. Then you can use a channel for 512-byte arrays to transmit them over the network.

There are two different types of addressing the receiver: unicast and multicast. When using multicast, note that you have to provide a bind address on some operating systems (eg Windows). You can use both at the same time and any number of unicast addresses. To set wether multicast should be used, call `transmitter.SetMulticast(<universe>, <bool>)`. You can set multiple unicast destinations as slice via `transmitter.SetDestinations(<universe>, <[]string>)`. Note that any existing destinations will be overwritten. If you want to append a destination, you can use `transmitter.Destination(<universe>)` which returns a deep copy of the used net.UDPAddr objects.

Example

package main

import (
	"log"
	"math/rand"
	"time"

	"github.com/Hundemeier/go-sacn/sacn"
)

func main() {
	//instead of "" you could provide an ip-address that the socket should bind to
	trans, err := sacn.NewTransmitter("", [16]byte{1, 2, 3}, "test")
	if err != nil {
		log.Fatal(err)
	}

	//activates the first universe
	ch, err := trans.Activate(1)
	if err != nil {
		log.Fatal(err)
	}
	//deactivate the channel on exit
	defer close(ch)

	//set a unicast destination, and/or use multicast
	trans.SetMulticast(1, true)//this specific setup will not multicast on windows,
	//because no bind address was provided

	//set some example ip-addresses
	trans.SetDestinations(1, []string{"192.168.1.13", "192.168.1.1"})

	//send some random data for 10 seconds
	for i := 0; i < 20; i++ {
		ch <- [512]byte{byte(rand.Int()), byte(i & 0xFF)}
		time.Sleep(500 * time.Millisecond)
	}
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type DataPacket

type DataPacket struct {
	// contains filtered or unexported fields
}

DataPacket is a byte array with unspecific length

func NewDataPacket

func NewDataPacket() DataPacket

NewDataPacket creates a new DataPacket with an empty 638-length byte slice

func NewDataPacketRaw

func NewDataPacketRaw(raw []byte) (DataPacket, error)

NewDataPacketRaw creates a new DataPacket based on the given raw bytes

func (*DataPacket) CID

func (d *DataPacket) CID() [16]byte

CID returns the cid that is set for this object

func (*DataPacket) Data

func (d *DataPacket) Data() []byte

Data returns the DMX data that is set for this DataPacket. Length: [0-512]

func (*DataPacket) DmxStartCode

func (d *DataPacket) DmxStartCode() byte

DmxStartCode return the start code of the given packet

func (*DataPacket) ForceSync

func (d *DataPacket) ForceSync() bool

ForceSync returns the state of the force_synchronization flag

func (*DataPacket) PreviewData

func (d *DataPacket) PreviewData() bool

PreviewData returns wether this packet has the preview flag set

func (*DataPacket) Priority

func (d *DataPacket) Priority() byte

Priority returns the byte value of the priority field of the packet. Value range: [0-200]

func (*DataPacket) Sequence

func (d *DataPacket) Sequence() byte

Sequence returns the sequence number of the packet

func (*DataPacket) SequenceIncr

func (d *DataPacket) SequenceIncr()

SequenceIncr increments the sequence number

func (*DataPacket) SetCID

func (d *DataPacket) SetCID(cid [16]byte)

SetCID sets the CID unique identifier

func (*DataPacket) SetData

func (d *DataPacket) SetData(data []byte)

SetData sets the dmx data for the given DataPacket

func (*DataPacket) SetDmxStartCode

func (d *DataPacket) SetDmxStartCode(startCode byte)

SetDmxStartCode sets the DMX start code that is transmitted together with the DMX data

func (*DataPacket) SetForceSync

func (d *DataPacket) SetForceSync(value bool)

SetForceSync sets the force_synchronization bit flag

func (*DataPacket) SetPreviewData

func (d *DataPacket) SetPreviewData(value bool)

SetPreviewData sets the preview_data flag in this packet to the given value

func (*DataPacket) SetPriority

func (d *DataPacket) SetPriority(prio byte) error

SetPriority sets the priority field for the packet. Value must be [0-200]!

func (*DataPacket) SetSequence

func (d *DataPacket) SetSequence(sequ byte)

SetSequence sets the sequence number of the packet

func (*DataPacket) SetSourceName

func (d *DataPacket) SetSourceName(s string)

SetSourceName sets the source name field to the given string values. Note that only the first 64 characters are used!

func (*DataPacket) SetStreamTerminated

func (d *DataPacket) SetStreamTerminated(value bool)

SetStreamTerminated sets the stream_termination flag on or off

func (*DataPacket) SetSyncAddress

func (d *DataPacket) SetSyncAddress(sync uint16)

SetSyncAddress sets the synchronization universe for the given packet

func (*DataPacket) SetUniverse

func (d *DataPacket) SetUniverse(universe uint16)

SetUniverse sets the universe value of the packet

func (*DataPacket) SourceName

func (d *DataPacket) SourceName() string

SourceName returns the stored source name. Note that the source name max length is 64!

func (*DataPacket) StreamTerminated

func (d *DataPacket) StreamTerminated() bool

StreamTerminated returns the state of the stream_termination flag

func (*DataPacket) SyncAddress

func (d *DataPacket) SyncAddress() uint16

SyncAddress returns the sync universe of the given packet

func (*DataPacket) Universe

func (d *DataPacket) Universe() uint16

Universe returns the universe value of the packet

type ReceiverSocket

type ReceiverSocket struct {
	// contains filtered or unexported fields
}

ReceiverSocket is used to listen on a network interface for sACN data. The OnChangeCallback is used for changed DMX data. So if a source or priority changed, this callback will not be invoked if not the DMX data has changed. This Receiver checks for out-of-order packets and sorts out packets with too low priority.

Example (Multicast)
package main

import (
	"fmt"
	"log"
	"net"
	"time"

	"github.com/Hundemeier/go-sacn/sacn"
)

func main() {
	ifi, err := net.InterfaceByName("eth0") //this name depends on your machine!
	if err != nil {
		log.Fatal(err)
	}
	recv, err := sacn.NewReceiverSocket("", ifi)
	if err != nil {
		log.Fatal(err)
	}
	recv.SetOnChangeCallback(func(old sacn.DataPacket, newD sacn.DataPacket) {
		fmt.Println("data changed on", newD.Universe())
	})
	recv.SetTimeoutCallback(func(univ uint16) {
		fmt.Println("timeout on", univ)
	})
	recv.Start()
	recv.JoinUniverse(1)
	time.Sleep(10 * time.Second) //only join for 10 seconds, just for testing
	recv.LeaveUniverse(1)
	fmt.Println("Leaved")
	select {} //only that our program does not exit. Exit with Ctrl+C
}
Output:

Example (Unicast)
package main

import (
	"fmt"
	"log"

	"github.com/Hundemeier/go-sacn/sacn"
)

func main() {
	recv, err := sacn.NewReceiverSocket("", nil)
	if err != nil {
		log.Fatal(err)
	}
	recv.SetOnChangeCallback(func(old sacn.DataPacket, newD sacn.DataPacket) {
		fmt.Println("data changed on", newD.Universe())
	})
	recv.SetTimeoutCallback(func(univ uint16) {
		fmt.Println("timeout on", univ)
	})
	recv.Start()
	select {} //only that our program does not exit. Exit with Ctrl+C
}
Output:

func NewReceiverSocket

func NewReceiverSocket(bind string, ifi *net.Interface) (*ReceiverSocket, error)

NewReceiverSocket creates a new unicast Receiver socket that is capable of listening on the given interface (string is for binding). bind can be something like "192.168.1.2" (without a port!). This bind is only used for unicast receiving. The net.Interface is used to join multicast groups. On some OS (eg Windows) you have to provide an interface for multicast to work. On others "nil" may be enough. If you don't want to use multicast for receiving, just provide "nil".

func (*ReceiverSocket) Close

func (r *ReceiverSocket) Close()

Close will close the open udp socket and stops the running goroutine. If you want to receive again, use Start(). Do not call close twice!

func (*ReceiverSocket) JoinUniverse

func (r *ReceiverSocket) JoinUniverse(universe uint16)

JoinUniverse joins the used udp socket to the multicast-group that is used for the universe. After the multicast-group was joined, any source that transmit on this universe via multicast should reach this socket. Please read the notice above about multicast use.

func (*ReceiverSocket) LeaveUniverse

func (r *ReceiverSocket) LeaveUniverse(universe uint16)

LeaveUniverse will leave the multicast-group of the given universe. If the the socket was not joined to the multicast-group nothing will happen. Please note, that if you leave a group, a timeout may occur, because no more data has arrived.

func (*ReceiverSocket) SetOnChangeCallback

func (r *ReceiverSocket) SetOnChangeCallback(callback func(old DataPacket, new DataPacket))

SetOnChangeCallback sets the given function as callback for the receiver. If no old DataPacket can be provided, it is a packet with universe 0.

func (*ReceiverSocket) SetTimeoutCallback

func (r *ReceiverSocket) SetTimeoutCallback(callback func(universe uint16))

SetTimeoutCallback sets the callback for timeouts. The callback gets called every time a timeout is recognized.

func (*ReceiverSocket) Start

func (r *ReceiverSocket) Start()

Start starts a separate goroutine for handling incoming sACN traffic. If the goroutine is already running, nothing happens. If Close() was called previously, keep in mind, that it takes up to 2.5 seconds to stop the existing goroutine.

type Transmitter

type Transmitter struct {
	// contains filtered or unexported fields
}

Transmitter : This struct is for managing the transmitting of sACN data. It handles all channels and over watches what universes are already used.

func NewTransmitter

func NewTransmitter(binding string, cid [16]byte, sourceName string) (Transmitter, error)

NewTransmitter creates a new Transmitter object and returns it. Only use one object for one network interface. bind is a string like "192.168.2.34" or "". It is used for binding the udp connection. In most cases an empty string will be sufficient. The caller is responsible for closing! If you want to use multicast, you have to provide a binding string on some operation systems (eg Windows).

func (*Transmitter) Activate

func (t *Transmitter) Activate(universe uint16) (chan<- []byte, error)

Activate starts sending out DMX data on the given universe. It returns a channel that accepts byte slices and transmits them to the unicast or multicast destination. If you want to deactivate the universe, simply close the channel.

func (*Transmitter) Destinations

func (t *Transmitter) Destinations(universe uint16) []net.UDPAddr

Destinations returns all destinations that have been set via SetDestinations. Note: the returned slice contains deep copies and no change will affect the internal slice.

func (*Transmitter) GetActivated

func (t *Transmitter) GetActivated() (list []uint16)

GetActivated returns a slice with all activated universes

func (*Transmitter) IsActivated

func (t *Transmitter) IsActivated(universe uint16) bool

IsActivated checks if the given universe was activated and returns true if this is the case

func (*Transmitter) IsMulticast

func (t *Transmitter) IsMulticast(universe uint16) bool

IsMulticast returns wether or not multicast is turned on for the given universe. true: on

func (*Transmitter) SetDestinations

func (t *Transmitter) SetDestinations(universe uint16, destinations []string) []error

SetDestinations sets a slice of destinations for the universe that is used for sending out. So multiple destinations are supported. Note: the existing slice will be overwritten! If you want no unicasting, just set an empty slice. If there is a string that could not be converted to an ip-address, this one is left out and an error slice will be returned, but the indices of the errors are not the same as the string indices on which the errors happened.

func (*Transmitter) SetKeepAlive

func (t *Transmitter) SetKeepAlive(interval time.Duration)

Allows the user to set a different interval than the internal default of 1 second when the current data will be re-written to the network to the outputs. (e.g. a much higher interval for less dynamically changing lighting and lower overall network traffic.)

func (*Transmitter) SetMulticast

func (t *Transmitter) SetMulticast(universe uint16, multicast bool)

SetMulticast is for setting wether or not a universe should be send out via multicast. Keep in mind, that on some operating systems you have to provide a bind address.

func (*Transmitter) SetPriority

func (t *Transmitter) SetPriority(prio byte)

Allows the caller to set a priority on the sACN packets to be used in situations when a destination receives data from multiple sources and needs to decide which one to ignore.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL