         rxBuffer.removeAll()
         self.waitingForReply = false
 
-        log("Received reply message id \(rm.id) --> Payload size: \(rm.data.count)")
-        let replyRequestType = self.replyRequestTypeDict[rm.id]!
-
-        switch replyRequestType {
-            case .Auth:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveAuthReply(sender: self, result: rm.result)
-            case .GetDeviceId:
+        self.onReplyCallback!(rm)
+    }
+
+
+
+    //MARK: Messages
+    func sendAuth(password: String, callback: @escaping (ControlReplyErrorType) -> ()) {
+        var requestMsgPayload = Particle_Ctrl_Mesh_AuthRequest()
+        requestMsgPayload.password = password
+
+        self.prepareRequestMessage(type: .Auth, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+
+    func sendGetDeviceId(callback: @escaping (ControlReplyErrorType, String?) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_GetDeviceIdRequest()
+
+        self.prepareRequestMessage(type: .GetDeviceId, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
                 let decodedReply = try! Particle_Ctrl_GetDeviceIdReply(serializedData: rm.data) as! Particle_Ctrl_GetDeviceIdReply
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveDeviceIdReply(sender: self, result:rm.result, deviceId: decodedReply.id)
-            case .SetClaimCode:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveSetClaimCodeReply(sender: self, result: rm.result)
-            case .GetSerialNumber:
+                callback(rm.result, decodedReply.id)
+            } else {
+                callback(.TIMEOUT, nil)
+            }
+        })
+    }
+
+
+    func sendSetClaimCode(claimCode: String, callback: @escaping (ControlReplyErrorType) -> ()) {
+        var requestMsgPayload = Particle_Ctrl_SetClaimCodeRequest()
+        requestMsgPayload.code = claimCode
+
+        self.prepareRequestMessage(type: .SetClaimCode, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+
+    func sendGetSerialNumber(callback: @escaping (ControlReplyErrorType, String?) -> ()) {
+        var requestMsgPayload = Particle_Ctrl_GetSerialNumberRequest()
+
+        self.prepareRequestMessage(type: .GetSerialNumber, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
                 let decodedReply = try! Particle_Ctrl_GetSerialNumberReply(serializedData: rm.data) as! Particle_Ctrl_GetSerialNumberReply
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveGetSerialNumberReply(sender: self, result: rm.result, serialNumber: decodedReply.serial)
-            case .GetConnectionStatus:
+                callback(rm.result, decodedReply.serial)
+            } else {
+                callback(.TIMEOUT, nil)
+            }
+        })
+    }
+
+
+    func sendGetConnectionStatus(callback: @escaping (ControlReplyErrorType, CloudConnectionStatus?) -> ()) {
+        var requestMsgPayload = Particle_Ctrl_Cloud_GetConnectionStatusRequest()
+
+        self.prepareRequestMessage(type: .GetConnectionStatus, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
                 let decodedReply = try! Particle_Ctrl_Cloud_GetConnectionStatusReply(serializedData: rm.data) as! Particle_Ctrl_Cloud_GetConnectionStatusReply
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveGetConnectionStatusReply(sender: self, result: rm.result, connectionStatus: decodedReply.status)
-            case .IsClaimed:
+                callback(rm.result, decodedReply.status)
+            } else {
+                callback(.TIMEOUT, nil)
+            }
+        })
+    }
+
+
+    func sendIsClaimed(callback: @escaping (ControlReplyErrorType, Bool?) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_IsClaimedRequest()
+
+        self.prepareRequestMessage(type: .IsClaimed, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
                 let decodedReply = try! Particle_Ctrl_IsClaimedReply(serializedData: rm.data) as! Particle_Ctrl_IsClaimedReply
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveIsClaimedReply(sender: self, result: rm.result, isClaimed: decodedReply.claimed)
-            case .CreateNetwork:
+                callback(rm.result, decodedReply.claimed)
+            } else {
+                callback(.TIMEOUT, nil)
+            }
+        })
+    }
+
+
+    func sendCreateNetwork(name: String, password: String, callback: @escaping (ControlReplyErrorType, MeshSetupNetworkInfo?) -> ()) {
+        var requestMsgPayload = Particle_Ctrl_Mesh_CreateNetworkRequest()
+        requestMsgPayload.name = name
+        requestMsgPayload.password = password
+
+        self.prepareRequestMessage(type: .CreateNetwork, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
                 let decodedReply = try! Particle_Ctrl_Mesh_CreateNetworkReply(serializedData: rm.data) as! Particle_Ctrl_Mesh_CreateNetworkReply
-                log("Received reply: \(replyRequestType)")
-                log("NetworkInfo:\nName: \(decodedReply.network.name)\nXPAN ID: \(decodedReply.network.extPanID)\nPAN ID: \(decodedReply.network.panID)\nChannel: \(decodedReply.network.channel)")
-                self.delegate.didReceiveCreateNetworkReply(sender: self, result: rm.result, networkInfo: decodedReply.network)
-            case .StartCommissioner:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveStartCommissionerReply(sender: self, result: rm.result)
-            case .StopCommissioner:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveStopCommissionerReply(sender: self, result: rm.result)
-            case .StartListening:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveStartListeningReply(sender: self, result: rm.result)
-            case .StopListening:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveStopListeningReply(sender: self, result: rm.result)
-            case .DeviceSetupDone:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveDeviceSetupDoneReply(sender: self, result: rm.result)
-            case .IsDeviceSetupDone:
+                callback(rm.result, decodedReply.network)
+            } else {
+                callback(.TIMEOUT, nil)
+            }
+        })
+    }
+
+
+    func sendStartCommissioner(callback: @escaping (ControlReplyErrorType) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_Mesh_StartCommissionerRequest()
+
+        self.prepareRequestMessage(type: .StartCommissioner, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+
+    func sendStopCommissioner(callback: @escaping (ControlReplyErrorType) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_Mesh_StopCommissionerRequest()
+
+        self.prepareRequestMessage(type: .StopCommissioner, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+
+    func sendStarListening(callback: @escaping (ControlReplyErrorType) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_StartListeningModeRequest();
+
+        self.prepareRequestMessage(type: .StartListening, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+
+    func sendStopListening(callback: @escaping (ControlReplyErrorType) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_StopListeningModeRequest();
+
+        self.prepareRequestMessage(type: .StopListening, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+
+    func sendDeviceSetupDone(callback: @escaping (ControlReplyErrorType) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_SetDeviceSetupDoneRequest();
+
+        self.prepareRequestMessage(type: .DeviceSetupDone, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+    //No documented errors
+    func sendIsDeviceSetupDone(callback: @escaping (ControlReplyErrorType, Bool?) -> Void) {
+        let requestMsgPayload = Particle_Ctrl_IsDeviceSetupDoneRequest();
+
+        self.prepareRequestMessage(type: .IsDeviceSetupDone, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
                 let decodedReply = try! Particle_Ctrl_IsDeviceSetupDoneReply(serializedData: rm.data) as! Particle_Ctrl_IsDeviceSetupDoneReply
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveIsDeviceSetupDoneReply(sender: self, result: rm.result, isDone: decodedReply.done)
-            case .PrepareJoiner:
+                callback(rm.result, decodedReply.done)
+            } else {
+                callback(.TIMEOUT, nil)
+            }
+        })
+    }
+
+    //result eui64, password
+    func sendPrepareJoiner(networkInfo: MeshSetupNetworkInfo, callback: @escaping (ControlReplyErrorType, String?, String?) -> ()) {
+        var requestMsgPayload = Particle_Ctrl_Mesh_PrepareJoinerRequest()
+        requestMsgPayload.network = networkInfo
+
+        self.prepareRequestMessage(type: .PrepareJoiner, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
                 let decodedReply = try! Particle_Ctrl_Mesh_PrepareJoinerReply(serializedData: rm.data) as! Particle_Ctrl_Mesh_PrepareJoinerReply
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceivePrepareJoinerReply(sender: self, result: rm.result, eui64: decodedReply.eui64, password: decodedReply.password)
-            case .AddJoiner:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveAddJoinerReply(sender: self, result: rm.result)
-            case .RemoveJoiner:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveRemoveJoinerReply(sender: self, result: rm.result)
-            case .JoinNetwork:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveJoinNetworkReply(sender: self, result: rm.result)
-            case .LeaveNetwork:
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveLeaveNetworkReply(sender: self, result: rm.result)
-            case .GetNetworkInfo:
+                callback(rm.result, decodedReply.eui64, decodedReply.password)
+            } else {
+                callback(.TIMEOUT, nil, nil)
+            }
+        })
+    }
+
+
+    func sendAddJoiner(eui64: String, password: String, callback: @escaping (_ result: ControlReplyErrorType) -> ()) {
+        var requestMsgPayload = Particle_Ctrl_Mesh_AddJoinerRequest()
+        requestMsgPayload.eui64 = eui64
+        requestMsgPayload.password = password
+
+        self.prepareRequestMessage(type: .AddJoiner, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+
+    func sendRemoveJoiner(eui64: String, callback: @escaping (ControlReplyErrorType) -> ()) {
+        var requestMsgPayload = Particle_Ctrl_Mesh_RemoveJoinerRequest()
+        requestMsgPayload.eui64 = eui64
+
+        self.prepareRequestMessage(type: .RemoveJoiner, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+
+    func sendJoinNetwork(callback: @escaping (ControlReplyErrorType) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_Mesh_JoinNetworkRequest()
+
+        self.prepareRequestMessage(type: .JoinNetwork, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+
+    func sendLeaveNetwork(callback: @escaping (ControlReplyErrorType) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_Mesh_LeaveNetworkRequest()
+
+        self.prepareRequestMessage(type: .LeaveNetwork, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
+                callback(rm.result)
+            } else {
+                callback(.TIMEOUT)
+            }
+        })
+    }
+
+
+    func sendGetNetworkInfo(callback: @escaping (ControlReplyErrorType, MeshSetupNetworkInfo?) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_Mesh_GetNetworkInfoRequest()
+
+        self.prepareRequestMessage(type: .GetNetworkInfo, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
                 let decodedReply = try! Particle_Ctrl_Mesh_GetNetworkInfoReply(serializedData: rm.data) as! Particle_Ctrl_Mesh_GetNetworkInfoReply
-                log("Received reply: \(replyRequestType)")
-                log("NetworkInfo:\nName: \(decodedReply.network.name)\nXPAN ID: \(decodedReply.network.extPanID)\nPAN ID: \(decodedReply.network.panID)\nChannel: \(decodedReply.network.channel)")
-                self.delegate.didReceiveGetNetworkInfoReply(sender: self, result: rm.result, networkInfo: decodedReply.network)
-            case .ScanNetworks:
+                callback(rm.result, decodedReply.network)
+            } else {
+                callback(.TIMEOUT, nil)
+            }
+        })
+    }
+
+
+    func sendScanNetworks(callback: @escaping (ControlReplyErrorType, [MeshSetupNetworkInfo]?) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_Mesh_ScanNetworksRequest()
+
+        self.prepareRequestMessage(type: .ScanNetworks, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
                 let decodedReply = try! Particle_Ctrl_Mesh_ScanNetworksReply(serializedData: rm.data) as! Particle_Ctrl_Mesh_ScanNetworksReply
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveScanNetworksReply(sender: self, result: rm.result, networks: decodedReply.networks)
-            case .GetInterfaceList:
+                callback(rm.result, decodedReply.networks)
+            } else {
+                callback(.TIMEOUT, nil)
+            }
+        })
+    }
+
+    func sendGetInterfaceList(callback: @escaping (ControlReplyErrorType, [MeshSetupNetworkInterface]?) -> ()) {
+        let requestMsgPayload = Particle_Ctrl_GetInterfaceListRequest()
+
+        self.prepareRequestMessage(type: .GetInterfaceList, payload: self.serialize(message: requestMsgPayload))
+        self.sendRequestMessage(onReply: {
+            replyMessage in
+            if let rm = replyMessage {
                 let decodedReply = try! Particle_Ctrl_GetInterfaceListReply(serializedData: rm.data) as! Particle_Ctrl_GetInterfaceListReply
-                log("Received reply: \(replyRequestType)")
-                self.delegate.didReceiveGetInterfaceListReply(sender: self, result: rm.result, networks: decodedReply.interfaces)
-
-        }
+                callback(rm.result, decodedReply.interfaces)
+            } else {
+                callback(.TIMEOUT, nil)
+            }
+        })
     }
 }


typealias MeshSetupNetworkInfo = Particle_Ctrl_Mesh_NetworkInfo
typealias CloudConnectionStatus = Particle_Ctrl_Cloud_ConnectionStatus
typealias NetworkInterface = Particle_Ctrl_InterfaceEntry

protocol MeshSetupTransceiverDelegate {
    //Optional
    func didReceiveAuthReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveDeviceIdReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, deviceId: String)
    func didReceiveSetClaimCodeReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveGetSerialNumberReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, serialNumber: String)
    func didReceiveGetConnectionStatusReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, connectionStatus: CloudConnectionStatus)
    func didReceiveIsClaimedReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, isClaimed: Bool)
    func didReceiveCreateNetworkReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, networkInfo: MeshSetupNetworkInfo)
    func didReceiveStartCommissionerReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveStopCommissionerReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveStartListeningReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveStopListeningReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveDeviceSetupDoneReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveIsDeviceSetupDoneReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, isDone: Bool)
    func didReceivePrepareJoinerReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, eui64: String, password: String)
    func didReceiveAddJoinerReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveRemoveJoinerReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveJoinNetworkReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveLeaveNetworkReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType)
    func didReceiveGetNetworkInfoReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, networkInfo: MeshSetupNetworkInfo?)
    func didReceiveScanNetworksReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, networks: [MeshSetupNetworkInfo])
    func didReceiveGetInterfaceListReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, networks: [NetworkInterface])
    
    //Non-Optional
    func didTimeoutSendingMessage(sender: MeshSetupProtocolTransceiver)
}

