diff --git a/bk_aidk/bk_avdk/bk_idk/components/bk_cli/cli_ota.c b/bk_aidk/bk_avdk/bk_idk/components/bk_cli/cli_ota.c index 8e74673d..99df39d4 100755 --- a/bk_aidk/bk_avdk/bk_idk/components/bk_cli/cli_ota.c +++ b/bk_aidk/bk_avdk/bk_idk/components/bk_cli/cli_ota.c @@ -113,6 +113,9 @@ char *https_url = NULL; int bk_https_ota_download(const char *url); void bk_https_start_download(beken_thread_arg_t arg) { int ret; + //退出WEBSOCKET + + //退出语音识别 ret = bk_https_ota_download(https_url); if(ret != BK_OK) { os_printf("%s download fail, ret:%d\r\n", __func__, ret); diff --git a/bk_aidk/bk_avdk/bk_idk/tools/build_tools/kconfig_new/__pycache__/gen_kconfig_doc.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/build_tools/kconfig_new/__pycache__/gen_kconfig_doc.cpython-310.pyc new file mode 100644 index 00000000..508c2c3b Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/build_tools/kconfig_new/__pycache__/gen_kconfig_doc.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/build_tools/kconfig_new/__pycache__/kconfiglib.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/build_tools/kconfig_new/__pycache__/kconfiglib.cpython-310.pyc new file mode 100644 index 00000000..4bcac75f Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/build_tools/kconfig_new/__pycache__/kconfiglib.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/build_tools/part_table_tools/config/gen_files_list.txt b/bk_aidk/bk_avdk/bk_idk/tools/build_tools/part_table_tools/config/gen_files_list.txt index a65ec833..0b489067 100755 --- a/bk_aidk/bk_avdk/bk_idk/tools/build_tools/part_table_tools/config/gen_files_list.txt +++ b/bk_aidk/bk_avdk/bk_idk/tools/build_tools/part_table_tools/config/gen_files_list.txt @@ -1 +1,2 @@ -/home/harmony/armino/git_bk258/bk_zuixin/bk7258_iR58/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_packager/partition_bk7256_ota_a_new.json +/home/harmony/work/bk7258_iR58/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_packager/partition_bk7256_ota_a_new.json + diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/__init__.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 00000000..104a936a Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/__init__.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/bl1_sign.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/bl1_sign.cpython-310.pyc new file mode 100644 index 00000000..eb8cf402 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/bl1_sign.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/bl2_sign.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/bl2_sign.cpython-310.pyc new file mode 100644 index 00000000..dc95df25 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/bl2_sign.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/common.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/common.cpython-310.pyc new file mode 100644 index 00000000..39f6a70c Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/common.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/compress.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/compress.cpython-310.pyc new file mode 100644 index 00000000..886c66a3 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/compress.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/copy_json_data_csv.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/copy_json_data_csv.cpython-310.pyc new file mode 100644 index 00000000..df1b3a84 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/copy_json_data_csv.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/crc.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/crc.cpython-310.pyc new file mode 100644 index 00000000..92b5d9d3 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/crc.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/encrypt.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/encrypt.cpython-310.pyc new file mode 100644 index 00000000..90fe6862 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/encrypt.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_code.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_code.cpython-310.pyc new file mode 100644 index 00000000..5759baf4 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_code.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_license.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_license.cpython-310.pyc new file mode 100644 index 00000000..a6d2ddec Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_license.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_mpc.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_mpc.cpython-310.pyc new file mode 100644 index 00000000..01547b69 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_mpc.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_ota.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_ota.cpython-310.pyc new file mode 100644 index 00000000..c15f6c38 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_ota.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_otp.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_otp.cpython-310.pyc new file mode 100644 index 00000000..3b5332a4 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_otp.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_otp_map.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_otp_map.cpython-310.pyc new file mode 100644 index 00000000..3335db0b Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_otp_map.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_partition.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_partition.cpython-310.pyc new file mode 100644 index 00000000..d336962f Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_partition.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_ppc.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_ppc.cpython-310.pyc new file mode 100644 index 00000000..7e438900 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_ppc.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_security.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_security.cpython-310.pyc new file mode 100644 index 00000000..33a9ca04 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/gen_security.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/genbl1.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/genbl1.cpython-310.pyc new file mode 100644 index 00000000..dd4ccb15 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/genbl1.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/mpc.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/mpc.cpython-310.pyc new file mode 100644 index 00000000..70841861 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/mpc.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/ota.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/ota.cpython-310.pyc new file mode 100644 index 00000000..2f653f8f Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/ota.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/otp.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/otp.cpython-310.pyc new file mode 100644 index 00000000..fddc4fb8 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/otp.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/pack.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/pack.cpython-310.pyc new file mode 100644 index 00000000..a5d8d90f Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/pack.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/parse_csv.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/parse_csv.cpython-310.pyc new file mode 100644 index 00000000..dd1d1568 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/parse_csv.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/partition.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/partition.cpython-310.pyc new file mode 100644 index 00000000..9b89a941 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/partition.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/pk_hash.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/pk_hash.cpython-310.pyc new file mode 100644 index 00000000..2b415567 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/pk_hash.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/ppc.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/ppc.cpython-310.pyc new file mode 100644 index 00000000..714655ea Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/ppc.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/rotpk_hash.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/rotpk_hash.cpython-310.pyc new file mode 100644 index 00000000..5c533c67 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/rotpk_hash.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/security.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/security.cpython-310.pyc new file mode 100644 index 00000000..ee913bb8 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/security.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/sign.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/sign.cpython-310.pyc new file mode 100644 index 00000000..c66b6fda Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/sign.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/solution_generator.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/solution_generator.cpython-310.pyc new file mode 100644 index 00000000..eaa46433 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/solution_generator.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/steps.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/steps.cpython-310.pyc new file mode 100644 index 00000000..8a361d75 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/steps.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/xts_aes.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/xts_aes.cpython-310.pyc new file mode 100644 index 00000000..97647f0a Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/beken_utils/scripts/__pycache__/xts_aes.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/rtt_ota/ota-rbl/__pycache__/aes.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/rtt_ota/ota-rbl/__pycache__/aes.cpython-310.pyc new file mode 100644 index 00000000..d602a4cb Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/rtt_ota/ota-rbl/__pycache__/aes.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/rtt_ota/ota-rbl/__pycache__/aes_tables.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/rtt_ota/ota-rbl/__pycache__/aes_tables.cpython-310.pyc new file mode 100644 index 00000000..f625bd24 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/rtt_ota/ota-rbl/__pycache__/aes_tables.cpython-310.pyc differ diff --git a/bk_aidk/bk_avdk/bk_idk/tools/env_tools/rtt_ota/ota-rbl/__pycache__/xts_aes.cpython-310.pyc b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/rtt_ota/ota-rbl/__pycache__/xts_aes.cpython-310.pyc new file mode 100644 index 00000000..1a1eb457 Binary files /dev/null and b/bk_aidk/bk_avdk/bk_idk/tools/env_tools/rtt_ota/ota-rbl/__pycache__/xts_aes.cpython-310.pyc differ diff --git a/bk_aidk/projects/beken_wss_paopao/main/CMakeLists.txt b/bk_aidk/projects/beken_wss_paopao/main/CMakeLists.txt index c7397dda..b381c0f0 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/CMakeLists.txt +++ b/bk_aidk/projects/beken_wss_paopao/main/CMakeLists.txt @@ -26,6 +26,8 @@ list(APPEND srcs iot/iot_sleep_helper.c iot/thing.c iot/iot_ota.c + mcp/mcp_server.c + application.c ) if (CONFIG_NETWORK_AUTO_RECONNECT) list(APPEND srcs diff --git a/bk_aidk/projects/beken_wss_paopao/main/app_main.c b/bk_aidk/projects/beken_wss_paopao/main/app_main.c index d0934f83..4008fbcb 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/app_main.c +++ b/bk_aidk/projects/beken_wss_paopao/main/app_main.c @@ -42,7 +42,7 @@ #include "app_main.h" #include "spi_led.h" #include "bat_main.h" - +#include "application.h" extern void user_app_main(void); extern void rtos_set_user_app_entry(beken_thread_function_t entry); @@ -673,6 +673,7 @@ static void handle_system_event(key_event_t event) //poka ws2812_init(); thing_init(); + app_start(); init_bat_timer(); // spi_led_init(); bk_printf("VER:%s\r\n","1.0.6"); diff --git a/bk_aidk/projects/beken_wss_paopao/main/application.c b/bk_aidk/projects/beken_wss_paopao/main/application.c index e69de29b..23d5fd99 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/application.c +++ b/bk_aidk/projects/beken_wss_paopao/main/application.c @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include +#include "bk_private/bk_init.h" +#include +#include +#include "components/webclient.h" +#include "cJSON.h" +#include "components/bk_uid.h" +#include "bk_genie_comm.h" + +#include "thing.h" +#include "iot_lamp.h" +#include "iot_speaker.h" +#include "iot_sleep_helper.h" +#include "bat_main.h" +#include "application.h" +#include "mcp/mcp_server.h" +#include "beken_rtc.h" + +#include "iot_lamp.h" +#include "iot_speaker.h" +#include "iot_sleep_helper.h" +#include "bat_main.h" +#include "spi_led.h" +#include "app_event.h" + +#define TAG "APP" +#define LOGI(...) BK_LOGI(TAG, ##__VA_ARGS__) +#define LOGW(...) BK_LOGW(TAG, ##__VA_ARGS__) +#define LOGE(...) BK_LOGE(TAG, ##__VA_ARGS__) +#define LOGD(...) BK_LOGD(TAG, ##__VA_ARGS__) + + + +static ReturnValue sleep_helper_set_mode_callback(const PropertyList* properties) { + Property* mode_prop = property_list_get_by_name(properties, "mode"); + if (!mode_prop || property_get_type(mode_prop) != PROPERTY_TYPE_INTEGER) { + return return_value_create_string("{\"error\":\"Invalid level parameter\"}"); + } + + int mode = property_get_integer_value(mode_prop); + sleep_helper_set_mode(mode); + LOGE("sleep_helper_setmode ->%d\n",mode); + return return_value_create_string("{\"success\":true}"); +} + +static ReturnValue sleep_helper_set_level_callback(const PropertyList* properties) { + Property* level_prop = property_list_get_by_name(properties, "mode"); + if (!level_prop || property_get_type(level_prop) != PROPERTY_TYPE_INTEGER) { + return return_value_create_string("{\"error\":\"Invalid level parameter\"}"); + } + int level = property_get_integer_value(level_prop); + sleep_helper_set_level(level); + LOGE("sleep_helper_set_level ->%d\n",level); + return return_value_create_string("{\"success\":true}"); +} + +static ReturnValue sleep_helper_open_callback(const PropertyList* properties) { + LOGE("sleep_helper_open_callback\n"); + int result = sleep_helper_open(); + if(result == -1){ + return return_value_create_string("{\"success\":false,\"error\":\"耳夹未接入\"}"); + }else{ + return return_value_create_string("{\"success\":true}"); + } + //return return_value_create_string("{\"success\":true}"); +} + +static ReturnValue sleep_helper_close_callback(const PropertyList* properties) { + LOGE("sleep_helper_close_callback\n"); + sleep_helper_close(); + return return_value_create_string("{\"success\":true}"); +} + +// 设备状态工具回调 +static ReturnValue get_device_status_callback(const PropertyList* properties) { + cJSON* status = cJSON_CreateObject(); + + //软件版本 + cJSON* application = cJSON_CreateObject(); + cJSON_AddStringToObject(application, "version", APPLICATION_VERSION); + cJSON_AddItemToObject(status, "application", application); + + //扬声器状态 + cJSON* audio_speaker = cJSON_CreateObject(); + cJSON_AddNumberToObject(audio_speaker, "volume", speaker_volume_get_current()); + cJSON_AddItemToObject(status, "audio_speaker", audio_speaker); + //灯光状态 不需要获取 肉眼所见 + cJSON* light = cJSON_CreateObject(); + cJSON_AddNumberToObject(light, "brightness", lamp_get_bright()); + //cJSON_AddStringToObject(screen, "theme", "light"); + cJSON_AddItemToObject(status, "light", light); + //电池状态 + cJSON* battery = cJSON_CreateObject(); + cJSON_AddNumberToObject(battery, "level", battery_get_percent()); + cJSON_AddItemToObject(status, "battery", battery); + + char *jsonString = cJSON_PrintUnformatted(status); + + ReturnValue ret = return_value_create_string(jsonString); + cJSON_Delete(status); + return ret; +} + +// 设置音量工具回调 +static ReturnValue set_volume_callback(const PropertyList* properties) { + Property* volume_prop = property_list_get_by_name(properties, "volume"); + if (!volume_prop || property_get_type(volume_prop) != PROPERTY_TYPE_INTEGER) { + return return_value_create_string("{\"error\":\"Invalid volume parameter\"}"); + } + + int volume = property_get_integer_value(volume_prop); + LOGE("board_set_volume ->%d\n",volume); + //board_set_volume(volume); + //uint32_t speaker_volume_get_current(); + speaker_set_volume(volume); + return return_value_create_string("{\"success\":true}"); +} + +// 设置亮度工具回调 +static ReturnValue set_brightness_callback(const PropertyList* properties) { + Property* brightness_prop = property_list_get_by_name(properties, "brightness"); + if (!brightness_prop || property_get_type(brightness_prop) != PROPERTY_TYPE_INTEGER) { + return return_value_create_string("{\"error\":\"Invalid brightness parameter\"}"); + } + int brightness = property_get_integer_value(brightness_prop); + if(brightness == 0){ + ws2812_led_clear_all(); + }else{ + //ws2812_set_all_led(0xFFFFFF,brightness); + ws2812_set_all_led_brightness(brightness); + } + LOGE("board_set_brightness ->%d\n",brightness); + return return_value_create_string("{\"success\":true}"); +} + +// 设置主题工具回调 +static ReturnValue set_theme_callback(const PropertyList* properties) { + Property* theme_prop = property_list_get_by_name(properties, "theme"); + if (!theme_prop || property_get_type(theme_prop) != PROPERTY_TYPE_STRING) { + return return_value_create_string("{\"error\":\"Invalid theme parameter\"}"); + } + const char* theme = property_get_string_value(theme_prop); + LOGE("board_set_theme ->%s\n",theme); + return return_value_create_string("{\"success\":true}"); +} + +// 拍照工具回调 +static ReturnValue take_photo_callback(const PropertyList* properties) { + ReturnValue ret = return_value_create_string("photo_data"); + return ret; +} + +// OTA升级检测工具回调 +static ReturnValue ota_update_device_callback(const PropertyList* properties) { + // ReturnValue ret = return_value_create_string("photo_data"); + // 电量低于25 不允许执行OTA + int battery = battery_get_percent(); + if (battery < 25) + { + LOGE("power low bat:%d ,don't ota !!\n", battery); + app_event_send_msg(APP_EVT_LOW_VOLTAGE, 0); + return return_value_create_string("{\"success\":false,\"error\":\"电量低,不允许升级设备\"}"); + } + iot_lamp_check_ota(); + return return_value_create_string("{\"success\":true}"); +} + +// 设备助眠仪状态回调 +static ReturnValue sleep_helper_get_device_status_callback(const PropertyList* properties) { + + cJSON* status = cJSON_CreateObject(); + //助眠仪的状态 + cJSON* sleep_helper = cJSON_CreateObject(); + + cJSON_AddNumberToObject(sleep_helper, "model", sleep_helper_get_mode()); + cJSON_AddNumberToObject(sleep_helper, "level", sleep_helper_get_level()); + cJSON_AddItemToObject(status, "sleep_helper", sleep_helper); + + char *jsonString = cJSON_PrintUnformatted(status); + ReturnValue ret = return_value_create_string(jsonString); + cJSON_Delete(status); + return ret; +} + +void app_mcp_init(){ + + McpServer* mcp_server = mcp_server_get_instance(); + // 助眠仪模式 + { + PropertyList* props = property_list_create(); + Property* prop_mode = property_create_integer("mode", false, 0, true, 0, 3); + property_list_add_property(props, prop_mode); + mcp_server_add_tool_with_params(mcp_server, "self.sleep_helper.set_mode", "设置助眠仪的模式", props, sleep_helper_set_mode_callback); + } + // 助眠仪等级 + { + PropertyList* props = property_list_create(); + Property* prop_level = property_create_integer("level", false, 1, true, 1, 9); + property_list_add_property(props, prop_level); + mcp_server_add_tool_with_params(mcp_server, "self.sleep_helper.set_level", "设置助眠仪的等级", props, sleep_helper_set_level_callback); + } + //打开助眠仪 + { + PropertyList* props = property_list_create(); + mcp_server_add_tool_with_params(mcp_server, "self.sleep_helper.open", "打开助眠仪", props, sleep_helper_open_callback); + } + //关闭助眠仪 + { + PropertyList* props = property_list_create(); + mcp_server_add_tool_with_params(mcp_server, "self.sleep_helper.close", "关闭助眠仪", props, sleep_helper_close_callback); + } + + // 获取助眠仪状态 + { + PropertyList* props = property_list_create(); + mcp_server_add_tool_with_params(mcp_server, "self.sleep_helper.get_status", + "获取助眠仪状态 (mode=0 表示已经关闭, mode=1 表示模式1, mode=2 表示模式2,mode=3 表示模式3,level (0-9)分别代表9个不同等级", props, sleep_helper_get_device_status_callback); + } + + // 添加获取设备状态工具 + { + PropertyList* props = property_list_create(); + mcp_server_add_tool_with_params(mcp_server, "self.get_device_status", "获取软件版本,设备音量,灯光亮度,设备电池状态", props, get_device_status_callback); + } + + // 添加设置音量工具 + { + PropertyList* props = property_list_create(); + Property* volume_prop = property_create_integer("volume", false, 0, true, 0, 100); + property_list_add_property(props, volume_prop); + + //Property* vol_prop = property_create_integer("vol", false, 0, true, 0, 100); + //property_list_add_property(props, vol_prop); + mcp_server_add_tool_with_params( + mcp_server, + "self.audio_speaker.set_volume", + "Set the volume of the audio speaker. If the current volume is unknown, you must call `self.get_device_status` tool first and then call this tool.", + props, set_volume_callback); + + } + // 添加设置亮度工具 + { + PropertyList* props = property_list_create(); + Property* brightness_prop = property_create_integer("brightness", false, 0, true, 0, 100); + property_list_add_property(props, brightness_prop); + mcp_server_add_tool_with_params(mcp_server, "self.screen.set_brightness", "Set screen brightness", props, set_brightness_callback); + } + // 添加拍照工具 + //{ + // PropertyList* props = property_list_create(); + // mcp_server_add_tool_with_params(mcp_server, "take_photo", "Take a photo", props, take_photo_callback); + //} + + // OTA + { + PropertyList* props = property_list_create(); + mcp_server_add_tool_with_params(mcp_server, "self.ota.update_device", "更新拍拍灯乐小牛软件,执行该指令需要和用户二次确认才允许下发这个指令", props, ota_update_device_callback); + } +} + +void app_start(){ + app_mcp_init(); +} \ No newline at end of file diff --git a/bk_aidk/projects/beken_wss_paopao/main/application.h b/bk_aidk/projects/beken_wss_paopao/main/application.h index 90ef7805..d3acb7e3 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/application.h +++ b/bk_aidk/projects/beken_wss_paopao/main/application.h @@ -80,7 +80,7 @@ enum ListeningMode { * 解决调用BLE设置灯光常亮时异常问题 */ -#define APPLICATION_VERSION "1.1.5" +#define APPLICATION_VERSION "1.1.6" #define APPLICATION_DEFULT_OTA_URL "https://xiaozhi.xa-poka.com/xiaozhi/ota/" #define APPLICATION_CONFIG_KEY_AI_URL "ai_url" /** @@ -95,10 +95,17 @@ enum ListeningMode { *助眠超时关闭 单位分钟 10 - 表示助眠10分钟后关闭 */ #define APPLICATION_DEFULT_SLEEP_TIMEOUT 10 +/** + * 使用本地MCP协议 + */ +#define APPLICATION_IOT_PROTOCOL_MCP 1 +#define APPLICATION_DEVICE_BOARD_NAME "Poka" void app_set_ota_url(char * ota_url); char* app_get_ota_url(); +void app_start(); + #ifdef __cplusplus } #endif diff --git a/bk_aidk/projects/beken_wss_paopao/main/bat_main.c b/bk_aidk/projects/beken_wss_paopao/main/bat_main.c index a1af7cfd..d6c622f6 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/bat_main.c +++ b/bk_aidk/projects/beken_wss_paopao/main/bat_main.c @@ -52,7 +52,7 @@ #define BAT_DETEC_ADC_STEADY_CTRL 7 #define BAT_DETEC_ADC_SAMPLE_RATE 0 -#define BATTERY_MAX_VOLTAGE 4200 +#define BATTERY_MAX_VOLTAGE 4100 #define BATTERY_MIN_VOLTAGE 3400 static int batt_percent = 0; diff --git a/bk_aidk/projects/beken_wss_paopao/main/bat_main.h b/bk_aidk/projects/beken_wss_paopao/main/bat_main.h index 8b4f1eb6..bc2c883a 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/bat_main.h +++ b/bk_aidk/projects/beken_wss_paopao/main/bat_main.h @@ -1,3 +1,16 @@ +/************************************************************* + * + * Copyright (C) POKA + * All rights reserved. + * + *************************************************************/ +#ifndef __BATTERY_H__ +#define __BATTERY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + typedef enum{ EVT_BATTERY_MAIN_CHARGING = 0, EVT_BATTERY_MAIN_LOW_VOLTAGE, @@ -14,4 +27,10 @@ void poweroff_voice(); /** * 获取电量百分百 */ -int battery_get_percent(); \ No newline at end of file +int battery_get_percent(); + +#ifdef __cplusplus +} +#endif +#endif /* __BATTERY_H__ */ + diff --git a/bk_aidk/projects/beken_wss_paopao/main/beken_sdk/beken_rtc.c b/bk_aidk/projects/beken_wss_paopao/main/beken_sdk/beken_rtc.c index 4f9d174f..6ada8cc4 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/beken_sdk/beken_rtc.c +++ b/bk_aidk/projects/beken_wss_paopao/main/beken_sdk/beken_rtc.c @@ -14,6 +14,7 @@ #endif #include "bk_genie_comm.h" #include "thing.h" +#include "application.h" #define TAG "beken_rtc" #define LOGI(...) BK_LOGI(TAG, ##__VA_ARGS__) @@ -810,68 +811,39 @@ int rtc_websocket_send_text(transport web_socket, void *str, enum MsgType msgtyp case BEKEN_RTC_SEND_ABORT:{ cJSON *abortMessage = cJSON_CreateObject(); - if (abortMessage == NULL) { - - } - cJSON_AddStringToObject(abortMessage, "type", "abort") ; cJSON_AddStringToObject(abortMessage, "reason", "user_interrupted") ; - - char *jsonString = cJSON_Print(abortMessage); - + char *jsonString = cJSON_PrintUnformatted(abortMessage); websocket_client_send_text(web_socket, jsonString, strlen(jsonString), 10*1000); cJSON_Delete(abortMessage); break; } case BEKEN_RTC_SEND_LISTEN:{ - // ������ JSON ���� - cJSON *listenMessage = cJSON_CreateObject(); - if (listenMessage == NULL) { - - } - - cJSON_AddStringToObject(listenMessage, "session_id", ""); - - - cJSON_AddStringToObject(listenMessage, "type", "listen"); - - cJSON_AddStringToObject(listenMessage, "state", "detect"); - cJSON_AddStringToObject(listenMessage, "mode", "auto"); - cJSON_AddStringToObject(listenMessage, "text", "С��ͬѧ"); - - // �� cJSON ����ת��Ϊ�ַ��� - char *jsonString = cJSON_Print(listenMessage); - BK_LOGE("WebSocket", "Sending: %s\r\n", jsonString); - websocket_client_send_text(web_socket, jsonString, strlen(jsonString), 10*1000); - // ɾ�� cJSON �������ͷ��ڴ� - cJSON_Delete(listenMessage); + cJSON *listenMessage = cJSON_CreateObject(); + cJSON_AddStringToObject(listenMessage, "session_id", ""); + cJSON_AddStringToObject(listenMessage, "type", "listen"); + cJSON_AddStringToObject(listenMessage, "state", "detect"); + cJSON_AddStringToObject(listenMessage, "mode", "auto"); + cJSON_AddStringToObject(listenMessage, "text", ""); + + char *jsonString = cJSON_PrintUnformatted(listenMessage); + BK_LOGE("WebSocket", "Sending: %s\r\n", jsonString); + websocket_client_send_text(web_socket, jsonString, strlen(jsonString), 10*1000); + cJSON_Delete(listenMessage); break; } case BEKEN_RTC_SEND_START_LISTEN:{ cJSON *startlistent = cJSON_CreateObject(); - - // char *session_id = getGlobalSessionId(); - - // bk_printf("Global session_id_BEKEN_RTC_SEND_START_LISTEN: %s\n", session_id); - - // ����session_id�ֶ� - cJSON_AddStringToObject(startlistent, "session_id", ""); + extern char *getGlobalSessionId(void); + cJSON_AddStringToObject(startlistent, "session_id", getGlobalSessionId()); - // ����type�ֶ� cJSON_AddStringToObject(startlistent, "type", "listen"); - - // ����state�ֶ� cJSON_AddStringToObject(startlistent, "state", "start"); - - // ����mode�ֶ� cJSON_AddStringToObject(startlistent, "mode", "auto") ; - - // ����JSON�ַ��� - char *jsonString = cJSON_Print(startlistent); - + char *jsonString = cJSON_PrintUnformatted(startlistent); websocket_client_send_text(web_socket, jsonString, strlen(jsonString), 10*1000); cJSON_Delete(startlistent); break; @@ -879,29 +851,15 @@ int rtc_websocket_send_text(transport web_socket, void *str, enum MsgType msgtyp case BEKEN_RTC_SEND_STOP_LISTEN:{ - cJSON *stoplistent = cJSON_CreateObject(); - - // char *session_id = getGlobalSessionId(); - - // bk_printf("Global session_id_BEKEN_RTC_SEND_STOP_LISTEN: %s\n", session_id); - - // ����session_id�ֶ� - cJSON_AddStringToObject(stoplistent, "session_id", ""); - - // ����type�ֶ� - cJSON_AddStringToObject(stoplistent, "type", "listen"); - - // ����state�ֶ� - cJSON_AddStringToObject(stoplistent, "state", "stop"); - - // ����mode�ֶ� - cJSON_AddStringToObject(stoplistent, "mode", "auto") ; - - // ����JSON�ַ��� - char *jsonString = cJSON_Print(stoplistent); - - websocket_client_send_text(web_socket, jsonString, strlen(jsonString), 10*1000); - cJSON_Delete(stoplistent); + cJSON *stoplistent = cJSON_CreateObject(); + extern char *getGlobalSessionId(void); + cJSON_AddStringToObject(stoplistent, "session_id", getGlobalSessionId()); + cJSON_AddStringToObject(stoplistent, "type", "listen"); + cJSON_AddStringToObject(stoplistent, "state", "stop"); + cJSON_AddStringToObject(stoplistent, "mode", "auto"); + char *jsonString = cJSON_PrintUnformatted(stoplistent); + websocket_client_send_text(web_socket, jsonString, strlen(jsonString), 10 * 1000); + cJSON_Delete(stoplistent); break; } @@ -934,7 +892,7 @@ int rtc_websocket_send_text(transport web_socket, void *str, enum MsgType msgtyp cJSON_AddItemToObject(startMessage, "audio_params", audio_params); // �� cJSON ����ת��Ϊ�ַ��� - char *jsonString = cJSON_Print(startMessage); + char *jsonString = cJSON_PrintUnformatted(startMessage); BK_LOGI("WebSocket", "Sending: %s\r\n", jsonString); websocket_client_send_text(web_socket, jsonString, strlen(jsonString), 10*1000); // ɾ�� cJSON �������ͷ��ڴ� @@ -942,53 +900,32 @@ int rtc_websocket_send_text(transport web_socket, void *str, enum MsgType msgtyp break;} case BEKEN_RTC_SEND_HELLO:{ - // ������ JSON ���� cJSON *helloMessage = cJSON_CreateObject(); - if (helloMessage == NULL) { - //return NULL; - } - - // ���� "type" �ֶ� cJSON_AddStringToObject(helloMessage, "type", "hello"); - - // ���� "version" �ֶ� cJSON_AddNumberToObject(helloMessage, "version", 3); - - // ���� "transport" �ֶ� cJSON_AddStringToObject(helloMessage, "transport", "websocket"); - - // ���� "audio_params" JSON ���� + + #if APPLICATION_IOT_PROTOCOL_MCP + cJSON* features = cJSON_CreateObject(); + cJSON_AddBoolToObject(features, "mcp", true); + cJSON_AddItemToObject(helloMessage, "features", features); + #endif + cJSON *audio_params = cJSON_CreateObject(); - if (audio_params == NULL) { - cJSON_Delete(helloMessage); - //return NULL; - } - - // �� "audio_params" �����ֶ� + cJSON_AddStringToObject(audio_params, "format", "opus"); cJSON_AddNumberToObject(audio_params, "sample_rate", 16000); cJSON_AddNumberToObject(audio_params, "channels", 1); cJSON_AddNumberToObject(audio_params, "frame_duration", 60); - // �� "audio_params" ���ӵ��� JSON ���� cJSON_AddItemToObject(helloMessage, "audio_params", audio_params); - // �� cJSON ����ת��Ϊ�ַ��� - char *jsonString = cJSON_Print(helloMessage); - BK_LOGI("WebSocket", "Sending: %s\r\n", jsonString); + char *jsonString = cJSON_PrintUnformatted(helloMessage); + BK_LOGE("WebSocket", "Sending: %s\r\n", jsonString); websocket_client_send_text(web_socket, jsonString, strlen(jsonString), 10*1000); + cJSON_Delete(helloMessage); - // ɾ�� cJSON �������ͷ��ڴ� - cJSON_Delete(helloMessage); - - /* - n = snprintf(buf, BEKEN_RTC_TXT_SIZE, - "{\"type\":\"hello\",\"config\":{\"version\": 2,\"audio\":{\"to_server\":{\"format\":\"%s\", \"sample_rate\":%d, \"channels\":1, \"frame_duration\":%d}, \"from_server\":{\"format\":\"%s\", \"sample_rate\":%d, \"channels\":1, \"frame_duration\":%d}}}}", - ((audio_info_t *)str)->encoding_type, ((audio_info_t *)str)->adc_samp_rate, ((audio_info_t *)str)->enc_samp_interval, - ((audio_info_t *)str)->encoding_type, ((audio_info_t *)str)->dac_samp_rate, ((audio_info_t *)str)->dec_samp_interval); - BK_LOGE("WebSocket", "Sending: %s\r\n", buf); - - websocket_client_send_text(web_socket, buf, n, 10*1000);*/ + break;} case BEKEN_RTC_SEND_IOT_DESC:{ extern char *getGlobalSessionId(void); diff --git a/bk_aidk/projects/beken_wss_paopao/main/iot/iot_lamp.c b/bk_aidk/projects/beken_wss_paopao/main/iot/iot_lamp.c index 78f77508..ae2e530b 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/iot/iot_lamp.c +++ b/bk_aidk/projects/beken_wss_paopao/main/iot/iot_lamp.c @@ -323,7 +323,7 @@ void iot_lamp_parser_invoke(char* cmd,char * paramters_json){ //ws2812_set_all_led(0xFFFFFF,brightness); ws2812_set_all_led_brightness(brightness); } - thing_report_iot_state_number(IOT_LAMP_DEVICE_NAME,IOT_LAMP_DEVICE_PARAM_BRIGHTNESS,brightness); + //thing_report_iot_state_number(IOT_LAMP_DEVICE_NAME,IOT_LAMP_DEVICE_PARAM_BRIGHTNESS,brightness); cJSON_Delete(params); } else if (strcmp(cmd, IOT_LAMP_DEVICE_OTA) == 0){ diff --git a/bk_aidk/projects/beken_wss_paopao/main/iot/iot_sleep_helper.c b/bk_aidk/projects/beken_wss_paopao/main/iot/iot_sleep_helper.c index 8b413539..fb7404a0 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/iot/iot_sleep_helper.c +++ b/bk_aidk/projects/beken_wss_paopao/main/iot/iot_sleep_helper.c @@ -272,7 +272,7 @@ void sleep_helper_set_mode(sleep_mode mode){ sleep_msg_t msg; msg.mode = mode; rtos_push_to_queue(&sleep_helper_msg_que, &msg, BEKEN_NO_WAIT); - thing_report_iot_state_number(IOT_SLEEP_HELPER_DEVICE_NAME,IOT_SLEEP_HELPER_DEVICE_PARAM_MODE,mode); + //thing_report_iot_state_number(IOT_SLEEP_HELPER_DEVICE_NAME,IOT_SLEEP_HELPER_DEVICE_PARAM_MODE,mode); } } @@ -339,11 +339,11 @@ void sleep_helper_set_level(sleep_model_level level){ LOGE("sleep_helper period_cycle s %d duty_cycle %d\n",config.period_cycle,config.duty_cycle); bk_pwm_set_init_signal_low(pwm_chan); bk_pwm_set_period_duty(pwm_chan,&config); - thing_report_iot_state_number(IOT_SLEEP_HELPER_DEVICE_NAME,IOT_SLEEP_HELPER_DEVICE_PARAM_LEVEL,level); + //thing_report_iot_state_number(IOT_SLEEP_HELPER_DEVICE_NAME,IOT_SLEEP_HELPER_DEVICE_PARAM_LEVEL,level); } } -void sleep_helper_open(){ +int sleep_helper_open(){ if(current_mode != SLEEP_MODE_OFF){ sleep_helper_close(); } @@ -360,7 +360,7 @@ void sleep_helper_open(){ socket_insert = insert_value; if(socket_insert == 1){ LOGE("sleep_helper open fail!! cable not insert %d \n",insert_value); - return ; + return -1; } pwm_init_config_t config = {0}; @@ -375,7 +375,8 @@ void sleep_helper_open(){ //默认模式1 sleep_helper_set_mode(SLEEP_MODE_1); sleep_helper_start_timer(); - thing_report_iot_state_number(IOT_SLEEP_HELPER_DEVICE_NAME,IOT_SLEEP_HELPER_DEVICE_PARAM_MODE,SLEEP_MODE_1); + //thing_report_iot_state_number(IOT_SLEEP_HELPER_DEVICE_NAME,IOT_SLEEP_HELPER_DEVICE_PARAM_MODE,SLEEP_MODE_1); + return 0; } void sleep_helper_close(){ @@ -389,7 +390,7 @@ void sleep_helper_close(){ bk_gpio_set_output_low(GPIO_44); bk_gpio_set_output_low(GPIO_45); - thing_report_iot_state_number(IOT_SLEEP_HELPER_DEVICE_NAME,IOT_SLEEP_HELPER_DEVICE_PARAM_MODE,0); + //thing_report_iot_state_number(IOT_SLEEP_HELPER_DEVICE_NAME,IOT_SLEEP_HELPER_DEVICE_PARAM_MODE,0); } cJSON* iot_sleep_helper_get_device_desc() diff --git a/bk_aidk/projects/beken_wss_paopao/main/iot/iot_sleep_helper.h b/bk_aidk/projects/beken_wss_paopao/main/iot/iot_sleep_helper.h index 3763e41f..695687c4 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/iot/iot_sleep_helper.h +++ b/bk_aidk/projects/beken_wss_paopao/main/iot/iot_sleep_helper.h @@ -65,7 +65,7 @@ typedef struct void sleep_helper_init(); -void sleep_helper_open(); +int sleep_helper_open(); void sleep_helper_close(); void sleep_helper_set_mode(sleep_mode mode); void sleep_helper_set_timeout(int timeout); diff --git a/bk_aidk/projects/beken_wss_paopao/main/iot/iot_speaker.c b/bk_aidk/projects/beken_wss_paopao/main/iot/iot_speaker.c index c0fe5a75..f440c8e9 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/iot/iot_speaker.c +++ b/bk_aidk/projects/beken_wss_paopao/main/iot/iot_speaker.c @@ -209,7 +209,7 @@ void speaker_set_volume(int volume) int level = volume / 10; LOGE("speaker_setVolume--> volume :%d level:%d\n", volume, level); speaker_volume_set_abs(level, 0); - thing_report_iot_state_number(IOT_SPEAKER_DEVICE_NAME, IOT_SPEAKER_DEVICE_PARAM_VOL, volume); + //thing_report_iot_state_number(IOT_SPEAKER_DEVICE_NAME, IOT_SPEAKER_DEVICE_PARAM_VOL, volume); } } void iot_speaker_parser_invoke(char* cmd,char * paramters_json){ diff --git a/bk_aidk/projects/beken_wss_paopao/main/mcp/mcp_server.c b/bk_aidk/projects/beken_wss_paopao/main/mcp/mcp_server.c new file mode 100755 index 00000000..8bf767f5 --- /dev/null +++ b/bk_aidk/projects/beken_wss_paopao/main/mcp/mcp_server.c @@ -0,0 +1,1221 @@ +/* + * MCP Server C Implementation + * Reference: https://modelcontextprotocol.io/specification/2024-11-05 + */ + +#include "mcp_server.h" +#include +#include +#include +#include +#include +#include +#include "bk_private/bk_init.h" +#include +#include +#include "components/webclient.h" +#include "cJSON.h" +#include "components/bk_uid.h" +#include "bk_genie_comm.h" +#include "application.h" +#include "beken_rtc.h" + + + +#define TAG "MCP_SER" +#define LOGI(...) BK_LOGI(TAG, ##__VA_ARGS__) +#define LOGW(...) BK_LOGW(TAG, ##__VA_ARGS__) +#define LOGE(...) BK_LOGE(TAG, ##__VA_ARGS__) +#define LOGD(...) BK_LOGD(TAG, ##__VA_ARGS__) + + +#define DEFAULT_TOOLCALL_STACK_SIZE 6144 +#define DEFAULT_CAPACITY 20 +#define MAX_JSON_SIZE 8000 + +// 全局单例 +McpServer* g_mcp_server = NULL; + +extern rtc_session *__get_beken_rtc(void); +extern char *getGlobalSessionId(void); +extern bool g_connected_flag; +static beken_queue_t thing_msg_que = NULL; +static beken_thread_t thing_thread_hdl = NULL; +static int thing_start = 0; +typedef struct +{ + int type ; + char *data; + int data_len; +} thing_msg_t; + + + +// 线程相关 +typedef struct { + int id; + McpTool* tool; + PropertyList* properties; +} ToolCallThreadArgs; + +// 工具线程函数 +static void* tool_call_thread_func(void* arg); + +// 辅助函数 +static void send_mcp_message( char* message); +static void reply_result(int id, const char* result); +static void reply_error(int id, const char* message); +static char* escape_json_string(const char* str); +static char* strdup_safe(const char* str); +static void mcp_send_thread_task(void *arg); + +// 属性函数实现 +Property* property_create_boolean(const char* name, bool has_default, bool default_value) { + Property* property = (Property*)malloc(sizeof(Property)); + if (!property) { + LOGE( "Failed to allocate memory for property\n"); + return NULL; + } + + property->name = strdup_safe(name); + property->type = PROPERTY_TYPE_BOOLEAN; + property->has_default_value = has_default; + property->value.boolean_value = default_value; + property->has_range = false; + + return property; +} + +Property* property_create_integer(const char* name, bool has_default, int default_value, bool has_range, int min_value, int max_value) { + Property* property = (Property*)malloc(sizeof(Property)); + if (!property) { + LOGE( "Failed to allocate memory for property\n"); + return NULL; + } + + property->name = strdup_safe(name); + property->type = PROPERTY_TYPE_INTEGER; + property->has_default_value = has_default; + property->value.integer_value = default_value; + property->has_range = has_range; + property->min_value = min_value; + property->max_value = max_value; + LOGE("property_create_integer property->name:%s\n", property->name); + return property; +} + +Property* property_create_string(const char* name, bool has_default, const char* default_value) { + Property* property = (Property*)malloc(sizeof(Property)); + if (!property) { + LOGE( "Failed to allocate memory for property\n"); + return NULL; + } + + property->name = strdup_safe(name); + property->type = PROPERTY_TYPE_STRING; + property->has_default_value = has_default; + property->value.string_value = default_value ? strdup_safe(default_value) : NULL; + property->has_range = false; + + return property; +} + +void property_destroy(Property* property) { + if (!property) return; + + free(property->name); + + if (property->type == PROPERTY_TYPE_STRING && property->value.string_value) { + free(property->value.string_value); + } + + // 注意:不再释放property本身,因为它现在是数组的一部分 +} + +const char* property_get_name(const Property* property) { + return property ? property->name : NULL; +} + +PropertyType property_get_type(const Property* property) { + return property ? property->type : PROPERTY_TYPE_BOOLEAN; +} + +bool property_has_default_value(const Property* property) { + return property ? property->has_default_value : false; +} + +bool property_has_range(const Property* property) { + return property ? property->has_range : false; +} + +int property_get_min_value(const Property* property) { + return property && property->has_range ? property->min_value : 0; +} + +int property_get_max_value(const Property* property) { + return property && property->has_range ? property->max_value : 0; +} + +bool property_get_boolean_value(const Property* property) { + return property && property->type == PROPERTY_TYPE_BOOLEAN ? property->value.boolean_value : false; +} + +int property_get_integer_value(const Property* property) { + return property && property->type == PROPERTY_TYPE_INTEGER ? property->value.integer_value : 0; +} + +const char* property_get_string_value(const Property* property) { + return property && property->type == PROPERTY_TYPE_STRING ? property->value.string_value : NULL; +} + +void property_set_boolean_value(Property* property, bool value) { + if (property && property->type == PROPERTY_TYPE_BOOLEAN) { + property->value.boolean_value = value; + } +} + +void property_set_integer_value(Property* property, int value) { + if (property && property->type == PROPERTY_TYPE_INTEGER) { + property->value.integer_value = value; + } +} + +void property_set_string_value(Property* property, const char* value) { + if (property && property->type == PROPERTY_TYPE_STRING) { + if (property->value.string_value) { + free(property->value.string_value); + } + property->value.string_value = strdup_safe(value); + } +} + +char* property_to_json(const Property* property) { + if (!property) return NULL; + + char* json = NULL; + char* escaped_name = escape_json_string(property->name); + + if (property->type == PROPERTY_TYPE_BOOLEAN) { + json = (char*)malloc(strlen(escaped_name) + 50); + if (json) { + sprintf(json, "\"%s\":%s", escaped_name, property->value.boolean_value ? "true" : "false"); + } + } else if (property->type == PROPERTY_TYPE_INTEGER) { + json = (char*)malloc(strlen(escaped_name) + 50); + if (json) { + sprintf(json, "\"%s\":%d", escaped_name, property->value.integer_value); + } + } else if (property->type == PROPERTY_TYPE_STRING) { + char* escaped_value = escape_json_string(property->value.string_value ? property->value.string_value : ""); + json = (char*)malloc(strlen(escaped_name) + strlen(escaped_value) + 10); + if (json) { + sprintf(json, "\"%s\":\"%s\"", escaped_name, escaped_value); + } + free(escaped_value); + } + + free(escaped_name); + return json; +} + +// 属性列表函数实现 +PropertyList* property_list_create(void) { + return property_list_create_with_capacity(DEFAULT_CAPACITY); +} + +PropertyList* property_list_create_with_capacity(int capacity) { + PropertyList* list = (PropertyList*)malloc(sizeof(PropertyList)); + if (!list) { + LOGE( "Failed to allocate memory for property list\n"); + return NULL; + } + + list->properties = (Property*)malloc(sizeof(Property) * capacity); + if (!list->properties) { + LOGE( "Failed to allocate memory for properties array\n"); + free(list); + return NULL; + } + + list->count = 0; + list->capacity = capacity; + + return list; +} + +void property_list_destroy(PropertyList* list) { + if (!list) return; + + if (list->properties) { + for (int i = 0; i < list->count; i++) { + free(list->properties[i].name); + + if (list->properties[i].type == PROPERTY_TYPE_STRING && list->properties[i].value.string_value) { + free(list->properties[i].value.string_value); + } + } + + free(list->properties); + } + + free(list); +} + +void property_list_add_property(PropertyList* list, Property* property) { + if (!list || !property) return; + + // 检查是否需要扩容 + if (list->count >= list->capacity) { + int new_capacity = list->capacity * 2; + Property* new_properties = (Property*)realloc(list->properties, sizeof(Property) * new_capacity); + if (!new_properties) { + LOGE( "Failed to reallocate memory for properties array\n"); + return; + } + + list->properties = new_properties; + list->capacity = new_capacity; + } + + + //LOGE( "@@@ properties %s\n,",property->name); + // 复制属性到数组中 + memcpy(&list->properties[list->count], property, sizeof(Property)); + //LOGE( "^^^ properties %s\n,",list->properties[list->count].name); + + + list->count++; + + //下方代码有BUG 会引起list列表里边的值错乱 + // 释放原始属性,因为我们已经复制了它 + //free(property->name); + //if (property->type == PROPERTY_TYPE_STRING && property->value.string_value) { + // free(property->value.string_value); + //} + //free(property); + // LOGE( "~~~ properties0 %s\n,",list->properties[0].name); + // LOGE( "~~~ properties1 %s\n,",list->properties[1].name); +} + +Property* property_list_get_by_name(const PropertyList* list, const char* name) { + if (!list || !name) return NULL; + + for (int i = 0; i < list->count; i++) { + if (strcmp(list->properties[i].name, name) == 0) { + return &list->properties[i]; + } + } + + return NULL; +} + +char** property_list_get_required(const PropertyList* list, int* count) { + if (!list || !count) return NULL; + + // 计算必需属性的数量 + int required_count = 0; + for (int i = 0; i < list->count; i++) { + if (!list->properties[i].has_default_value) { + required_count++; + } + } + + *count = required_count; + if (required_count == 0) return NULL; + + // 分配必需属性数组 + char** required = (char**)malloc(sizeof(char*) * required_count); + if (!required) { + LOGE( "Failed to allocate memory for required properties array\n"); + return NULL; + } + + // 填充必需属性数组 + int index = 0; + for (int i = 0; i < list->count; i++) { + if (!list->properties[i].has_default_value) { + required[index++] = strdup_safe(list->properties[i].name); + } + } + + return required; +} + +char* property_list_to_json(const PropertyList* list) { + if (!list || list->count == 0) return strdup_safe("{}"); + + // 计算JSON字符串的大致长度 + int json_length = 2; // 开始的 { 和结束的 } + + for (int i = 0; i < list->count; i++) { + char* prop_json = property_to_json(&list->properties[i]); + if (prop_json) { + json_length += strlen(prop_json) + 2; // +2 for comma and space + free(prop_json); + } + } + + // 分配内存 + char* json = (char*)malloc(json_length + 1); // +1 for null terminator + if (!json) { + LOGE( "Failed to allocate memory for property list JSON\n"); + return NULL; + } + + // 构建JSON字符串 + strcpy(json, "{"); + int pos = 1; + + for (int i = 0; i < list->count; i++) { + char* prop_json = property_to_json(&list->properties[i]); + if (prop_json) { + if (i > 0) { + json[pos++] = ','; + json[pos++] = ' '; + } + + strcpy(json + pos, prop_json); + pos += strlen(prop_json); + free(prop_json); + } + } + + json[pos++] = '}'; + json[pos] = '\0'; + + return json; +} + +// 返回值函数实现 +ReturnValue return_value_create_boolean(bool value) { + ReturnValue ret; + ret.type = RETURN_TYPE_BOOLEAN; + ret.value.boolean_value = value; + return ret; +} + +ReturnValue return_value_create_integer(int value) { + ReturnValue ret; + ret.type = RETURN_TYPE_INTEGER; + ret.value.integer_value = value; + return ret; +} + +ReturnValue return_value_create_string(const char* value) { + ReturnValue ret; + ret.type = RETURN_TYPE_STRING; + ret.value.string_value = strdup_safe(value); + return ret; +} + +void return_value_destroy(ReturnValue* value) { + if (!value) return; + + if (value->type == RETURN_TYPE_STRING && value->value.string_value) { + free(value->value.string_value); + value->value.string_value = NULL; + } +} + +// MCP工具函数实现 +McpTool* mcp_tool_create(const char* name, const char* description, PropertyList* properties, McpToolCallback callback) { + McpTool* tool = (McpTool*)malloc(sizeof(McpTool)); + if (!tool) { + LOGE( "Failed to allocate memory for MCP tool\n"); + return NULL; + } + + tool->name = strdup_safe(name); + tool->description = strdup_safe(description); + + if (properties) { + + tool->properties = *properties; + //LOGE( "mcp_tool_create properties %d\n,",properties->count); + //LOGE( "mcp_tool_create properties %s\n,",properties->properties[0].name); + + //LOGE( "mcp_tool_create tool->properties %d\n,",tool->properties.count); + //LOGE( "mcp_tool_create tool->properties %s\n,",tool->properties.properties[0].name); + + free(properties); // 释放PropertyList结构体,但保留其内容 + } else { + tool->properties.properties = NULL; + tool->properties.count = 0; + tool->properties.capacity = 0; + } + + tool->callback = callback; + + return tool; +} + +void mcp_tool_destroy(McpTool* tool) { + if (!tool) return; + + free(tool->name); + free(tool->description); + + // 直接释放属性数组中的资源 + if (tool->properties.properties) { + for (int i = 0; i < tool->properties.count; i++) { + free(tool->properties.properties[i].name); + + if (tool->properties.properties[i].type == PROPERTY_TYPE_STRING && + tool->properties.properties[i].value.string_value) { + free(tool->properties.properties[i].value.string_value); + } + } + + free(tool->properties.properties); + } + + free(tool); +} + +const char* mcp_tool_get_name(const McpTool* tool) { + return tool ? tool->name : NULL; +} + +const char* mcp_tool_get_description(const McpTool* tool) { + return tool ? tool->description : NULL; +} + +const PropertyList* mcp_tool_get_properties(const McpTool* tool) { + return tool ? &tool->properties : NULL; +} + +char* mcp_tool_to_json(const McpTool* tool) { + if (!tool) return NULL; + + char* escaped_name = escape_json_string(tool->name); + char* escaped_description = escape_json_string(tool->description); + + //LOGE("mcp_tool_to_json escaped_name:%d\n", escaped_name); + //LOGE("mcp_tool_to_json escaped_description:%s\n\n", escaped_description); + + // 获取属性的JSON表示 + //char* properties_json = NULL; + cJSON* input_schema = cJSON_CreateObject(); + cJSON* properties_obj = cJSON_CreateObject(); + cJSON* required_array = cJSON_CreateArray(); + + cJSON_AddStringToObject(input_schema, "type", "object"); + cJSON_AddItemToObject(input_schema, "properties", properties_obj); + + // 添加属性 + for (int i = 0; i < tool->properties.count; i++) { + const Property* prop = &tool->properties.properties[i]; + // Property* prop = &(tool->properties.properties[i]); + //LOGE("mcp_tool_to_json prop->name:%d type:%d\n", prop->name,prop->type); + cJSON* prop_obj = cJSON_CreateObject(); + + // 添加属性类型 + if (prop->type == PROPERTY_TYPE_BOOLEAN) { + cJSON_AddStringToObject(prop_obj, "type", "boolean"); + } else if (prop->type == PROPERTY_TYPE_INTEGER) { + cJSON_AddStringToObject(prop_obj, "type", "integer"); + + // 添加范围 + if (prop->has_range) { + cJSON_AddNumberToObject(prop_obj, "minimum", prop->min_value); + cJSON_AddNumberToObject(prop_obj, "maximum", prop->max_value); + } + } else if (prop->type == PROPERTY_TYPE_STRING) { + cJSON_AddStringToObject(prop_obj, "type", "string"); + } + //LOGE("mcp_tool_to_json prop->name:%s\n\n", prop->name); + // 添加描述 + cJSON_AddStringToObject(prop_obj, "description", prop->name); + + // 添加到properties对象 + + cJSON_AddItemToObject(properties_obj, prop->name, prop_obj); + + // 如果是必需属性,添加到required数组 + if (!prop->has_default_value) { + cJSON_AddItemToArray(required_array, cJSON_CreateString(prop->name)); + } + } + + // 如果有必需属性,添加required数组 + if (cJSON_GetArraySize(required_array) > 0) { + cJSON_AddItemToObject(input_schema, "required", required_array); + } else { + cJSON_Delete(required_array); + } + + // 转换为JSON字符串 + char* input_schema_str = cJSON_PrintUnformatted(input_schema); + cJSON_Delete(input_schema); + + // 构建工具的JSON表示 + char* json = (char*)malloc(strlen(escaped_name) + strlen(escaped_description) + strlen(input_schema_str) + 100); + if (json) { + sprintf(json, "{\"name\":\"%s\",\"description\":\"%s\",\"inputSchema\":%s}", + escaped_name, escaped_description, input_schema_str); + } + + free(escaped_name); + free(escaped_description); + free(input_schema_str); + + return json; +} + +char* mcp_tool_call(const McpTool* tool, const PropertyList* properties) { + if (!tool || !tool->callback) return NULL; + + // 调用回调函数 + ReturnValue result = tool->callback(properties); + + // 根据返回值类型构建JSON响应 + char* json = NULL; + + if (result.type == RETURN_TYPE_BOOLEAN) { + json = (char*)malloc(20); + if (json) { + sprintf(json, "%s", result.value.boolean_value ? "true" : "false"); + } + } else if (result.type == RETURN_TYPE_INTEGER) { + json = (char*)malloc(20); + if (json) { + sprintf(json, "%d", result.value.integer_value); + } + } else if (result.type == RETURN_TYPE_STRING) { + char* escaped_value = escape_json_string(result.value.string_value ? result.value.string_value : ""); + json = (char*)malloc(strlen(escaped_value) + 3); + if (json) { + sprintf(json, "\"%s\"", escaped_value); + } + free(escaped_value); + } + + // 释放返回值中的资源 + return_value_destroy(&result); + + return json; +} + +// MCP服务器函数实现 +McpServer* mcp_server_create(void) { + McpServer* server = (McpServer*)malloc(sizeof(McpServer)); + if (!server) { + LOGE( "Failed to allocate memory for MCP server\n"); + return NULL; + } + + server->tools = (McpTool**)malloc(sizeof(McpTool*) * DEFAULT_CAPACITY); + if (!server->tools) { + LOGE( "Failed to allocate memory for tools array\n"); + free(server); + return NULL; + } + + server->tool_count = 0; + server->tool_capacity = DEFAULT_CAPACITY; + + + thing_start = 1; + bk_err_t ret = BK_OK; + ret = rtos_init_queue(&thing_msg_que, "mcp_msg_que", sizeof(thing_msg_t), 5); + if (ret != kNoErr) + { + bk_printf("create thing_msg_que queue fail\n"); + } + ret = rtos_create_thread(&thing_thread_hdl, + 4, + "mcp_send", + (beken_thread_function_t)mcp_send_thread_task, + 5 * 1024, + NULL); + if (ret != kNoErr) + { + thing_thread_hdl = NULL; + } + + return server; +} + +void mcp_server_destroy(McpServer* server) { + if (!server) return; + + for (int i = 0; i < server->tool_count; i++) { + mcp_tool_destroy(server->tools[i]); + } + + free(server->tools); + free(server); +} + +McpServer* mcp_server_get_instance(void) { + if (!g_mcp_server) { + g_mcp_server = mcp_server_create(); + if (g_mcp_server) { + mcp_server_add_common_tools(g_mcp_server); + } + } + + return g_mcp_server; +} + +// 声明外部C++函数,用于调用Board类的方法 +#ifdef __cplusplus +extern "C" { +#endif + char* board_get_status_json(void); + void board_set_volume(int volume); + void board_set_brightness(int brightness); + void board_set_theme(const char* theme); + bool board_has_camera(void); + char* board_take_photo(void); +#ifdef __cplusplus +} +#endif + + +void mcp_server_add_common_tools(McpServer* server) { + if (!server) return; + + +} + +void mcp_server_add_tool(McpServer* server, McpTool* tool) { + if (!server || !tool) return; + + // 检查是否需要扩容 + if (server->tool_count >= server->tool_capacity) { + int new_capacity = server->tool_capacity * 2; + McpTool** new_tools = (McpTool**)realloc(server->tools, sizeof(McpTool*) * new_capacity); + if (!new_tools) { + LOGE( "Failed to reallocate memory for tools array\n"); + return; + } + + server->tools = new_tools; + server->tool_capacity = new_capacity; + } + + server->tools[server->tool_count++] = tool; +} + +void mcp_server_add_tool_with_params(McpServer* server, const char* name, const char* description, PropertyList* properties, McpToolCallback callback) { + if (!server || !name || !description || !callback) return; + LOGE( "!!!!properties %d\n,",properties->count); + + McpTool* tool = mcp_tool_create(name, description, properties, callback); + if (tool) { + mcp_server_add_tool(server, tool); + } +} + +void mcp_server_parse_message(McpServer* server, const char* message) { + if (!server || !message) return; + + cJSON* json = cJSON_Parse(message); + if (!json) { + LOGE( "Failed to parse JSON message: %s\n", message); + return; + } + + mcp_server_parse_message_json(server, json); + cJSON_Delete(json); +} + +void mcp_server_parse_message_json(McpServer* server, const cJSON* json) { + if (!server || !json) return; + + // Check JSONRPC version + cJSON* version = cJSON_GetObjectItem(json, "jsonrpc"); + if (version == NULL || !cJSON_IsString(version) || strcmp(version->valuestring, "2.0") != 0) { + LOGE("Invalid JSONRPC version: %s\n", version ? version->valuestring : "null"); + return; + } + + // Check method + cJSON* method = cJSON_GetObjectItem(json, "method"); + if (method == NULL || !cJSON_IsString(method)) { + LOGE("Missing method\n"); + return; + } + + cJSON* id = cJSON_GetObjectItem(json, "id"); + if (id == NULL || !cJSON_IsNumber(id)) { + return; + } + int id_int = id->valueint; + + LOGE( "mcp:%d %s\n",id_int,method->valuestring); + // Check params + cJSON* params = cJSON_GetObjectItem(json, "params"); + // 获取消息类型 + //cJSON* type = cJSON_GetObjectItem(json, "type"); + //if (!type || !cJSON_IsString(type)) { + // LOGE( "Missing or invalid 'type' field in message\n"); + // return; + //} + + // 处理不同类型的消息 + if (strcmp(method->valuestring, "initialize") == 0) { + + char message[256] = {0}; + sprintf(message, "{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{\"tools\":{}},\"serverInfo\":{\"name\":\"%s\",\"version\":\"%s\"}}", APPLICATION_DEVICE_BOARD_NAME, APPLICATION_VERSION); + reply_result(id_int, message); + } + // + else if (strcmp(method->valuestring, "tools/list") == 0) { + + LOGE( "------> tools/list\n"); + // 处理列出工具请求 + cJSON* id = cJSON_GetObjectItem(json, "id"); + if (!id || !cJSON_IsNumber(id)) { + LOGE( "Missing or invalid 'id' field in list_tools message\n"); + return; + } + //mcp_server_add_common_tools(server); + + LOGE( "------> server->tool_count :%d\n",server->tool_count); + // 构建工具列表响应 + #if 1 + cJSON* tools_array = cJSON_CreateArray(); + for (int i = 0; i < server->tool_count; i++) { + char* tool_json_str = mcp_tool_to_json(server->tools[i]); + if (tool_json_str) { + + cJSON* tool_json = cJSON_Parse(tool_json_str); + if (tool_json) { + cJSON_AddItemToArray(tools_array, tool_json); + } + LOGE("tool(%d) %s\n",i,tool_json_str); + free(tool_json_str); + } + } + #endif + cJSON* response = cJSON_CreateObject(); + cJSON_AddItemToObject(response, "tools", tools_array); + + char* response_str = cJSON_PrintUnformatted(response); + if (response_str) { + //send_mcp_message(response_str); + reply_result(id_int, response_str); + free(response_str); + } + cJSON_Delete(response); + } else if (strcmp(method->valuestring, "tools/call") == 0) { + // 处理调用工具请求 + //{"type":"mcp","payload":{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"self.screen.set_brightness","arguments":{"brightness":100}}}} + //cJSON* id = cJSON_GetObjectItem(json, "id"); + + if (!cJSON_IsObject(params)) { + LOGE( "tools/call: Missing params"); + reply_error(id_int, "Missing params"); + return; + } + cJSON* name = cJSON_GetObjectItem(params, "name"); + if (!cJSON_IsString(name)) { + LOGE( "tools/call: Missing name"); + reply_error(id_int, "Missing name"); + return; + } + cJSON* arguments = cJSON_GetObjectItem(params, "arguments"); + if (arguments != NULL && !cJSON_IsObject(arguments)) { + LOGE( "tools/call: Invalid arguments"); + reply_error(id_int, "Invalid arguments"); + return; + } + + //cJSON* name = cJSON_GetObjectItem(json, "name"); + //cJSON* arguments = cJSON_GetObjectItem(json, "arguments"); + + // 查找工具 + McpTool* tool = NULL; + for (int i = 0; i < server->tool_count; i++) { + if (strcmp(server->tools[i]->name, name->valuestring) == 0) { + tool = server->tools[i]; + break; + } + } + + if (!tool) { + reply_error(id->valueint, "Tool not found"); + return; + } + + // 解析参数 + PropertyList* props = property_list_create(); + if (!props) { + reply_error(id->valueint, "Failed to create property list"); + return; + } + + // 复制工具的属性定义 + for (int i = 0; i < tool->properties.count; i++) { + Property* prop = &tool->properties.properties[i]; + Property* new_prop = NULL; + + if (prop->type == PROPERTY_TYPE_BOOLEAN) { + new_prop = property_create_boolean(prop->name, prop->has_default_value, prop->value.boolean_value); + } else if (prop->type == PROPERTY_TYPE_INTEGER) { + new_prop = property_create_integer(prop->name, prop->has_default_value, prop->value.integer_value, prop->has_range, prop->min_value, prop->max_value); + } else if (prop->type == PROPERTY_TYPE_STRING) { + new_prop = property_create_string(prop->name, prop->has_default_value, prop->value.string_value); + } + + if (new_prop) { + property_list_add_property(props, new_prop); + } + } + + // 设置参数值 + if (arguments && cJSON_IsObject(arguments)) { + cJSON* arg; + cJSON_ArrayForEach(arg, arguments) { + LOGE("cJSON_ArrayForEach arguments %s\n",arg->string); + Property* prop = property_list_get_by_name(props, arg->string); + if (prop) { + if (prop->type == PROPERTY_TYPE_BOOLEAN && cJSON_IsBool(arg)) { + property_set_boolean_value(prop, cJSON_IsTrue(arg)); + } else if (prop->type == PROPERTY_TYPE_INTEGER && cJSON_IsNumber(arg)) { + property_set_integer_value(prop, arg->valueint); + } else if (prop->type == PROPERTY_TYPE_STRING && cJSON_IsString(arg)) { + property_set_string_value(prop, arg->valuestring); + } + } + } + } + + // 检查必需参数 + int required_count = 0; + char** required = property_list_get_required(&tool->properties, &required_count); + bool missing_required = false; + + for (int i = 0; i < required_count; i++) { + LOGE("required %s\n",required[i]); + Property* prop = property_list_get_by_name(props, required[i]); + if (!prop) { + missing_required = true; + break; + } + } + + // 释放必需参数数组 + for (int i = 0; i < required_count; i++) { + free(required[i]); + } + free(required); + + if (missing_required) { + reply_error(id->valueint, "Missing required parameters"); + property_list_destroy(props); + return; + } + + // 创建线程参数 + ToolCallThreadArgs* thread_args = (ToolCallThreadArgs*)malloc(sizeof(ToolCallThreadArgs)); + if (!thread_args) { + reply_error(id->valueint, "Failed to allocate memory for thread arguments"); + property_list_destroy(props); + return; + } + + thread_args->id = id->valueint; + thread_args->tool = tool; + thread_args->properties = props; + + // 创建线程 + bk_err_t ret = BK_OK; + ret = rtos_create_thread(NULL, BEKEN_APPLICATION_PRIORITY, + "ToolCall", + (beken_thread_function_t)tool_call_thread_func, + 5120, + thread_args); + + if (kNoErr != ret){ + reply_error(id->valueint, "Failed to create thread"); + property_list_destroy(props); + free(thread_args); + } + + } else { + LOGE("Unknown message method: %s\n", method->valuestring); + } +} + +// 工具线程函数 +static void* tool_call_thread_func(void* arg) { + ToolCallThreadArgs* thread_args = (ToolCallThreadArgs*)arg; + if (!thread_args) { + return NULL; + } + + int id = thread_args->id; + McpTool* tool = thread_args->tool; + PropertyList* properties = thread_args->properties; + + // 调用工具 + char* result = mcp_tool_call(tool, properties); + + // 发送响应 + if (result) { + reply_result(id, result); + free(result); + } else { + reply_error(id, "Tool call failed"); + } + + // 清理资源 + property_list_destroy(properties); + free(thread_args); + + return NULL; +} + + + + +static void mcp_send_thread_task(void *arg) +{ + bk_err_t ret = BK_OK; + while(thing_start){ + + thing_msg_t msg; + ret = rtos_pop_from_queue(&thing_msg_que, &msg, BEKEN_WAIT_FOREVER); + if (kNoErr == ret) + { + switch (msg.type) + { + // 发送数据到平台 + case 0: + { + //没有连接平台的情况下 不允许发送数据 + if(!g_connected_flag){ + break; + } + rtc_session *beken_rtc = __get_beken_rtc(); + if(beken_rtc == NULL){ + break; + } + transport bk_rtc_ws = beken_rtc->bk_rtc_client; + // bk_printf("!!!!!!!!!!!!!!!!\n"); + if(bk_rtc_ws == NULL){\ + break; + } + websocket_client_send_text(bk_rtc_ws, msg.data, msg.data_len, 10*1000); + os_free(msg.data); + //bk_printf("555555\n"); + break; + } + } + } + } + /* delete msg queue */ + ret = rtos_deinit_queue(&thing_msg_que); + if (ret != kNoErr) + { + bk_printf("delete spi_led_msg_que fail\n"); + } + thing_msg_que = NULL; + /* delete task */ + if(thing_thread_hdl!= NULL) { + rtos_delete_thread(&thing_thread_hdl); + thing_thread_hdl = NULL; + } + bk_printf("delete thing_thread_hdl task\n"); +} + +// 辅助函数 +static void send_mcp_message( char *message) +{ + if (!message) + return; + + // 在实际实现中,这里应该将消息发送到适当的通信通道 + // 例如,通过WebSocket、MQTT或其他通信方式 + // 这里简单地打印消息 + //LOGE("SEND MCP (%d): %s\n", strlen(message),message); + // 没有连接平台的情况下 不允许发送数据 + if (!g_connected_flag) + { + return; + } + if (thing_msg_que != NULL) + { + thing_msg_t msg; + msg.type = 0; + msg.data = os_malloc(strlen(message)+1); + strcpy(msg.data, message); + msg.data_len = strlen(message); + rtos_push_to_queue(&thing_msg_que, &msg, BEKEN_NO_WAIT); + } +} + +static void reply_result(int id, const char* result) { + if (!result) return; + + cJSON* response = cJSON_CreateObject(); + cJSON_AddStringToObject(response, "session_id", getGlobalSessionId()); + cJSON_AddStringToObject(response, "type", "mcp"); + + cJSON* playload = cJSON_CreateObject(); + cJSON_AddStringToObject(playload, "jsonrpc", "2.0"); + cJSON_AddNumberToObject(playload, "id", id); + // 尝试解析结果为JSON + cJSON* result_json = cJSON_Parse(result); + if (result_json) { + cJSON_AddItemToObject(playload, "result", result_json); + } else { + cJSON_AddStringToObject(playload, "result", result); + } + cJSON_AddItemToObject(response, "payload", playload); + + char* response_str = cJSON_PrintUnformatted(response); + if (response_str) { + send_mcp_message(response_str); + free(response_str); + } + cJSON_Delete(response); +} + +static void reply_error(int id, const char* message) { + if (!message) return; + + cJSON* response = cJSON_CreateObject(); + cJSON_AddStringToObject(response, "session_id", getGlobalSessionId()); + cJSON_AddStringToObject(response, "type", "mcp"); + + cJSON* playload = cJSON_CreateObject(); + cJSON_AddStringToObject(playload, "jsonrpc", "2.0"); + cJSON_AddNumberToObject(playload, "id", id); + + + cJSON* msg = cJSON_CreateObject(); + cJSON_AddStringToObject(msg, "message", message); + cJSON_AddItemToObject(playload, "error", msg); + cJSON_AddItemToObject(response, "payload", playload); + char* response_str = cJSON_PrintUnformatted(response); + if (response_str) { + send_mcp_message(response_str); + free(response_str); + } + + cJSON_Delete(response); +} + +static char* escape_json_string(const char* str) { + if (!str) return strdup_safe(""); + + // 计算转义后的长度 + size_t len = 0; + const unsigned char* p = (const unsigned char*)str; + while (*p) { + // 检查是否是UTF-8多字节字符的开始 + if ((*p & 0x80) == 0) { + // ASCII字符 + if (*p == '\"' || *p == '\\' || *p < 32) { + len += 2; // 需要转义 + } else { + len += 1; + } + p++; + } else if ((*p & 0xE0) == 0xC0) { + // 2字节UTF-8字符 + len += 2; + p += 2; + } else if ((*p & 0xF0) == 0xE0) { + // 3字节UTF-8字符(大多数中文) + len += 3; + p += 3; + } else if ((*p & 0xF8) == 0xF0) { + // 4字节UTF-8字符 + len += 4; + p += 4; + } else { + // 无效的UTF-8序列,按单字节处理 + len += 1; + p++; + } + } + + // 分配内存(预留额外空间以防万一) + char* escaped = (char*)malloc(len * 2 + 1); + if (!escaped) { + LOGE("Failed to allocate memory for JSON string escaping"); + return strdup_safe(str); + } + + // 转义字符 + const unsigned char* src = (const unsigned char*)str; + char* dst = escaped; + + while (*src) { + // 检查是否是UTF-8多字节字符的开始 + if ((*src & 0x80) == 0) { + // ASCII字符 + if (*src == '\"') { + *dst++ = '\\'; + *dst++ = '\"'; + } else if (*src == '\\') { + *dst++ = '\\'; + *dst++ = '\\'; + } else if (*src < 32) { + *dst++ = '\\'; + switch (*src) { + case '\b': *dst++ = 'b'; break; + case '\f': *dst++ = 'f'; break; + case '\n': *dst++ = 'n'; break; + case '\r': *dst++ = 'r'; break; + case '\t': *dst++ = 't'; break; + default: + sprintf(dst, "u%04x", *src); + dst += 5; + break; + } + } else { + *dst++ = *src; + } + src++; + } else if ((*src & 0xE0) == 0xC0 && *(src+1) && (*(src+1) & 0xC0) == 0x80) { + // 2字节UTF-8字符 + *dst++ = *src++; + *dst++ = *src++; + } else if ((*src & 0xF0) == 0xE0 && *(src+1) && (*(src+1) & 0xC0) == 0x80 && + *(src+2) && (*(src+2) & 0xC0) == 0x80) { + // 3字节UTF-8字符(大多数中文) + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } else if ((*src & 0xF8) == 0xF0 && *(src+1) && (*(src+1) & 0xC0) == 0x80 && + *(src+2) && (*(src+2) & 0xC0) == 0x80 && *(src+3) && (*(src+3) & 0xC0) == 0x80) { + // 4字节UTF-8字符 + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + *dst++ = *src++; + } else { + // 无效的UTF-8序列,按单字节处理 + *dst++ = *src++; + } + } + *dst = '\0'; + + return escaped; +} + +static char* strdup_safe(const char* str) { + if (!str) return NULL; + + size_t len = strlen(str); + char* dup = (char*)malloc(len + 1); + if (dup) { + // 使用strcpy而不是memcpy,确保正确处理字符串终止符 + strcpy(dup, str); + + // 验证复制的字符串是否有效 + if (strlen(dup) != len) { + LOGW("String length mismatch after duplication\n"); + } + } else { + LOGE("Failed to allocate memory for string duplication\n"); + } + + return dup; +} \ No newline at end of file diff --git a/bk_aidk/projects/beken_wss_paopao/main/mcp/mcp_server.h b/bk_aidk/projects/beken_wss_paopao/main/mcp/mcp_server.h new file mode 100755 index 00000000..e2709a1c --- /dev/null +++ b/bk_aidk/projects/beken_wss_paopao/main/mcp/mcp_server.h @@ -0,0 +1,137 @@ +#ifndef MCP_SERVER_C_H +#define MCP_SERVER_C_H + +#include +#include +#include "cJSON.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// 属性类型枚举 +typedef enum { + PROPERTY_TYPE_BOOLEAN, + PROPERTY_TYPE_INTEGER, + PROPERTY_TYPE_STRING +} PropertyType; + +// 返回值类型枚举 +typedef enum { + RETURN_TYPE_BOOLEAN, + RETURN_TYPE_INTEGER, + RETURN_TYPE_STRING +} ReturnType; + +// 返回值联合体 +typedef struct { + ReturnType type; + union { + bool boolean_value; + int integer_value; + char* string_value; + } value; +} ReturnValue; + +// 属性结构体 +typedef struct { + char* name; + char* description; + PropertyType type; + bool has_default_value; + union { + bool boolean_value; + int integer_value; + char* string_value; + } value; + bool has_range; + int min_value; + int max_value; +} Property; + +// 属性列表结构体 +typedef struct { + Property* properties; + int count; + int capacity; +} PropertyList; + +// MCP工具回调函数类型 +typedef ReturnValue (*McpToolCallback)(const PropertyList* properties); + +// MCP工具结构体 +typedef struct { + char* name; + char* description; + PropertyList properties; + McpToolCallback callback; +} McpTool; + +// MCP服务器结构体 +typedef struct { + McpTool** tools; + int tool_count; + int tool_capacity; +} McpServer; + +// 全局单例 +extern McpServer* g_mcp_server; + +// 属性函数 +Property* property_create_boolean(const char* name, bool has_default, bool default_value); +Property* property_create_integer(const char* name, bool has_default, int default_value, bool has_range, int min_value, int max_value); +Property* property_create_string(const char* name, bool has_default, const char* default_value); +void property_destroy(Property* property); +const char* property_get_name(const Property* property); +PropertyType property_get_type(const Property* property); +bool property_has_default_value(const Property* property); +bool property_has_range(const Property* property); +int property_get_min_value(const Property* property); +int property_get_max_value(const Property* property); +bool property_get_boolean_value(const Property* property); +int property_get_integer_value(const Property* property); +const char* property_get_string_value(const Property* property); +void property_set_boolean_value(Property* property, bool value); +void property_set_integer_value(Property* property, int value); +void property_set_string_value(Property* property, const char* value); +char* property_to_json(const Property* property); + +// 属性列表函数 +PropertyList* property_list_create(void); +PropertyList* property_list_create_with_capacity(int capacity); +void property_list_destroy(PropertyList* list); +void property_list_add_property(PropertyList* list, Property* property); +Property* property_list_get_by_name(const PropertyList* list, const char* name); +char** property_list_get_required(const PropertyList* list, int* count); +char* property_list_to_json(const PropertyList* list); + +// 返回值函数 +ReturnValue return_value_create_boolean(bool value); +ReturnValue return_value_create_integer(int value); +ReturnValue return_value_create_string(const char* value); +void return_value_destroy(ReturnValue* value); + +// MCP工具函数 +McpTool* mcp_tool_create(const char* name, const char* description, PropertyList* properties, McpToolCallback callback); +void mcp_tool_destroy(McpTool* tool); +const char* mcp_tool_get_name(const McpTool* tool); +const char* mcp_tool_get_description(const McpTool* tool); +const PropertyList* mcp_tool_get_properties(const McpTool* tool); +char* mcp_tool_to_json(const McpTool* tool); +char* mcp_tool_call(const McpTool* tool, const PropertyList* properties); + +// MCP服务器函数 +McpServer* mcp_server_create(void); +void mcp_server_destroy(McpServer* server); +McpServer* mcp_server_get_instance(void); +void mcp_server_add_common_tools(McpServer* server); +void mcp_server_add_tool(McpServer* server, McpTool* tool); +void mcp_server_add_tool_with_params(McpServer* server, const char* name, const char* description, PropertyList* properties, McpToolCallback callback); +void mcp_server_parse_message(McpServer* server, const char* message); +void mcp_server_parse_message_json(McpServer* server, const cJSON* json); + +#ifdef __cplusplus +} +#endif + +#endif // MCP_SERVER_C_H \ No newline at end of file diff --git a/bk_aidk/projects/beken_wss_paopao/main/websocket_rtc_demo.c b/bk_aidk/projects/beken_wss_paopao/main/websocket_rtc_demo.c index c5d9ac91..dff72a3f 100755 --- a/bk_aidk/projects/beken_wss_paopao/main/websocket_rtc_demo.c +++ b/bk_aidk/projects/beken_wss_paopao/main/websocket_rtc_demo.c @@ -35,6 +35,8 @@ #include "thing.h" #include "iot_ota.h" #include "iot_lamp.h" +#include "application.h" +#include "mcp/mcp_server.h" #define TAG "WS_MAIN" #define LOGI(...) BK_LOGI(TAG, ##__VA_ARGS__) @@ -525,7 +527,7 @@ void rtc_websocket_msg_handle(char *json_text, unsigned int size) LOGE("Error: Failed to parse JSON text:%s\n", json_text); return; } - // bk_printf("rtc_websocket_msg_handle json_text : %s \n",json_text); + //bk_printf("TEXT: %s \n",cJSON_PrintUnformatted(root)); cJSON *type = cJSON_GetObjectItem(root, "type"); if (type == NULL) { @@ -566,6 +568,42 @@ void rtc_websocket_msg_handle(char *json_text, unsigned int size) { thing_iot_invoke(json_text); } + else if (strcmp(type->valuestring, "llm") == 0) + { + cJSON *emotion = cJSON_GetObjectItem(root, "emotion"); + if(emotion != NULL){ + LOGE("emotion--> %s\n",emotion->valuestring); + } + + } + else if (strcmp(type->valuestring, "stt") == 0) + { + cJSON *text = cJSON_GetObjectItem(root, "text"); + if(text != NULL){ + LOGE(">> %s\n",text->valuestring); + } + + } + else if (strcmp(type->valuestring, "tts") == 0) + { + cJSON *state = cJSON_GetObjectItem(root, "state"); + cJSON *text = cJSON_GetObjectItem(root, "text"); + if(state != NULL && text != NULL){ + LOGE("<< (%s) %s\n",state->valuestring,text->valuestring); + } + } + + #if APPLICATION_IOT_PROTOCOL_MCP + else if (strcmp(type->valuestring, "mcp") == 0) { + cJSON * payload = cJSON_GetObjectItem(root, "payload"); + if (cJSON_IsObject(payload)) { + //LOGE("MCP: %s\n", cJSON_PrintUnformatted(payload)); + McpServer* mcp_server = mcp_server_get_instance(); + mcp_server_parse_message_json(mcp_server, payload); + //McpServer::GetInstance().ParseMessage(payload); + } + } + #endif // else if ((strcmp(type->valuestring, "reply_text") == 0) || (strcmp(type->valuestring, "request_text") == 0)) { // text_info_t info = {0}; @@ -690,7 +728,7 @@ void sent_abort_msg() //bk_printf("rtc_websocket_send_text_BEKEN_RTC_SEND_ABORT_BEKEN_RTC_SEND_STOP_LISTEN_BEKEN_RTC_SEND_START_LISTEN\r\n"); rtc_websocket_send_text(client, (void *)(&audio_info), BEKEN_RTC_SEND_ABORT); - rtc_websocket_send_text(client, (void *)(&audio_info), BEKEN_RTC_SEND_START); + rtc_websocket_send_text(client, (void *)(&audio_info), BEKEN_RTC_SEND_START_LISTEN); // rtc_websocket_send_text(client, (void *)(&audio_info), BEKEN_RTC_SEND_STOP_LISTEN); @@ -769,12 +807,14 @@ void rtc_websocket_event_handler(void *event_handler_arg, char *event_base, int3 LOGE("Connected to WebSocket server\r\n"); rtc_websocket_send_text(client, (void *)(&audio_info), BEKEN_RTC_SEND_HELLO); rtos_delay_milliseconds(100); - rtc_websocket_send_text(client, (void *)(&audio_info), BEKEN_RTC_SEND_START); + rtc_websocket_send_text(client, (void *)(&audio_info), BEKEN_RTC_SEND_START_LISTEN); + + //2025.07.07 + //rtos_delay_milliseconds(100); + //rtc_websocket_send_text(client, (void *)(&audio_info), BEKEN_RTC_SEND_IOT_DESC); + //rtos_delay_milliseconds(20); + //thing_report_device_state(); - rtos_delay_milliseconds(100); - rtc_websocket_send_text(client, (void *)(&audio_info), BEKEN_RTC_SEND_IOT_DESC); - rtos_delay_milliseconds(20); - thing_report_device_state(); // rtc_websocket_send_text(client, (void *)(&audio_info), BEKEN_RTC_SEND_START_LISTEN); // rtos_delay_milliseconds(200); @@ -787,7 +827,7 @@ void rtc_websocket_event_handler(void *event_handler_arg, char *event_base, int3 __get_beken_rtc()->disconnecting_state++; if (__get_beken_rtc()->disconnecting_state == 1) { - app_event_send_msg(APP_EVT_RTC_CONNECTION_LOST, 0); + //app_event_send_msg(APP_EVT_RTC_CONNECTION_LOST, 0); } // beken_rtc_stop();//zhanyu @@ -1019,6 +1059,7 @@ void beken_auto_run(void) } */ //bk_https_ota_download("https://xiaozhi.xa-poka.com/xiaozhi/otaMag/download/59cc091e-eaf3-417d-a524-d5e3d95883f4"); + beken_rtc_start(); } }