Skip to content

Commit

Permalink
Support for sending unacknowledged config messages
Browse files Browse the repository at this point in the history
  • Loading branch information
philips77 committed Jun 22, 2023
1 parent 67b1256 commit d220b41
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 1 deletion.
2 changes: 1 addition & 1 deletion nRFMeshProvision/Layers/Access Layer/AccessLayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ internal class AccessLayer {
/// - initialTtl: The initial TTL (Time To Live) value of the message.
/// If `nil`, the default Node TTL will be used.
/// - completion: The completion handler with the response.
func send(_ message: AcknowledgedConfigMessage,
func send(_ message: ConfigMessage,
from element: Element, to destination: Address,
withTtl initialTtl: UInt8?) {
guard let node = meshNetwork.node(withAddress: destination),
Expand Down
37 changes: 37 additions & 0 deletions nRFMeshProvision/Layers/NetworkManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,43 @@ internal class NetworkManager {
retransmit: false)
}

/// Encrypts the message with the Device Key and the first Network Key
/// known to the target device, and sends to the given destination address.
///
/// The ``ConfigNetKeyDelete`` will be signed with a different Network Key
/// that is removing.
///
/// This method does not send nor return PDUs to be sent. Instead,
/// for each created segment it calls transmitter's ``Transmitter/send(_:ofType:)``
/// method, which should send the PDU over the air. This is in order to support
/// retransmission in case a packet was lost and needs to be sent again
/// after block acknowledgment was received.
///
/// - parameters:
/// - configMessage: The message to be sent.
/// - element: The source Element.
/// - destination: The destination address.
/// - initialTtl: The initial TTL (Time To Live) value of the message.
/// If `nil`, the default Node TTL will be used.
/// - completion: The completion handler called when the message was sent.
func send(_ configMessage: UnacknowledgedConfigMessage,
from element: Element, to destination: Address,
withTtl initialTtl: UInt8?,
completion: ((Result<Void, Error>) -> ())?) {
mutex.sync {
guard !outgoingMessages.contains(destination) else {
completion?(.failure(AccessError.busy))
return
}
outgoingMessages.insert(destination)
if let completion = completion {
deliveryCallbacks[destination] = completion
}
}
accessLayer.send(configMessage, from: element, to: destination,
withTtl: initialTtl)
}

/// Encrypts the message with the Device Key and the first Network Key
/// known to the target device, and sends to the given destination address.
///
Expand Down
91 changes: 91 additions & 0 deletions nRFMeshProvision/MeshNetworkManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,97 @@ public extension MeshNetworkManager {
withTtl: initialTtl, completion: completion)
}

/// Sends Configuration Message to the Node with given destination Address.
///
/// The `destination` must be a Unicast Address, otherwise the method
/// throws an ``AccessError/invalidDestination`` error.
///
/// An appropriate callback of the ``MeshNetworkDelegate`` will be called when
/// the message has been sent successfully or a problem occured.
///
/// - parameters:
/// - message: The message to be sent.
/// - destination: The destination Unicast Address.
/// - initialTtl: The initial TTL (Time To Live) value of the message.
/// If `nil`, the default Node TTL will be used.
/// - completion: The completion handler called when the message
/// has been sent.
/// - throws: This method throws when the mesh network has not been created,
/// the local Node does not have configuration capabilities
/// (no Unicast Address assigned), or the destination address
/// is not a Unicast Address or it belongs to an unknown Node.
/// Error ``AccessError/cannotDelete`` is sent when trying to
/// delete the last Network Key on the device.
/// - returns: Message handle that can be used to cancel sending.
@discardableResult
func send(_ message: UnacknowledgedConfigMessage, to destination: Address,
withTtl initialTtl: UInt8? = nil,
completion: ((Result<Void, Error>) -> ())? = nil) throws -> MessageHandle {
guard let networkManager = networkManager,
let meshNetwork = meshNetwork else {
print("Error: Mesh Network not created")
throw MeshNetworkError.noNetwork
}
guard let localProvisioner = meshNetwork.localProvisioner,
let element = localProvisioner.node?.primaryElement else {
print("Error: Local Provisioner has no Unicast Address assigned")
throw AccessError.invalidSource
}
guard destination.isUnicast else {
print("Error: Address: 0x\(destination.hex) is not a Unicast Address")
throw AccessError.invalidDestination
}
guard let node = meshNetwork.node(withAddress: destination) else {
print("Error: Unknown destination Node")
throw AccessError.invalidDestination
}
guard let _ = node.networkKeys.first else {
print("Fatal Error: The target Node does not have Network Key")
throw AccessError.invalidDestination
}
guard let _ = node.deviceKey else {
print("Error: Node's Device Key is unknown")
throw AccessError.noDeviceKey
}
guard initialTtl == nil || initialTtl! <= 127 else {
print("Error: TTL value \(initialTtl!) is invalid")
throw AccessError.invalidTtl
}
queue.async {
networkManager.send(message, from: element, to: destination,
withTtl: initialTtl, completion: completion)
}
return MessageHandle(for: message, sentFrom: element.unicastAddress,
to: destination, using: networkManager)
}

/// Sends a Configuration Message to the primary Element on the given ``Node``.
///
/// An appropriate callback of the ``MeshNetworkDelegate`` will be called when
/// the message has been sent successfully or a problem occured.
///
/// - parameters:
/// - message: The message to be sent.
/// - node: The destination Node.
/// - initialTtl: The initial TTL (Time To Live) value of the message.
/// If `nil`, the default Node TTL will be used.
/// - completion: The completion handler which is called when the response
/// has been received.
/// - throws: This method throws when the mesh network has not been created,
/// the local Node does not have configuration capabilities
/// (no Unicast Address assigned), or the destination address
/// is not a Unicast Address or it belongs to an unknown Node.
/// Error ``AccessError/cannotDelete`` is sent when trying to
/// delete the last Network Key on the device.
/// - returns: Message handle that can be used to cancel sending.
@discardableResult
func send(_ message: UnacknowledgedConfigMessage, to node: Node,
withTtl initialTtl: UInt8? = nil,
completion: ((Result<Void, Error>) -> ())? = nil) throws -> MessageHandle {
return try send(message, to: node.primaryUnicastAddress,
withTtl: initialTtl, completion: completion)
}

/// Sends Configuration Message to the Node with given destination Address.
///
/// The `destination` must be a Unicast Address, otherwise the method
Expand Down

0 comments on commit d220b41

Please sign in to comment.