| package com.google.chip.chiptool.clusterclient |
| |
| import android.app.AlertDialog |
| import android.os.Bundle |
| import android.util.Log |
| import android.view.LayoutInflater |
| import android.view.View |
| import android.view.ViewGroup |
| import android.widget.ArrayAdapter |
| import android.widget.Button |
| import android.widget.EditText |
| import android.widget.Spinner |
| import android.widget.TextView |
| import android.widget.Toast |
| import androidx.fragment.app.Fragment |
| import androidx.lifecycle.lifecycleScope |
| import chip.devicecontroller.ChipDeviceController |
| import chip.devicecontroller.ChipIdLookup |
| import chip.devicecontroller.InvokeCallback |
| import chip.devicecontroller.ReportCallback |
| import chip.devicecontroller.ResubscriptionAttemptCallback |
| import chip.devicecontroller.SubscriptionEstablishedCallback |
| import chip.devicecontroller.WriteAttributesCallback |
| import chip.devicecontroller.model.AttributeWriteRequest |
| import chip.devicecontroller.model.ChipAttributePath |
| import chip.devicecontroller.model.ChipEventPath |
| import chip.devicecontroller.model.ChipPathId |
| import chip.devicecontroller.model.InvokeElement |
| import chip.devicecontroller.model.NodeState |
| import chip.tlv.AnonymousTag |
| import chip.tlv.ContextSpecificTag |
| import chip.tlv.TlvReader |
| import chip.tlv.TlvWriter |
| import com.google.chip.chiptool.ChipClient |
| import com.google.chip.chiptool.R |
| import com.google.chip.chiptool.databinding.WildcardFragmentBinding |
| import com.google.protobuf.ByteString |
| import java.lang.StringBuilder |
| import java.util.Optional |
| import kotlinx.coroutines.CoroutineScope |
| import kotlinx.coroutines.launch |
| import kotlin.coroutines.resume |
| import kotlin.coroutines.suspendCoroutine |
| |
| class WildcardFragment : Fragment() { |
| private var _binding: WildcardFragmentBinding? = null |
| private val binding get() = _binding!! |
| |
| private val deviceController: ChipDeviceController |
| get() = ChipClient.getDeviceController(requireContext()) |
| |
| private lateinit var scope: CoroutineScope |
| |
| private lateinit var addressUpdateFragment: AddressUpdateFragment |
| |
| private val attributePath = ArrayList<ChipAttributePath>() |
| private val eventPath = ArrayList<ChipEventPath>() |
| private val subscribeIdList = ArrayList<ULong>() |
| |
| private val reportCallback = object : ReportCallback { |
| override fun onError(attributePath: ChipAttributePath?, eventPath: ChipEventPath?, ex: Exception) { |
| if (attributePath != null) |
| { |
| Log.e(TAG, "Report error for $attributePath: $ex") |
| } |
| if (eventPath != null) |
| { |
| Log.e(TAG, "Report error for $eventPath: $ex") |
| } |
| } |
| |
| override fun onReport(nodeState: NodeState) { |
| Log.i(TAG, "Received wildcard report") |
| |
| val debugString = nodeStateToDebugString(nodeState) |
| Log.i(TAG, debugString) |
| requireActivity().runOnUiThread { binding.outputTv.text = debugString } |
| } |
| |
| override fun onDone() { |
| Log.i(TAG, "wildcard report Done") |
| } |
| } |
| |
| private val writeAttributeCallback = object : WriteAttributesCallback { |
| override fun onError(attributePath: ChipAttributePath?, ex: Exception?) { |
| Log.e(TAG, "Report error for $attributePath: $ex") |
| } |
| |
| override fun onResponse(attributePath: ChipAttributePath?) { |
| val text = "$attributePath : Write Success" |
| requireActivity().runOnUiThread { binding.outputTv.text = text } |
| } |
| |
| override fun onDone() { |
| Log.i(TAG, "write attribute Done") |
| } |
| } |
| |
| private val invokeCallback = object : InvokeCallback { |
| override fun onError(e: java.lang.Exception?) { |
| Log.e(TAG, "Report error", e) |
| } |
| |
| override fun onResponse(invokeElement: InvokeElement?, successCode: Long) { |
| val text = "Invoke Response : $invokeElement, $successCode" |
| requireActivity().runOnUiThread { binding.outputTv.text = text } |
| } |
| |
| } |
| |
| override fun onCreateView( |
| inflater: LayoutInflater, |
| container: ViewGroup?, |
| savedInstanceState: Bundle?, |
| ): View { |
| _binding = WildcardFragmentBinding.inflate(inflater, container, false) |
| scope = viewLifecycleOwner.lifecycleScope |
| |
| binding.selectTypeRadioGroup.setOnCheckedChangeListener { _, i -> |
| val readBtnOn = (i == R.id.readRadioBtn) |
| val subscribeBtnOn = (i == R.id.subscribeRadioBtn) |
| val writeBtnOn = (i == R.id.writeRadioBtn) |
| val invokeBtnOn = (i == R.id.invokeRadioBtn) |
| |
| binding.addLayout.visibility = getVisibility(readBtnOn || subscribeBtnOn) |
| binding.attributeIdLabel.visibility = getVisibility(readBtnOn || subscribeBtnOn || writeBtnOn) |
| binding.attributeIdEd.visibility = getVisibility(readBtnOn || subscribeBtnOn || writeBtnOn) |
| binding.eventIdLabel.visibility = getVisibility(readBtnOn || subscribeBtnOn) |
| binding.eventIdEd.visibility = getVisibility(readBtnOn || subscribeBtnOn) |
| binding.commandIdLabel.visibility = getVisibility(invokeBtnOn) |
| binding.commandIdEd.visibility = getVisibility(invokeBtnOn) |
| binding.isUrgentLabel.visibility = getVisibility(subscribeBtnOn) |
| binding.isUrgentSp.visibility = getVisibility(subscribeBtnOn) |
| binding.shutdownSubscriptionBtn.visibility = getVisibility(subscribeBtnOn) |
| } |
| |
| binding.sendBtn.setOnClickListener { |
| if (binding.readRadioBtn.isChecked) { |
| showReadDialog() |
| } else if (binding.subscribeRadioBtn.isChecked) { |
| showSubscribeDialog() |
| } else if (binding.writeRadioBtn.isChecked) { |
| showWriteDialog() |
| } else if (binding.invokeRadioBtn.isChecked) { |
| showInvokeDialog() |
| } |
| } |
| |
| binding.shutdownSubscriptionBtn.setOnClickListener { showShutdownSubscriptionDialog() } |
| |
| binding.addAttributeBtn.setOnClickListener { addPathList(ATTRIBUTE) } |
| binding.addEventBtn.setOnClickListener { addPathList(EVENT) } |
| binding.resetBtn.setOnClickListener { resetPath() } |
| |
| addressUpdateFragment = |
| childFragmentManager.findFragmentById(R.id.addressUpdateFragment) as AddressUpdateFragment |
| |
| return binding.root |
| } |
| |
| private fun getVisibility(isShowing: Boolean) : Int { |
| return if (isShowing) { View.VISIBLE } else { View.GONE } |
| } |
| |
| private fun addPathList(type: Int) { |
| val endpointId = getChipPathIdForText(binding.endpointIdEd.text.toString()) |
| val clusterId = getChipPathIdForText(binding.clusterIdEd.text.toString()) |
| val attributeId = getChipPathIdForText(binding.attributeIdEd.text.toString()) |
| val eventId = getChipPathIdForText(binding.eventIdEd.text.toString()) |
| // Only Subscribe used |
| val isUrgent = (binding.subscribeRadioBtn.isChecked) && (binding.isUrgentSp.selectedItem.toString().toBoolean()) |
| |
| if (type == ATTRIBUTE) { |
| attributePath.add(ChipAttributePath.newInstance(endpointId, clusterId, attributeId)) |
| } else if (type == EVENT) { |
| eventPath.add(ChipEventPath.newInstance(endpointId, clusterId, eventId, isUrgent)) |
| } |
| updateAddListView() |
| } |
| |
| private fun resetPath() { |
| attributePath.clear() |
| eventPath.clear() |
| updateAddListView() |
| } |
| |
| private fun updateAddListView() { |
| val builder = StringBuilder() |
| for (attribute in attributePath) { |
| builder.append("attribute($attribute)\n") |
| } |
| for (event in eventPath) { |
| builder.append("event($event)\n") |
| } |
| binding.sendListView.text = builder.toString() |
| } |
| |
| override fun onDestroyView() { |
| super.onDestroyView() |
| _binding = null |
| } |
| |
| private fun nodeStateToDebugString(nodeState: NodeState): String { |
| val stringBuilder = StringBuilder() |
| nodeState.endpointStates.forEach { (endpointId, endpointState) -> |
| stringBuilder.append("Endpoint $endpointId: {\n") |
| endpointState.clusterStates.forEach { (clusterId, clusterState) -> |
| stringBuilder.append("\t${ChipIdLookup.clusterIdToName(clusterId)}Cluster: {\n") |
| clusterState.attributeStates.forEach { (attributeId, attributeState) -> |
| val attributeName = ChipIdLookup.attributeIdToName(clusterId, attributeId) |
| stringBuilder.append("\t\t$attributeName: ${attributeState.value}\n") |
| } |
| clusterState.eventStates.forEach { (eventId, events) -> |
| for (event in events) |
| { |
| stringBuilder.append("\t\teventNumber: ${event.eventNumber}\n") |
| stringBuilder.append("\t\tpriorityLevel: ${event.priorityLevel}\n") |
| stringBuilder.append("\t\tsystemTimeStamp: ${event.systemTimeStamp}\n") |
| |
| val eventName = ChipIdLookup.eventIdToName(clusterId, eventId) |
| stringBuilder.append("\t\t$eventName: ${event.value}\n") |
| } |
| } |
| stringBuilder.append("\t}\n") |
| } |
| stringBuilder.append("}\n") |
| } |
| return stringBuilder.toString() |
| } |
| |
| private suspend fun subscribe(minInterval: Int, maxInterval: Int, keepSubscriptions: Boolean, isFabricFiltered: Boolean, eventMin: Long?) { |
| val subscriptionEstablishedCallback = |
| SubscriptionEstablishedCallback { |
| subscriptionId -> |
| Log.i(TAG, "Subscription to device established : ${subscriptionId.toULong()}") |
| subscribeIdList.add(subscriptionId.toULong()) |
| requireActivity().runOnUiThread { |
| Toast.makeText(requireActivity(), "${getString(R.string.wildcard_subscribe_established_toast_message)} : $subscriptionId", Toast.LENGTH_SHORT).show() |
| } |
| } |
| |
| val resubscriptionAttemptCallback = |
| ResubscriptionAttemptCallback { terminationCause, nextResubscribeIntervalMsec |
| -> Log.i(TAG, "ResubscriptionAttempt terminationCause:$terminationCause, nextResubscribeIntervalMsec:$nextResubscribeIntervalMsec") } |
| |
| deviceController.subscribeToPath(subscriptionEstablishedCallback, |
| resubscriptionAttemptCallback, |
| reportCallback, |
| ChipClient.getConnectedDevicePointer(requireContext(), |
| addressUpdateFragment.deviceId), |
| attributePath.ifEmpty { null }, |
| eventPath.ifEmpty { null }, |
| minInterval, |
| maxInterval, |
| keepSubscriptions, |
| isFabricFiltered, |
| /* imTimeoutMs= */ 0, |
| eventMin) |
| } |
| |
| private suspend fun read(isFabricFiltered: Boolean, eventMin: Long?) { |
| deviceController.readPath(reportCallback, |
| ChipClient.getConnectedDevicePointer(requireContext(), |
| addressUpdateFragment.deviceId), |
| attributePath.ifEmpty { null }, |
| eventPath.ifEmpty { null }, |
| isFabricFiltered, |
| /* imTimeoutMs= */ 0, |
| eventMin) |
| } |
| |
| private suspend fun write(writeValueType: String, writeValue: String, dataVersion: Int?, timedRequestTimeoutMs: Int, imTimeoutMs: Int) { |
| val endpointId = getChipPathIdForText(binding.endpointIdEd.text.toString()) |
| val clusterId = getChipPathIdForText(binding.clusterIdEd.text.toString()) |
| val attributeId = getChipPathIdForText(binding.attributeIdEd.text.toString()) |
| val tlvWriter = TlvWriter() |
| val values = writeValue.split(",") |
| |
| if (values.size > 1) tlvWriter.startArray(AnonymousTag) |
| for (value in values) { |
| try { |
| TLV_MAP[writeValueType]?.generate(tlvWriter, value.trim()) |
| } catch (ex: Exception) { |
| Log.e(TAG, "Invalid Data Type", ex) |
| return |
| } |
| } |
| if (values.size > 1) tlvWriter.endArray() |
| |
| val version = if (dataVersion == null) { Optional.empty() } else { Optional.of(dataVersion) } |
| |
| val writeRequest = AttributeWriteRequest.newInstance(endpointId, clusterId, attributeId, tlvWriter.getEncoded(), version) |
| deviceController.write(writeAttributeCallback, |
| ChipClient.getConnectedDevicePointer(requireContext(), |
| addressUpdateFragment.deviceId), |
| listOf(writeRequest), |
| timedRequestTimeoutMs, |
| imTimeoutMs) |
| } |
| |
| private suspend fun invoke(invokeField: String, timedRequestTimeoutMs: Int, imTimeoutMs: Int) { |
| val endpointId = getChipPathIdForText(binding.endpointIdEd.text.toString()) |
| val clusterId = getChipPathIdForText(binding.clusterIdEd.text.toString()) |
| val commandId = getChipPathIdForText(binding.commandIdEd.text.toString()) |
| |
| val tlvWriter = TlvWriter() |
| val fields = if (invokeField.isEmpty()) { listOf() } else { invokeField.split(",") } |
| var count = 0 |
| tlvWriter.startStructure(AnonymousTag) |
| for (field in fields) { |
| try { |
| val type = field.split(":")[0] |
| val value = field.split(":")[1] |
| |
| Log.d(TAG, "value : $type - $value") |
| TLV_MAP[type]?.generate(tlvWriter, value.trim(), ContextSpecificTag(count++)) |
| } catch (ex: Exception) { |
| Log.e(TAG, "Invalid value", ex) |
| return |
| } |
| } |
| tlvWriter.endStructure() |
| val invokeElement = InvokeElement.newInstance(endpointId, clusterId, commandId, tlvWriter.getEncoded(), null) |
| deviceController.invoke(invokeCallback, |
| ChipClient.getConnectedDevicePointer(requireContext(), |
| addressUpdateFragment.deviceId), |
| invokeElement, |
| timedRequestTimeoutMs, |
| imTimeoutMs) |
| } |
| |
| private fun showReadDialog() { |
| if (attributePath.isEmpty() && eventPath.isEmpty()) { |
| requireActivity().runOnUiThread { |
| Toast.makeText(requireActivity(), R.string.wildcard_empty_error_toast_message, Toast.LENGTH_SHORT).show() |
| } |
| return |
| } |
| val dialogView = requireActivity().layoutInflater.inflate(R.layout.read_dialog, null) |
| val eventMinEd = dialogView.findViewById<EditText>(R.id.eventMinEd) |
| eventMinEd.visibility = if (eventPath.isNotEmpty()) { View.VISIBLE } else { View.GONE } |
| val dialog = AlertDialog.Builder(requireContext()).apply { |
| setView(dialogView) |
| }.create() |
| |
| val isFabricFilteredEd = dialogView.findViewById<Spinner>(R.id.isFabricFilteredSp) |
| dialogView.findViewById<Button>(R.id.readBtn).setOnClickListener { |
| scope.launch { |
| var eventMin : Long? = null |
| if (eventPath.isNotEmpty() && eventMinEd.text.isNotBlank()) { |
| eventMin = eventMinEd.text.toString().toULong().toLong() |
| } |
| read(isFabricFilteredEd.selectedItem.toString().toBoolean(), eventMin) |
| requireActivity().runOnUiThread { dialog.dismiss() } |
| } |
| } |
| dialog.show() |
| } |
| |
| private fun showWriteDialog() { |
| binding.outputTv.text = "" |
| val dialogView = requireActivity().layoutInflater.inflate(R.layout.write_dialog, null) |
| val writeValueTypeSp = dialogView.findViewById<Spinner>(R.id.writeValueTypeSp) |
| val spinnerAdapter = ArrayAdapter(requireActivity(), android.R.layout.simple_spinner_dropdown_item, TLV_MAP.keys.toList()) |
| writeValueTypeSp.adapter = spinnerAdapter |
| val dialog = AlertDialog.Builder(requireContext()).apply { |
| setView(dialogView) |
| }.create() |
| |
| dialogView.findViewById<Button>(R.id.writeBtn).setOnClickListener { |
| val writeValue = dialogView.findViewById<EditText>(R.id.writeValueEd).text.toString() |
| val dataVersion = dialogView.findViewById<EditText>(R.id.dataVersionEd).text.toString() |
| val timedRequestTimeoutMs = dialogView.findViewById<EditText>(R.id.timedRequestTimeoutEd).text.toString() |
| val imTimeout = dialogView.findViewById<EditText>(R.id.imTimeoutEd).text.toString() |
| scope.launch { |
| write( writeValueTypeSp.selectedItem.toString(), |
| writeValue, |
| if (dataVersion.isEmpty()) { null } else { dataVersion.toInt() }, |
| if (timedRequestTimeoutMs.isEmpty()) { 0 } else { timedRequestTimeoutMs.toInt() }, |
| if (imTimeout.isEmpty()) { 0 } else { imTimeout.toInt() } ) |
| requireActivity().runOnUiThread { dialog.dismiss() } |
| } |
| } |
| dialog.show() |
| } |
| |
| private fun showSubscribeDialog() { |
| if (attributePath.isEmpty() && eventPath.isEmpty()) { |
| requireActivity().runOnUiThread { |
| Toast.makeText(requireActivity(), R.string.wildcard_empty_error_toast_message, Toast.LENGTH_SHORT).show() |
| } |
| return |
| } |
| val dialogView = requireActivity().layoutInflater.inflate(R.layout.subscribe_dialog, null) |
| val eventMinEd = dialogView.findViewById<EditText>(R.id.eventMinEd) |
| eventMinEd.visibility = if (eventPath.isNotEmpty()) { View.VISIBLE } else { View.GONE } |
| val dialog = AlertDialog.Builder(requireContext()).apply { |
| setView(dialogView) |
| }.create() |
| |
| val minIntervalEd = dialogView.findViewById<EditText>(R.id.minIntervalEd) |
| val maxIntervalEd = dialogView.findViewById<EditText>(R.id.maxIntervalEd) |
| val keepSubscriptionsSp = dialogView.findViewById<Spinner>(R.id.keepSubscriptionsSp) |
| val isFabricFilteredSp = dialogView.findViewById<Spinner>(R.id.isFabricFilteredSp) |
| dialogView.findViewById<Button>(R.id.subscribeBtn).setOnClickListener { |
| scope.launch { |
| if(minIntervalEd.text.isNotBlank() && maxIntervalEd.text.isNotBlank()) { |
| var eventMin : Long? = null |
| if (eventPath.isNotEmpty() && eventMinEd.text.isNotBlank()) { |
| eventMin = eventMinEd.text.toString().toULong().toLong() |
| } |
| subscribe( |
| minIntervalEd.text.toString().toInt(), |
| maxIntervalEd.text.toString().toInt(), |
| keepSubscriptionsSp.selectedItem.toString().toBoolean(), |
| isFabricFilteredSp.selectedItem.toString().toBoolean(), |
| eventMin, |
| ) |
| } else { |
| Log.e(TAG, "minInterval or maxInterval is empty!" ) |
| } |
| requireActivity().runOnUiThread { dialog.dismiss() } |
| } |
| } |
| dialog.show() |
| } |
| |
| private fun showInvokeDialog() { |
| binding.outputTv.text = "" |
| val dialogView = requireActivity().layoutInflater.inflate(R.layout.invoke_dialog, null) |
| val invokeValueEd = dialogView.findViewById<EditText>(R.id.invokeValueEd) |
| val dialog = AlertDialog.Builder(requireContext()).apply { |
| setView(dialogView) |
| }.create() |
| |
| dialogView.findViewById<Button>(R.id.invokeBtn).setOnClickListener { |
| val invokeValue = invokeValueEd.text.toString() |
| val timedRequestTimeoutMs = dialogView.findViewById<EditText>(R.id.timedRequestTimeoutEd).text.toString() |
| val imTimeout = dialogView.findViewById<EditText>(R.id.imTimeoutEd).text.toString() |
| scope.launch { |
| invoke(invokeValue, |
| if (timedRequestTimeoutMs.isEmpty()) { 0 } else { timedRequestTimeoutMs.toInt() }, |
| if (imTimeout.isEmpty()) { 0 } else { imTimeout.toInt() } ) |
| requireActivity().runOnUiThread { dialog.dismiss() } |
| } |
| } |
| dialog.show() |
| } |
| |
| private suspend fun readCurrentFabricIndex() : UInt { |
| val context = requireContext() |
| val endpointId = 0 |
| val clusterId = 62L // OperationalCredentials |
| val attributeId = 5L // CurrentFabricIndex |
| val deviceId = addressUpdateFragment.deviceId |
| val devicePointer = ChipClient.getConnectedDevicePointer(context, deviceId) |
| return suspendCoroutine { cont -> |
| deviceController.readAttributePath(object : ReportCallback { |
| override fun onError(attributePath: ChipAttributePath?, eventPath: ChipEventPath?, e: java.lang.Exception) { |
| cont.resume(0u) |
| } |
| |
| override fun onReport(nodeState: NodeState?) { |
| val state = nodeState?.getEndpointState(endpointId.toInt())?. |
| getClusterState(clusterId)?. |
| getAttributeState(attributeId) |
| if (state == null) { |
| cont.resume(0u) |
| return |
| } |
| val ret = TlvReader(state.tlv).getUInt(AnonymousTag) |
| cont.resume(ret) |
| } |
| }, devicePointer, |
| listOf(ChipAttributePath.newInstance(endpointId, clusterId, attributeId)), |
| 0 /* imTimeoutMs */ |
| ) |
| } |
| } |
| |
| private fun shutdownSubscription(fabricIndex: UInt, subscribeId: ULong? = null) { |
| val deviceId = addressUpdateFragment.deviceId |
| if (subscribeId != null) { |
| deviceController.shutdownSubscriptions(fabricIndex.toInt(), deviceId, subscribeId.toLong()) |
| subscribeIdList.remove(subscribeId) |
| } else { |
| deviceController.shutdownSubscriptions(fabricIndex.toInt(), deviceId) |
| } |
| } |
| |
| private fun showShutdownSubscriptionDialog() { |
| val dialogView = requireActivity().layoutInflater.inflate(R.layout.shutdown_subscribe_dialog, null) |
| val subscriptionIdSp = dialogView.findViewById<Spinner>(R.id.subscribeIdSp) |
| val fabricIndexTv = dialogView.findViewById<TextView>(R.id.fabricIndexValue) |
| val shutdownBtn = dialogView.findViewById<Button>(R.id.shutdownBtn) |
| val shutdownAllBtn = dialogView.findViewById<Button>(R.id.shutdownAllBtn) |
| val spinnerAdapter = ArrayAdapter(requireActivity(), android.R.layout.simple_spinner_dropdown_item, subscribeIdList) |
| subscriptionIdSp.adapter = spinnerAdapter |
| val dialog = AlertDialog.Builder(requireContext()).apply { |
| setView(dialogView) |
| }.create() |
| |
| shutdownBtn.setOnClickListener { |
| val fabricIndex = fabricIndexTv.text.toString().toUInt() |
| val subscribeId = subscriptionIdSp.selectedItem.toString().toULong() |
| scope.launch { |
| shutdownSubscription(fabricIndex, subscribeId) |
| requireActivity().runOnUiThread { dialog.dismiss() } |
| } |
| } |
| |
| shutdownAllBtn.setOnClickListener { |
| scope.launch { |
| val fabricIndex = fabricIndexTv.text.toString().toUInt() |
| shutdownSubscription(fabricIndex) |
| requireActivity().runOnUiThread { dialog.dismiss() } |
| } |
| } |
| dialog.show() |
| |
| scope.launch { |
| val fabricIndex = readCurrentFabricIndex() |
| requireActivity().runOnUiThread { |
| fabricIndexTv.text = fabricIndex.toString() |
| shutdownBtn.isEnabled = true |
| shutdownAllBtn.isEnabled = true |
| } |
| } |
| } |
| |
| private fun getChipPathIdForText(text: String): ChipPathId { |
| return if (text.isEmpty()) ChipPathId.forWildcard() else ChipPathId.forId(text.toLong()) |
| } |
| |
| interface TlvWriterInterface { |
| fun generate(writer : TlvWriter, value: String, tag: chip.tlv.Tag = AnonymousTag) |
| } |
| |
| companion object { |
| private const val TAG = "WildcardFragment" |
| private const val ATTRIBUTE = 1 |
| private const val EVENT = 2 |
| fun newInstance(): WildcardFragment = WildcardFragment() |
| |
| private val TLV_MAP = mapOf( |
| "UnsignedInt" to object:TlvWriterInterface { |
| override fun generate(writer : TlvWriter, value: String, tag: chip.tlv.Tag) { |
| writer.put(tag, value.toULong()) |
| } |
| }, |
| "Int" to object:TlvWriterInterface { |
| override fun generate(writer : TlvWriter, value: String, tag: chip.tlv.Tag) { |
| writer.put(tag, value.toLong()) |
| } |
| }, |
| "Boolean" to object:TlvWriterInterface { |
| override fun generate(writer : TlvWriter, value: String, tag: chip.tlv.Tag) { |
| writer.put(tag, value.toBoolean()) |
| } |
| }, |
| "Float" to object:TlvWriterInterface { |
| override fun generate(writer : TlvWriter, value: String, tag: chip.tlv.Tag) { |
| writer.put(tag, value.toFloat()) |
| } |
| }, |
| "Double" to object:TlvWriterInterface { |
| override fun generate(writer : TlvWriter, value: String, tag: chip.tlv.Tag) { |
| writer.put(tag, value.toDouble()) |
| } |
| }, |
| "String" to object:TlvWriterInterface { |
| override fun generate(writer : TlvWriter, value: String, tag: chip.tlv.Tag) { |
| writer.put(tag, value) |
| } |
| }, |
| "ByteArray(Hex)" to object:TlvWriterInterface { |
| override fun generate(writer : TlvWriter, value: String, tag: chip.tlv.Tag) { |
| writer.put(tag, value.chunked(2).map { it.toInt(16) and 0xFF }.map { it.toByte() }.toByteArray()) |
| } |
| }, |
| ) |
| } |
| } |