Skip to content

Commit

Permalink
Merge branch 'master' into feature/add-tag-list
Browse files Browse the repository at this point in the history
  • Loading branch information
mideayanghui committed Aug 25, 2023
2 parents 141dd00 + 2e59655 commit 2c61aba
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 32 deletions.
2 changes: 1 addition & 1 deletion examples/all-clusters-app/linux/main-common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ void ApplicationShutdown()
using namespace chip::app::Clusters::LaundryWasherControls;
void emberAfLaundryWasherControlsClusterInitCallback(EndpointId endpoint)
{
LaundryWasherControlsServer::SetDefaultDelegate(1, &LaundryWasherControlDelegate::getLaundryWasherControlDelegate());
LaundryWasherControlsServer::SetDefaultDelegate(endpoint, &LaundryWasherControlDelegate::getLaundryWasherControlDelegate());
}

void emberAfLowPowerClusterInitCallback(EndpointId endpoint)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package com.matter.controller.commands.pairing
import chip.devicecontroller.ChipDeviceController
import chip.devicecontroller.GetConnectedDeviceCallbackJni.GetConnectedDeviceCallback
import chip.devicecontroller.ReportCallback
import chip.devicecontroller.model.AttributeState
import chip.devicecontroller.model.ChipAttributePath
import chip.devicecontroller.model.ChipEventPath
import chip.devicecontroller.model.ChipPathId
import chip.devicecontroller.model.EventState
import chip.devicecontroller.model.NodeState
import com.matter.controller.commands.common.CredentialsIssuer
import java.util.Collections
import java.util.logging.Level
import java.util.logging.Logger

Expand Down Expand Up @@ -35,9 +37,83 @@ class PairOnNetworkLongImReadCommand(
setFailure("read failure")
}

// kotlin-detect complains that bytearray as a magic number, but we cannot define bytearray
// as a well named constant and const can only support with primitive and string.
@Suppress("MagicNumber")
fun checkLocalConfigDisableAttributeTlv(attribute: AttributeState): Boolean =
attribute.getTlv().contentEquals(byteArrayOf(0x8))

fun checkLocalConfigDisableAttributeJson(attribute: AttributeState): Boolean =
attribute.getJson().toString() == """{"16:BOOL":false}"""

// kotlin-detect complains that bytearray as a magic number, but we cannot define bytearray
// as a well named constant and const can only support with primitive and string.
@Suppress("MagicNumber")
fun checkStartUpEventTlv(event: EventState): Boolean =
event.getTlv().contentEquals(byteArrayOf(0x15, 0x24, 0x0, 0x1, 0x18))

fun checkStartUpEventJson(event: EventState): Boolean =
event.getJson().toString() == """{"0:STRUCT":{"0:UINT":1}}"""

fun checkAllAttributesJsonForBasicCluster(cluster: String): Boolean {
val expected =
"""{"16:BOOL":false,""" +
""""65531:ARRAY-UINT":[""" +
"""0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19,20,65528,65529,65531,65532,65533]}"""
return cluster.equals(expected)
}

private fun validateResponse(nodeState: NodeState) {
val endpointZero =
requireNotNull(nodeState.getEndpointState(0)) { "Endpoint zero not found." }

val basicCluster =
requireNotNull(endpointZero.getClusterState(CLUSTER_ID_BASIC)) {
"Basic cluster not found."
}

val localConfigDisabledAttribute =
requireNotNull(basicCluster.getAttributeState(ATTR_ID_LOCAL_CONFIG_DISABLED)) {
"No local config disabled attribute found."
}

val startUpEvents =
requireNotNull(basicCluster.getEventState(EVENT_ID_START_UP)) { "No start up event found." }

val clusterAttributes =
requireNotNull(basicCluster.getAttributesJson()) { "No basicCluster attribute found." }

require(checkLocalConfigDisableAttributeTlv(localConfigDisabledAttribute)) {
"Invalid local config disabled attribute TLV ${localConfigDisabledAttribute.getTlv().contentToString()}"
}

require(checkLocalConfigDisableAttributeJson(localConfigDisabledAttribute)) {
"Invalid local config disabled attribute Json ${localConfigDisabledAttribute.getJson().toString()}"
}

require(startUpEvents.isNotEmpty()) { "Unexpected: startUpEvents is empty" }

require(checkStartUpEventTlv(startUpEvents[0])) {
"Invalid start up event TLV ${startUpEvents[0].getTlv().contentToString()}"
}

require(checkStartUpEventJson(startUpEvents[0])) {
"Invalid start up event Json ${startUpEvents[0].getJson().toString()}"
}

require(checkAllAttributesJsonForBasicCluster(clusterAttributes)) {
"Invalid basic cluster attributes Json ${clusterAttributes}"
}
}

override fun onReport(nodeState: NodeState) {
logger.log(Level.INFO, "Read receve onReport")
setSuccess()
logger.log(Level.INFO, nodeState.toString())
try {
validateResponse(nodeState)
setSuccess()
} catch (ex: IllegalArgumentException) {
setFailure(ex.message)
}
}
}

