Skip to content

Commit

Permalink
OCA server
Browse files Browse the repository at this point in the history
  • Loading branch information
lhoward committed Jul 26, 2023
1 parent 2a19dbb commit c9c9036
Show file tree
Hide file tree
Showing 44 changed files with 2,276 additions and 335 deletions.
14 changes: 14 additions & 0 deletions .swiftformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--indent 4
--indentcase false
--trimwhitespace always
--voidtype tuple
--nospaceoperators ..<,...
--ifdef noindent
--stripunusedargs closure-only
--maxwidth 100
--wraparguments before-first
--funcattributes prev-line
--typeattributes prev-line
--varattributes prev-line
--disable andOperator
--swiftversion 5.6
21 changes: 21 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
disabled_rules:
- trailing_comma
- identifier_name
- void_return
- operator_whitespace
- nesting
- cyclomatic_complexity
- multiple_closures_with_trailing_closure
- type_name
- todo
- large_tuple
- opening_brace

line_length: 100

function_body_length:
- 50

included:
- Sources
- Tests
42 changes: 42 additions & 0 deletions Examples/OCADevice/DeviceApp.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import Foundation
import SwiftOCA
import SwiftOCADevice

private var localhost = sockaddr_in(
sin_len: UInt8(MemoryLayout<sockaddr_in>.size),
sin_family: sa_family_t(AF_INET),
sin_port: in_port_t(65000).bigEndian,
sin_addr: in_addr(s_addr: INADDR_ANY),
sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)
)

class TestActuator: SwiftOCADevice.OcaBooleanActuator {
override public func handleCommand(
_ command: Ocp1Command,
from controller: AES70OCP1Controller
) async throws -> Ocp1Response {
debugPrint("got command \(command) from controller \(controller)")
return try await super.handleCommand(command, from: controller)
}
}

@main
public enum DeviceApp {
static var testActuator: SwiftOCADevice.OcaBooleanActuator?

public static func main() async throws {
var device: AES70OCP1Device!

withUnsafePointer(to: &localhost) {
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) { cSockAddr in
device = AES70OCP1Device(address: cSockAddr)
}
}

testActuator = try await SwiftOCADevice.OcaBooleanActuator(
role: "Test Actuator",
deviceDelegate: device
)
try await device.start()
}
}
15 changes: 15 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ let package = Package(
.package(url: "https://github.com/PADL/swift-binary-coder", branch: "inferno"),
.package(url: "https://github.com/lhoward/AsyncExtensions", branch: "linux"),
.package(url: "https://github.com/OpenCombine/OpenCombine.git", from: "0.14.0"),
.package(url: "https://github.com/swhitty/FlyingFox", branch: "main"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a
Expand All @@ -40,6 +41,20 @@ let package = Package(
.product(name: "FlyingSocks", package: "FlyingFox"),
]
),
.target(
name: "SwiftOCADevice",
dependencies: [
"SwiftOCA",
.product(name: "FlyingSocks", package: "FlyingFox"),
]
),
.executableTarget(
name: "OCADevice",
dependencies: [
"SwiftOCADevice",
],
path: "Examples/OCADevice"
),
],
swiftLanguageVersions: [.v5]
)
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ private extension Ocp1Message {
}
}

