Skip to content

Commit 05d861b

Browse files
authored
Merge pull request #6 from dsmurfin/receiver
Add receiver functionality
2 parents cc0544a + f919d90 commit 05d861b

40 files changed

+4855
-1011
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2022 Dan Murfin
3+
Copyright (c) 2023 Dan Murfin
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import PackageDescription
66
let package = Package(
77
name: "sACNKit",
88
platforms: [
9-
.iOS(.v10),
10-
.macOS(.v10_14),
9+
.iOS(.v12),
10+
.macOS(.v11),
1111
],
1212
products: [
1313
.library(

README.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
11
# sACNKit
22

3-
A description of this package.
3+
An implementation of ANSI E1.31-2018 Entertainment Technology Lightweight streaming protocol for transport of DMX512 using ACN (sACN)
4+
5+
## Source
6+
7+
`sACNSource`
8+
9+
## Receiver
10+
11+
`sACNReceiverGroup`
12+
13+
`sACNReceiver`
14+
15+
## Discovery Receiver
16+
17+
`sACNDiscoveryReceiver`
18+
19+
## Advanced
20+
21+
`sACNReceiverRaw`
22+
23+
`sACNMerger`

Sources/sACNKit/Layers/DMPLayer.swift

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DMPLayer.swift
33
//
4-
// Copyright (c) 2022 Daniel Murfin
4+
// Copyright (c) 2023 Daniel Murfin
55
//
66
// Permission is hereby granted, free of charge, to any person obtaining a copy
77
// of this software and associated documentation files (the "Software"), to deal
@@ -27,16 +27,17 @@ import Foundation
2727
/// DMP Layer
2828
///
2929
/// Implements the DMP Layer and handles creation and parsing.
30-
///
3130
struct DMPLayer {
3231

3332
/// The flags and length. 0x720b: 20b = 523 (starting octet 115) = 638
33+
/// This must only be used for constructing packets as received packets may have differing lengths.
3434
private static let flagsAndLength = Data([0x72, 0x0b])
3535

3636
/// The address type and data type, first property address (DMX512-A START Code is at DMP address 0), and address increment.
3737
private static let addressPropertyBlock = Data([0xa1, 0x00, 0x00, 0x00, 0x01])
3838

3939
/// The number of slots in the message (plus the START Code).
40+
/// This must only be used for constructing packets as received packets may have differing lengths.
4041
private static let propertyValueCount = Data([0x02, 0x01])
4142

4243
/// DMP Layer Vectors
@@ -62,19 +63,8 @@ struct DMPLayer {
6263
case propertyValues = 10
6364
}
6465

65-
/// DMP Layer DMX512-A START Codes
66-
///
67-
/// Enumerates the data offset for each field in this layer.
68-
///
69-
enum STARTCode: UInt8 {
70-
/// Contains dmx level data.
71-
case null = 0x00
72-
/// Contains per-slot priority data.
73-
case perAddressPriority = 0xdd
74-
}
75-
7666
/// The start code for this message.
77-
var startCode: STARTCode
67+
var startCode: DMX.STARTCode
7868

7969
/// The values for this message.
8070
var values: [UInt8]
@@ -87,7 +77,7 @@ struct DMPLayer {
8777
///
8878
/// - Returns: A `DMPLayer` as a `Data` object.
8979
///
90-
static func createAsData(startCode: STARTCode, values: [UInt8]) -> Data {
80+
static func createAsData(startCode: DMX.STARTCode, values: [UInt8]) -> Data {
9181
var data = Data()
9282
data.append(contentsOf: DMPLayer.flagsAndLength)
9383
data.append(Vector.setProperty.rawValue.data)
@@ -111,8 +101,8 @@ struct DMPLayer {
111101
guard data.count > Offset.propertyValues.rawValue+1 else { throw DMPLayerValidationError.lengthOutOfRange }
112102

113103
// the flags and length
114-
guard data[Offset.flagsAndLength.rawValue..<Offset.vector.rawValue] == Self.flagsAndLength else {
115-
throw DMPLayerValidationError.invalidFlagsAndLength
104+
guard let flagsAndLength = data.toFlagsAndLength(atOffset: Offset.flagsAndLength.rawValue), flagsAndLength.length == data.count-Offset.flagsAndLength.rawValue else {
105+
throw DataFramingLayerValidationError.invalidFlagsAndLength
116106
}
117107
// the vector for this layer
118108
guard let vector: UInt8 = data.toUInt8(atOffset: Offset.vector.rawValue) else {
@@ -129,15 +119,15 @@ struct DMPLayer {
129119
guard let propertyValueCount: UInt16 = data.toUInt16(atOffset: Offset.propertyValueCount.rawValue) else {
130120
throw DMPLayerValidationError.unableToParse(field: "Property Value Count")
131121
}
132-
guard propertyValueCount < 513 else {
122+
guard propertyValueCount <= 513 && data.count >= Offset.propertyValues.rawValue + Int(propertyValueCount) else {
133123
throw DMPLayerValidationError.invalidPropertyValueCount(propertyValueCount)
134124
}
135125
// the START Code
136-
guard let code: UInt8 = data.toUInt8(atOffset: Offset.propertyValues.rawValue), let STARTCode = STARTCode(rawValue: code) else {
126+
guard let code: UInt8 = data.toUInt8(atOffset: Offset.propertyValues.rawValue), let STARTCode = DMX.STARTCode(rawValue: code) else {
137127
throw DMPLayerValidationError.unableToParse(field: "START Code")
138128
}
139129
let propertyValuesOffset = Offset.propertyValues.rawValue+1
140-
let values = data.subdata(in: propertyValuesOffset..<propertyValuesOffset+Int(propertyValueCount)).bytes
130+
let values = data.subdata(in: propertyValuesOffset..<propertyValuesOffset+Int(propertyValueCount-1)).bytes
141131

142132
return Self(startCode: STARTCode, values: values)
143133
}

Sources/sACNKit/Layers/DataFramingLayer.swift

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DataFramingLayer.swift
33
//
4-
// Copyright (c) 2022 Daniel Murfin
4+
// Copyright (c) 2023 Daniel Murfin
55
//
66
// Permission is hereby granted, free of charge, to any person obtaining a copy
77
// of this software and associated documentation files (the "Software"), to deal
@@ -27,10 +27,10 @@ import Foundation
2727
/// Data Framing Layer
2828
///
2929
/// Implements the Data Framing Layer and handles creation and parsing.
30-
///
3130
struct DataFramingLayer {
3231

3332
/// The flags and length. 0x7258: 258 = 600 (starting octet 38) = 638.
33+
/// This must only be used for constructing packets as received packets may have differing lengths.
3434
private static let flagsAndLength = Data([0x72, 0x58])
3535

3636
/// Data Framing Layer Vectors
@@ -73,22 +73,22 @@ struct DataFramingLayer {
7373
private var vector: Vector
7474

7575
/// A name for this source, such as a user specified human-readable string, or serial number for the device.
76-
var sourceName: String
76+
private (set) var sourceName: String
7777

7878
/// The priority of this source.
79-
var priority: UInt8
79+
private (set) var priority: UInt8
8080

8181
/// The sequence number for this message.
82-
var sequenceNumber: UInt8
82+
private (set) var sequenceNumber: UInt8
8383

8484
/// The options for this message.
85-
var options: Options
85+
private (set) var options: Options
8686

8787
/// The unvierse number for this message.
88-
var universe: UInt16
88+
private (set) var universe: UInt16
8989

9090
/// The data contained in the layer.
91-
private var data: Data
91+
private (set) var data: Data
9292

9393
/// Creates a Framing Layer as Data.
9494
///
@@ -123,7 +123,7 @@ struct DataFramingLayer {
123123
guard data.count > Offset.data.rawValue else { throw DataFramingLayerValidationError.lengthOutOfRange }
124124

125125
// the flags and length
126-
guard data[Offset.flagsAndLength.rawValue..<Offset.vector.rawValue] == Self.flagsAndLength else {
126+
guard let flagsAndLength = data.toFlagsAndLength(atOffset: Offset.flagsAndLength.rawValue), flagsAndLength.length == data.count-Offset.flagsAndLength.rawValue else {
127127
throw DataFramingLayerValidationError.invalidFlagsAndLength
128128
}
129129
// the vector for this layer
@@ -158,10 +158,9 @@ struct DataFramingLayer {
158158
guard let universe: UInt16 = data.toUInt16(atOffset: Offset.universe.rawValue) else {
159159
throw DataFramingLayerValidationError.unableToParse(field: "Universe Number")
160160
}
161-
guard Universe.dataUniverseNumbers.contains(universe) else {
161+
guard SourceUniverse.dataUniverseNumbers.contains(universe) else {
162162
throw DataFramingLayerValidationError.invalidUniverse(universe)
163163
}
164-
165164
// layer data
166165
let data = data.subdata(in: Offset.data.rawValue..<data.count)
167166

Sources/sACNKit/Layers/RootLayer.swift

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// RootLayer.swift
33
//
4-
// Copyright (c) 2022 Daniel Murfin
4+
// Copyright (c) 2023 Daniel Murfin
55
//
66
// Permission is hereby granted, free of charge, to any person obtaining a copy
77
// of this software and associated documentation files (the "Software"), to deal
@@ -27,7 +27,6 @@ import Foundation
2727
/// Root Layer
2828
///
2929
/// Implements the Root Layer and handles creation and parsing.
30-
///
3130
struct RootLayer {
3231

3332
/// The offset at which length counting starts.
@@ -42,8 +41,9 @@ struct RootLayer {
4241
/// The packet identifier which begins every sACN message.
4342
private static let packetIdentifier = Data([0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00])
4443

45-
/// The flags and length. 0x726e: 26e = 622 (starting octet 16) = 638.
46-
private static let flagsAndLength = Data([0x72, 0x6e])
44+
/// The flags and length for a data framing layer message. 0x726e: 26e = 622 (starting octet 16) = 638.
45+
/// This must only be used for constructing data packets as received packets may have differing lengths.
46+
private static let dataFlagsAndLength = Data([0x72, 0x6e])
4747

4848
/// Root Layer Vectors
4949
///
@@ -52,7 +52,7 @@ struct RootLayer {
5252
enum Vector: UInt32 {
5353
/// Contains a `DataFramingLayer`.
5454
case data = 0x00000004
55-
/// Contains a `ExtendedFramingLayer`.
55+
/// Contains an `ExtendedFramingLayer`.
5656
case extended = 0x00000008
5757
}
5858

@@ -71,13 +71,13 @@ struct RootLayer {
7171
}
7272

7373
/// The vector describing the data in the layer.
74-
private var vector: Vector
74+
private (set) var vector: Vector
7575

7676
/// A globally unique identifier (UUID) representing the `Source`, compliant with RFC 4122.
77-
var cid: UUID
77+
private (set) var cid: UUID
7878

7979
/// The data contained in the layer.
80-
private var data: Data
80+
private (set) var data: Data
8181

8282
/// Creates a Root Layer as Data.
8383
///
@@ -92,7 +92,7 @@ struct RootLayer {
9292
data.append(contentsOf: RootLayer.preambleSize)
9393
data.append(contentsOf: RootLayer.postambleSize)
9494
data.append(contentsOf: RootLayer.packetIdentifier)
95-
data.append(contentsOf: RootLayer.flagsAndLength)
95+
data.append(contentsOf: RootLayer.dataFlagsAndLength)
9696
data.append(vector.rawValue.data)
9797
data.append(cid.data)
9898
return data
@@ -123,8 +123,7 @@ struct RootLayer {
123123
throw RootLayerValidationError.invalidPacketIdentifier
124124
}
125125
// the flags and length
126-
// TODO: This needs to be checked for universe discovery
127-
guard data[Offset.flagsAndLength.rawValue..<Offset.vector.rawValue] == Self.flagsAndLength else {
126+
guard let flagsAndLength = data.toFlagsAndLength(atOffset: Offset.flagsAndLength.rawValue), flagsAndLength.length == data.count-Offset.flagsAndLength.rawValue else {
128127
throw RootLayerValidationError.invalidFlagsAndLength
129128
}
130129
// the vector for this message
@@ -150,7 +149,7 @@ struct RootLayer {
150149
///
151150
/// Extensions for modifying fields within an existing `RootLayer` stored as `Data`.
152151
///
153-
internal extension Data {
152+
extension Data {
154153
/// Replaces the `RootLayer` Flags and Length.
155154
///
156155
/// - Parameters:

Sources/sACNKit/Layers/UniverseDiscoveryFramingLayer.swift

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// UniverseDiscoveryFramingLayer.swift
33
//
4-
// Copyright (c) 2022 Daniel Murfin
4+
// Copyright (c) 2023 Daniel Murfin
55
//
66
// Permission is hereby granted, free of charge, to any person obtaining a copy
77
// of this software and associated documentation files (the "Software"), to deal
@@ -27,7 +27,6 @@ import Foundation
2727
/// Universe Discovery Framing Layer
2828
///
2929
/// Implements the Universe Discovery Framing Layer and handles creation and parsing.
30-
///
3130
struct UniverseDiscoveryFramingLayer {
3231

3332
/// Universe Discovery Layer Vectors
@@ -47,17 +46,18 @@ struct UniverseDiscoveryFramingLayer {
4746
case flagsAndLength = 0
4847
case vector = 2
4948
case sourceName = 6
50-
case data = 70
49+
case reserved = 70
50+
case data = 74
5151
}
5252

5353
/// The vector describing the data in the layer.
54-
private var vector: Vector
54+
private (set) var vector: Vector
5555

5656
/// A name for this source, such as a user specified human-readable string, or serial number for the device.
57-
var sourceName: String
57+
private (set) var sourceName: String
5858

5959
/// The data contained in the layer.
60-
private var data: Data
60+
private (set) var data: Data
6161

6262
/// Creates a Framing Layer as Data.
6363
///
@@ -88,11 +88,7 @@ struct UniverseDiscoveryFramingLayer {
8888
guard data.count > Offset.data.rawValue else { throw UniverseDiscoveryFramingLayerValidationError.lengthOutOfRange }
8989

9090
// the flags and length
91-
guard let flagsAndLength = data.toUInt16(atOffset: Offset.flagsAndLength.rawValue) else {
92-
throw UniverseDiscoveryFramingLayerValidationError.unableToParse(field: "Flags And Length")
93-
}
94-
// TODO: Validate length and get universes being advertised
95-
guard let length = FlagsAndLength.toLength(from: flagsAndLength) else {
91+
guard let flagsAndLength = data.toFlagsAndLength(atOffset: Offset.flagsAndLength.rawValue), flagsAndLength.length == data.count-Offset.flagsAndLength.rawValue else {
9692
throw UniverseDiscoveryFramingLayerValidationError.invalidFlagsAndLength
9793
}
9894
// the vector for this layer

Sources/sACNKit/Layers/UniverseDiscoveryLayer.swift

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// UniverseDiscoveryLayer.swift
33
//
4-
// Copyright (c) 2022 Daniel Murfin
4+
// Copyright (c) 2023 Daniel Murfin
55
//
66
// Permission is hereby granted, free of charge, to any person obtaining a copy
77
// of this software and associated documentation files (the "Software"), to deal
@@ -27,7 +27,6 @@ import Foundation
2727
/// Universe Discovery Layer
2828
///
2929
/// Implements the Universe Discovery Layer and handles creation and parsing.
30-
///
3130
struct UniverseDiscoveryLayer {
3231

3332
/// The maximum number of universe numbers to include in this layer.
@@ -98,9 +97,9 @@ struct UniverseDiscoveryLayer {
9897
guard data.count >= Offset.listOfUniverses.rawValue else { throw UniverseDiscoveryLayerValidationError.lengthOutOfRange }
9998

10099
// the flags and length
101-
guard let _ = data.toUInt16(atOffset: Offset.flagsAndLength.rawValue) else {
102-
throw UniverseDiscoveryLayerValidationError.unableToParse(field: "Flags And Length")
103-
}
100+
guard let flagsAndLength = data.toFlagsAndLength(atOffset: Offset.flagsAndLength.rawValue), flagsAndLength.length == data.count-Offset.flagsAndLength.rawValue else {
101+
throw UniverseDiscoveryLayerValidationError.invalidFlagsAndLength
102+
}
104103
// the vector for this layer
105104
guard let vector: UInt32 = data.toUInt32(atOffset: Offset.vector.rawValue) else {
106105
throw UniverseDiscoveryLayerValidationError.unableToParse(field: "Vector")

0 commit comments

Comments
 (0)