Expand All @@ -56,9 +132,23 @@ class PairOnNetworkLongImReadCommand(
val attributePathList =
listOf(
ChipAttributePath.newInstance(
/* endpointId= */ 0,
CLUSTER_ID_BASIC,
ATTR_ID_LOCAL_CONFIG_DISABLED
ChipPathId.forId(/* endpointId= */ 0),
ChipPathId.forId(CLUSTER_ID_BASIC),
ChipPathId.forId(ATTR_ID_LOCAL_CONFIG_DISABLED),
),
ChipAttributePath.newInstance(
ChipPathId.forId(/* endpointId= */ 0),
ChipPathId.forId(CLUSTER_ID_BASIC),
ChipPathId.forId(GLOBAL_ATTRIBUTE_LIST),
)
)

val eventPathList =
listOf(
ChipEventPath.newInstance(
ChipPathId.forWildcard(),
ChipPathId.forWildcard(),
ChipPathId.forWildcard()
)
)

Expand All @@ -77,14 +167,7 @@ class PairOnNetworkLongImReadCommand(
.getConnectedDevicePointer(getNodeId(), InternalGetConnectedDeviceCallback())
clear()
currentCommissioner()
.readPath(
InternalReportCallback(),
devicePointer,
attributePathList,
Collections.emptyList(),
false,
0
)
.readPath(InternalReportCallback(), devicePointer, attributePathList, eventPathList, false, 0)
waitCompleteMs(getTimeoutMillis())
}

Expand All @@ -94,5 +177,7 @@ class PairOnNetworkLongImReadCommand(
private const val MATTER_PORT = 5540
private const val CLUSTER_ID_BASIC = 0x0028L
private const val ATTR_ID_LOCAL_CONFIG_DISABLED = 16L
private const val EVENT_ID_START_UP = 0L
private const val GLOBAL_ATTRIBUTE_LIST = 65531L
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,50 @@ void MatterLaundryWasherControlsPluginServerInitCallback()
LaundryWasherControlsServer & laundryWasherControlsServer = LaundryWasherControlsServer::Instance();
registerAttributeAccessOverride(&laundryWasherControlsServer);
}

Status MatterLaundryWasherControlsClusterServerPreAttributeChangedCallback(const chip::app::ConcreteAttributePath & attributePath,
EmberAfAttributeType attributeType, uint16_t size,
uint8_t * value)
{
Delegate * delegate = GetDelegate(attributePath.mEndpointId);
VerifyOrDie((delegate != nullptr) && "Washer Controls implementation requires a registered delegate for validation.");
switch (attributePath.mAttributeId)
{
case Attributes::SpinSpeedCurrent::Id: {
if (NumericAttributeTraits<uint8_t>::IsNullValue(*value))
{
return Status::Success;
}
char buffer[LaundryWasherControlsServer::kMaxSpinSpeedLength];
MutableCharSpan spinSpeed(buffer);
uint8_t spinSpeedIndex = *value;
auto err = delegate->GetSpinSpeedAtIndex(spinSpeedIndex, spinSpeed);
if (err == CHIP_NO_ERROR)
{
return Status::Success;
}
return Status::ConstraintError;
}
case Attributes::NumberOfRinses::Id: {
uint8_t supportedRinseIdx = 0;
while (true)
{
NumberOfRinsesEnum supportedRinse;
auto err = delegate->GetSupportedRinseAtIndex(supportedRinseIdx, supportedRinse);
if (err != CHIP_NO_ERROR)
{
// Can't find the attribute to be written in the supported list (CHIP_ERROR_PROVIDER_LIST_EXHAUSTED)
// Or can't get the correct supported list
return Status::InvalidInState;
}
if (supportedRinse == static_cast<NumberOfRinsesEnum>(*value))
{
// The written attribute is one of the supported item
return Status::Success;
}
supportedRinseIdx++;
}
}
}
return Status::Success;
}
1 change: 1 addition & 0 deletions src/app/common/templates/config-data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,4 @@ ClustersWithPreAttributeChangeFunctions:
- Mode Select
- Fan Control
- Thermostat
- Laundry Washer Controls
53 changes: 38 additions & 15 deletions src/controller/java/AndroidCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include <lib/support/JniReferences.h>
#include <lib/support/JniTypeWrappers.h>
#include <lib/support/jsontlv/JsonToTlv.h>
#include <lib/support/jsontlv/TlvJson.h>
#include <lib/support/jsontlv/TlvToJson.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/PlatformManager.h>
Expand All @@ -40,6 +39,8 @@ namespace Controller {

static const int MILLIS_SINCE_BOOT = 0;
static const int MILLIS_SINCE_EPOCH = 1;
// Add the bytes for attribute tag(1:control + 8:tag + 8:length) and structure(1:struct + 1:close container)
static const int EXTRA_SPACE_FOR_ATTRIBUTE_TAG = 19;

GetConnectedDeviceCallback::GetConnectedDeviceCallback(jobject wrapperCallback, jobject javaCallback) :
mOnSuccess(OnDeviceConnectedFn, this), mOnFailure(OnDeviceConnectionFailureFn, this)
Expand Down Expand Up @@ -224,6 +225,32 @@ void ReportCallback::OnReportEnd()
VerifyOrReturn(!env->ExceptionCheck(), env->ExceptionDescribe());
}

// Convert TLV blob to Json with structure, the element's tag is replaced with the actual attributeId.
CHIP_ERROR ConvertReportTlvToJson(const uint32_t id, TLV::TLVReader & data, std::string & json)
{
TLV::TLVWriter writer;
TLV::TLVReader readerForJavaTLV;
uint32_t size = 0;
size_t bufferLen = readerForJavaTLV.GetTotalLength() + EXTRA_SPACE_FOR_ATTRIBUTE_TAG;
readerForJavaTLV.Init(data);
std::unique_ptr<uint8_t[]> buffer = std::unique_ptr<uint8_t[]>(new uint8_t[bufferLen]);
writer.Init(buffer.get(), bufferLen);
TLV::TLVType outer;

ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer));
TLV::Tag tag;
ReturnErrorOnFailure(ConvertTlvTag(id, tag));
ReturnErrorOnFailure(writer.CopyElement(tag, readerForJavaTLV));
ReturnErrorOnFailure(writer.EndContainer(outer));
size = writer.GetLengthWritten();