extension AES70OCP1Connection {
func encodeOcp1MessagePdu(
public extension AES70OCP1Connection {
static func encodeOcp1MessagePdu(
_ messages: [Ocp1Message],
type messageType: OcaMessageType
) throws -> Data {
Expand All @@ -54,10 +54,11 @@ extension AES70OCP1Connection {
messagePduData.encodeInteger(OcaUint32(messagePduData.count - 1), index: 3)
return messagePduData
}
}

extension AES70OCP1Connection.Monitor {
func decodeOcp1MessagePdu(from data: Data, messages: inout [Data]) throws -> OcaMessageType {
static func decodeOcp1MessagePdu(
from data: Data,
messages: inout [Data]
) throws -> OcaMessageType {
precondition(data.count >= Self.MinimumPduSize)
precondition(data[0] == Ocp1SyncValue)

Expand Down Expand Up @@ -116,7 +117,7 @@ extension AES70OCP1Connection.Monitor {
return messageType
}

func decodeOcp1Message(
nonisolated static func decodeOcp1Message(
from messageData: Data,
type messageType: OcaMessageType
) throws -> Ocp1Message {
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftOCA/AES70/AES70OCP1Connection+Messages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extension AES70OCP1Connection {
_ messages: [Ocp1Message],
type messageType: OcaMessageType
) async throws {
let messagePduData = try encodeOcp1MessagePdu(messages, type: messageType)
let messagePduData = try Self.encodeOcp1MessagePdu(messages, type: messageType)

do {
guard try await write(messagePduData) == messagePduData.count else {
Expand Down
4 changes: 2 additions & 2 deletions Sources/SwiftOCA/AES70/AES70OCP1Connection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public struct AES70OCP1ConnectionOptions {

@MainActor
public class AES70OCP1Connection: CustomStringConvertible, ObservableObject {
public static let MinimumPduSize = 7

let options: AES70OCP1ConnectionOptions

/// Keepalive/ping interval (only necessary for UDP)
Expand Down Expand Up @@ -86,8 +88,6 @@ public class AES70OCP1Connection: CustomStringConvertible, ObservableObject {

/// Monitor structure for matching requests and responses
actor Monitor {
static let MinimumPduSize = 7

private let connection: AES70OCP1Connection!
typealias Continuation = CheckedContinuation<Ocp1Response, Error>
private var continuations = [OcaUint32: Continuation]()
Expand Down
16 changes: 10 additions & 6 deletions Sources/SwiftOCA/AES70/AES70OCP1ConnectionMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ extension AES70OCP1Connection.Monitor {
_ connection: AES70OCP1Connection,
messages: inout [Data]
) async throws -> OcaMessageType {
var messagePduData = try await connection.read(Self.MinimumPduSize)
var messagePduData = try await connection.read(AES70OCP1Connection.MinimumPduSize)

/// just parse enough of the protocol in order to read rest of message
/// `syncVal: OcaUint8` || `protocolVersion: OcaUint16` || `pduSize: OcaUint32`
guard messagePduData.count >= Self.MinimumPduSize else {
guard messagePduData.count >= AES70OCP1Connection.MinimumPduSize else {
debugPrint("receiveMessagePdu: PDU of size \(messagePduData.count) is too short")
throw Ocp1Error.pduTooShort
}
Expand All @@ -39,17 +39,21 @@ extension AES70OCP1Connection.Monitor {
}

let pduSize: OcaUint32 = messagePduData.decodeInteger(index: 3)
guard pduSize >= (Self.MinimumPduSize - 1) else { // doesn't include sync byte
guard pduSize >= (AES70OCP1Connection.MinimumPduSize - 1)
else { // doesn't include sync byte
debugPrint("receiveMessagePdu: PDU size \(pduSize) is less than minimum PDU size")
throw Ocp1Error.invalidPduSize
}

let bytesLeft = Int(pduSize) - (Self.MinimumPduSize - 1)
let bytesLeft = Int(pduSize) - (AES70OCP1Connection.MinimumPduSize - 1)
if bytesLeft > 0 {
messagePduData += try await connection.read(bytesLeft)
}

return try decodeOcp1MessagePdu(from: messagePduData, messages: &messages)
return try await AES70OCP1Connection.decodeOcp1MessagePdu(
from: messagePduData,
messages: &messages
)
}

private func processMessage(
Expand Down Expand Up @@ -83,7 +87,7 @@ extension AES70OCP1Connection.Monitor {
var messagePdus = [Data]()
let messageType = try await receiveMessagePdu(connection, messages: &messagePdus)
let messages = try messagePdus.map {
try decodeOcp1Message(from: $0, type: messageType)
try AES70OCP1Connection.decodeOcp1Message(from: $0, type: messageType)
}

updateLastMessageReceivedTime()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import BinaryCoder
import Foundation

extension BinaryCodingConfiguration {
public extension BinaryCodingConfiguration {
static var ocp1Configuration: Self {
BinaryCodingConfiguration(
endianness: .bigEndian,
Expand Down
Loading

0 comments on commit c9c9036

Please sign in to comment.