Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
stonehouse committed Jul 30, 2021
0 parents commit ca898be
Show file tree
Hide file tree
Showing 47 changed files with 9,659 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.DS_Store
DerivedData
.swiftpm
Package.resolved
27 changes: 27 additions & 0 deletions LIFXProtocol.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#
# Be sure to run `pod spec lint Protocol.podspec' to ensure this is a
# valid spec and to remove all comments including this before submitting the spec.
#
# To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
# To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
#

Pod::Spec.new do |s|

s.name = "LIFXProtocol"
s.version = "1.0.0"
s.summary = "Swift implemenation of the LIFX binary protocol."

s.license = { :type => 'Proprietary', :file => 'LICENSE' }
s.homepage = "https://github.com/LIFX/protocol"
s.author = { "Alex Stonehouse" => "alexander@lifx.co" }
s.source = { :git => "https://github.com/LIFX/protocol.git", :branch => "swift" }

# Version
s.platform = :ios
s.swift_version = "5.0"
s.ios.deployment_target = "10.3"

s.source_files = "Sources/LIFXProtocol/**/*"

end
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
test:
swift test --package-path ./ --parallel --enable-test-discovery
clean:
rm -rf .swiftpm DerivedData .build
24 changes: 24 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// swift-tools-version:5.0

import PackageDescription

let package = Package(
name: "LIFX-Protocol",
products: [
.library(
name: "LIFXProtocol",
targets: ["LIFXProtocol"]),
],
dependencies: [
.package(url: "https://github.com/LIFX/swift-byte-buffer", .branch("main")),
.package(url: "https://github.com/Quick/Nimble", .upToNextMinor(from: "9.2.0")),
],
targets: [
.target(
name: "LIFXProtocol",
dependencies: ["ByteBuffer"]),
.testTarget(
name: "LIFXProtocolTests",
dependencies: ["LIFXProtocol", "Nimble"]),
]
)
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Swift Implementation of the LIFX Binary Protocol

This is the Swift implementation of the LIFX Binary Protocol, and supports serializing and deserializing all supported message types.

### Using This Library

The Messages class has simple tools for deserializing data received via the LAN.

```
let messages = Messages.read(data: data)
```

### Using with Xcode

Just open the swift folder with Xcode 11 or later and it will be handled as a SwiftPM project. The library also supports CocoaPods.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
///
/// AcknowledgementMessagetype+Init.swift
/// LIFXProtocol
///
/// - Copyright: 2021 Lifi Labs, Inc.
/// - Authors: Alexander Stonehouse
/// - Date: 27/7/21

import Foundation

extension AcknowledgementMessageType {
public init(
source: UInt32 = 2,
target: TargetType,
resRequired: Bool = false,
ackRequired: Bool = false,
sequence: UInt8 = 0
) {
let targetBytes: Data
let tagged: Bool
switch target {
case .broadcast:
tagged = true
targetBytes = Header.broadcastTarget
case .macAddress(let mac):
tagged = false
targetBytes = mac.bytes
}
do {
let header = try Header(
size: UInt16(Self.size),
tagged: tagged,
source: source,
target: targetBytes,
resRequired: resRequired,
ackRequired: ackRequired,
sequence: sequence,
type: Self.messageType.rawValue
)
self.init(header: header)
} catch let e { fatalError("Unexpected error handling target, TargetType should always be valid! \(e)") }
}
}
15 changes: 15 additions & 0 deletions Sources/LIFXProtocol/Extensions/DeviceStateService+stub.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
///
/// DeviceStateService+stub.swift
/// LIFXProtocol
///
/// - Copyright: 2021 Lifi Labs, Inc.
/// - Authors: Alexander Stonehouse
/// - Date: 27/7/21

import Foundation

extension Device.StateServiceMessage {
static func stub(for mac: MACAddress) -> Device.StateServiceMessage {
Device.StateService(service: .udp, port: 56700).toMessage(target: TargetType.macAddress(mac))
}
}
53 changes: 53 additions & 0 deletions Sources/LIFXProtocol/Extensions/Header+Init.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
///
/// Header+Init.swift
/// LIFXProtocol
///
/// - Copyright: 2021 Lifi Labs, Inc.
/// - Authors: Alexander Stonehouse
/// - Date: 27/7/21

import ByteBuffer
import Foundation

extension Header {
var source: UInt32 {
do {
var buffer = ByteBuffer(data: reserved1 + reserved2)
return try buffer.readUInt32()
} catch { return 0 }
}
public init(
size: UInt16,
addressable: Bool = true,
tagged: Bool,
source: UInt32 = 2,
target: Data,
resRequired: Bool,
ackRequired: Bool,
sequence: UInt8 = 0,
type: UInt16
) throws {
var buffer = ByteBuffer(capacity: 4)
buffer.write(uint32: source)
try self.init(
size: size,
protocol: protocolVersion,
addressable: addressable,
tagged: tagged,
origin: 0,
reserved1: Data(buffer.data[0...1]),
reserved2: Data(buffer.data[2...3]),
target: target,
reserved3: Data(count: 6),
resRequired: resRequired,
ackRequired: ackRequired,
reserved4: Data(count: 1),
reserved5: Data(count: 1),
sequence: sequence,
reserved6: Data(count: 8),
type: type,
reserved7: Data(count: 1),
reserved8: Data(count: 1)
)
}
}
63 changes: 63 additions & 0 deletions Sources/LIFXProtocol/Extensions/PayloadMessageType+Init.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
///
/// PayloadMessageType+Init.swift
/// LIFXProtocol
///
/// - Copyright: 2021 Lifi Labs, Inc.
/// - Authors: Alexander Stonehouse
/// - Date: 27/7/21

import Foundation

extension PayloadMessageType {
public init(
source: UInt32 = 2,
target: TargetType,
resRequired: Bool = false,
ackRequired: Bool = false,
sequence: UInt8 = 0,
payload: Payload
) {
let targetBytes: Data
let tagged: Bool
switch target {
case .broadcast:
tagged = true
targetBytes = Header.broadcastTarget
case .macAddress(let mac):
tagged = false
targetBytes = mac.bytes
}
do {
let header = try Header(
size: UInt16(Self.size),
tagged: tagged,
source: source,
target: targetBytes,
resRequired: resRequired,
ackRequired: ackRequired,
sequence: sequence,
type: Self.messageType.rawValue
)
self.init(header: header, payload: payload)
} catch let e { fatalError("Unexpected error handling target, TargetType should always be valid! \(e)") }
}
}

extension MessagePayload where Message.Payload == Self {
public func toMessage(
source: UInt32 = 2,
target: TargetType,
resRequired: Bool = false,
ackRequired: Bool = false,
sequence: UInt8 = 0
) -> Message {
return Message(
source: source,
target: target,
resRequired: resRequired,
ackRequired: ackRequired,
sequence: sequence,
payload: self
)
}
}
Loading

0 comments on commit ca898be

Please sign in to comment.