From 953f3187dfd937d2af7e6f7a4f69615ae2fc8875 Mon Sep 17 00:00:00 2001 From: wjw Date: Thu, 10 Jul 2025 11:57:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=99=AF=E7=82=B9=E9=95=BF?= =?UTF-8?q?=E6=92=AD=E6=94=BE=E8=AF=AD=E9=9F=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- custom/attr_broadcast/src/attr_broadcast.c | 148 +++++++++++++++++---- 1 file changed, 123 insertions(+), 25 deletions(-) diff --git a/custom/attr_broadcast/src/attr_broadcast.c b/custom/attr_broadcast/src/attr_broadcast.c index f116a6a..e72c36f 100644 --- a/custom/attr_broadcast/src/attr_broadcast.c +++ b/custom/attr_broadcast/src/attr_broadcast.c @@ -28,18 +28,31 @@ #define PLAY_DISTANCE_THRESHOLD 50.0 // 有效播报距离(米) #define DISTANCE_CHANGE_THRESHOLD 10.0 // 距离变化阈值(米) #define TTS_PRIORITY 5 // TTS播报优先级 +#define MAX_TTS_SEGMENT_LEN 50 // TTS每段最大长度(字符) + static nmeaPARSER parser; //该版本仅实现基本的靠近播报功能,长文字播放功能待开发 -// 全局景点链表 +// 文本分段结构 [新增] +typedef struct { + char** segments; // 分段文本数组 + int count; // 分段数量 +} SegmentedText; + + +// 修改景点节点结构 [修改] typedef struct AttractionNode { - Attraction attraction; + double longitude; + double latitude; + char name[50]; + SegmentedText description; // 从char[]改为SegmentedText结构 [关键修改] struct AttractionNode* next; } AttractionNode; + // 播报状态 typedef struct { AttractionNode* last_broadcast; @@ -76,6 +89,48 @@ static int tts_volume = 10; static osThreadId_t Attr_Broadcast_ThreadId = NULL; //串口数据接收、解析任务Handle +// 智能分段函数 +SegmentedText smart_segment_text(const char* text, int max_segment_len) { + SegmentedText result = {0}; + if (!text || *text == '\0') return result; + + int text_len = strlen(text); + int max_segments = (text_len / max_segment_len) + 2; + result.segments = cm_malloc(max_segments * sizeof(char*)); + + int start = 0; + int segment_count = 0; + + while (start < text_len && segment_count < max_segments) { + int end = start + max_segment_len; + if (end > text_len) end = text_len; + + if (end < text_len) { + // 寻找最佳分割点(标点符号优先) + int best_break = end; + for (int i = end; i > start; i--) { + if (strchr("。!?,;.!?", text[i])) { + best_break = i + 1; + break; + } + } + end = best_break; + } + + // 创建分段 + int seg_len = end - start; + result.segments[segment_count] = cm_malloc(seg_len + 1); + strncpy(result.segments[segment_count], text + start, seg_len); + result.segments[segment_count][seg_len] = '\0'; + segment_count++; + + start = end; + } + + result.count = segment_count; + return result; +} + //多文字tts,景区播报专用 @@ -92,6 +147,18 @@ void safe_tts_play(const char* segments[], int count) { } +// 释放分段内存 [新增] +void free_segmented_text(SegmentedText* st) { + if (st && st->segments) { + for (int i = 0; i < st->count; i++) { + cm_free(st->segments[i]); + } + cm_free(st->segments); + st->segments = NULL; + st->count = 0; + } +} + //计算到景点的距离 double location_service_calculate_distance(Location loc1, Location loc2) { @@ -141,11 +208,13 @@ void attr_broadcast_add_attraction(double lon, double lat, } // 填充景点信息 - new_node->attraction.longitude = lon; - new_node->attraction.latitude = lat; - strncpy(new_node->attraction.name, name, sizeof(new_node->attraction.name)-1); - strncpy(new_node->attraction.description, desc, sizeof(new_node->attraction.description)-1); - + new_node->longitude = lon; + new_node->latitude = lat; + strncpy(new_node->name, name, sizeof(new_node->name)-1); + new_node->name[sizeof(new_node->name)-1] = '\0'; + + new_node->description = smart_segment_text(desc, MAX_TTS_SEGMENT_LEN); + // 添加到链表头部 new_node->next = attractions_head; attractions_head = new_node; @@ -154,6 +223,26 @@ void attr_broadcast_add_attraction(double lon, double lat, } +// 释放所有景点内存 最新添加 +void attr_broadcast_free_all() { + if (attractions_mutex == NULL) return; + + osMutexAcquire(attractions_mutex, osWaitForever); + + AttractionNode* current = attractions_head; + while (current) { + AttractionNode* next = current->next; + free_segmented_text(¤t->description); + cm_free(current); + current = next; + } + + attractions_head = NULL; + osMutexRelease(attractions_mutex); +} + + + // 设置播报距离阈值 (米) void attr_broadcast_set_distance_threshold(double threshold) { if (threshold > 0) { @@ -171,13 +260,13 @@ static AttractionNode* find_nearest_attraction(Location current_pos) { AttractionNode* current = attractions_head; AttractionNode* nearest = attractions_head; double min_distance = location_service_calculate_distance( - (Location){current->attraction.longitude, current->attraction.latitude}, + (Location){current->longitude, current->latitude}, current_pos ); while (current != NULL) { double distance = location_service_calculate_distance( - (Location){current->attraction.longitude, current->attraction.latitude}, + (Location){current->longitude, current->latitude}, current_pos ); @@ -197,25 +286,34 @@ static AttractionNode* find_nearest_attraction(Location current_pos) { static void play_attraction_info(AttractionNode* attraction, double distance) { if (!attraction) return; - // 构建播报文本 - char buffer[300]; - snprintf(buffer, sizeof(buffer), "您已到达%s,%s。距离%.1f米。", - attraction->attraction.name, - attraction->attraction.description, - distance); - - - broadcast_state.is_playing = 1; - // 调用TTS接口播放文本 - local_tts_text_play(buffer, 0, 1); + // 构建距离提示 + char distance_msg[100]; + snprintf(distance_msg, sizeof(distance_msg), "您已到达%s,距离%.1f米。", + attraction->name, distance); - //等待 - while(local_tts_get_play_state() != 0) { - osDelay(100); + // 创建播放数组(距离提示 + 所有描述分段) + int total_segments = attraction->description.count + 1; + const char** segments = cm_malloc(total_segments * sizeof(char*)); + if (!segments) return; + + segments[0] = distance_msg; + for (int i = 0; i < attraction->description.count; i++) { + segments[i+1] = attraction->description.segments[i]; } + + broadcast_state.is_playing = 1; + DEBUG("Playing attraction info: %s (%d segments)\n", + attraction->name, total_segments); + + // 播放所有分段 + safe_tts_play(segments, total_segments); + + cm_free(segments); + // 更新播报状态 broadcast_state.last_broadcast = attraction; broadcast_state.last_distance = distance; + broadcast_state.is_playing = 0; } @@ -247,7 +345,7 @@ static void attr_broadcast_task(void* arg) { if (nearest != NULL) { // 计算距离 double distance = location_service_calculate_distance( - (Location){nearest->attraction.longitude, nearest->attraction.latitude}, + (Location){nearest->longitude, nearest->latitude}, current_pos ); @@ -314,7 +412,7 @@ void attr_broadcast_init(void) { osThreadAttr_t attr_broadcast_task_attr = {0}; attr_broadcast_task_attr.name = "attr_broadcast_task"; - attr_broadcast_task_attr.stack_size = 4096 * 5; + attr_broadcast_task_attr.stack_size = 4096 * 8; attr_broadcast_task_attr.priority= osPriorityNormal; Attr_Broadcast_ThreadId= osThreadNew(attr_broadcast_task, 0, &attr_broadcast_task_attr);