extension MeshSetupTransceiverDelegate {
    func didReceiveAuthReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveDeviceIdReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, deviceId: String) { fatalError("Not Implemented!") }
    func didReceiveSetClaimCodeReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveGetSerialNumberReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, serialNumber: String) { fatalError("Not Implemented!") }
    func didReceiveGetConnectionStatusReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, connectionStatus: CloudConnectionStatus)  { fatalError("Not Implemented!") }
    func didReceiveIsClaimedReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, isClaimed: Bool)  { fatalError("Not Implemented!") }
    func didReceiveCreateNetworkReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, networkInfo: MeshSetupNetworkInfo) { fatalError("Not Implemented!") }
    func didReceiveStartCommissionerReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveStopCommissionerReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveStartListeningReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveStopListeningReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveDeviceSetupDoneReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveIsDeviceSetupDoneReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, isDone: Bool) { fatalError("Not Implemented!") }
    func didReceivePrepareJoinerReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, eui64: String, password: String) { fatalError("Not Implemented!") }
    func didReceiveAddJoinerReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveRemoveJoinerReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveJoinNetworkReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveLeaveNetworkReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType) { fatalError("Not Implemented!") }
    func didReceiveGetNetworkInfoReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, networkInfo: MeshSetupNetworkInfo?) { fatalError("Not Implemented!") }
    func didReceiveScanNetworksReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, networks: [MeshSetupNetworkInfo]) { fatalError("Not Implemented!") }
    func didReceiveGetInterfaceListReply(sender: MeshSetupProtocolTransceiver, result: ControlReplyErrorType, networks: [NetworkInterface]) { fatalError("Not Implemented!") }
}

