542 lines
17 KiB
C
542 lines
17 KiB
C
/*
|
|
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
|
|
* Licensed under the MIT License (the "License"); you may not use this file except in
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
* http://opensource.org/licenses/MIT
|
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is
|
|
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
|
* either express or implied. See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#include "ble_qiot_template.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "ble_qiot_export.h"
|
|
#include "ble_qiot_common.h"
|
|
#include "ble_qiot_param_check.h"
|
|
|
|
|
|
extern void property_power_switch(const char *data, uint16_t len);
|
|
extern void action_led_blink(int ms);
|
|
extern void report_reply_blink(void);
|
|
|
|
|
|
static uint8_t sg_test_power_switch = false;
|
|
|
|
static int ble_property_power_switch_set(const char *data, uint16_t len)
|
|
{
|
|
ble_qiot_log_d("set property power_switch %d", *(uint8_t *)data);
|
|
property_power_switch(data, len);
|
|
sg_test_power_switch = data[0];
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ble_property_power_switch_get(char *data, uint16_t buf_len)
|
|
{
|
|
ble_qiot_log_d("get property power_switch %d", sg_test_power_switch);
|
|
data[0] = sg_test_power_switch;
|
|
|
|
return sizeof(uint8_t);
|
|
}
|
|
|
|
static uint16_t sg_test_color = 0;
|
|
|
|
static int ble_property_color_set(const char *data, uint16_t len)
|
|
{
|
|
uint16_t color_value = 0;
|
|
|
|
memcpy(&color_value, data, sizeof(uint16_t));
|
|
color_value = NTOHS(color_value);
|
|
ble_qiot_log_d("set property color %d", color_value);
|
|
sg_test_color = color_value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ble_property_color_get(char *data, uint16_t buf_len)
|
|
{
|
|
uint16_t color_value = 0;
|
|
|
|
ble_qiot_log_d("get property color %d", color_value);
|
|
color_value = HTONS(sg_test_color);
|
|
memcpy(data, &color_value, sizeof(uint16_t));
|
|
|
|
return sizeof(uint16_t);
|
|
}
|
|
|
|
static int sg_test_brightness = 0;
|
|
|
|
static int ble_property_brightness_set(const char *data, uint16_t len)
|
|
{
|
|
int brightness_value = 0;
|
|
|
|
memcpy(&brightness_value, data, sizeof(int));
|
|
brightness_value = NTOHL(brightness_value);
|
|
|
|
if ((brightness_value < BLE_QIOT_PROPERTY_BRIGHTNESS_MIN) ||
|
|
(brightness_value > BLE_QIOT_PROPERTY_BRIGHTNESS_MAX)) {
|
|
ble_qiot_log_e("invalid brightness value %d", brightness_value);
|
|
return -1;
|
|
}
|
|
|
|
ble_qiot_log_d("set property brightness %d", brightness_value);
|
|
sg_test_brightness = brightness_value;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ble_property_brightness_get(char *data, uint16_t buf_len)
|
|
{
|
|
int brightness_value = 0;
|
|
|
|
ble_qiot_log_d("get property brightness %d", sg_test_brightness);
|
|
brightness_value = HTONL(sg_test_brightness);
|
|
memcpy(data, &brightness_value, sizeof(int));
|
|
|
|
return sizeof(uint32_t);
|
|
}
|
|
|
|
static char sg_test_name[100 + 1] = "default name";
|
|
|
|
static int ble_property_name_set(const char *data, uint16_t len)
|
|
{
|
|
ble_qiot_log_d("set property name %.*s", len, data);
|
|
if (len > sizeof(sg_test_name) - 1) {
|
|
ble_qiot_log_d("too long name");
|
|
return -1;
|
|
}
|
|
memset(sg_test_name, 0, sizeof(sg_test_name));
|
|
memcpy(sg_test_name, data, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ble_property_name_get(char *data, uint16_t buf_len)
|
|
{
|
|
int i = 0;
|
|
|
|
ble_qiot_log_d("get property name %s", sg_test_name);
|
|
if (0 == strncmp("default name", sg_test_name, sizeof("default name") - 1)) {
|
|
for (i = 0; i < 26 * 3; i++) {
|
|
data[i] = 'a' + (i % 26);
|
|
}
|
|
return i;
|
|
} else {
|
|
memcpy(data, sg_test_name, strlen(sg_test_name));
|
|
return strlen(sg_test_name);
|
|
}
|
|
}
|
|
|
|
static ble_property_t sg_ble_property_array[BLE_QIOT_PROPERTY_ID_BUTT] = {
|
|
{ble_property_power_switch_set, ble_property_power_switch_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_BOOL},
|
|
{ble_property_color_set, ble_property_color_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_ENUM},
|
|
{ble_property_brightness_set, ble_property_brightness_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_INT},
|
|
{ble_property_name_set, ble_property_name_get, BLE_QIOT_PROPERTY_AUTH_RW, BLE_QIOT_DATA_TYPE_STRING},
|
|
};
|
|
|
|
static bool ble_check_space_enough_by_type(uint8_t type, uint16_t left_size)
|
|
{
|
|
switch (type) {
|
|
case BLE_QIOT_DATA_TYPE_BOOL:
|
|
return left_size >= sizeof(uint8_t);
|
|
case BLE_QIOT_DATA_TYPE_INT:
|
|
case BLE_QIOT_DATA_TYPE_FLOAT:
|
|
case BLE_QIOT_DATA_TYPE_TIME:
|
|
return left_size >= sizeof(uint32_t);
|
|
case BLE_QIOT_DATA_TYPE_ENUM:
|
|
return left_size >= sizeof(uint16_t);
|
|
default:
|
|
// string length is unknow, default true
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static uint16_t ble_check_ret_value_by_type(uint8_t type, uint16_t buf_len, uint16_t ret_val)
|
|
{
|
|
switch (type) {
|
|
case BLE_QIOT_DATA_TYPE_BOOL:
|
|
return ret_val <= sizeof(uint8_t);
|
|
case BLE_QIOT_DATA_TYPE_INT:
|
|
case BLE_QIOT_DATA_TYPE_FLOAT:
|
|
case BLE_QIOT_DATA_TYPE_TIME:
|
|
return ret_val <= sizeof(uint32_t);
|
|
case BLE_QIOT_DATA_TYPE_ENUM:
|
|
return ret_val <= sizeof(uint16_t);
|
|
default:
|
|
// string length is unknow, default true
|
|
return ret_val <= buf_len;
|
|
}
|
|
}
|
|
|
|
uint8_t ble_get_property_type_by_id(uint8_t id)
|
|
{
|
|
if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
|
|
ble_qiot_log_e("invalid property id %d", id);
|
|
return BLE_QIOT_DATA_TYPE_BUTT;
|
|
}
|
|
return sg_ble_property_array[id].type;
|
|
}
|
|
|
|
int ble_user_property_set_data(const e_ble_tlv *tlv)
|
|
{
|
|
POINTER_SANITY_CHECK(tlv, BLE_QIOT_RS_ERR_PARA);
|
|
if (tlv->id >= BLE_QIOT_PROPERTY_ID_BUTT) {
|
|
ble_qiot_log_e("invalid property id %d", tlv->id);
|
|
return BLE_QIOT_RS_ERR;
|
|
}
|
|
|
|
if (NULL != sg_ble_property_array[tlv->id].set_cb) {
|
|
if (0 != sg_ble_property_array[tlv->id].set_cb(tlv->val, tlv->len)) {
|
|
ble_qiot_log_e("set property id %d failed", tlv->id);
|
|
return BLE_QIOT_RS_ERR;
|
|
} else {
|
|
return BLE_QIOT_RS_OK;
|
|
}
|
|
}
|
|
ble_qiot_log_e("invalid set callback, id %d", tlv->id);
|
|
|
|
return BLE_QIOT_RS_ERR;
|
|
}
|
|
|
|
int ble_user_property_get_data_by_id(uint8_t id, char *buf, uint16_t buf_len)
|
|
{
|
|
int ret_len = 0;
|
|
|
|
POINTER_SANITY_CHECK(buf, BLE_QIOT_RS_ERR_PARA);
|
|
if (id >= BLE_QIOT_PROPERTY_ID_BUTT) {
|
|
ble_qiot_log_e("invalid property id %d", id);
|
|
return -1;
|
|
}
|
|
|
|
if (NULL != sg_ble_property_array[id].get_cb) {
|
|
if (!ble_check_space_enough_by_type(sg_ble_property_array[id].type, buf_len)) {
|
|
ble_qiot_log_e("not enough space get property id %d data", id);
|
|
return -1;
|
|
}
|
|
ret_len = sg_ble_property_array[id].get_cb(buf, buf_len);
|
|
if (ret_len < 0) {
|
|
ble_qiot_log_e("get property id %d data failed", id);
|
|
return -1;
|
|
} else {
|
|
if (ble_check_ret_value_by_type(sg_ble_property_array[id].type, buf_len, ret_len)) {
|
|
return ret_len;
|
|
} else {
|
|
ble_qiot_log_e("property id %d length invalid, type %d", id, sg_ble_property_array[id].type);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
ble_qiot_log_e("invalid callback, property id %d", id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ble_user_property_report_reply_handle(uint8_t result)
|
|
{
|
|
ble_qiot_log_d("report reply result %d", result);
|
|
if (0 == result) {
|
|
report_reply_blink();
|
|
}
|
|
|
|
return BLE_QIOT_RS_OK;
|
|
}
|
|
|
|
static int ble_event_get_status_report_status(char *buf, uint16_t buf_len)
|
|
{
|
|
buf[0] = 1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int ble_event_get_status_report_message(char *buf, uint16_t buf_len)
|
|
{
|
|
int i = 0;
|
|
|
|
for (i = 0; i < 26 * 3; i++) {
|
|
buf[i] = 'a' + (i % 26);
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static ble_event_param sg_ble_event_status_report_array[BLE_QIOT_EVENT_STATUS_REPORT_PARAM_ID_BUTT] = {
|
|
{ble_event_get_status_report_status, BLE_QIOT_DATA_TYPE_BOOL},
|
|
{ble_event_get_status_report_message, BLE_QIOT_DATA_TYPE_STRING},
|
|
};
|
|
|
|
static int ble_event_get_low_voltage_voltage(char *data, uint16_t buf_len)
|
|
{
|
|
float tmp = 1.0;
|
|
|
|
memcpy(data, &tmp, sizeof(float));
|
|
|
|
return sizeof(float);
|
|
}
|
|
|
|
static ble_event_param sg_ble_event_low_voltage_array[BLE_QIOT_EVENT_LOW_VOLTAGE_PARAM_ID_BUTT] = {
|
|
{ble_event_get_low_voltage_voltage, BLE_QIOT_DATA_TYPE_FLOAT},
|
|
};
|
|
|
|
static int ble_event_get_hardware_fault_name(char *data, uint16_t buf_len)
|
|
{
|
|
memcpy(data, "hardware_fault", sizeof("hardware_fault") - 1);
|
|
|
|
return sizeof("hardware_fault") - 1;
|
|
}
|
|
|
|
static int ble_event_get_hardware_fault_error_code(char *data, uint16_t buf_len)
|
|
{
|
|
int error_code = HTONL(1024);
|
|
|
|
memcpy(data, &error_code, sizeof(int));
|
|
|
|
return sizeof(int);
|
|
}
|
|
|
|
static ble_event_param sg_ble_event_hardware_fault_array[BLE_QIOT_EVENT_HARDWARE_FAULT_PARAM_ID_BUTT] = {
|
|
{ble_event_get_hardware_fault_name, BLE_QIOT_DATA_TYPE_STRING},
|
|
{ble_event_get_hardware_fault_error_code, BLE_QIOT_DATA_TYPE_INT},
|
|
};
|
|
|
|
static ble_event_t sg_ble_event_array[BLE_QIOT_EVENT_ID_BUTT] = {
|
|
{sg_ble_event_status_report_array, sizeof(sg_ble_event_status_report_array) / sizeof(ble_event_param)},
|
|
{sg_ble_event_low_voltage_array, sizeof(sg_ble_event_low_voltage_array) / sizeof(ble_event_param)},
|
|
{sg_ble_event_hardware_fault_array, sizeof(sg_ble_event_hardware_fault_array) / sizeof(ble_event_param)},
|
|
};
|
|
|
|
int ble_event_get_id_array_size(uint8_t event_id)
|
|
{
|
|
if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
|
|
ble_qiot_log_e("invalid event id %d", event_id);
|
|
return -1;
|
|
}
|
|
|
|
return sg_ble_event_array[event_id].array_size;
|
|
}
|
|
|
|
uint8_t ble_event_get_param_id_type(uint8_t event_id, uint8_t param_id)
|
|
{
|
|
if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
|
|
ble_qiot_log_e("invalid event id %d", event_id);
|
|
return BLE_QIOT_DATA_TYPE_BUTT;
|
|
}
|
|
if (param_id >= sg_ble_event_array[event_id].array_size) {
|
|
ble_qiot_log_e("invalid param id %d", param_id);
|
|
return BLE_QIOT_DATA_TYPE_BUTT;
|
|
}
|
|
|
|
return sg_ble_event_array[event_id].event_array[param_id].type;
|
|
}
|
|
|
|
int ble_event_get_data_by_id(uint8_t event_id, uint8_t param_id, char *out_buf, uint16_t buf_len)
|
|
{
|
|
int ret_len = 0;
|
|
|
|
if (event_id >= BLE_QIOT_EVENT_ID_BUTT) {
|
|
ble_qiot_log_e("invalid event id %d", event_id);
|
|
return -1;
|
|
}
|
|
if (param_id >= sg_ble_event_array[event_id].array_size) {
|
|
ble_qiot_log_e("invalid param id %d", param_id);
|
|
return -1;
|
|
}
|
|
if (NULL == sg_ble_event_array[event_id].event_array[param_id].get_cb) {
|
|
ble_qiot_log_e("invalid callback, event id %d, param id %d", event_id, param_id);
|
|
return 0;
|
|
}
|
|
|
|
if (!ble_check_space_enough_by_type(sg_ble_event_array[event_id].event_array[param_id].type, buf_len)) {
|
|
ble_qiot_log_e("not enough space get data, event id %d, param id %d", event_id, param_id);
|
|
return -1;
|
|
}
|
|
ret_len = sg_ble_event_array[event_id].event_array[param_id].get_cb(out_buf, buf_len);
|
|
if (ret_len < 0) {
|
|
ble_qiot_log_e("get event data failed, event id %d, param id %d", event_id, param_id);
|
|
return -1;
|
|
} else {
|
|
if (ble_check_ret_value_by_type(sg_ble_event_array[event_id].event_array[param_id].type, buf_len, ret_len)) {
|
|
return ret_len;
|
|
} else {
|
|
ble_qiot_log_e("evnet data length invalid, event id %d, param id %d, type %d", event_id, param_id,
|
|
sg_ble_event_array[event_id].event_array[param_id].type);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
int ble_user_event_reply_handle(uint8_t event_id, uint8_t result)
|
|
{
|
|
ble_qiot_log_d("event id %d, reply result %d", event_id, result);
|
|
|
|
return BLE_QIOT_RS_OK;
|
|
}
|
|
|
|
static int ble_action_handle_loop_input_cb(e_ble_tlv *input_param_array, uint8_t input_array_size,
|
|
uint8_t *output_id_array)
|
|
{
|
|
int result = 0;
|
|
|
|
if (NULL == input_param_array || NULL == output_id_array) {
|
|
ble_qiot_log_e("invalid param");
|
|
return -1;
|
|
}
|
|
|
|
report_reply_blink();
|
|
for (int i = 0; i < input_array_size; i++) {
|
|
ble_qiot_log_d("id %d", input_param_array[i].id);
|
|
}
|
|
|
|
memcpy(&result, input_param_array[0].val, sizeof(int));
|
|
result = NTOHL(result);
|
|
ble_qiot_log_d("id %d, val %d", input_param_array[0].id, result);
|
|
action_led_blink(result);
|
|
|
|
output_id_array[BLE_QIOT_ACTION_LOOP_OUTPUT_ID_RESULT] = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ble_action_handle_loop_output_cb(uint8_t output_id, char *buf, uint16_t buf_len)
|
|
{
|
|
int data_len = 0;
|
|
int i = 0;
|
|
|
|
switch (output_id) {
|
|
case BLE_QIOT_ACTION_LOOP_OUTPUT_ID_RESULT:
|
|
for (i = 0; i < 26 * 3; i++) {
|
|
buf[i] = 'a' + (i % 26);
|
|
}
|
|
data_len = i;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return data_len;
|
|
}
|
|
|
|
static uint8_t sg_ble_action_loop_input_type_array[BLE_QIOT_ACTION_LOOP_INPUT_ID_BUTT] = {
|
|
BLE_QIOT_DATA_TYPE_INT,
|
|
};
|
|
|
|
static uint8_t sg_ble_action_loop_output_type_array[BLE_QIOT_ACTION_LOOP_OUTPUT_ID_BUTT] = {
|
|
BLE_QIOT_DATA_TYPE_STRING,
|
|
};
|
|
|
|
static ble_action_t sg_ble_action_array[BLE_QIOT_ACTION_ID_BUTT] = {
|
|
{ble_action_handle_loop_input_cb, ble_action_handle_loop_output_cb, sg_ble_action_loop_input_type_array,
|
|
sg_ble_action_loop_output_type_array, sizeof(sg_ble_action_loop_input_type_array) / sizeof(uint8_t),
|
|
sizeof(sg_ble_action_loop_output_type_array) / sizeof(uint8_t)},
|
|
};
|
|
|
|
uint8_t ble_action_get_intput_type_by_id(uint8_t action_id, uint8_t input_id)
|
|
{
|
|
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
|
|
ble_qiot_log_e("invalid action id %d", action_id);
|
|
return BLE_QIOT_DATA_TYPE_BUTT;
|
|
}
|
|
if (input_id >= sg_ble_event_array[action_id].array_size) {
|
|
ble_qiot_log_e("invalid input id %d", input_id);
|
|
return BLE_QIOT_DATA_TYPE_BUTT;
|
|
}
|
|
|
|
return sg_ble_action_array[action_id].input_type_array[input_id];
|
|
}
|
|
|
|
uint8_t ble_action_get_output_type_by_id(uint8_t action_id, uint8_t output_id)
|
|
{
|
|
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
|
|
ble_qiot_log_e("invalid action id %d", action_id);
|
|
return BLE_QIOT_DATA_TYPE_BUTT;
|
|
}
|
|
if (output_id >= sg_ble_event_array[action_id].array_size) {
|
|
ble_qiot_log_e("invalid output id %d", output_id);
|
|
return BLE_QIOT_DATA_TYPE_BUTT;
|
|
}
|
|
|
|
return sg_ble_action_array[action_id].output_type_array[output_id];
|
|
}
|
|
|
|
int ble_action_get_input_id_size(uint8_t action_id)
|
|
{
|
|
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
|
|
ble_qiot_log_e("invalid action id %d", action_id);
|
|
return -1;
|
|
}
|
|
|
|
return sg_ble_action_array[action_id].input_id_size;
|
|
}
|
|
|
|
int ble_action_get_output_id_size(uint8_t action_id)
|
|
{
|
|
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
|
|
ble_qiot_log_e("invalid action id %d", action_id);
|
|
return -1;
|
|
}
|
|
|
|
return sg_ble_action_array[action_id].output_id_size;
|
|
}
|
|
|
|
int ble_action_user_handle_input_param(uint8_t action_id, e_ble_tlv *input_param_array, uint8_t input_array_size,
|
|
uint8_t *output_id_array)
|
|
{
|
|
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
|
|
ble_qiot_log_e("invalid action id %d", action_id);
|
|
return -1;
|
|
}
|
|
|
|
if (NULL != sg_ble_action_array[action_id].input_cb) {
|
|
if (0 != sg_ble_action_array[action_id].input_cb(input_param_array, input_array_size, output_id_array)) {
|
|
ble_qiot_log_e("input handle error");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ble_action_user_handle_output_param(uint8_t action_id, uint8_t output_id, char *buf, uint16_t buf_len)
|
|
{
|
|
int ret_len = 0;
|
|
|
|
if (action_id >= BLE_QIOT_ACTION_ID_BUTT) {
|
|
ble_qiot_log_e("invalid action id %d", action_id);
|
|
return -1;
|
|
}
|
|
if (NULL == sg_ble_action_array[action_id].output_cb) {
|
|
ble_qiot_log_e("invalid callback, action id %d", action_id);
|
|
return 0;
|
|
}
|
|
|
|
if (!ble_check_space_enough_by_type(sg_ble_action_array[action_id].output_type_array[output_id], buf_len)) {
|
|
ble_qiot_log_e("not enough space get data, action id %d, output id %d", action_id, output_id);
|
|
return -1;
|
|
}
|
|
|
|
ret_len = sg_ble_action_array[action_id].output_cb(output_id, buf, buf_len);
|
|
if (ret_len < 0) {
|
|
ble_qiot_log_e("get action data failed, action id %d, output id %d", action_id, output_id);
|
|
return -1;
|
|
} else {
|
|
if (ble_check_ret_value_by_type(sg_ble_action_array[action_id].output_type_array[output_id], buf_len,
|
|
ret_len)) {
|
|
return ret_len;
|
|
} else {
|
|
ble_qiot_log_e("action data length invalid, action id %d, output id %d", action_id, output_id);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|