blob: 18fee6db1b72114dc10106c9b1772dc75bf88c47 [file] [log] [blame]
/*
* Copyright (c) 2023 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.matter.controller.commands.pairing
import chip.devicecontroller.ICDDeviceInfo
import com.matter.controller.commands.common.CredentialsIssuer
import com.matter.controller.commands.common.IPAddress
import com.matter.controller.commands.common.MatterCommand
import java.net.InetAddress
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicLong
import java.util.logging.Level
import java.util.logging.Logger
import matter.controller.MatterController
abstract class PairingCommand(
controller: MatterController,
commandName: String,
credsIssuer: CredentialsIssuer?,
private val pairingMode: PairingModeType = PairingModeType.NONE,
private val networkType: PairingNetworkType = PairingNetworkType.NONE,
private val filterType: DiscoveryFilterType = DiscoveryFilterType.NONE
) : MatterCommand(controller, credsIssuer, commandName), MatterController.CompletionListener {
private val remoteAddr: IPAddress = IPAddress(InetAddress.getByName("::1"))
private val nodeId = AtomicLong()
private val discoveryFilterCode = AtomicLong()
private val timeoutMillis = AtomicLong()
private val discoverOnce = AtomicBoolean()
private val useOnlyOnNetworkDiscovery = AtomicBoolean()
private val remotePort = AtomicInteger()
private val discriminator = AtomicInteger()
private val setupPINCode = AtomicLong()
private val operationalDataset = StringBuffer()
private val ssid = StringBuffer()
private val password = StringBuffer()
private val onboardingPayload = StringBuffer()
private val discoveryFilterInstanceName = StringBuffer()
init {
addArgument("node-id", 0, Long.MAX_VALUE, nodeId, null, false)
when (networkType) {
PairingNetworkType.NONE -> {}
PairingNetworkType.WIFI -> {
addArgument("ssid", ssid, null, false)
addArgument("password", password, null, false)
}
PairingNetworkType.THREAD ->
addArgument("operationalDataset", operationalDataset, null, false)
}
when (pairingMode) {
PairingModeType.NONE -> {}
PairingModeType.CODE,
PairingModeType.CODE_PASE_ONLY -> {
addArgument("payload", onboardingPayload, null, false)
addArgument("discover-once", discoverOnce, null, true)
addArgument("use-only-onnetwork-discovery", useOnlyOnNetworkDiscovery, null, true)
}
PairingModeType.ADDRESS_PASE_ONLY -> {
addArgument("setup-pin-code", 0, 134217727, setupPINCode, null, false)
addArgument("device-remote-ip", remoteAddr, false)
addArgument("device-remote-port", 0.toShort(), Short.MAX_VALUE, remotePort, null, false)
}
PairingModeType.BLE -> {
addArgument("setup-pin-code", 0, 134217727, setupPINCode, null, false)
addArgument("discriminator", 0.toShort(), 4096.toShort(), discriminator, null, false)
}
PairingModeType.ON_NETWORK ->
addArgument("setup-pin-code", 0, 134217727, setupPINCode, null, false)
PairingModeType.SOFT_AP -> {
addArgument("setup-pin-code", 0, 134217727, setupPINCode, null, false)
addArgument("discriminator", 0.toShort(), 4096.toShort(), discriminator, null, false)
addArgument("device-remote-ip", remoteAddr, false)
addArgument("device-remote-port", 0.toShort(), Short.MAX_VALUE, remotePort, null, false)
}
PairingModeType.ALREADY_DISCOVERED -> {
addArgument("setup-pin-code", 0, 134217727, setupPINCode, null, false)
addArgument("device-remote-ip", remoteAddr, false)
addArgument("device-remote-port", 0.toShort(), Short.MAX_VALUE, remotePort, null, false)
}
}
when (filterType) {
DiscoveryFilterType.NONE -> {}
DiscoveryFilterType.SHORT_DISCRIMINATOR,
DiscoveryFilterType.LONG_DISCRIMINATOR ->
addArgument("discriminator", 0.toShort(), 4096.toShort(), discriminator, null, false)
DiscoveryFilterType.VENDOR_ID ->
addArgument("vendor-id", 1.toShort(), Short.MAX_VALUE, discoveryFilterCode, null, false)
DiscoveryFilterType.COMPRESSED_FABRIC_ID ->
addArgument("fabric-id", 0L, Long.MAX_VALUE, discoveryFilterCode, null, false)
DiscoveryFilterType.COMMISSIONING_MODE,
DiscoveryFilterType.COMMISSIONER -> {}
DiscoveryFilterType.DEVICE_TYPE ->
addArgument("device-type", 0.toShort(), Short.MAX_VALUE, discoveryFilterCode, null, false)
DiscoveryFilterType.INSTANCE_NAME ->
addArgument("name", discoveryFilterInstanceName, null, false)
}
addArgument("timeout", 0L, Long.MAX_VALUE, timeoutMillis, null, false)
}
override fun onConnectDeviceComplete() {
logger.log(Level.INFO, "onConnectDeviceComplete")
}
override fun onStatusUpdate(status: Int) {
logger.log(Level.INFO, "onStatusUpdate with status: $status")
}
override fun onPairingComplete(errorCode: UInt) {
logger.log(Level.INFO, "onPairingComplete with error code: $errorCode")
if (errorCode != 0U) {
setFailure("onPairingComplete failure")
}
}
override fun onPairingDeleted(errorCode: UInt) {
logger.log(Level.INFO, "onPairingDeleted with error code: $errorCode")
}
override fun onCommissioningComplete(nodeId: Long, errorCode: UInt) {
logger.log(Level.INFO, "onCommissioningComplete with error code: $errorCode")
if (errorCode == 0U) {
setSuccess()
} else {
setFailure("onCommissioningComplete failure")
}
}
override fun onReadCommissioningInfo(
vendorId: Int,
productId: Int,
wifiEndpointId: Int,
threadEndpointId: Int
) {
logger.log(Level.INFO, "onReadCommissioningInfo")
}
override fun onCommissioningStatusUpdate(nodeId: Long, stage: String?, errorCode: UInt) {
logger.log(Level.INFO, "onCommissioningStatusUpdate")
}
override fun onNotifyChipConnectionClosed() {
logger.log(Level.INFO, "onNotifyChipConnectionClosed")
}
override fun onError(error: Throwable) {
setFailure(error.toString())
logger.log(Level.INFO, "onError with error: $error")
}
override fun onOpCSRGenerationComplete(csr: ByteArray) {
logger.log(Level.INFO, "onOpCSRGenerationComplete")
for (i in csr.indices) {
print(csr[i].toString() + " ")
}
}
override fun onICDRegistrationInfoRequired() {
logger.log(Level.INFO, "onICDRegistrationInfoRequired")
}
override fun onICDRegistrationComplete(errorCode: UInt, icdDeviceInfo: ICDDeviceInfo) {
logger.log(
Level.INFO,
"onICDRegistrationComplete with errorCode: $errorCode, symmetricKey: ${icdDeviceInfo.symmetricKey.toHex()}, icdDeviceInfo: $icdDeviceInfo"
)
}
fun getNodeId(): Long {
return nodeId.get()
}
fun getRemoteAddr(): IPAddress {
return remoteAddr
}
fun getRemotePort(): Int {
return remotePort.get()
}
fun getSetupPINCode(): Long {
return setupPINCode.get()
}
fun getDiscriminator(): Int {
return discriminator.get()
}
fun getTimeoutMillis(): Long {
return timeoutMillis.get()
}
fun getOnboardingPayload(): String {
return onboardingPayload.toString()
}
private fun ByteArray.toHex(): String =
joinToString(separator = "") { eachByte -> "%02x".format(eachByte) }
private fun String.hexToByteArray(): ByteArray {
return chunked(2).map { byteStr -> byteStr.toUByte(16).toByte() }.toByteArray()
}
fun getDiscoverOnce(): Boolean {
return discoverOnce.get()
}
fun getUseOnlyOnNetworkDiscovery(): Boolean {
return useOnlyOnNetworkDiscovery.get()
}
companion object {
private val logger = Logger.getLogger(PairingCommand::class.java.name)
}
}