class MeshSetupProtocolTransceiver: NSObject, MeshSetupBluetoothConnectionDataDelegate {
    
    var delegate: MeshSetupTransceiverDelegate

    private var bluetoothConnection: MeshSetupBluetoothConnection
    private var encryptionManager: MeshSetupEncryptionManager

    private var requestMessageId: UInt16 = 1
    private var replyRequestTypeDict: [UInt16: ControlRequestMessageType] = [:]

    private var waitingForReply: Bool = false
    private var rxBuffer: Data = Data()
    private var txBuffer: Data!
    private var retryCount: Int = 0

    private lazy var sendTimeoutWorker: DispatchWorkItem  = DispatchWorkItem() {
        [weak self] in

        if let sSelf = self {
            sSelf.messageSendTimeout()
        }
    }


    
    required init(delegate: MeshSetupTransceiverDelegate, connection: MeshSetupBluetoothConnection) {
        self.delegate = delegate
        self.bluetoothConnection = connection
        self.encryptionManager = MeshSetupEncryptionManager(derivedSecret: bluetoothConnection.derivedSecret!)


        self.encryptionManager.encrypt(requestMsg)

        // add to state machine dict to know which type of reply to deserialize
        //self.replyRequestTypeDict[requestMsg.id] = requestMsg.type

        self.waitingForReply = true

        self.requestMessageId += 1
        if (requestMessageId >= 0xff00) {
