#include "cm_iomux.h" #include "cm_gpio.h" #include "stdio.h" #include "stdlib.h" #include "stdarg.h" #include "stdbool.h" #include "math.h" #include "cm_os.h" #include "cm_mem.h" #include "cm_sys.h" #include "cm_uart.h" #include "app_common.h" #include "app_uart.h" #include "attr_broadcast.h" #include "gps_config.h" #include "local_tts.h" #if 0 #include "app_uart.h" #define DEBUG(fmt, args...) app_printf("[GPS]" fmt, ##args) #else #include "app_uart.h" #define DEBUG(fmt, ...) #endif #define MAX_ATTRACTIONS 50 // 最大景点数量 #define PLAY_DISTANCE_THRESHOLD 50.0 // 有效播报距离(米) #define DISTANCE_CHANGE_THRESHOLD 10.0 // 距离变化阈值(米) #define TTS_PRIORITY 5 // TTS播报优先级 static osMutexId_t attractions_mutex = NULL; static AttractionNode* attractions_head = NULL; static BroadcastState broadcast_state = {0}; static osThreadId_t guide_task_id = NULL; static int tts_speed = 5; static int tts_volume = 10; static nmeaPARSER parser; typedef enum { false, true } bool; // 手动定义布尔类型 // 全局景点链表 typedef struct AttractionNode { Attraction attraction; struct AttractionNode* next; } AttractionNode; // 播报状态 typedef struct { AttractionNode* last_broadcast; // 上次播报的景点 double last_distance; // 上次播报时的距离 uint8_t is_playing; // TTS是否正在播放 } BroadcastState; //位置信息 typedef struct { double longitude; double latitude; } Location; //计算到景点的距离 double location_service_calculate_distance(Location loc1, Location loc2) { // 使用Haversine公式计算真实距离 const double R = 6371000; // 地球半径(米) double dLat = (loc2.latitude - loc1.latitude) * M_PI / 180.0; double dLon = (loc2.longitude - loc1.longitude) * M_PI / 180.0; double a = sin(dLat/2) * sin(dLat/2) + cos(loc1.latitude * M_PI / 180.0) * cos(loc2.latitude * M_PI / 180.0) * sin(dLon/2) * sin(dLon/2); double c = 2 * atan2(sqrt(a), sqrt(1-a)); return R * c; } // 获取当前位置 Location location_service_get_current(void) { Location current = {0}; // 加锁保护全局数据 if (osMutexAcquire(gps_mutex, 100) == osOK) { // 检查数据是否有效 if (gps_data.info.sig > 0 && gps_data.info.fix > 0) { current.longitude = gps_data.dpos.lon; current.latitude = gps_data.dpos.lat; } osMutexRelease(gps_mutex); } return current; } // 添加景点 void attr_broadcast_add_attraction(double lon, double lat, const char* name, const char* desc) { if (attractions_mutex == NULL) return; osMutexAcquire(attractions_mutex, osWaitForever); AttractionNode* new_node = malloc(sizeof(AttractionNode)); if (!new_node) { osMutexRelease(attractions_mutex); return; } // 填充景点信息 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->next = attractions_head; attractions_head = new_node; osMutexRelease(attractions_mutex); } // 设置播报距离阈值 (米) void attr_broadcast_set_distance_threshold(double threshold) { if (threshold > 0) { broadcast_state.distance_threshold = threshold; } } //设置tts参数 void attr_broadcast_set_tts_params(int speed, int volume) { tts_speed = speed; tts_volume = volume; if (guide_task_id != NULL) { // 如果任务已启动,更新TTS参数 local_tts_set(tts_speed, tts_volume, CM_LOCAL_TTS_DIGIT_AUTO); } } // 根据当前位置查找最近的景区节点 static AttractionNode* find_nearest_attraction(Location current_pos) { if (attractions_head == NULL) return NULL; osMutexAcquire(attractions_mutex, osWaitForever); AttractionNode* current = attractions_head; AttractionNode* nearest = attractions_head; double min_distance = location_service_calculate_distance( (Location){current->attraction.longitude, current->attraction.latitude}, current_pos ); while (current != NULL) { double distance = location_service_calculate_distance( (Location){current->attraction.longitude, current->attraction.latitude}, current_pos ); if (distance < min_distance) { min_distance = distance; nearest = current; } current = current->next; } osMutexRelease(attractions_mutex); return nearest; } 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); // 调用TTS接口播放文本 local_tts_text_play(buffer, 0, 1); // 更新播报状态 broadcast_state.last_broadcast = attraction; broadcast_state.last_distance = distance; broadcast_state.is_playing = 1; } static void attr_broadcast_task(void* arg) { (void)arg; // 避免未使用参数警告 while (1) { // 获取当前位置 Location current_pos = location_service_get_current(); // 查找最近景点 AttractionNode* nearest = find_nearest_attraction(current_pos); if (nearest != NULL) { // 计算距离 double distance = location_service_calculate_distance( (Location){nearest->attraction.longitude, nearest->attraction.latitude}, current_pos ); // 检查是否在有效范围内 if (distance <= broadcast_state.distance_threshold) { // 检查是否需要播报 bool should_play = false; if (broadcast_state.last_broadcast == NULL) { should_play = true; // 首次播报 } else if (broadcast_state.last_broadcast != nearest) { should_play = true; // 新景点 } else if (fabs(distance - broadcast_state.last_distance) > 10.0) { should_play = true; // 同一景点但距离变化大 } // 触发播报 if (should_play && !broadcast_state.is_playing) { play_attraction_info(nearest, distance); } } } // 5秒检测一次 osDelay(5000); } } void attr_broadcast_init(void) { // 初始化互斥锁 if (attractions_mutex == NULL) { attractions_mutex = osMutexNew(NULL); } // 初始化状态 memset(&broadcast_state, 0, sizeof(broadcast_state)); broadcast_state.distance_threshold = 50.0; // 默认阈值50米 }