背景
- 首先贴上官方github地址https://github.com/NordicSemiconductor/Android-nRF-Mesh-Library
- 本次修改基于官方SDK 2.4.1版本.
- 阅读此文章之前,我们默认您对蓝牙mesh协议已经有了一定了解.
- 本次修复了一个问题,是关于Nordic Android SDK解析未知model时候出错的问题.
问题分析
问题的根源是从SDK的导入导出发现的,从 Nordic SDK中导出来mesh json后发现设备的信息中model的配置信息都丢失了,如下图:
经过排查发现,固件里面出现了两个Nordic未知的model,最后通过与固件沟通,发现是瑞昱定义了两个sig model未被Nordic识别,从而导致model未被解析出现来,最终导致了信息丢失的情况.
通过代码排查,我们发现SDK在解析sig model的时候,如果遇到未定义的model,它最后会返回null,
代码如下:
/**
* Returns the Bluetooth sig model based on the model id.
*
* @param modelId bluetooth sig model id
* @return SigModel
*/
public static SigModel getSigModel(final int modelId) {
switch (modelId) {
case CONFIGURATION_SERVER:
return new ConfigurationServerModel(modelId);
case CONFIGURATION_CLIENT:
return new ConfigurationClientModel(modelId);
case HEALTH_SERVER_MODEL:
return new HealthServerModel(modelId);
case HEALTH_CLIENT_MODEL:
return new HealthClientModel(modelId);
case GENERIC_ON_OFF_SERVER:
return new GenericOnOffServerModel(modelId);
case GENERIC_ON_OFF_CLIENT:
return new GenericOnOffClientModel(modelId);
case GENERIC_LEVEL_SERVER:
return new GenericLevelServerModel(modelId);
case GENERIC_LEVEL_CLIENT:
return new GenericLevelClientModel(modelId);
case GENERIC_DEFAULT_TRANSITION_TIME_SERVER:
return new GenericDefaultTransitionTimeServer(modelId);
case GENERIC_DEFAULT_TRANSITION_TIME_CLIENT:
return new GenericDefaultTransitionTimeClient(modelId);
case GENERIC_POWER_ON_OFF_SERVER:
return new GenericPowerOnOffServer(modelId);
case GENERIC_POWER_ON_OFF_SETUP_SERVER:
return new GenericPowerOnOffSetupServer(modelId);
case GENERIC_POWER_ON_OFF_CLIENT:
return new GenericPowerOnOffClient(modelId);
case GENERIC_POWER_LEVEL_SERVER:
return new GenericPowerLevelServer(modelId);
case GENERIC_POWER_LEVEL_SETUP_SERVER:
return new GenericPowerLevelSetupServer(modelId);
case GENERIC_POWER_LEVEL_CLIENT:
return new GenericPowerLevelClient(modelId);
case GENERIC_BATTERY_SERVER:
return new GenericBatteryServer(modelId);
case GENERIC_BATTERY_CLIENT:
return new GenericBatteryClient(modelId);
case GENERIC_LOCATION_SERVER:
return new GenericLocationServer(modelId);
case GENERIC_LOCATION_SETUP_SERVER:
return new GenericLocationSetupServer(modelId);
case GENERIC_LOCATION_CLIENT:
return new GenericLocationClient(modelId);
case GENERIC_ADMIN_PROPERTY_SERVER:
return new GenericAdminPropertyServer(modelId);
case GENERIC_MANUFACTURER_PROPERTY_SERVER:
return new GenericManufacturerPropertyServer(modelId);
case GENERIC_USER_PROPERTY_SERVER:
return new GenericUserPropertyServer(modelId);
case GENERIC_CLIENT_PROPERTY_SERVER:
return new GenericClientPropertyServer(modelId);
case GENERIC_PROPERTY_CLIENT:
return new GenericPropertyClient(modelId);
case SENSOR_SERVER:
return new SensorServer(modelId);
case SENSOR_SETUP_SERVER:
return new SensorSetupServer(modelId);
case SENSOR_CLIENT:
return new SensorClient(modelId);
case TIME_SERVER:
return new TimeServer(modelId);
case TIME_SETUP_SERVER:
return new TimeSetupServer(modelId);
case TIME_CLIENT:
return new TimeClient(modelId);
case SCENE_SERVER:
return new SceneServer(modelId);
case SCENE_SETUP_SERVER:
return new SceneSetupServer(modelId);
case SCENE_CLIENT:
return new SceneClient(modelId);
case SCHEDULER_SERVER:
return new SchedulerServer(modelId);
case SCHEDULER_SETUP_SERVER:
return new SchedulerSetupServer(modelId);
case SCHEDULER_CLIENT:
return new SchedulerClient(modelId);
case LIGHT_LIGHTNESS_SERVER:
return new LightLightnessServer(modelId);
case LIGHT_LIGHTNESS_SETUP_SERVER:
return new LightLightnessSetupServer(modelId);
case LIGHT_LIGHTNESS_CLIENT:
return new LightLightnessClient(modelId);
case LIGHT_CTL_SERVER:
return new LightCtlServer(modelId);
case LIGHT_CTL_SETUP_SERVER:
return new LightCtlSetupServer(modelId);
case LIGHT_CTL_CLIENT:
return new LightCtlClient(modelId);
case LIGHT_CTL_TEMPERATURE_SERVER:
return new LightCtlTemperatureServer(modelId);
case LIGHT_HSL_SERVER:
return new LightHslServer(modelId);
case LIGHT_HSL_SETUP_SERVER:
return new LightHslSetupServer(modelId);
case LIGHT_HSL_CLIENT:
return new LightHslClient(modelId);
case LIGHT_HSL_HUE_SERVER:
return new LightHslHueServer(modelId);
case LIGHT_HSL_SATURATION_SERVER:
return new LightHslSaturationServer(modelId);
case LIGHT_XYL_SERVER:
return new LightXylServer(modelId);
case LIGHT_XYL_SETUP_SERVER:
return new LightXylSetupServer(modelId);
case LIGHT_XYL_CLIENT:
return new LightXylClient(modelId);
case LIGHT_LC_SERVER:
return new LightLcServer(modelId);
case LIGHT_LC_SETUP_SERVER:
return new LightLcSetupServer(modelId);
case LIGHT_LC_CLIENT:
return new LightLcClient(modelId);
default: {
Log.v(TAG, "Model ID: " + String.format(Locale.US, "%04X", modelId));
return null;
}
}
}
很明显,如果我们固件里面出现了上述未定义好的model,那么最后就会返回null,这是我们不想要的结果.然而瑞昱的两个model就未出现在上述定义之内.
修改内容
解决上述问题的方法其实很简单,通过比较IOS的SDK的做法,我们可以新建一个UnKnown Model,来接收Nordic未定义好的model.方法如下:
- 首先我们可以新建一个Unknown Model类
/*
* Copyright (c) 2018, Nordic Semiconductor
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package no.nordicsemi.android.meshprovisioner.models;
import android.os.Parcel;
@SuppressWarnings("WeakerAccess")
public class UnknowModel extends SigModel {
public static final Creator<UnknowModel> CREATOR = new Creator<UnknowModel>() {
@Override
public UnknowModel createFromParcel(final Parcel source) {
return new UnknowModel(source);
}
@Override
public UnknowModel[] newArray(final int size) {
return new UnknowModel[size];
}
};
public UnknowModel(final int modelId) {
super(modelId);
}
private UnknowModel(final Parcel source) {
super(source);
}
@Override
public String getModelName() {
return "Unkown model";
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(final Parcel dest, final int flags) {
super.parcelMeshModel(dest, flags);
}
}
2.如果我们在case里面没找到对应的model,我们在getSigModel的default里面加上UnknowModel配置.代码如下:
/**
* Returns the Bluetooth sig model based on the model id.
*
* @param modelId bluetooth sig model id
* @return SigModel
*/
public static SigModel getSigModel(final int modelId) {
switch (modelId) {
//代码省略
default: {
Log.v(TAG, "Model ID: " + String.format(Locale.US, "%04X", modelId));
return new UnknowModel(modelId);
}
}
}
因此,问题得到迎刃而解.
如果任何疑问,请联系邮箱:569133338@qq.com