Skip to content

Commit a4e9366

Browse files
committed
Add Lock, InitiationComplete & SourceTallies
Added new messages + published Topology Message
1 parent 3bafcf2 commit a4e9366

2 files changed

Lines changed: 167 additions & 23 deletions

File tree

Sources/Atem/MessageTypes.swift

Lines changed: 151 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -66,20 +66,20 @@ struct AtemType: Serializable {
6666
}
6767

6868
/// The resources of an atem
69-
struct Topology: Serializable {
70-
static var title = MessageTitle(string: "_top")
71-
72-
let mixEffectBanks: UInt8
73-
let sources: UInt8
74-
let colorGenerators: UInt8
75-
let auxiliaryBusses: UInt8
76-
let downstreamKeyers: UInt8
77-
let stingers: UInt8
78-
let digitalVideoEffects: UInt8
79-
let superSources: UInt8
80-
let standardDefinitionOutput: Bool
81-
82-
init(with bytes: ArraySlice<UInt8>) {
69+
public struct Topology: Serializable {
70+
public static var title = MessageTitle(string: "_top")
71+
72+
public let mixEffectBanks: UInt8
73+
public let sources: UInt8
74+
public let colorGenerators: UInt8
75+
public let auxiliaryBusses: UInt8
76+
public let downstreamKeyers: UInt8
77+
public let stingers: UInt8
78+
public let digitalVideoEffects: UInt8
79+
public let superSources: UInt8
80+
public let standardDefinitionOutput: Bool
81+
82+
public init(with bytes: ArraySlice<UInt8>) {
8383
mixEffectBanks = bytes[bytes.startIndex ]
8484
sources = bytes[bytes.startIndex + 1]
8585
colorGenerators = bytes[bytes.startIndex + 2]
@@ -91,7 +91,7 @@ struct Topology: Serializable {
9191
standardDefinitionOutput = bytes[bytes.startIndex + 9].firstBit
9292
}
9393

94-
init(mixEffectBanks: UInt8,
94+
public init(mixEffectBanks: UInt8,
9595
sources: UInt8,
9696
colorGenerators: UInt8,
9797
auxiliaryBusses: UInt8,
@@ -112,15 +112,24 @@ struct Topology: Serializable {
112112
self.standardDefinitionOutput = standardDefinitionOutput
113113
}
114114

115-
var dataBytes: [UInt8] {
115+
public var dataBytes: [UInt8] {
116116
return [mixEffectBanks, sources, colorGenerators, auxiliaryBusses, downstreamKeyers, stingers, digitalVideoEffects, superSources, 0, standardDefinitionOutput ? 1:0, 0]
117117
}
118118

119-
var debugDescription: String {
120-
return [
121-
""
122-
].joined(separator: "\n")
119+
public var debugDescription: String {
120+
return "Topology(\n" + ([
121+
"mixEffectBanks": mixEffectBanks,
122+
"sources": sources,
123+
"colorGenerators": colorGenerators,
124+
"auxiliaryBusses": auxiliaryBusses,
125+
"downstreamKeyers": downstreamKeyers,
126+
"stingers": stingers,
127+
"digitalVideoEffects": digitalVideoEffects,
128+
"superSources": superSources,
129+
"standardDefinitionOutput": standardDefinitionOutput
130+
] as DictionaryLiteral ).map{"\t\($0): \($1),"}.joined(separator: "\n") + "\n)"
123131
}
132+
124133
}
125134

126135
/// The message that should be sent at the end of the connection initiation. The connection initiation is the sequence of packets that is sent at the very beginning of a connection and they contain messages that represent the state of the device at the moment of conection.
@@ -298,3 +307,125 @@ public struct TransitionPositionChanged: Serializable {
298307

299308
public var debugDescription: String { return "Change transition position of ME\(mixEffect+1) to \(position)"}
300309
}
310+
311+
public struct LockRequest: Serializable {
312+
public static var title = MessageTitle(string: "LOCK")
313+
public let store: UInt16
314+
public let state: UInt16
315+
316+
public init(with bytes: ArraySlice<UInt8>) throws {
317+
store = UInt16(from: bytes)
318+
state = UInt16(from: bytes[relative: 2..<4])
319+
}
320+
321+
public var debugDescription: String {return "Lock store \(store) to \(String(state, radix: 16))"}
322+
323+
public var dataBytes: [UInt8] {
324+
return store.bytes + state.bytes
325+
}
326+
}
327+
328+
public struct LockPositionRequest: Message {
329+
public static var title = MessageTitle(string: "PLCK")
330+
public let store: UInt16
331+
public let index: UInt16
332+
public let type: UInt16
333+
334+
public init(with bytes: ArraySlice<UInt8>) throws {
335+
store = UInt16(from: bytes)
336+
index = UInt16(from: bytes[relative: 2..<4])
337+
type = UInt16(from: bytes[relative: 4..<6])
338+
print(bytes)
339+
}
340+
341+
public var debugDescription: String {return "Lock request \(store): for index \(index), type \(type)"}
342+
}
343+
344+
public struct LockChange: Serializable {
345+
public static var title = MessageTitle(string: "LKST")
346+
public let store: UInt16
347+
public let isLocked: Bool
348+
349+
public init(with bytes: ArraySlice<UInt8>) throws {
350+
store = .init(from: bytes)
351+
isLocked = bytes[relative: 2] == 1
352+
}
353+
354+
public init(store: UInt16, isLocked: Bool) {
355+
self.store = store
356+
self.isLocked = isLocked
357+
}
358+
359+
public var dataBytes: [UInt8] {
360+
return store.bytes + [isLocked ? 1:0, 0]
361+
}
362+
363+
public var debugDescription: String { return "Lock for store \(store) is \(isLocked ? "established" : "released")" }
364+
}
365+
366+
public struct LockObtained: Serializable {
367+
public static var title = MessageTitle(string: "LKOB")
368+
let store: UInt16
369+
370+
public init(with bytes: ArraySlice<UInt8>) throws {
371+
store = .init(from: bytes)
372+
}
373+
374+
public init(store: UInt16) {
375+
self.store = store
376+
}
377+
378+
public var debugDescription: String { return "Lock obtained" }
379+
380+
public var dataBytes: [UInt8] {
381+
return store.bytes + [0, 0]
382+
}
383+
}
384+
385+
public struct InitiationComplete: Message {
386+
public static var title = MessageTitle(string: "InCm")
387+
388+
public init(with bytes: ArraySlice<UInt8>) throws {
389+
print("InCm", bytes)
390+
}
391+
392+
public let debugDescription = "Initiation complete"
393+
}
394+
public struct SourceTallies: Serializable {
395+
public static var title = MessageTitle(string: "TlSr")
396+
public let tallies: [VideoSource:TallyLight]
397+
398+
public init(with bytes: ArraySlice<UInt8>) throws {
399+
let sourceCount = Int(UInt16(from: bytes))
400+
precondition(sourceCount*3 <= bytes.count-2, "Message is too short, it cannot contain tally info for \(sourceCount) sources")
401+
402+
var tallies = [VideoSource:TallyLight](minimumCapacity: sourceCount)
403+
for cursor in stride(from: 2, to: sourceCount*3 + 2, by: 3) {
404+
let source = try VideoSource.decode(from: UInt16(from: bytes[relative: cursor...]))
405+
tallies[source] = try TallyLight.decode(from: bytes[relative: cursor+2])
406+
}
407+
self.tallies = tallies
408+
}
409+
public init(tallies: [VideoSource:TallyLight]) {
410+
self.tallies = tallies
411+
}
412+
413+
public var dataBytes: [UInt8] {
414+
var bytes = [UInt8]()
415+
bytes.reserveCapacity(2 + tallies.count*3)
416+
417+
bytes.append(contentsOf: UInt16(tallies.count).bytes)
418+
// Todo: check if sources really need to be sorted
419+
for (source, tally) in tallies.sorted(by: {$0.0.rawValue < $1.0.rawValue}) {
420+
bytes.append(contentsOf: source.rawValue.bytes)
421+
bytes.append(tally.rawValue)
422+
}
423+
return bytes
424+
}
425+
426+
public var debugDescription: String {
427+
return "Source tallies (\n" +
428+
"\(tallies.sorted{$0.0.rawValue < $1.0.rawValue}.map{"\t\($0.0): \($0.1)"}.joined(separator: "\n"))" +
429+
"\n)"
430+
}
431+
}

Sources/Atem/Utilities/IntOperators.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ extension UInt8 {
1414

1515
extension FixedWidthInteger {
1616
init(from slice: ArraySlice<UInt8>) {
17-
self.init(slice.withUnsafeBytes{ $0.load(as: Self.self).byteSwapped })
17+
self.init(slice.withUnsafeBufferPointer{
18+
$0.baseAddress!.withMemoryRebound(to: Self.self, capacity: 1) {$0.pointee.byteSwapped}
19+
})
1820
}
1921
}
2022

@@ -37,13 +39,24 @@ extension ArraySlice {
3739
return self[startIndex + index]
3840
}
3941

40-
subscript(relative range: CountableRange<Index>) -> SubSequence {
42+
subscript<R: AdvancableRange>(relative range: R) -> SubSequence where R.Bound == Index {
4143
return self[range.advanced(by: startIndex)]
4244
}
45+
46+
}
47+
48+
protocol AdvancableRange: RangeExpression where Bound: Strideable {
49+
func advanced(by stride: Bound.Stride) -> Self
4350
}
4451

45-
extension CountableRange {
52+
extension CountableRange: AdvancableRange {
4653
func advanced(by stride: Bound.Stride) -> CountableRange<Bound> {
4754
return CountableRange(uncheckedBounds: (lower: lowerBound.advanced(by: stride), upper: upperBound.advanced(by: stride)))
4855
}
4956
}
57+
58+
extension CountablePartialRangeFrom: AdvancableRange {
59+
func advanced(by stride: Bound.Stride) -> CountablePartialRangeFrom<Bound> {
60+
return CountablePartialRangeFrom(lowerBound.advanced(by: stride))
61+
}
62+
}

0 commit comments

Comments
 (0)