2025-07-03 15:12:57 +08:00
|
|
|
|
#include "cm_iomux.h"
|
|
|
|
|
|
#include "cm_gpio.h"
|
|
|
|
|
|
#include "stdio.h"
|
|
|
|
|
|
#include "stdlib.h"
|
|
|
|
|
|
#include "stdarg.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"
|
|
|
|
|
|
|
2025-07-10 10:01:23 +08:00
|
|
|
|
#if 1
|
2025-07-03 15:12:57 +08:00
|
|
|
|
#include "app_uart.h"
|
2025-07-10 10:01:23 +08:00
|
|
|
|
#define DEBUG(fmt, args...) app_printf("[Broadcast]" fmt, ##args)
|
2025-07-03 15:12:57 +08:00
|
|
|
|
#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播报优先级
|
2025-07-11 11:22:25 +08:00
|
|
|
|
#define MAX_TTS_SEGMENT_LEN 70 // TTS每段最大长度(字符)
|
2025-07-10 11:57:26 +08:00
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
|
|
|
|
|
|
static nmeaPARSER parser;
|
|
|
|
|
|
|
2025-07-10 10:05:00 +08:00
|
|
|
|
//该版本仅实现基本的靠近播报功能,长文字播放功能待开发
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
|
2025-07-10 11:57:26 +08:00
|
|
|
|
// 文本分段结构 [新增]
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
|
char** segments; // 分段文本数组
|
|
|
|
|
|
int count; // 分段数量
|
|
|
|
|
|
} SegmentedText;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 修改景点节点结构 [修改]
|
2025-07-03 15:12:57 +08:00
|
|
|
|
typedef struct AttractionNode {
|
2025-07-10 11:57:26 +08:00
|
|
|
|
double longitude;
|
|
|
|
|
|
double latitude;
|
|
|
|
|
|
char name[50];
|
|
|
|
|
|
SegmentedText description; // 从char[]改为SegmentedText结构 [关键修改]
|
2025-07-03 15:12:57 +08:00
|
|
|
|
struct AttractionNode* next;
|
|
|
|
|
|
} AttractionNode;
|
|
|
|
|
|
|
2025-07-10 11:57:26 +08:00
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
// 播报状态
|
|
|
|
|
|
typedef struct {
|
2025-07-10 10:01:23 +08:00
|
|
|
|
AttractionNode* last_broadcast;
|
|
|
|
|
|
double last_distance;
|
|
|
|
|
|
uint8_t is_playing;
|
|
|
|
|
|
double distance_threshold;
|
2025-07-03 15:12:57 +08:00
|
|
|
|
} BroadcastState;
|
|
|
|
|
|
|
2025-07-10 10:01:23 +08:00
|
|
|
|
|
|
|
|
|
|
typedef int BOOL;
|
|
|
|
|
|
#define true 1
|
|
|
|
|
|
#define false 0
|
|
|
|
|
|
|
|
|
|
|
|
const char *park_desc[] = {
|
|
|
|
|
|
"尊敬的游客欢迎来到顾村公园游玩",
|
|
|
|
|
|
"顾村公园,位于上海市宝山区顾村镇沪太路4788号",
|
|
|
|
|
|
"东起沪太路,西至陈广路,北邻镜泊湖路,南靠外环",
|
|
|
|
|
|
"高速公路,占帝总面积430公顷,其中一期占帝180",
|
|
|
|
|
|
"公顷,二期占帝244.7公顷,顾村公园一期于2007年8月",
|
|
|
|
|
|
"动工建设,二期于2012年10月22日动工建设.公园",
|
|
|
|
|
|
"建设理念为“亲民人文,以生态休闲娱乐为主题.",
|
|
|
|
|
|
"集生态防护、景观观赏、休闲健身、文化娱乐旅游",
|
|
|
|
|
|
"度假等功能于一体,与传统的城市公园形成功能互补",
|
|
|
|
|
|
"并以中心河为界分两期实施。顾村公园为国家4A级",
|
|
|
|
|
|
"景区,上海市科普教育基地、上海市志愿者服务基地等。"
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static osMutexId_t attractions_mutex = NULL;
|
|
|
|
|
|
static AttractionNode* attractions_head = NULL;
|
|
|
|
|
|
static BroadcastState broadcast_state = {0};
|
|
|
|
|
|
static int tts_speed = 5;
|
|
|
|
|
|
static int tts_volume = 10;
|
|
|
|
|
|
static osThreadId_t Attr_Broadcast_ThreadId = NULL; //串口数据接收、解析任务Handle
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-10 11:57:26 +08:00
|
|
|
|
// 智能分段函数
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-10 10:01:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//多文字tts,景区播报专用
|
|
|
|
|
|
void safe_tts_play(const char* segments[], int count) {
|
|
|
|
|
|
for(int i = 0; i < count; i++) {
|
|
|
|
|
|
local_tts_text_play(segments[i], 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
// 等待当前播放完成
|
|
|
|
|
|
while(local_tts_get_play_state() != 0) {
|
|
|
|
|
|
osDelay(100); // 每100ms检查一次
|
|
|
|
|
|
}
|
|
|
|
|
|
osDelay(200); // 额外缓冲
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
|
2025-07-10 11:57:26 +08:00
|
|
|
|
// 释放分段内存 [新增]
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
|
|
|
|
|
|
//计算到景点的距离
|
|
|
|
|
|
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};
|
|
|
|
|
|
|
|
|
|
|
|
// 加锁保护全局数据
|
2025-07-10 10:01:23 +08:00
|
|
|
|
osMutexAcquire(gps_data.mutex, osWaitForever);
|
2025-07-03 15:12:57 +08:00
|
|
|
|
// 检查数据是否有效
|
|
|
|
|
|
if (gps_data.info.sig > 0 && gps_data.info.fix > 0) {
|
2025-07-10 10:01:23 +08:00
|
|
|
|
current.longitude = gps_data.longitude;
|
|
|
|
|
|
current.latitude = gps_data.latitude;
|
2025-07-03 15:12:57 +08:00
|
|
|
|
}
|
2025-07-10 10:01:23 +08:00
|
|
|
|
osMutexRelease(gps_data.mutex);
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
2025-07-11 11:22:25 +08:00
|
|
|
|
AttractionNode* new_node = cm_malloc(sizeof(AttractionNode));
|
2025-07-03 15:12:57 +08:00
|
|
|
|
if (!new_node) {
|
|
|
|
|
|
osMutexRelease(attractions_mutex);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 填充景点信息
|
2025-07-10 11:57:26 +08:00
|
|
|
|
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);
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
// 添加到链表头部
|
|
|
|
|
|
new_node->next = attractions_head;
|
|
|
|
|
|
attractions_head = new_node;
|
|
|
|
|
|
|
|
|
|
|
|
osMutexRelease(attractions_mutex);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-10 11:57:26 +08:00
|
|
|
|
// 释放所有景点内存 最新添加
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
// 设置播报距离阈值 (米)
|
|
|
|
|
|
void attr_broadcast_set_distance_threshold(double threshold) {
|
|
|
|
|
|
if (threshold > 0) {
|
|
|
|
|
|
broadcast_state.distance_threshold = threshold;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 根据当前位置查找最近的景区节点
|
|
|
|
|
|
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(
|
2025-07-10 11:57:26 +08:00
|
|
|
|
(Location){current->longitude, current->latitude},
|
2025-07-03 15:12:57 +08:00
|
|
|
|
current_pos
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
while (current != NULL) {
|
|
|
|
|
|
double distance = location_service_calculate_distance(
|
2025-07-10 11:57:26 +08:00
|
|
|
|
(Location){current->longitude, current->latitude},
|
2025-07-03 15:12:57 +08:00
|
|
|
|
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;
|
|
|
|
|
|
|
2025-07-10 11:57:26 +08:00
|
|
|
|
// 构建距离提示
|
|
|
|
|
|
char distance_msg[100];
|
|
|
|
|
|
snprintf(distance_msg, sizeof(distance_msg), "您已到达%s,距离%.1f米。",
|
|
|
|
|
|
attraction->name, distance);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建播放数组(距离提示 + 所有描述分段)
|
|
|
|
|
|
int total_segments = attraction->description.count + 1;
|
|
|
|
|
|
const char** segments = cm_malloc(total_segments * sizeof(char*));
|
|
|
|
|
|
if (!segments) return;
|
2025-07-03 15:12:57 +08:00
|
|
|
|
|
2025-07-10 11:57:26 +08:00
|
|
|
|
segments[0] = distance_msg;
|
|
|
|
|
|
for (int i = 0; i < attraction->description.count; i++) {
|
|
|
|
|
|
segments[i+1] = attraction->description.segments[i];
|
2025-07-10 10:01:23 +08:00
|
|
|
|
}
|
2025-07-10 11:57:26 +08:00
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
// 更新播报状态
|
|
|
|
|
|
broadcast_state.last_broadcast = attraction;
|
|
|
|
|
|
broadcast_state.last_distance = distance;
|
2025-07-10 11:57:26 +08:00
|
|
|
|
broadcast_state.is_playing = 0;
|
2025-07-03 15:12:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void attr_broadcast_task(void* arg) {
|
|
|
|
|
|
(void)arg; // 避免未使用参数警告
|
2025-07-10 10:01:23 +08:00
|
|
|
|
BOOL should_play; //是否播放最后判断量
|
|
|
|
|
|
BOOL introduc=true; //是否播报景区介绍
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DEBUG("task begin\r\n");
|
|
|
|
|
|
|
|
|
|
|
|
if(0)
|
|
|
|
|
|
{
|
|
|
|
|
|
safe_tts_play(park_desc,11);
|
2025-07-03 15:12:57 +08:00
|
|
|
|
|
2025-07-10 10:01:23 +08:00
|
|
|
|
introduc=false;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2025-07-03 15:12:57 +08:00
|
|
|
|
while (1) {
|
|
|
|
|
|
// 获取当前位置
|
|
|
|
|
|
Location current_pos = location_service_get_current();
|
|
|
|
|
|
|
|
|
|
|
|
// 查找最近景点
|
|
|
|
|
|
AttractionNode* nearest = find_nearest_attraction(current_pos);
|
2025-07-10 10:01:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DEBUG("location ok\r\n");
|
2025-07-03 15:12:57 +08:00
|
|
|
|
if (nearest != NULL) {
|
|
|
|
|
|
// 计算距离
|
|
|
|
|
|
double distance = location_service_calculate_distance(
|
2025-07-10 11:57:26 +08:00
|
|
|
|
(Location){nearest->longitude, nearest->latitude},
|
2025-07-03 15:12:57 +08:00
|
|
|
|
current_pos
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2025-07-10 10:01:23 +08:00
|
|
|
|
DEBUG("calculate ok\r\n");
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
// 检查是否在有效范围内
|
|
|
|
|
|
if (distance <= broadcast_state.distance_threshold) {
|
|
|
|
|
|
// 检查是否需要播报
|
2025-07-10 10:01:23 +08:00
|
|
|
|
should_play = false;
|
|
|
|
|
|
DEBUG("check ok:%d\r\n",should_play);
|
2025-07-03 15:12:57 +08:00
|
|
|
|
|
|
|
|
|
|
if (broadcast_state.last_broadcast == NULL) {
|
|
|
|
|
|
should_play = true; // 首次播报
|
2025-07-10 10:01:23 +08:00
|
|
|
|
DEBUG("check ok:%d\r\n",should_play);
|
2025-07-03 15:12:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (broadcast_state.last_broadcast != nearest) {
|
|
|
|
|
|
should_play = true; // 新景点
|
2025-07-10 10:01:23 +08:00
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
}
|
2025-07-10 10:01:23 +08:00
|
|
|
|
else if (fabs(distance - broadcast_state.last_distance) > 50.0) {
|
|
|
|
|
|
should_play = true; // 同一景点但距离变化大 是否需要播报可以商榷
|
2025-07-03 15:12:57 +08:00
|
|
|
|
}
|
2025-07-10 10:01:23 +08:00
|
|
|
|
DEBUG("stat ok:%d\r\n",should_play);
|
2025-07-03 15:12:57 +08:00
|
|
|
|
// 触发播报
|
|
|
|
|
|
if (should_play && !broadcast_state.is_playing) {
|
2025-07-10 10:01:23 +08:00
|
|
|
|
DEBUG("ready to play\r\n");
|
2025-07-03 15:12:57 +08:00
|
|
|
|
play_attraction_info(nearest, distance);
|
2025-07-10 10:01:23 +08:00
|
|
|
|
broadcast_state.is_playing=0;
|
|
|
|
|
|
DEBUG("play ok\r\n");
|
2025-07-03 15:12:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-10 10:01:23 +08:00
|
|
|
|
DEBUG("dist:%0.3f,threshold:%0.3f\r\n",distance,broadcast_state.distance_threshold);
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 5秒检测一次
|
2025-07-10 10:01:23 +08:00
|
|
|
|
osDelay(5000/5);
|
2025-07-03 15:12:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-10 10:01:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
void attr_broadcast_init(void) {
|
|
|
|
|
|
// 初始化互斥锁
|
|
|
|
|
|
if (attractions_mutex == NULL) {
|
|
|
|
|
|
attractions_mutex = osMutexNew(NULL);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-10 10:01:23 +08:00
|
|
|
|
//增加初始景点
|
2025-07-11 11:22:25 +08:00
|
|
|
|
attr_broadcast_add_attraction(121.377232, 31.347311, "谭杨桥", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.378406, 31.346974, "荷花亭", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.377243, 31.346191, "广福桥", "取名于顾村镇(原刘行镇)广福村,广福村以广福寺得名。传说广福寺规模庞大,鼎盛时期占地方圆近1公里,号称江南第一寺,为当年名僧的游学之地。 \"八·一三\"淞沪抗战,广福寺及广福桥等建筑物毁于战火。而今,杏花疏影中的广福寺虽不复存在,然而公园内新建的汉白玉七孔长桥——广福桥,犹如一道彩虹飞架于粼粼碧波之上,为公园徒增许多诗情画意。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.377107, 31.345321, "梅樱林", "梅樱林位于樱花大道和红粉路交叉口,占地面积约5000平方米,种植以梅花和樱花相融合为主题的特色林带,樱花品种以华中樱为主。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.363918, 31.342592, "恐龙乐园后门", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.377183, 31.345215, "小卖部", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.377747, 31.344542, "紫藤阁", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.375954, 31.343419, "梦熊桥", "原位于顾村镇白杨村境内。经查,原\"梦熊桥\",建于公元1695年(即康熙33年),距今已有314年历史。\"梦熊\"一词出自《诗经·小雅·斯干》,意指生男孩,或为祝贺生男孩之语。据说,该桥的来历与当时宅上妇女大都生育男孩有关。顾村公园的梦熊桥是园内唯一的一座双桥,采用超越天然大理石建造。桥旁碧水荡漾,绿树掩映,是绝佳的赏景之桥。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.375293, 31.345056, "太平桥", "原太平桥位于顾村镇(原刘行镇)老安村境内沪太路上,始建于清同治年间。沪太路曾是上海市最早的一条省际公路,故太平桥的作用十分重要。现顾村公园太平桥又称十二生肖桥,桥两侧栏杆共雕刻着二十四只栩栩如生相对应的生肖动物。如此走在桥上,游客都会情不自禁地边走边摸生肖动物,看看属于自己的生肖可爱形象,真是情趣横生。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.374492, 31.344662, "严家港桥", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.373485, 31.344425, "砚池桥", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.373685, 31.346686, "东南亚风情园", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.373297, 31.346479, "樱花文化艺术展示馆", "顾村公园\"樱花文化艺术展示馆\"建于2020年,展馆以顾村公园樱花文化为设计理念,以\"永不落幕的·上海樱花节\"为主题,浓缩了十届\"上海樱花节\"的盛景,多形态的展示樱花摄影作品、樱花历史文化、樱花科普知识、樱花系列文创产品等内容,传播并丰富公园的樱花文化,呈现更绚烂的樱花情景。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.371509, 31.345411, "樱悦书院", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.372022, 31.344942, "万年桥", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.372601, 31.344801, "1号游船码头", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.373195, 31.342009, "2号游船码头", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.372599, 31.342228, "樱舞桥", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.371710, 31.341834, "小樱广场", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.370535, 31.342174, "游乐园", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.370519, 31.342064, "摩天轮", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.369894, 31.341977, "商店", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.370991, 31.343946, "樱悦大桥", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.369933, 31.341000, "星火服务站", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.369659, 31.340968, "汉服体验馆", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.36613, 31.33925, "樱花广场", "亲爱的游客现在您看到的是顾村公园樱花广场,一寸春心十年相守,为纪念上海樱花节十周年,顾村公园特意打造了樱花广场,广场设计简洁通畅,十朵樱花十个花坛,十颗樱树,片片花瓣和公园图标都融入了广场之中,十年之恋景观墙更是将上海樱花节十年历程铭刻记录,让我们可以借此回顾过往,展望将来,愿明年的樱花更烂漫,祖国的未来更辉煌");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.364349, 31.339023, "盛宅桥", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.363623, 31.338906, "迎春林", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.362796, 31.339624, "3号游船码头", "游客三号游船码头到了,顾村公园浏中湖景区有约10公顷的湖面和沿岸森林湿地,沿岸包括水上码头,鸟岛,湿地,垂钓,索桥等景点,绝对会让您觉得不虚此行");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.364350, 31.342175, "彩虹桥", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.36799, 31.34449, "恐龙乐园正门", "您好自然谷恐龙园到了,这是一个人工搭建的,模拟三叠纪,侏罗纪,白垩纪等时代的恐龙生活场景的乐园,在这里您可以穿梭于恐龙像群,欣赏超前的7D电影,在自然中感受野趣,在怪石和岩洞中穿行,充分体验远古时代洪荒洞窟的神奇刺激和绝妙采用,这里的各类恐龙有着高仿真,活动自如的特性,虫现远古时代恐龙生活打斗等场景,让恐龙如同真的复活,园内霸王龙,三角龙,阿马加龙,剑龙,恐爪龙等几十条恐龙与您零距离接触,带您进入远古霸主的惊险旅程");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.367888, 31.343220, "矮人部落站", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.361532, 31.341848, "彩弹射击射箭运动中心", "上海顾村公园彩弹射击射箭运动中心坐落于顾村公园2号门往西200米冬青路,游客在这里可以进行彩弹射击真人CS实战对抗、气手枪竞技射击培训体验、M4-16气步枪打靶、10-50米靶射箭体验、worgame_BB弹真人吃鸡大作战。欢迎广大游客朋友们前来体验、游玩。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.362142, 31.340588, "想家桥", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.359204, 31.337386, "孔雀园", "这里是东方鸟世界的孔雀园,园内看到的是六大明星之一孔雀\"花花\"。在进入孔雀园时,请仔细阅读入园须知,不要投喂自带食物,照顾好您的宝宝,防止抓伤啄伤,如果您不认同与鸟类接触行为,请在护栏外观赏哦!孔雀园内居住着上百只孔雀,孔雀是鸡形目、雉科动物。一直以来,孔雀被视为\"百鸟之王\",是最美丽的观赏鸟,象征着爱情,更是吉祥、善良、美丽、华贵的象征。我们园内的孔雀是以蓝孔雀和白孔雀为主,孔雀体长可达2米以上,其中尾屏长约1.5米,体重达6公斤左右。尾部华丽的为雄孔雀,而雌孔雀其貌不扬。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.359030, 31.337262, "东方鸟世界便利店", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.359178, 31.337357, "鸵鸟园", "这里是东方鸟世界的\"鸵鸟园\",眼前看到的是六大明星之一\"大个\"。鸵鸟属鸵形目、鸵鸟科,是世界上最大的一种鸟类,成鸟身高可达2.5米,雄鸵鸟体重可达150千克。像蛇一样细长的脖颈上支撑着一个很小的头部,上面有一张短而扁平的、由数片角质鞘所组成的三角形的嘴,主要特点是龙骨突不发达,不能飞行,也是世界上现存鸟类中唯一的二趾鸟类,在它双脚的每个大脚趾上都长有长约7厘米的危险趾甲,后肢粗壮有力,适于奔走。作为世界上最大的鸟类,它的蛋也异乎寻常的坚毅,一般人的力量根本踩不碎它。它的长度15公分,宽度则有八公分左右,重量却能达到1.5公斤。我们园内有鸵鸟和鸸鹋两种。鸸鹋原产于澳洲,是澳洲的国鸟,体形大但不会飞,生活在较开阔的半沙漠、草原和开阔的林地等栖息地。鸸鹋是澳大利亚个子最高的鸟,以擅长奔跑而著名,是澳洲地区的特产,是世界上第二大的鸟类,由于外形与鸵鸟相似,因而也被称作澳洲鸵鸟。翅膀比非洲鸵鸟和美洲鸵鸟的更加退化,足三趾,是世界上最古老的鸟种之一。非洲鸵鸟拥有世界上最大的眼球,美丽而明亮,赶快把小游停在路边,和她比一比吧!");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.357985, 31.338391, "仙境奇缘", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.358695, 31.337023, "小鸟市集", "在天鹅湖的马路对面就是小鸟市集哦,这里是儿童的欢乐营地,更是各种萌宠的温馨之家,小朋友可以在这里与萌宠和小鸟们亲密互动,同时还有各种小朋友喜欢的精彩活动哦!");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.357883, 31.336482, "鹦鹉世界", "这是一个彩色的世界,来自五大洲的鹦鹉在此集结,是一个名副其实的世界鹦鹉博览园,这里有大型鹦鹉、中型和小型鹦鹉,这里不仅可以观赏到五彩缤纷的毛孩子,大朋友小朋友还可以与它们近距离亲密互动哦,但是在互动过程中千万不要用力抓它们,以免把他们弄疼哦,爱护鸟类,人人有责,从我做起。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.356022, 31.336296, "孔雀东南飞", "孔雀被誉为百鸟之王,是最美丽的观赏鸟,是美丽、华贵、吉祥的象征。孔雀的头顶翠绿,羽冠蓝绿而呈尖形;尾部上覆羽特别长,形成尾屏,开屏的时候像一个圆形的扇子,鲜艳美丽;孔雀东南飞表演非常的壮观美丽,上百只孔雀倾情演绎,一场凄美壮观的爱情故事让您不虚此行,流连忘返。孔雀东南飞,五里一徘徊。 大家一定要记好表演时间,准时前往孔雀东南飞表演场看台观看壮观的表演哦!");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.355376, 31.335896, "彩虹滑梯", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.355366, 31.336917, "兰兰广场", "兰兰广场位于悦林湖畔,1972年9月29日,将大熊猫\"兰兰\"和\"康康\"赠送给日本,没想到在日本大受欢迎,后为纪念熊猫\"兰兰\",松前在熊猫纪念日将这个新品种命名为\"兰兰\",2021年1月1日在公园建此兰兰广场,并树立熊猫雕塑,愿美好与和平永在。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.355916, 31.337299, "望湖桥", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.355457, 31.339899, "胭脂林", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.353600, 31.339272, "悦林湖", "悦林湖位于公园二期,湖上鸟类汇集、且拥有皮划艇这项老少皆宜的娱乐项目,沿湖岸边走一圈能欣赏到各种各样精彩纷呈的美景,有娇艳的月季、有灿烂的樱花、有羞涩的小花一阵风徐徐吹来,感受到别具一格的公园风采。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.34949, 31.33833, "樱花烧烤园", "您好樱花烧烤园到了,顾村公园樱花烧烤园通过户外野趣的烧烤方式,让您在享受美食的同时还可以尽情享受绿树红花和湖边美景,是家人,友人以及团体聚会的绝佳场所,在绿草如茵的花园旁品尝美食,与大自然共同感受此刻的美好");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.364371, 31.343164, "2号门便民处", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.359268, 31.339659, "洋庭花园餐厅", "");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.35677, 31.33876, "水上运动基地", "在上海大都市里,不需要经过严格的专业学习和训练,就可以亲身体验集健身,休闲,娱乐于一体的奥运会水上比赛项目,顾村公园水上运动基地带给您的绝对是一份意外的惊喜,这里阳光和煦,碧水蓝天,清新怡人,和公园集生态,休闲,娱乐一体的公园设施融为一体,水上运动基地设有皮划艇,平台舟,独木舟,SUP浆板,摩托艇,冲锋艇,香蕉船,拖拉圈,OP帆船,滑水等娱乐项目,或惊险刺激,或悠然自得,在悦林湖亦静亦动的水面,无论是运动,休闲,还是观水,赏景,都别有一番情趣,让人亲近自然之水,生命之水");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.35781, 31.33859, "东方鸟世界", "亲爱的游客东方鸟世界到了,这里是一个集观赏性,趣味性,参与性,科普性为一体的鸟类主题园区, 园内栖息着来自世界各地分属六十多个物种的两千余只珍稀鸟禽,建有孔雀东南飞,飞禽知识馆,鹦鹉世界,火烈鸟湾,鸵鸟园,游禽综合园,猛禽园,孵化中心等16个展区,涵盖游禽,涉禽,攀禽,鸣禽,猛禽,走禽六大鸟类品种,这里是要单独购票的哟,您要去游览的话记得将我停放在路边临时锁定哦");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.357591, 31.338533, "月季园", "月季主题花园位于二期悦林湖畔,总面积约534亩,其中陆地面积约358亩,月季种植面积22575平方米,展示品种128种,有灌木月季、藤本月季、大花月季、微型月季、树状月季等11个类别。月季主题花园将二期由生态林带向生态花园的品质内涵提升,建造上海第一大以月季为主题的花园。");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.376079, 31.347508, "1号门归还点", "您好一号门停放点到了,您可以把我归还至这里,并在手机小程序中结束订单,如果还想与我去其他地方玩耍我们就继续出发吧");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.364270, 31.343103, "2号门归还点", "您好二号门停放点到了,您可以把我归还至这里,并在手机小程序中结束订单,如果还想陪我去其他地方玩耍我们就继续出发吧");
|
|
|
|
|
|
attr_broadcast_add_attraction(121.356886, 31.340930, "3号门归还点", "您好三号门停放点到了,您可以把我归还至这里,并在手机小程序中结束订单,如果还想陪我去其他地方玩耍我们就继续出发吧");
|
2025-07-10 10:01:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-07-03 15:12:57 +08:00
|
|
|
|
// 初始化状态
|
|
|
|
|
|
memset(&broadcast_state, 0, sizeof(broadcast_state));
|
|
|
|
|
|
broadcast_state.distance_threshold = 50.0; // 默认阈值50米
|
|
|
|
|
|
|
2025-07-10 10:01:23 +08:00
|
|
|
|
osThreadAttr_t attr_broadcast_task_attr = {0};
|
|
|
|
|
|
attr_broadcast_task_attr.name = "attr_broadcast_task";
|
2025-07-11 11:22:25 +08:00
|
|
|
|
attr_broadcast_task_attr.stack_size = 4096 * 10;
|
2025-07-10 10:01:23 +08:00
|
|
|
|
attr_broadcast_task_attr.priority= osPriorityNormal;
|
|
|
|
|
|
|
|
|
|
|
|
Attr_Broadcast_ThreadId= osThreadNew(attr_broadcast_task, 0, &attr_broadcast_task_attr);
|
2025-07-03 15:12:57 +08:00
|
|
|
|
|
|
|
|
|
|
}
|