Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
car-controlserver
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wenzhongjian
car-controlserver
Commits
96051595
Commit
96051595
authored
Feb 06, 2026
by
DESKTOP-MC5UL36\dell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
增加扫码配wifi功能
parent
1ff4fcfc
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
344 additions
and
8 deletions
+344
-8
main.c
app/main/main.c
+20
-8
wifi_autoconfig.c
app/main/wifi_autoconfig.c
+314
-0
wifi_autoconfig.h
app/main/wifi_autoconfig.h
+10
-0
No files found.
app/main/main.c
View file @
96051595
#include "main.h"
#include "main.h"
#include "wifi_autoconfig.h"
int
main
()
int
main
()
{
{
...
@@ -25,6 +26,20 @@ int main()
...
@@ -25,6 +26,20 @@ int main()
return
-
4
;
return
-
4
;
}
}
// 初始化音频,确保配网时的提示音能听到
if
(
audio_config_init
()
!=
0
)
{
my_zlog_warn
(
"音频配置初始化失败"
);
}
if
(
audio_init
()
==
0
)
{
my_zlog_info
(
"音频命令执行初始化成功"
);
}
// 3. 在这里检查网络。如果没网 -> 进入扫码配网 (死循环直到成功)
check_and_autoconfig_wifi
();
if
(
request_date
()
!=
0
)
if
(
request_date
()
!=
0
)
{
{
my_zlog_error
(
"请求数据失败"
);
my_zlog_error
(
"请求数据失败"
);
...
@@ -50,10 +65,7 @@ int main()
...
@@ -50,10 +65,7 @@ int main()
return
-
8
;
return
-
8
;
}
}
if
(
audio_config_init
()
!=
0
)
// 音频初始化已移至开头
{
my_zlog_warn
(
"音频配置初始化失败"
);
}
if
(
hardware_iic_init
()
!=
0
)
if
(
hardware_iic_init
()
!=
0
)
{
{
...
@@ -66,10 +78,7 @@ int main()
...
@@ -66,10 +78,7 @@ int main()
my_zlog_warn
(
"该设备没有冷却"
);
my_zlog_warn
(
"该设备没有冷却"
);
}
}
if
(
audio_init
()
==
0
)
{
my_zlog_info
(
"音频命令执行初始化成功"
);
}
int
thread_rc
=
thread_start_init
(
thread_exit_time
,
thread_mqtt_beat
,
int
thread_rc
=
thread_start_init
(
thread_exit_time
,
thread_mqtt_beat
,
thread_open_browser
,
thread_mqtt_reconnect
,
thread_time_calculation
,
thread_play_mp3
);
thread_open_browser
,
thread_mqtt_reconnect
,
thread_time_calculation
,
thread_play_mp3
);
...
@@ -79,6 +88,9 @@ int main()
...
@@ -79,6 +88,9 @@ int main()
return
-
7
;
return
-
7
;
}
}
// 初始化全部完成,播放“连接成功”提示音,作为系统就绪的标志
play_audio_file
(
"connectionSuccessful.mp3"
);
thread_end_close
();
thread_end_close
();
device_end_close
(
g_device_type
);
device_end_close
(
g_device_type
);
self_control_thread_close
();
// 销毁自控的线程
self_control_thread_close
();
// 销毁自控的线程
...
...
app/main/wifi_autoconfig.c
0 → 100644
View file @
96051595
#include "wifi_autoconfig.h"
#include "main.h"
#include "cJSON.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#define AUDIO_BASE_URL "https://fcrs-1367068685.cos.ap-guangzhou.myqcloud.com/car/audio/"
static
const
char
*
AUDIO_FILES
[]
=
{
"noCameraDetected.mp3"
,
"connectionFailed.mp3"
,
"connectionSuccessful.mp3"
,
"scanSuccessful.mp3"
,
"toScanQRCode.mp3"
};
// 检查命令是否存在 (前置声明)
static
int
is_command_available
(
const
char
*
cmd
);
// 播放 ~/audio/ 下的音频文件
// 播放 ~/audio/ 下的音频文件,如果不存在则回退系统音
void
play_audio_file
(
const
char
*
filename
)
{
char
cmd
[
512
];
const
char
*
audio_dir
=
"/home/orangepi/audio"
;
// 固定路径
char
filepath
[
256
];
snprintf
(
filepath
,
sizeof
(
filepath
),
"%s/%s"
,
audio_dir
,
filename
);
my_zlog_debug
(
"尝试播放音频: %s"
,
filename
);
// 1. 检查自定义文件是否存在
if
(
access
(
filepath
,
F_OK
)
==
0
)
{
// 文件存在,优先使用 ffplay
if
(
is_command_available
(
"ffplay"
))
{
snprintf
(
cmd
,
sizeof
(
cmd
),
"ffplay -nodisp -autoexit -loglevel quiet
\"
%s
\"
"
,
filepath
);
if
(
system
(
cmd
)
==
0
)
{
my_zlog_debug
(
"ffplay 播放成功"
);
return
;
}
}
// 其次 paplay
if
(
is_command_available
(
"paplay"
))
{
snprintf
(
cmd
,
sizeof
(
cmd
),
"paplay
\"
%s
\"
"
,
filepath
);
if
(
system
(
cmd
)
==
0
)
{
my_zlog_debug
(
"paplay 播放成功"
);
return
;
}
}
my_zlog_warn
(
"自定义音频播放失败,尝试回退系统音..."
);
}
else
{
my_zlog_warn
(
"音频文件 %s 不存在,准备播放系统回退音。"
,
filepath
);
}
// 2. 文件不存在,或者播放工具缺失 -> 回退到系统默认声音
// 根据文件名映射一下大概的系统音
const
char
*
sys_sound
=
"dialog-information"
;
// 默认
if
(
strstr
(
filename
,
"noCamera"
))
sys_sound
=
"software-error"
;
else
if
(
strstr
(
filename
,
"Failed"
))
sys_sound
=
"dialog-error"
;
else
if
(
strstr
(
filename
,
"Success"
))
sys_sound
=
"service-login"
;
else
if
(
strstr
(
filename
,
"toScan"
))
sys_sound
=
"dialog-question"
;
// 尝试播放系统音
if
(
is_command_available
(
"paplay"
))
{
snprintf
(
cmd
,
sizeof
(
cmd
),
"paplay /usr/share/sounds/ubuntu/stereo/%s.ogg"
,
sys_sound
);
if
(
system
(
cmd
)
==
0
)
{
my_zlog_debug
(
"系统音 (paplay-ubuntu) 播放成功: %s"
,
sys_sound
);
return
;
}
snprintf
(
cmd
,
sizeof
(
cmd
),
"paplay /usr/share/sounds/freedesktop/stereo/%s.oga"
,
sys_sound
);
if
(
system
(
cmd
)
==
0
)
{
my_zlog_debug
(
"系统音 (paplay-freedesktop) 播放成功: %s"
,
sys_sound
);
return
;
}
}
if
(
is_command_available
(
"ffplay"
))
{
snprintf
(
cmd
,
sizeof
(
cmd
),
"ffplay -nodisp -autoexit -loglevel quiet /usr/share/sounds/ubuntu/stereo/%s.ogg"
,
sys_sound
);
if
(
system
(
cmd
)
==
0
)
{
my_zlog_debug
(
"系统音 (ffplay) 播放成功: %s"
,
sys_sound
);
return
;
}
}
my_zlog_error
(
"所有播放尝试均失败!"
);
}
// 下载音频文件
static
void
download_audio_files
()
{
const
char
*
audio_dir
=
"/home/orangepi/audio"
;
// 固定路径
// 1. 检查并创建目录
struct
stat
st
=
{
0
};
if
(
stat
(
audio_dir
,
&
st
)
==
-
1
)
{
my_zlog_info
(
"正在创建音频目录: %s"
,
audio_dir
);
mkdir
(
audio_dir
,
0755
);
}
// 2. 检查并下载每个文件
for
(
int
i
=
0
;
i
<
5
;
i
++
)
{
char
filepath
[
512
];
snprintf
(
filepath
,
sizeof
(
filepath
),
"%s/%s"
,
audio_dir
,
AUDIO_FILES
[
i
]);
if
(
access
(
filepath
,
F_OK
)
!=
0
)
{
my_zlog_info
(
"正在下载音频文件: %s"
,
AUDIO_FILES
[
i
]);
char
cmd
[
1024
];
// 使用 wget -q (安静模式) -P (指定目录)
snprintf
(
cmd
,
sizeof
(
cmd
),
"wget -q -P
\"
%s
\"
\"
%s%s
\"
"
,
audio_dir
,
AUDIO_BASE_URL
,
AUDIO_FILES
[
i
]);
if
(
system
(
cmd
)
!=
0
)
{
my_zlog_warn
(
"下载失败: %s"
,
AUDIO_FILES
[
i
]);
}
}
else
{
// my_zlog_debug("文件已存在: %s", AUDIO_FILES[i]);
}
}
}
// 检查命令是否存在
static
int
is_command_available
(
const
char
*
cmd
)
{
char
check_cmd
[
256
];
snprintf
(
check_cmd
,
sizeof
(
check_cmd
),
"which %s > /dev/null 2>&1"
,
cmd
);
return
system
(
check_cmd
)
==
0
;
}
// 检查并安装依赖
static
void
check_and_install_dependencies
()
{
int
need_install
=
0
;
char
packages
[
256
]
=
""
;
// 检查拍照工具
if
(
!
is_command_available
(
"fswebcam"
))
{
my_zlog_warn
(
"未检测到 fswebcam,准备安装..."
);
strcat
(
packages
,
" fswebcam"
);
need_install
=
1
;
}
// 检查扫码工具 (zbarimg 包含在 zbar-tools 中)
if
(
!
is_command_available
(
"zbarimg"
))
{
my_zlog_warn
(
"未检测到 zbar-tools,准备安装..."
);
strcat
(
packages
,
" zbar-tools"
);
need_install
=
1
;
}
// 检查音频工具
int
has_audio_tool
=
0
;
if
(
is_command_available
(
"paplay"
)
||
is_command_available
(
"ffplay"
))
{
has_audio_tool
=
1
;
}
if
(
!
has_audio_tool
)
{
my_zlog_warn
(
"未检测到 paplay 或 ffplay,准备安装 pulseaudio-utils..."
);
// 只有在没音频工具时才安装
strcat
(
packages
,
" pulseaudio-utils"
);
need_install
=
1
;
}
if
(
need_install
)
{
my_zlog_info
(
"正在尝试自动安装依赖: %s (需要 sudo 权限)..."
,
packages
);
char
install_cmd
[
512
];
snprintf
(
install_cmd
,
sizeof
(
install_cmd
),
"sudo apt-get update && sudo apt-get install -y %s"
,
packages
);
int
ret
=
system
(
install_cmd
);
if
(
ret
==
0
)
{
my_zlog_info
(
"依赖安装成功!"
);
}
else
{
my_zlog_error
(
"依赖安装失败,自动配网功能可能无法正常使用。"
);
}
}
else
{
my_zlog_info
(
"所需依赖 (fswebcam, zbar-tools, audio) 已就绪。"
);
}
}
// 检测是否有互联网连接 (只检查百度)
static
int
has_internet_connection
()
{
// -c 1: 发送1个包, -W 2: 超时2秒
int
ret
=
system
(
"ping -c 1 -W 2 baidu.com > /dev/null 2>&1"
);
// ret == 0 表示 ping 成功
return
(
ret
==
0
);
}
// 尝试连接 WiFi
static
int
try_connect_wifi
(
const
char
*
ssid
,
const
char
*
password
)
{
char
cmd
[
512
];
// 使用 nmcli 连接,成功会自动保存为默认
snprintf
(
cmd
,
sizeof
(
cmd
),
"nmcli dev wifi connect
\"
%s
\"
password
\"
%s
\"
"
,
ssid
,
password
);
my_zlog_info
(
"正在尝试连接 WiFi: %s ..."
,
ssid
);
return
system
(
cmd
)
==
0
;
}
// 自动配网主逻辑
void
check_and_autoconfig_wifi
()
{
my_zlog_info
(
"开始检查网络连接状态..."
);
// 1. 检查并处理依赖
check_and_install_dependencies
();
// 2. 检查网络
if
(
has_internet_connection
())
{
my_zlog_info
(
"网络连接正常,正在检查音频资源..."
);
download_audio_files
();
return
;
}
my_zlog_warn
(
"无法连接互联网,进入扫码配网模式 (拍照方案)。"
);
my_zlog_info
(
"进入扫码循环,将每隔几秒提示一次..."
);
const
char
*
img_path
=
"/tmp/wifi_scan.jpg"
;
time_t
last_prompt_time
=
0
;
// 首次播放
// play_audio_file("toScanQRCode.mp3"); // 改为进入循环后由定时逻辑触发(且会先检查网络)
last_prompt_time
=
0
;
// 设为 0,确保进入循环第一次就会满足 difftime > 10.0 并触发播放逻辑
while
(
1
)
{
// 0. 优先检查网络是否已恢复 (比如插上了网线)
if
(
has_internet_connection
())
{
my_zlog_info
(
"检测到网络已恢复,退出扫码模式。"
);
// 补一声连接成功的提示,让用户知道好了
play_audio_file
(
"connectionSuccessful.mp3"
);
download_audio_files
();
break
;
}
// 1. 周期性播放提示音 (每 10 秒)
time_t
now
=
time
(
NULL
);
if
(
difftime
(
now
,
last_prompt_time
)
>=
10
.
0
)
{
// 再检查一次,如果有网就不播了,避免干扰
if
(
!
has_internet_connection
())
{
play_audio_file
(
"toScanQRCode.mp3"
);
}
last_prompt_time
=
now
;
}
// 2. 调用 fswebcam 拍照
// -r 640x480: 分辨率
// --no-banner: 不加时间戳条
// -S 2: 跳过前2帧(预热), 防止黑屏
// -q: 静默模式
char
cap_cmd
[
256
];
snprintf
(
cap_cmd
,
sizeof
(
cap_cmd
),
"fswebcam -r 1280x720 --no-banner -S 2 -q %s > /dev/null 2>&1"
,
img_path
);
int
cap_ret
=
system
(
cap_cmd
);
if
(
cap_ret
!=
0
)
{
// 拍照失败,通常意味着没插摄像头或设备忙
my_zlog_error
(
"摄像头拍照失败 (fswebcam 返回 %d),请检查设备连接。"
,
cap_ret
);
play_audio_file
(
"noCameraDetected.mp3"
);
sleep
(
10
);
// 失败后多睡一会儿
continue
;
}
// 3. 调用 zbarimg 识别图片
char
scan_cmd
[
256
];
snprintf
(
scan_cmd
,
sizeof
(
scan_cmd
),
"zbarimg --raw -q %s"
,
img_path
);
FILE
*
pipe
=
popen
(
scan_cmd
,
"r"
);
if
(
!
pipe
)
{
my_zlog_error
(
"无法执行 zbarimg!"
);
sleep
(
2
);
continue
;
}
char
buffer
[
1024
];
int
scan_success
=
0
;
// zbarimg 输出即为识别结果 (可能有多行,我们只读第一行有效的)
while
(
fgets
(
buffer
,
sizeof
(
buffer
),
pipe
)
!=
NULL
)
{
buffer
[
strcspn
(
buffer
,
"
\r\n
"
)]
=
0
;
if
(
strlen
(
buffer
)
==
0
)
continue
;
my_zlog_debug
(
"识别到内容: %s"
,
buffer
);
cJSON
*
json
=
cJSON_Parse
(
buffer
);
if
(
!
json
)
continue
;
cJSON
*
ssid_item
=
cJSON_GetObjectItemCaseSensitive
(
json
,
"s"
);
cJSON
*
pwd_item
=
cJSON_GetObjectItemCaseSensitive
(
json
,
"p"
);
if
(
cJSON_IsString
(
ssid_item
)
&&
ssid_item
->
valuestring
&&
cJSON_IsString
(
pwd_item
)
&&
pwd_item
->
valuestring
)
{
my_zlog_info
(
"解析成功,SSID: %s"
,
ssid_item
->
valuestring
);
play_audio_file
(
"scanSuccessful.mp3"
);
if
(
try_connect_wifi
(
ssid_item
->
valuestring
,
pwd_item
->
valuestring
))
{
my_zlog_info
(
"WiFi 连接成功!"
);
download_audio_files
();
play_audio_file
(
"connectionSuccessful.mp3"
);
cJSON_Delete
(
json
);
scan_success
=
1
;
break
;
}
else
{
my_zlog_warn
(
"WiFi 连接失败"
);
play_audio_file
(
"connectionFailed.mp3"
);
}
}
cJSON_Delete
(
json
);
}
pclose
(
pipe
);
if
(
scan_success
)
break
;
// 没扫到码,等待一小会儿再拍下一张,避免 CPU 占用过高
// 不需要 sleep 太久,因为 fswebcam 启动本身就有开销(约0.5-1s),这就已经是天然的延迟了
usleep
(
500000
);
// 0.5秒
}
// 清理临时文件
unlink
(
img_path
);
my_zlog_info
(
"配网流程结束。"
);
}
app/main/wifi_autoconfig.h
0 → 100644
View file @
96051595
#ifndef WIFI_AUTOCONFIG_H__
#define WIFI_AUTOCONFIG_H__
// 启动断网自动配网流程
void
check_and_autoconfig_wifi
();
// 播放指定名称的音频文件 (位于 ~/audio/ 目录下)
void
play_audio_file
(
const
char
*
filename
);
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment