From 5ec9694a7d77cb536b92c334f76a30bd983466a4 Mon Sep 17 00:00:00 2001 From: Joonhaeng Heo Date: Mon, 21 Aug 2023 14:27:49 +0900 Subject: [PATCH 01/10] Support JSON in Android ChipTool --- .../clusterclient/BasicClientFragment.kt | 17 +- .../clusterclient/MultiAdminClientFragment.kt | 8 +- .../clusterclient/OnOffClientFragment.kt | 11 +- .../clusterclient/OpCredClientFragment.kt | 38 +--- .../clusterclient/SensorClientFragment.kt | 5 +- .../clusterclient/WildcardFragment.kt | 84 ++++---- .../google/chip/chiptool/util/TlvParseUtil.kt | 86 -------- .../java/src/chip/jsontlv/JsonToTlv.kt | 17 +- .../java/src/chip/jsontlv/TlvToJson.kt | 31 +++ src/controller/java/src/chip/tlv/values.kt | 16 ++ .../tests/chip/jsontlv/JsonToTlvToJsonTest.kt | 200 +++++++++++++++++- 11 files changed, 320 insertions(+), 193 deletions(-) delete mode 100644 examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvParseUtil.kt diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt index 4d19a56c10c5c5..26552b8f8c34f8 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt @@ -17,11 +17,14 @@ import chip.devicecontroller.model.AttributeWriteRequest import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.NodeState +import chip.jsontlv.toAny +import chip.tlv.AnonymousTag +import chip.tlv.TlvReader +import chip.tlv.TlvWriter import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R import com.google.chip.chiptool.databinding.BasicClientFragmentBinding -import com.google.chip.chiptool.util.TlvParseUtil import java.util.Optional import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch @@ -55,7 +58,7 @@ class BasicClientFragment : Fragment() { // TODO : Need to be implement poj-to-tlv sendWriteAttribute( BasicInformation.Attribute.NodeLabel, - TlvParseUtil.encode(binding.nodeLabelEd.text.toString()) + TlvWriter().put(AnonymousTag, binding.nodeLabelEd.text.toString()).getEncoded() ) binding.nodeLabelEd.onEditorAction(EditorInfo.IME_ACTION_DONE) } @@ -65,7 +68,7 @@ class BasicClientFragment : Fragment() { // TODO : Need to be implement poj-to-tlv sendWriteAttribute( BasicInformation.Attribute.Location, - TlvParseUtil.encode(binding.locationEd.text.toString()) + TlvWriter().put(AnonymousTag, binding.locationEd.text.toString()).getEncoded() ) binding.locationEd.onEditorAction(EditorInfo.IME_ACTION_DONE) } @@ -75,7 +78,7 @@ class BasicClientFragment : Fragment() { // TODO : Need to be implement poj-to-tlv sendWriteAttribute( BasicInformation.Attribute.LocalConfigDisabled, - TlvParseUtil.encode(isChecked) + TlvWriter().put(AnonymousTag, isChecked).getEncoded() ) } } @@ -150,13 +153,13 @@ class BasicClientFragment : Fragment() { } override fun onReport(nodeState: NodeState?) { - val value = + val tlv = nodeState ?.getEndpointState(endpointId) ?.getClusterState(clusterId) ?.getAttributeState(attributeId) - ?.value - ?: "null" + ?.tlv + val value = tlv?.let { TlvReader(it).toAny() } Log.i(TAG, "[Read Success] $attributeName: $value") showMessage("[Read Success] $attributeName: $value") } diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt index 4df9d2a1a1d230..3004d883d10894 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt @@ -16,7 +16,9 @@ import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.InvokeElement import chip.devicecontroller.model.NodeState +import chip.jsontlv.toAny import chip.tlv.AnonymousTag +import chip.tlv.TlvReader import chip.tlv.TlvWriter import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener @@ -209,13 +211,13 @@ class MultiAdminClientFragment : Fragment() { deviceController.readAttributePath( object : ReportCallback { override fun onReport(nodeState: NodeState?) { - val value = + val tlv = nodeState ?.getEndpointState(endpointId) ?.getClusterState(clusterId) ?.getAttributeState(attributeId) - ?.value - ?: "null" + ?.tlv + val value = tlv?.let { TlvReader(it).toAny() } Log.i(TAG, "read $attributeName: $value") showMessage("read $attributeName: $value") } diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt index b4bc72c103c986..464b708e7d9621 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt @@ -22,14 +22,15 @@ import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.InvokeElement import chip.devicecontroller.model.NodeState +import chip.jsontlv.toAny 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.GenericChipDeviceListener import com.google.chip.chiptool.R import com.google.chip.chiptool.databinding.OnOffClientFragmentBinding -import com.google.chip.chiptool.util.TlvParseUtil import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale @@ -116,13 +117,13 @@ class OnOffClientFragment : Fragment() { } override fun onReport(nodeState: NodeState?) { - val value = + val tlv = nodeState ?.getEndpointState(endpointId) ?.getClusterState(clusterId) ?.getAttributeState(attributeId) - ?.value - ?: "null" + ?.tlv + val value = tlv?.let { TlvReader(it).toAny() } Log.v(TAG, "On/Off attribute value: $value") showMessage("On/Off attribute value: $value") } @@ -201,7 +202,7 @@ class OnOffClientFragment : Fragment() { ?.tlv ?: return // TODO : Need to be implement poj-to-tlv - val value = TlvParseUtil.decodeBoolean(tlv) + val value = TlvReader(tlv).getBool(AnonymousTag) val formatter = SimpleDateFormat("HH:mm:ss", Locale.getDefault()) val time = formatter.format(Calendar.getInstance(Locale.getDefault()).time) val message = "Subscribed on/off value at $time: ${if (value) "ON" else "OFF"}" diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt index b14f4a57062a57..45f817b002d700 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt @@ -8,8 +8,6 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import chip.devicecontroller.ChipDeviceController -import chip.devicecontroller.ChipStructs -import chip.devicecontroller.ChipTLVValueDecoder import chip.devicecontroller.ClusterIDMapping.OperationalCredentials import chip.devicecontroller.InvokeCallback import chip.devicecontroller.ReportCallback @@ -17,8 +15,10 @@ import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.InvokeElement import chip.devicecontroller.model.NodeState +import chip.jsontlv.toAny 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.GenericChipDeviceListener @@ -115,13 +115,6 @@ class OpCredClientFragment : Fragment() { } override fun onReport(nodeState: NodeState?) { - val value = - nodeState - ?.getEndpointState(endpointId) - ?.getClusterState(clusterId) - ?.getAttributeState(attributeId) - ?.value - ?: "null" val tlv = nodeState ?.getEndpointState(endpointId) @@ -129,30 +122,9 @@ class OpCredClientFragment : Fragment() { ?.getAttributeState(attributeId) ?.tlv - if (tlv == null) { - Log.i(TAG, "OpCred $attributeName value: $value") - showMessage("OpCred $attributeName value: $value") - return - } - - val attributePath = ChipAttributePath.newInstance(endpointId, clusterId, attributeId) - when (attribute) { - OperationalCredentials.Attribute.Fabrics -> { - val ret = - ChipTLVValueDecoder.decodeAttributeValue< - List - >( - attributePath, - tlv - ) - Log.i(TAG, "OpCred $attributeName value: $value") - showMessage(ret.toString()) - } - else -> { - Log.i(TAG, "OpCred $attributeName value: $value") - showMessage("OpCred $attributeName value: $value") - } - } + val value = tlv?.let { TlvReader(it).toAny() } + Log.i(TAG, "OpCred $attributeName value: $value") + showMessage("OpCred $attributeName value: $value") } }, devicePtr, diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/SensorClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/SensorClientFragment.kt index 53294c8037f981..594d158ee04049 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/SensorClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/SensorClientFragment.kt @@ -17,11 +17,12 @@ import chip.devicecontroller.ReportCallback import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.NodeState +import chip.tlv.AnonymousTag +import chip.tlv.TlvReader import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.R import com.google.chip.chiptool.databinding.SensorClientFragmentBinding import com.google.chip.chiptool.util.DeviceIdUtil -import com.google.chip.chiptool.util.TlvParseUtil import com.jjoe64.graphview.LabelFormatter import com.jjoe64.graphview.Viewport import com.jjoe64.graphview.series.DataPoint @@ -224,7 +225,7 @@ class SensorClientFragment : Fragment() { // TODO : Need to be implement poj-to-tlv val value = try { - TlvParseUtil.decodeInt(tlv) + TlvReader(tlv).getInt(AnonymousTag) } catch (ex: Exception) { showMessage(R.string.sensor_client_read_error_text, "value is null") return diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt index f03f68eee8c089..d5239871eea6fa 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt @@ -27,6 +27,7 @@ import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.ChipPathId import chip.devicecontroller.model.InvokeElement import chip.devicecontroller.model.NodeState +import chip.jsontlv.putJsonString import chip.tlv.AnonymousTag import chip.tlv.ContextSpecificTag import chip.tlv.TlvReader @@ -305,19 +306,6 @@ class WildcardFragment : Fragment() { 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) { @@ -326,14 +314,35 @@ class WildcardFragment : Fragment() { Optional.of(dataVersion) } - val writeRequest = - AttributeWriteRequest.newInstance( - endpointId, - clusterId, - attributeId, - tlvWriter.getEncoded(), - version - ) + lateinit var writeRequest: AttributeWriteRequest + + if (writeValueType == "json") { + writeRequest = AttributeWriteRequest.newInstance(endpointId, clusterId, attributeId, writeValue, version) + } else { + 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() + + writeRequest = + AttributeWriteRequest.newInstance( + endpointId, + clusterId, + attributeId, + tlvWriter.getEncoded(), + version + ) + } + deviceController.write( writeAttributeCallback, ChipClient.getConnectedDevicePointer(requireContext(), addressUpdateFragment.deviceId), @@ -343,35 +352,16 @@ class WildcardFragment : Fragment() { ) } - private suspend fun invoke(invokeField: String, timedRequestTimeoutMs: Int, imTimeoutMs: Int) { + private suspend fun invoke(invokeJson: 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 - } + val jsonString = invokeJson.ifEmpty { + "{}" } - tlvWriter.endStructure() val invokeElement = - InvokeElement.newInstance(endpointId, clusterId, commandId, tlvWriter.getEncoded(), null) + InvokeElement.newInstance(endpointId, clusterId, commandId, null, jsonString) deviceController.invoke( invokeCallback, ChipClient.getConnectedDevicePointer(requireContext(), addressUpdateFragment.deviceId), @@ -652,6 +642,12 @@ class WildcardFragment : Fragment() { private val TLV_MAP = mapOf( + "json" to + object : TlvWriterInterface { + override fun generate(writer: TlvWriter, value: String, tag: chip.tlv.Tag) { + writer.putJsonString(tag, value) + } + }, "UnsignedInt" to object : TlvWriterInterface { override fun generate(writer: TlvWriter, value: String, tag: chip.tlv.Tag) { diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvParseUtil.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvParseUtil.kt deleted file mode 100644 index f153d35783a5de..00000000000000 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvParseUtil.kt +++ /dev/null @@ -1,86 +0,0 @@ -package com.google.chip.chiptool.util - -import chip.tlv.AnonymousTag -import chip.tlv.TlvReader -import chip.tlv.TlvWriter - -object TlvParseUtil { - fun encode(input: Boolean): ByteArray { - val tlvWriter = TlvWriter() - tlvWriter.put(AnonymousTag, input) - return tlvWriter.getEncoded() - } - - fun encode(input: String): ByteArray { - val tlvWriter = TlvWriter() - tlvWriter.put(AnonymousTag, input) - return tlvWriter.getEncoded() - } - - fun encode(input: ULong): ByteArray { - val tlvWriter = TlvWriter() - tlvWriter.put(AnonymousTag, input) - return tlvWriter.getEncoded() - } - - fun encode(input: Long): ByteArray { - val tlvWriter = TlvWriter() - tlvWriter.put(AnonymousTag, input) - return tlvWriter.getEncoded() - } - - fun encode(input: UInt): ByteArray { - val tlvWriter = TlvWriter() - tlvWriter.put(AnonymousTag, input) - return tlvWriter.getEncoded() - } - - fun encode(input: Int): ByteArray { - val tlvWriter = TlvWriter() - tlvWriter.put(AnonymousTag, input) - return tlvWriter.getEncoded() - } - - fun encode(input: Float): ByteArray { - val tlvWriter = TlvWriter() - tlvWriter.put(AnonymousTag, input) - return tlvWriter.getEncoded() - } - - fun encode(input: Double): ByteArray { - val tlvWriter = TlvWriter() - tlvWriter.put(AnonymousTag, input) - return tlvWriter.getEncoded() - } - - fun encode(input: ByteArray): ByteArray { - val tlvWriter = TlvWriter() - tlvWriter.put(AnonymousTag, input) - return tlvWriter.getEncoded() - } - - fun decodeBoolean(tlv: ByteArray): Boolean { - val tlvReader = TlvReader(tlv) - return tlvReader.getBool(AnonymousTag) - } - - fun decodeInt(tlv: ByteArray): Int { - val tlvReader = TlvReader(tlv) - return tlvReader.getInt(AnonymousTag) - } - - fun decodeUInt(tlv: ByteArray): UInt { - val tlvReader = TlvReader(tlv) - return tlvReader.getUInt(AnonymousTag) - } - - fun decodeLong(tlv: ByteArray): Long { - val tlvReader = TlvReader(tlv) - return tlvReader.getLong(AnonymousTag) - } - - fun decodeULong(tlv: ByteArray): ULong { - val tlvReader = TlvReader(tlv) - return tlvReader.getULong(AnonymousTag) - } -} diff --git a/src/controller/java/src/chip/jsontlv/JsonToTlv.kt b/src/controller/java/src/chip/jsontlv/JsonToTlv.kt index 6f7cc05bde7081..c2c836f0b8a67c 100644 --- a/src/controller/java/src/chip/jsontlv/JsonToTlv.kt +++ b/src/controller/java/src/chip/jsontlv/JsonToTlv.kt @@ -43,9 +43,20 @@ import java.util.Base64 * @param json string representing Json encoded data to be converted into TLV format * @throws IllegalArgumentException if the data was invalid */ -fun TlvWriter.fromJsonString(json: String): ByteArray { - validateIsJsonObjectAndConvert(JsonParser.parseString(json), AnonymousTag) - return validateTlv().getEncoded() +fun TlvWriter.fromJsonStringToByteArray(json: String): ByteArray { + return putJsonString(AnonymousTag, json).validateTlv().getEncoded() +} + +/** + * Converts Json string into TLV writer object. + * + * @param tag the TLV tag to be encoded. + * @param json String representing Json to be converted to TLV. + * @throws IllegalArgumentException if the data was invalid + */ +fun TlvWriter.putJsonString(tag: Tag, json: String): TlvWriter { + validateIsJsonObjectAndConvert(JsonParser.parseString(json), tag) + return this } /** diff --git a/src/controller/java/src/chip/jsontlv/TlvToJson.kt b/src/controller/java/src/chip/jsontlv/TlvToJson.kt index 12dea48346a21d..d1989fac8991a3 100644 --- a/src/controller/java/src/chip/jsontlv/TlvToJson.kt +++ b/src/controller/java/src/chip/jsontlv/TlvToJson.kt @@ -55,6 +55,37 @@ fun TlvReader.toJsonString(): String { } return getStructJson().toString() } + +/** + * Encodes TLV into kotlin Object. If the TLV reader is positioned TLV Structure, Object will return + * to json format. + */ +fun TlvReader.toAny(tag: Tag = AnonymousTag): Any? { + val element = peekElement() + val value = element.value + value.toAny()?.let { + skipElement() + return it + } + return when (value) { + is ArrayValue -> { + buildList { + enterArray(tag) + while (!isEndOfContainer()) { + add(toAny()) + } + exitContainer() + } + } + is StructureValue -> { + skipElement() + getStructJson().toString() + } + else -> { + null + } + } +} /** * Encodes TLV Structure into Json Object. The TLV reader should be positioned at the start of a TLV * Structure (StructureValue element). After this call the TLV reader is positioned at the end of diff --git a/src/controller/java/src/chip/tlv/values.kt b/src/controller/java/src/chip/tlv/values.kt index 21dc88fb958126..8f9c27a83e2c3b 100644 --- a/src/controller/java/src/chip/tlv/values.kt +++ b/src/controller/java/src/chip/tlv/values.kt @@ -26,6 +26,8 @@ sealed class Value { internal abstract fun toType(): Type internal abstract fun encode(): ByteArray + + open fun toAny(): Any? = null } /** Represents a signed integer value of a TLV element. */ @@ -33,6 +35,8 @@ data class IntValue(val value: Long) : Value() { override fun toType() = SignedIntType(signedIntSize(value)) override fun encode() = value.toByteArrayLittleEndian(toType().valueSize) + + override fun toAny() = value } /** Represents an unsigned integer value of a TLV element. */ @@ -40,6 +44,8 @@ data class UnsignedIntValue(val value: Long) : Value() { override fun toType() = UnsignedIntType(unsignedIntSize(value.toULong())) override fun encode() = value.toByteArrayLittleEndian(toType().valueSize) + + override fun toAny() = value } /** Represents a boolean value of a TLV element. */ @@ -47,6 +53,8 @@ data class BooleanValue(val value: Boolean) : Value() { override fun toType() = BooleanType(value) override fun encode() = ByteArray(0) + + override fun toAny() = value } /** Represents a floating-point Float value of a TLV element. */ @@ -54,6 +62,8 @@ data class FloatValue(val value: Float) : Value() { override fun toType() = FloatType() override fun encode() = floatToIntBits(value).toByteArrayLittleEndian(4) + + override fun toAny() = value } /** Represents a floating-point DoubleFloat value of a TLV element. */ @@ -61,6 +71,8 @@ data class DoubleValue(val value: Double) : Value() { override fun toType() = DoubleType() override fun encode() = doubleToLongBits(value).toByteArrayLittleEndian(8) + + override fun toAny() = value } /** Represents a UTF8 string value of a TLV element. */ @@ -69,6 +81,8 @@ data class Utf8StringValue(val value: String) : Value() { override fun encode() = value.toByteArray().size.toByteArrayLittleEndian(toType().lengthSize) + value.toByteArray() + + override fun toAny() = value } /** Represents an octet string value of a TLV element. */ @@ -76,6 +90,8 @@ data class ByteStringValue(val value: ByteArray) : Value() { override fun toType() = ByteStringType(unsignedIntSize(value.size.toULong())) override fun encode() = value.size.toByteArrayLittleEndian(toType().lengthSize) + value + + override fun toAny() = value } /** Represents a null value in a TLV element. */ diff --git a/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt b/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt index 04ea7340e33198..968656300b5b4b 100644 --- a/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt +++ b/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt @@ -37,11 +37,11 @@ class JsonToTlvToJsonTest { tlvEncoding: ByteArray, jsonExpected: String = jsonOriginal ) { - assertThat(TlvWriter().fromJsonString(jsonOriginal)).isEqualTo(tlvEncoding) + assertThat(TlvWriter().fromJsonStringToByteArray(jsonOriginal)).isEqualTo(tlvEncoding) assertThat(TlvReader(tlvEncoding).toJsonString()) .isEqualTo(JsonParser.parseString(jsonExpected).asJsonObject.toString()) if (jsonOriginal != jsonExpected) { - assertThat(TlvWriter().fromJsonString(jsonExpected)).isEqualTo(tlvEncoding) + assertThat(TlvWriter().fromJsonStringToByteArray(jsonExpected)).isEqualTo(tlvEncoding) } } @@ -865,7 +865,7 @@ class JsonToTlvToJsonTest { // Throws exception because subtype encoded in the Json key (Boolean) doesn't match the // String // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonString(json) } + assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } } @Test @@ -884,7 +884,7 @@ class JsonToTlvToJsonTest { // Throws exception because subtype encoded in the Json key (Boolean) doesn't match the // String // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonString(json) } + assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } } @Test @@ -905,7 +905,7 @@ class JsonToTlvToJsonTest { // Throws exception because subtype encoded in the Json key (Float) doesn't match the // Structure // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonString(json) } + assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } } @Test @@ -921,7 +921,7 @@ class JsonToTlvToJsonTest { // Throws exception because subtype encoded in the Json key (UInt) doesn't match the Null // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonString(json) } + assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } } @Test @@ -937,7 +937,7 @@ class JsonToTlvToJsonTest { """ // Throws exception because string is invalid base64 encoded value - assertFailsWith { TlvWriter().fromJsonString(json) } + assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } } @Test @@ -972,7 +972,7 @@ class JsonToTlvToJsonTest { """ // Throws exception because element within structure cannot have anonymous tag - assertFailsWith { TlvWriter().fromJsonString(json) } + assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } } @Test @@ -985,7 +985,7 @@ class JsonToTlvToJsonTest { """ // Throws exception because Json key must have valid tag field - assertFailsWith { TlvWriter().fromJsonString(json) } + assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } } @Test @@ -1074,7 +1074,7 @@ class JsonToTlvToJsonTest { """ // 4294967296 exceeds valid context specific or common profile tag value of 32-bits - assertFailsWith { TlvWriter().fromJsonString(json) } + assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } } @Test @@ -1633,4 +1633,184 @@ class JsonToTlvToJsonTest { checkValidConversion(json, encoding) } + + @Test + fun convertJsonString() { + val encoding = + TlvWriter() + .startStructure(AnonymousTag) + .put(ContextSpecificTag(0), 42) + .put(ContextSpecificTag(1), "Test array member 0".toByteArray()) + .put(ContextSpecificTag(2), 156.398) + .put(ContextSpecificTag(3), 73709551615U) + .put(ContextSpecificTag(4), true) + .putNull(ContextSpecificTag(5)) + .startStructure(ContextSpecificTag(6)) + .put(ContextSpecificTag(1), "John") + .put(ContextSpecificTag(2), 34U) + .put(ContextSpecificTag(3), true) + .startArray(ContextSpecificTag(4)) + .put(AnonymousTag, 5) + .put(AnonymousTag, 9) + .put(AnonymousTag, 10) + .endArray() + .startArray(ContextSpecificTag(5)) + .put(AnonymousTag, "Ammy") + .put(AnonymousTag, "David") + .put(AnonymousTag, "Larry") + .endArray() + .startArray(ContextSpecificTag(6)) + .put(AnonymousTag, true) + .put(AnonymousTag, false) + .put(AnonymousTag, true) + .endArray() + .endStructure() + .put(ContextSpecificTag(7), 0.0f) + .endStructure() + .validateTlv() + .getEncoded() + + val compareJson = + """ + { + "0:INT": 42, + "1:BYTES": "VGVzdCBhcnJheSBtZW1iZXIgMA==", + "2:DOUBLE": 156.398, + "3:UINT": "73709551615", + "4:BOOL": true, + "5:NULL": null, + "6:STRUCT": { + "1:STRING": "John", + "2:UINT": 34, + "3:BOOL": true, + "4:ARRAY-INT": [ + 5, + 9, + 10 + ], + "5:ARRAY-STRING": [ + "Ammy", + "David", + "Larry" + ], + "6:ARRAY-BOOL": [ + true, + false, + true + ] + }, + "7:FLOAT": 0.0 + } + """ + val tlvWriterJson = TlvWriter().putJsonString(AnonymousTag, compareJson) + + assertThat(encoding).isEqualTo(tlvWriterJson.getEncoded()) + } + + @Test + fun convertNullToTlv() { + val value: Any? = null + val tlv = "14".octetsToByteArray() + + val tlvReader = TlvReader(tlv) + val compareValue = tlvReader.toAny() + + assertThat(value).isEqualTo(compareValue) + } + + @Test + fun convertIntToTlv() { + val value = 33L + val tlv = "0021".octetsToByteArray() + + val tlvReader = TlvReader(tlv) + val compareValue = tlvReader.toAny() + + assertThat(value).isEqualTo(compareValue) + } + + @Test + fun convertUIntToTlv() { + val value: ULong = 475UL + val tlv = "05db01".octetsToByteArray() + + val tlvReader = TlvReader(tlv) + val compareValue = tlvReader.toAny() + + assert(compareValue is ULong) + assert(value == compareValue) + } + + @Test + fun convertBooleanToTlv() { + val value = false + val tlv = "08".octetsToByteArray() + + val tlvReader = TlvReader(tlv) + val compareValue = tlvReader.toAny() + + assertThat(value).isEqualTo(compareValue) + } + + @Test + fun convertFloatToTlv() { + val value = 1.4f + val tlv = "0a3333b33f".octetsToByteArray() + + val tlvReader = TlvReader(tlv) + val compareValue = tlvReader.toAny() + + assertThat(value).isEqualTo(compareValue) + } + + @Test + fun convertDoubleToTlv() { + val value = 3.543 + val tlv = "0bf2d24d6210580c40".octetsToByteArray() + + val tlvReader = TlvReader(tlv) + val compareValue = tlvReader.toAny() + + assertThat(value).isEqualTo(compareValue) + } + + @Test + fun convertByteArrayToTlv() { + val value = "0123456789aabbccddeeff".octetsToByteArray() + val tlv = "100b0123456789aabbccddeeff".octetsToByteArray() + + val tlvReader = TlvReader(tlv) + val compareValue = tlvReader.toAny() + + assertThat(value).isEqualTo(compareValue) + } + + @Test + fun convertStringToTlv() { + val value = "@Hello! Matter!!! I like Matter." + val tlv = + "0c204048656c6c6f21204d61747465722121212049206c696b65204d61747465722e".octetsToByteArray() + + val tlvReader = TlvReader(tlv) + val compareValue = tlvReader.toAny() + + assertThat(value).isEqualTo(compareValue) + } + + @Test + fun convertListToTlv() { + // Int + val test = listOf(1L, 3L, 5L, 7L, 9L, 2L, 4L, 6L, 8L, 10L) + val tlvWriter = + TlvWriter().apply { + startArray(AnonymousTag) + test.forEach { put(AnonymousTag, it) } + endArray() + } + val tlv = tlvWriter.getEncoded() + val tlvReaderObject = TlvReader(tlv).toAny() + + assert(tlvReaderObject is List<*>) + assertThat(tlvReaderObject).isEqualTo(test) + } } From 1b537ab4d1dc0f914f2335ea7e0524f5e806496b Mon Sep 17 00:00:00 2001 From: Joonhaeng Heo Date: Mon, 21 Aug 2023 14:30:35 +0900 Subject: [PATCH 02/10] restyle kotlin --- .../chiptool/clusterclient/WildcardFragment.kt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt index d5239871eea6fa..c295adeaf68f40 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt @@ -29,7 +29,6 @@ import chip.devicecontroller.model.InvokeElement import chip.devicecontroller.model.NodeState import chip.jsontlv.putJsonString import chip.tlv.AnonymousTag -import chip.tlv.ContextSpecificTag import chip.tlv.TlvReader import chip.tlv.TlvWriter import com.google.chip.chiptool.ChipClient @@ -317,7 +316,8 @@ class WildcardFragment : Fragment() { lateinit var writeRequest: AttributeWriteRequest if (writeValueType == "json") { - writeRequest = AttributeWriteRequest.newInstance(endpointId, clusterId, attributeId, writeValue, version) + writeRequest = + AttributeWriteRequest.newInstance(endpointId, clusterId, attributeId, writeValue, version) } else { val tlvWriter = TlvWriter() val values = writeValue.split(",") @@ -335,11 +335,11 @@ class WildcardFragment : Fragment() { writeRequest = AttributeWriteRequest.newInstance( - endpointId, - clusterId, - attributeId, - tlvWriter.getEncoded(), - version + endpointId, + clusterId, + attributeId, + tlvWriter.getEncoded(), + version ) } @@ -357,9 +357,7 @@ class WildcardFragment : Fragment() { val clusterId = getChipPathIdForText(binding.clusterIdEd.text.toString()) val commandId = getChipPathIdForText(binding.commandIdEd.text.toString()) - val jsonString = invokeJson.ifEmpty { - "{}" - } + val jsonString = invokeJson.ifEmpty { "{}" } val invokeElement = InvokeElement.newInstance(endpointId, clusterId, commandId, null, jsonString) deviceController.invoke( From be8d775b12b1ac4b20b08d9eef7ab50749e030ab Mon Sep 17 00:00:00 2001 From: Joonhaeng Heo Date: Tue, 22 Aug 2023 09:16:24 +0900 Subject: [PATCH 03/10] Fix build error --- scripts/build/builders/android.py | 1 + src/controller/java/BUILD.gn | 1 + 2 files changed, 2 insertions(+) diff --git a/scripts/build/builders/android.py b/scripts/build/builders/android.py index 7b12090b9f15f5..a5b86e7ccd1388 100644 --- a/scripts/build/builders/android.py +++ b/scripts/build/builders/android.py @@ -234,6 +234,7 @@ def copyToSrcAndroid(self): "CHIPController.jar": "src/controller/java/CHIPController.jar", "OnboardingPayload.jar": "src/controller/java/OnboardingPayload.jar", "AndroidPlatform.jar": "src/platform/android/AndroidPlatform.jar", + "libCHIPJson.jar": "src/controller/java/libCHIPJson.jar", "libCHIPTlv.jar": "src/controller/java/libCHIPTlv.jar", "CHIPClusters.jar": "src/controller/java/CHIPClusters.jar", "CHIPClusterID.jar": "src/controller/java/CHIPClusterID.jar", diff --git a/src/controller/java/BUILD.gn b/src/controller/java/BUILD.gn index a2865ffd326c1c..2cbb402a512f87 100644 --- a/src/controller/java/BUILD.gn +++ b/src/controller/java/BUILD.gn @@ -372,6 +372,7 @@ android_library("java") { deps = [ ":chipcluster", ":chipclusterID", + ":jsontlv", ":tlv", "${chip_root}/third_party/java_deps:annotation", ] From 564d0d31e38d5d65cc419d3cb63156283b8a3dce Mon Sep 17 00:00:00 2001 From: Joonhaeng Heo Date: Tue, 22 Aug 2023 09:38:52 +0900 Subject: [PATCH 04/10] Check isEndOfTlv in ArrayValue --- .../java/src/chip/jsontlv/JsonToTlv.kt | 2 +- .../java/src/chip/jsontlv/TlvToJson.kt | 3 ++- .../tests/chip/jsontlv/JsonToTlvToJsonTest.kt | 20 +++++++++---------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/controller/java/src/chip/jsontlv/JsonToTlv.kt b/src/controller/java/src/chip/jsontlv/JsonToTlv.kt index c2c836f0b8a67c..01b16c2b1b6515 100644 --- a/src/controller/java/src/chip/jsontlv/JsonToTlv.kt +++ b/src/controller/java/src/chip/jsontlv/JsonToTlv.kt @@ -43,7 +43,7 @@ import java.util.Base64 * @param json string representing Json encoded data to be converted into TLV format * @throws IllegalArgumentException if the data was invalid */ -fun TlvWriter.fromJsonStringToByteArray(json: String): ByteArray { +fun TlvWriter.fromJsonString(json: String): ByteArray { return putJsonString(AnonymousTag, json).validateTlv().getEncoded() } diff --git a/src/controller/java/src/chip/jsontlv/TlvToJson.kt b/src/controller/java/src/chip/jsontlv/TlvToJson.kt index d1989fac8991a3..c75dd8362221cd 100644 --- a/src/controller/java/src/chip/jsontlv/TlvToJson.kt +++ b/src/controller/java/src/chip/jsontlv/TlvToJson.kt @@ -71,7 +71,8 @@ fun TlvReader.toAny(tag: Tag = AnonymousTag): Any? { is ArrayValue -> { buildList { enterArray(tag) - while (!isEndOfContainer()) { + // TODO: to be added isLastElement() + while (!isEndOfTlv() && !isEndOfContainer()) { add(toAny()) } exitContainer() diff --git a/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt b/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt index 968656300b5b4b..51a1f979f5b26b 100644 --- a/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt +++ b/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt @@ -37,11 +37,11 @@ class JsonToTlvToJsonTest { tlvEncoding: ByteArray, jsonExpected: String = jsonOriginal ) { - assertThat(TlvWriter().fromJsonStringToByteArray(jsonOriginal)).isEqualTo(tlvEncoding) + assertThat(TlvWriter().fromJsonString(jsonOriginal)).isEqualTo(tlvEncoding) assertThat(TlvReader(tlvEncoding).toJsonString()) .isEqualTo(JsonParser.parseString(jsonExpected).asJsonObject.toString()) if (jsonOriginal != jsonExpected) { - assertThat(TlvWriter().fromJsonStringToByteArray(jsonExpected)).isEqualTo(tlvEncoding) + assertThat(TlvWriter().fromJsonString(jsonExpected)).isEqualTo(tlvEncoding) } } @@ -865,7 +865,7 @@ class JsonToTlvToJsonTest { // Throws exception because subtype encoded in the Json key (Boolean) doesn't match the // String // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } + assertFailsWith { TlvWriter().fromJsonString(json) } } @Test @@ -884,7 +884,7 @@ class JsonToTlvToJsonTest { // Throws exception because subtype encoded in the Json key (Boolean) doesn't match the // String // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } + assertFailsWith { TlvWriter().fromJsonString(json) } } @Test @@ -905,7 +905,7 @@ class JsonToTlvToJsonTest { // Throws exception because subtype encoded in the Json key (Float) doesn't match the // Structure // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } + assertFailsWith { TlvWriter().fromJsonString(json) } } @Test @@ -921,7 +921,7 @@ class JsonToTlvToJsonTest { // Throws exception because subtype encoded in the Json key (UInt) doesn't match the Null // type of the elements in the array - assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } + assertFailsWith { TlvWriter().fromJsonString(json) } } @Test @@ -937,7 +937,7 @@ class JsonToTlvToJsonTest { """ // Throws exception because string is invalid base64 encoded value - assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } + assertFailsWith { TlvWriter().fromJsonString(json) } } @Test @@ -972,7 +972,7 @@ class JsonToTlvToJsonTest { """ // Throws exception because element within structure cannot have anonymous tag - assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } + assertFailsWith { TlvWriter().fromJsonString(json) } } @Test @@ -985,7 +985,7 @@ class JsonToTlvToJsonTest { """ // Throws exception because Json key must have valid tag field - assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } + assertFailsWith { TlvWriter().fromJsonString(json) } } @Test @@ -1074,7 +1074,7 @@ class JsonToTlvToJsonTest { """ // 4294967296 exceeds valid context specific or common profile tag value of 32-bits - assertFailsWith { TlvWriter().fromJsonStringToByteArray(json) } + assertFailsWith { TlvWriter().fromJsonString(json) } } @Test From 331eb8f64f73ca6194094515973885a95346608d Mon Sep 17 00:00:00 2001 From: Joonhaeng Heo Date: Tue, 22 Aug 2023 09:47:41 +0900 Subject: [PATCH 05/10] Add kotlin exclude codeing check --- kotlin-detect-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/kotlin-detect-config.yaml b/kotlin-detect-config.yaml index 3af04f5b389369..a620f227246360 100644 --- a/kotlin-detect-config.yaml +++ b/kotlin-detect-config.yaml @@ -160,6 +160,7 @@ style: - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt" - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterInteractionFragment.kt" - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/AddressCommissioningFragment.kt" + - "**/src/controller/java/src/chip/jsontlv/TlvToJson.kt" - "**/src/controller/java/src/chip/onboardingpayload/QRCodeOnboardingPayloadParser.kt" ExplicitItLambdaParameter: excludes: From ca3cdb7c25097b6b4961b43eb773a6893e3e5cf8 Mon Sep 17 00:00:00 2001 From: Joonhaeng Heo Date: Tue, 22 Aug 2023 10:49:25 +0900 Subject: [PATCH 06/10] Add TestData in Android ChipTool --- scripts/build/testdata/dry_run_android-arm64-chip-tool.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/build/testdata/dry_run_android-arm64-chip-tool.txt b/scripts/build/testdata/dry_run_android-arm64-chip-tool.txt index 766a82be3bb318..41de17332bd7e7 100644 --- a/scripts/build/testdata/dry_run_android-arm64-chip-tool.txt +++ b/scripts/build/testdata/dry_run_android-arm64-chip-tool.txt @@ -29,6 +29,8 @@ cp {out}/android-arm64-chip-tool/lib/src/controller/java/OnboardingPayload.jar { cp {out}/android-arm64-chip-tool/lib/src/platform/android/AndroidPlatform.jar {root}/examples/android/CHIPTool/app/libs/AndroidPlatform.jar +cp {out}/android-arm64-chip-tool/lib/src/controller/java/libCHIPJson.jar {root}/examples/android/CHIPTool/app/libs/libCHIPJson.jar + cp {out}/android-arm64-chip-tool/lib/src/controller/java/libCHIPTlv.jar {root}/examples/android/CHIPTool/app/libs/libCHIPTlv.jar cp {out}/android-arm64-chip-tool/lib/src/controller/java/CHIPClusters.jar {root}/examples/android/CHIPTool/app/libs/CHIPClusters.jar From 60636219f379e642a776d2e0754e292e3efa7059 Mon Sep 17 00:00:00 2001 From: Joonhaeng Heo Date: Mon, 28 Aug 2023 17:02:51 +0900 Subject: [PATCH 07/10] Move TlvReader toAny method to ChipTool --- .../clusterclient/BasicClientFragment.kt | 2 +- .../clusterclient/MultiAdminClientFragment.kt | 2 +- .../clusterclient/OnOffClientFragment.kt | 2 +- .../clusterclient/OpCredClientFragment.kt | 2 +- .../clusterclient/WildcardFragment.kt | 7 ++- .../com/google/chip/chiptool/util/TlvUtil.kt | 53 +++++++++++++++++++ .../java/src/chip/jsontlv/TlvToJson.kt | 35 +----------- 7 files changed, 64 insertions(+), 39 deletions(-) create mode 100644 examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvUtil.kt diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt index 26552b8f8c34f8..7e035a6d17149d 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/BasicClientFragment.kt @@ -17,7 +17,6 @@ import chip.devicecontroller.model.AttributeWriteRequest import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.NodeState -import chip.jsontlv.toAny import chip.tlv.AnonymousTag import chip.tlv.TlvReader import chip.tlv.TlvWriter @@ -25,6 +24,7 @@ import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R import com.google.chip.chiptool.databinding.BasicClientFragmentBinding +import com.google.chip.chiptool.util.toAny import java.util.Optional import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt index 3004d883d10894..e60520c6597bb6 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt @@ -16,7 +16,6 @@ import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.InvokeElement import chip.devicecontroller.model.NodeState -import chip.jsontlv.toAny import chip.tlv.AnonymousTag import chip.tlv.TlvReader import chip.tlv.TlvWriter @@ -24,6 +23,7 @@ import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R import com.google.chip.chiptool.databinding.MultiAdminClientFragmentBinding +import com.google.chip.chiptool.util.toAny import kotlinx.coroutines.* class MultiAdminClientFragment : Fragment() { diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt index 464b708e7d9621..8efe4334445f93 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OnOffClientFragment.kt @@ -22,7 +22,6 @@ import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.InvokeElement import chip.devicecontroller.model.NodeState -import chip.jsontlv.toAny import chip.tlv.AnonymousTag import chip.tlv.ContextSpecificTag import chip.tlv.TlvReader @@ -31,6 +30,7 @@ import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R import com.google.chip.chiptool.databinding.OnOffClientFragmentBinding +import com.google.chip.chiptool.util.toAny import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt index 45f817b002d700..86c96b34d1627c 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/OpCredClientFragment.kt @@ -15,7 +15,6 @@ import chip.devicecontroller.model.ChipAttributePath import chip.devicecontroller.model.ChipEventPath import chip.devicecontroller.model.InvokeElement import chip.devicecontroller.model.NodeState -import chip.jsontlv.toAny import chip.tlv.AnonymousTag import chip.tlv.ContextSpecificTag import chip.tlv.TlvReader @@ -24,6 +23,7 @@ import com.google.chip.chiptool.ChipClient import com.google.chip.chiptool.GenericChipDeviceListener import com.google.chip.chiptool.R import com.google.chip.chiptool.databinding.OpCredClientFragmentBinding +import com.google.chip.chiptool.util.toAny import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt index c295adeaf68f40..aa939250bdff51 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/WildcardFragment.kt @@ -34,6 +34,7 @@ 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.chip.chiptool.util.toAny import java.lang.StringBuilder import java.util.Optional import kotlin.coroutines.resume @@ -219,7 +220,8 @@ class WildcardFragment : Fragment() { 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") + val tlv = attributeState.tlv + stringBuilder.append("\t\t$attributeName: ${TlvReader(tlv).toAny()}\n") } clusterState.eventStates.forEach { (eventId, events) -> for (event in events) { @@ -229,7 +231,8 @@ class WildcardFragment : Fragment() { stringBuilder.append("\t\ttimestampValue: ${event.timestampValue}\n") val eventName = ChipIdLookup.eventIdToName(clusterId, eventId) - stringBuilder.append("\t\t$eventName: ${event.value}\n") + val tlv = event.tlv + stringBuilder.append("\t\t$eventName: ${TlvReader(tlv).toAny()}\n") } } stringBuilder.append("\t}\n") diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvUtil.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvUtil.kt new file mode 100644 index 00000000000000..36770d2546692d --- /dev/null +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvUtil.kt @@ -0,0 +1,53 @@ +package com.google.chip.chiptool.util + +import chip.tlv.AnonymousTag +import chip.tlv.ArrayValue +import chip.tlv.NullValue +import chip.tlv.Tag +import chip.tlv.TlvReader +import chip.tlv.StructureValue + +/** + * Encodes TLV into kotlin Object. If the TLV reader is positioned TLV Structure, Object will return + * to json format. + */ +fun TlvReader.toAny(tag: Tag = AnonymousTag): Any? { + val element = peekElement() + val value = element.value + value.toAny()?.let { + skipElement() + return it + } + return when (value) { + is ArrayValue -> { + buildList { + enterArray(tag) + while (!isEndOfTlv() && !isEndOfContainer()) { + add(toAny()) + } + exitContainer() + } + } + is StructureValue -> { + buildMap { + enterStructure(tag) + while (!isEndOfTlv() && !isEndOfContainer()) { + put(getTag(), toAny(getTag())) + } + exitContainer() + } + } + is NullValue -> { + skipElement() + null + } + else -> { + skipElement() + null + } + } +} + +private fun TlvReader.getTag(): Tag { + return peekElement().tag +} \ No newline at end of file diff --git a/src/controller/java/src/chip/jsontlv/TlvToJson.kt b/src/controller/java/src/chip/jsontlv/TlvToJson.kt index c75dd8362221cd..f2dfa3d019cde4 100644 --- a/src/controller/java/src/chip/jsontlv/TlvToJson.kt +++ b/src/controller/java/src/chip/jsontlv/TlvToJson.kt @@ -45,48 +45,17 @@ import java.util.Base64 * * @throws IllegalArgumentException if the data was invalid */ -fun TlvReader.toJsonString(): String { +fun TlvReader.toJsonString(tag: Tag = AnonymousTag): String { val element = nextElement() require(element.value is StructureValue) { "The top level element must be a structure. The actual value is ${element.value}" } - require(element.tag is AnonymousTag) { + require(element.tag == tag) { "The top level TLV Structure MUST have anonymous tag. The actual tag is ${element.tag}" } return getStructJson().toString() } -/** - * Encodes TLV into kotlin Object. If the TLV reader is positioned TLV Structure, Object will return - * to json format. - */ -fun TlvReader.toAny(tag: Tag = AnonymousTag): Any? { - val element = peekElement() - val value = element.value - value.toAny()?.let { - skipElement() - return it - } - return when (value) { - is ArrayValue -> { - buildList { - enterArray(tag) - // TODO: to be added isLastElement() - while (!isEndOfTlv() && !isEndOfContainer()) { - add(toAny()) - } - exitContainer() - } - } - is StructureValue -> { - skipElement() - getStructJson().toString() - } - else -> { - null - } - } -} /** * Encodes TLV Structure into Json Object. The TLV reader should be positioned at the start of a TLV * Structure (StructureValue element). After this call the TLV reader is positioned at the end of From 9631207c2a327b7a18d2f3d5fa73e4629fe9ca68 Mon Sep 17 00:00:00 2001 From: Joonhaeng Heo Date: Mon, 28 Aug 2023 17:06:09 +0900 Subject: [PATCH 08/10] rollback tlvtoJson class --- src/controller/java/src/chip/jsontlv/TlvToJson.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/controller/java/src/chip/jsontlv/TlvToJson.kt b/src/controller/java/src/chip/jsontlv/TlvToJson.kt index f2dfa3d019cde4..12dea48346a21d 100644 --- a/src/controller/java/src/chip/jsontlv/TlvToJson.kt +++ b/src/controller/java/src/chip/jsontlv/TlvToJson.kt @@ -45,17 +45,16 @@ import java.util.Base64 * * @throws IllegalArgumentException if the data was invalid */ -fun TlvReader.toJsonString(tag: Tag = AnonymousTag): String { +fun TlvReader.toJsonString(): String { val element = nextElement() require(element.value is StructureValue) { "The top level element must be a structure. The actual value is ${element.value}" } - require(element.tag == tag) { + require(element.tag is AnonymousTag) { "The top level TLV Structure MUST have anonymous tag. The actual tag is ${element.tag}" } return getStructJson().toString() } - /** * Encodes TLV Structure into Json Object. The TLV reader should be positioned at the start of a TLV * Structure (StructureValue element). After this call the TLV reader is positioned at the end of From 0afc4bb6c5ea250de8a0cb12d42ea4679bbcd64f Mon Sep 17 00:00:00 2001 From: Joonhaeng Heo Date: Mon, 28 Aug 2023 17:07:56 +0900 Subject: [PATCH 09/10] rollback json test --- .../tests/chip/jsontlv/JsonToTlvToJsonTest.kt | 180 ------------------ 1 file changed, 180 deletions(-) diff --git a/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt b/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt index 51a1f979f5b26b..04ea7340e33198 100644 --- a/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt +++ b/src/controller/java/tests/chip/jsontlv/JsonToTlvToJsonTest.kt @@ -1633,184 +1633,4 @@ class JsonToTlvToJsonTest { checkValidConversion(json, encoding) } - - @Test - fun convertJsonString() { - val encoding = - TlvWriter() - .startStructure(AnonymousTag) - .put(ContextSpecificTag(0), 42) - .put(ContextSpecificTag(1), "Test array member 0".toByteArray()) - .put(ContextSpecificTag(2), 156.398) - .put(ContextSpecificTag(3), 73709551615U) - .put(ContextSpecificTag(4), true) - .putNull(ContextSpecificTag(5)) - .startStructure(ContextSpecificTag(6)) - .put(ContextSpecificTag(1), "John") - .put(ContextSpecificTag(2), 34U) - .put(ContextSpecificTag(3), true) - .startArray(ContextSpecificTag(4)) - .put(AnonymousTag, 5) - .put(AnonymousTag, 9) - .put(AnonymousTag, 10) - .endArray() - .startArray(ContextSpecificTag(5)) - .put(AnonymousTag, "Ammy") - .put(AnonymousTag, "David") - .put(AnonymousTag, "Larry") - .endArray() - .startArray(ContextSpecificTag(6)) - .put(AnonymousTag, true) - .put(AnonymousTag, false) - .put(AnonymousTag, true) - .endArray() - .endStructure() - .put(ContextSpecificTag(7), 0.0f) - .endStructure() - .validateTlv() - .getEncoded() - - val compareJson = - """ - { - "0:INT": 42, - "1:BYTES": "VGVzdCBhcnJheSBtZW1iZXIgMA==", - "2:DOUBLE": 156.398, - "3:UINT": "73709551615", - "4:BOOL": true, - "5:NULL": null, - "6:STRUCT": { - "1:STRING": "John", - "2:UINT": 34, - "3:BOOL": true, - "4:ARRAY-INT": [ - 5, - 9, - 10 - ], - "5:ARRAY-STRING": [ - "Ammy", - "David", - "Larry" - ], - "6:ARRAY-BOOL": [ - true, - false, - true - ] - }, - "7:FLOAT": 0.0 - } - """ - val tlvWriterJson = TlvWriter().putJsonString(AnonymousTag, compareJson) - - assertThat(encoding).isEqualTo(tlvWriterJson.getEncoded()) - } - - @Test - fun convertNullToTlv() { - val value: Any? = null - val tlv = "14".octetsToByteArray() - - val tlvReader = TlvReader(tlv) - val compareValue = tlvReader.toAny() - - assertThat(value).isEqualTo(compareValue) - } - - @Test - fun convertIntToTlv() { - val value = 33L - val tlv = "0021".octetsToByteArray() - - val tlvReader = TlvReader(tlv) - val compareValue = tlvReader.toAny() - - assertThat(value).isEqualTo(compareValue) - } - - @Test - fun convertUIntToTlv() { - val value: ULong = 475UL - val tlv = "05db01".octetsToByteArray() - - val tlvReader = TlvReader(tlv) - val compareValue = tlvReader.toAny() - - assert(compareValue is ULong) - assert(value == compareValue) - } - - @Test - fun convertBooleanToTlv() { - val value = false - val tlv = "08".octetsToByteArray() - - val tlvReader = TlvReader(tlv) - val compareValue = tlvReader.toAny() - - assertThat(value).isEqualTo(compareValue) - } - - @Test - fun convertFloatToTlv() { - val value = 1.4f - val tlv = "0a3333b33f".octetsToByteArray() - - val tlvReader = TlvReader(tlv) - val compareValue = tlvReader.toAny() - - assertThat(value).isEqualTo(compareValue) - } - - @Test - fun convertDoubleToTlv() { - val value = 3.543 - val tlv = "0bf2d24d6210580c40".octetsToByteArray() - - val tlvReader = TlvReader(tlv) - val compareValue = tlvReader.toAny() - - assertThat(value).isEqualTo(compareValue) - } - - @Test - fun convertByteArrayToTlv() { - val value = "0123456789aabbccddeeff".octetsToByteArray() - val tlv = "100b0123456789aabbccddeeff".octetsToByteArray() - - val tlvReader = TlvReader(tlv) - val compareValue = tlvReader.toAny() - - assertThat(value).isEqualTo(compareValue) - } - - @Test - fun convertStringToTlv() { - val value = "@Hello! Matter!!! I like Matter." - val tlv = - "0c204048656c6c6f21204d61747465722121212049206c696b65204d61747465722e".octetsToByteArray() - - val tlvReader = TlvReader(tlv) - val compareValue = tlvReader.toAny() - - assertThat(value).isEqualTo(compareValue) - } - - @Test - fun convertListToTlv() { - // Int - val test = listOf(1L, 3L, 5L, 7L, 9L, 2L, 4L, 6L, 8L, 10L) - val tlvWriter = - TlvWriter().apply { - startArray(AnonymousTag) - test.forEach { put(AnonymousTag, it) } - endArray() - } - val tlv = tlvWriter.getEncoded() - val tlvReaderObject = TlvReader(tlv).toAny() - - assert(tlvReaderObject is List<*>) - assertThat(tlvReaderObject).isEqualTo(test) - } } From d3467a880b44e01a2ea5803cafb1e47203c52665 Mon Sep 17 00:00:00 2001 From: Joonhaeng Heo Date: Mon, 28 Aug 2023 17:11:37 +0900 Subject: [PATCH 10/10] Update kotlin codestyle --- .../com/google/chip/chiptool/util/TlvUtil.kt | 68 +++++++++---------- kotlin-detect-config.yaml | 1 - 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvUtil.kt b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvUtil.kt index 36770d2546692d..375381021c256e 100644 --- a/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvUtil.kt +++ b/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/util/TlvUtil.kt @@ -3,51 +3,51 @@ package com.google.chip.chiptool.util import chip.tlv.AnonymousTag import chip.tlv.ArrayValue import chip.tlv.NullValue +import chip.tlv.StructureValue import chip.tlv.Tag import chip.tlv.TlvReader -import chip.tlv.StructureValue /** * Encodes TLV into kotlin Object. If the TLV reader is positioned TLV Structure, Object will return * to json format. */ fun TlvReader.toAny(tag: Tag = AnonymousTag): Any? { - val element = peekElement() - val value = element.value - value.toAny()?.let { - skipElement() - return it - } - return when (value) { - is ArrayValue -> { - buildList { - enterArray(tag) - while (!isEndOfTlv() && !isEndOfContainer()) { - add(toAny()) - } - exitContainer() - } - } - is StructureValue -> { - buildMap { - enterStructure(tag) - while (!isEndOfTlv() && !isEndOfContainer()) { - put(getTag(), toAny(getTag())) - } - exitContainer() - } - } - is NullValue -> { - skipElement() - null + val element = peekElement() + val value = element.value + value.toAny()?.let { + skipElement() + return it + } + return when (value) { + is ArrayValue -> { + buildList { + enterArray(tag) + while (!isEndOfTlv() && !isEndOfContainer()) { + add(toAny()) } - else -> { - skipElement() - null + exitContainer() + } + } + is StructureValue -> { + buildMap { + enterStructure(tag) + while (!isEndOfTlv() && !isEndOfContainer()) { + put(getTag(), toAny(getTag())) } + exitContainer() + } + } + is NullValue -> { + skipElement() + null } + else -> { + skipElement() + null + } + } } private fun TlvReader.getTag(): Tag { - return peekElement().tag -} \ No newline at end of file + return peekElement().tag +} diff --git a/kotlin-detect-config.yaml b/kotlin-detect-config.yaml index a620f227246360..3af04f5b389369 100644 --- a/kotlin-detect-config.yaml +++ b/kotlin-detect-config.yaml @@ -160,7 +160,6 @@ style: - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/MultiAdminClientFragment.kt" - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/clusterclient/clusterinteraction/ClusterInteractionFragment.kt" - "**/examples/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/provisioning/AddressCommissioningFragment.kt" - - "**/src/controller/java/src/chip/jsontlv/TlvToJson.kt" - "**/src/controller/java/src/chip/onboardingpayload/QRCodeOnboardingPayloadParser.kt" ExplicitItLambdaParameter: excludes: