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 transmitt 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 transmitt 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 ¶
- type DataPacket
- func (d *DataPacket) CID() [16]byte
- func (d *DataPacket) Data() []byte
- func (d *DataPacket) DmxStartCode() byte
- func (d *DataPacket) ForceSync() bool
- func (d *DataPacket) PreviewData() bool
- func (d *DataPacket) Priority() byte
- func (d *DataPacket) Sequence() byte
- func (d *DataPacket) SequenceIncr()
- func (d *DataPacket) SetCID(cid [16]byte)
- func (d *DataPacket) SetData(data []byte)
- func (d *DataPacket) SetDmxStartCode(startCode byte)
- func (d *DataPacket) SetForceSync(value bool)
- func (d *DataPacket) SetPreviewData(value bool)
- func (d *DataPacket) SetPriority(prio byte) error
- func (d *DataPacket) SetSequence(sequ byte)
- func (d *DataPacket) SetSourceName(s string)
- func (d *DataPacket) SetStreamTerminated(value bool)
- func (d *DataPacket) SetSyncAddress(sync uint16)
- func (d *DataPacket) SetUniverse(universe uint16)
- func (d *DataPacket) SourceName() string
- func (d *DataPacket) StreamTerminated() bool
- func (d *DataPacket) SyncAddress() uint16
- func (d *DataPacket) Universe() uint16
- type ReceiverSocket
- func (r *ReceiverSocket) Close()
- func (r *ReceiverSocket) JoinUniverse(universe uint16)
- func (r *ReceiverSocket) LeaveUniverse(universe uint16)
- func (r *ReceiverSocket) SetOnChangeCallback(callback func(old DataPacket, new DataPacket))
- func (r *ReceiverSocket) SetTimeoutCallback(callback func(universe uint16))
- func (r *ReceiverSocket) Start()
- type Transmitter
- func (t *Transmitter) Activate(universe uint16) (chan<- [512]byte, error)
- func (t *Transmitter) Destinations(universe uint16) []net.UDPAddr
- func (t *Transmitter) GetActivated() (list []uint16)
- func (t *Transmitter) IsActivated(universe uint16) bool
- func (t *Transmitter) IsMulticast(universe uint16) bool
- func (t *Transmitter) SetDestinations(universe uint16, destinations []string) []error
- func (t *Transmitter) SetMulticast(universe uint16, multicast bool)
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 priorty 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_termiantion falg 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 ¶ added in v0.4.0
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.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) }) select {} //only that our program does not exit. Exit with Ctrl+C }
Output:
func NewReceiverSocket ¶ added in v0.4.0
func NewReceiverSocket(bind string, ifi *net.Interface) (*ReceiverSocket, error)
NewReceiverSocket creates a new unicast Receiversocket 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 dont want to use multicast for receiving, just provide "nil".
func (*ReceiverSocket) Close ¶ added in v0.4.0
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 ¶ added in v1.0.0
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 transmitt on this universe via multicast should reach this socket. Please read the notice above about multicast use.
func (*ReceiverSocket) LeaveUniverse ¶ added in v1.0.0
func (r *ReceiverSocket) LeaveUniverse(universe uint16)
LeaveUniverse will leave the mutlicast-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 occurr, because no more data has arrived.
func (*ReceiverSocket) SetOnChangeCallback ¶ added in v1.0.0
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 ¶ added in v1.0.0
func (r *ReceiverSocket) SetTimeoutCallback(callback func(universe uint16))
SetTimeoutCallback sets the callback for timeouts. The callback gets called everytime a timeout is recognized.
func (*ReceiverSocket) Start ¶ added in v1.0.0
func (r *ReceiverSocket) Start()
Start starts a seperate goroutine for handling incoming sACN traffic. If the goroutine is already running, nothing happens. If Close() was called previously, kkep in mind, that it takes up to 2.5 seconds to stop the existing goroutine.
type Transmitter ¶ added in v0.2.0
type Transmitter struct {
// contains filtered or unexported fields
}
Transmitter : This struct is for managing the transmitting of sACN data. It handles all channels and overwatches what universes are already used.
func NewTransmitter ¶ added in v0.2.0
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 udpconnection. 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 ¶ added in v0.2.0
func (t *Transmitter) Activate(universe uint16) (chan<- [512]byte, error)
Activate starts sending out DMX data on the given universe. It returns a channel that accepts byte slices and transmittes them to the unicast or multicast destination. If you want to deactivate the universe, simply close the channel.
func (*Transmitter) Destinations ¶ added in v0.2.0
func (t *Transmitter) Destinations(universe uint16) []net.UDPAddr
Destinations returns all destinations that have been set via SetDestinations. Note: the returned slice contains deep copys and no change will affect the internal slice.
func (*Transmitter) GetActivated ¶ added in v1.0.0
func (t *Transmitter) GetActivated() (list []uint16)
GetActivated returns a slice with all activated universes
func (*Transmitter) IsActivated ¶ added in v0.2.0
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 ¶ added in v1.0.0
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 ¶ added in v0.2.0
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) SetMulticast ¶ added in v0.2.0
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.