TLV::TLVReader readerForJson;
readerForJson.Init(buffer.get(), size);
ReturnErrorOnFailure(readerForJson.Next());
// Convert TLV to JSON
return TlvToJson(readerForJson, json);
}

void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPath, TLV::TLVReader * apData,
const app::StatusIB & aStatus)
{
Expand Down Expand Up @@ -252,9 +279,7 @@ void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPat
}

TLV::TLVReader readerForJavaTLV;
TLV::TLVReader readerForJson;
readerForJavaTLV.Init(*apData);
readerForJson.Init(*apData);

jobject value = nullptr;
#if USE_JAVA_TLV_ENCODE_DECODE
Expand All @@ -276,6 +301,7 @@ void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPat
size_t bufferLen = readerForJavaTLV.GetRemainingLength() + readerForJavaTLV.GetLengthRead();
std::unique_ptr<uint8_t[]> buffer = std::unique_ptr<uint8_t[]>(new uint8_t[bufferLen]);
uint32_t size = 0;

// The TLVReader's read head is not pointing to the first element in the container, instead of the container itself, use
// a TLVWriter to get a TLV with a normalized TLV buffer (Wrapped with an anonymous tag, no extra "end of container" tag
// at the end.)
Expand All @@ -287,11 +313,10 @@ void ReportCallback::OnAttributeData(const app::ConcreteDataAttributePath & aPat
chip::ByteArray jniByteArray(env, reinterpret_cast<jbyte *>(buffer.get()), size);

// Convert TLV to JSON
Json::Value json;
err = TlvToJson(readerForJson, json);
std::string json;
err = ConvertReportTlvToJson(static_cast<uint32_t>(aPath.mAttributeId), *apData, json);
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(attributePathObj, nullptr, err));

UtfString jsonString(env, JsonToString(json).c_str());
UtfString jsonString(env, json.c_str());

// Create AttributeState object
jclass attributeStateCls;
Expand Down Expand Up @@ -366,9 +391,7 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV
}

TLV::TLVReader readerForJavaTLV;
TLV::TLVReader readerForJson;
readerForJavaTLV.Init(*apData);
readerForJson.Init(*apData);

jlong eventNumber = static_cast<jlong>(aEventHeader.mEventNumber);
jint priorityLevel = static_cast<jint>(aEventHeader.mPriorityLevel);
Expand Down Expand Up @@ -420,11 +443,10 @@ void ReportCallback::OnEventData(const app::EventHeader & aEventHeader, TLV::TLV
chip::ByteArray jniByteArray(env, reinterpret_cast<jbyte *>(buffer.get()), size);

// Convert TLV to JSON
Json::Value json;
err = TlvToJson(readerForJson, json);
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(nullptr, eventPathObj, err));

UtfString jsonString(env, JsonToString(json).c_str());
std::string json;
err = ConvertReportTlvToJson(static_cast<uint32_t>(aEventHeader.mPath.mEventId), *apData, json);
VerifyOrReturn(err == CHIP_NO_ERROR, ReportError(eventPathObj, nullptr, err));
UtfString jsonString(env, json.c_str());

// Create EventState object
jclass eventStateCls;
Expand Down Expand Up @@ -492,7 +514,8 @@ CHIP_ERROR InvokeCallback::CreateInvokeElement(const app::ConcreteCommandPath &
readerForJavaTLV.Init(*apData);

// Create TLV byte array to pass to Java layer
size_t bufferLen = readerForJavaTLV.GetRemainingLength() + readerForJavaTLV.GetLengthRead();
size_t bufferLen = readerForJavaTLV.GetRemainingLength() + readerForJavaTLV.GetLengthRead();
;
std::unique_ptr<uint8_t[]> buffer = std::unique_ptr<uint8_t[]>(new uint8_t[bufferLen]);
uint32_t size = 0;

Expand Down
Loading

0 comments on commit 2c61aba

Please sign in to comment.