JLKJ天线控制器升级软件,ETC2.0的。接口功能:通过URL和资源名下载。
1.选择使用libcurl实现业务功能。下载curl-8.13.0源码包进行编译,并使用libcurl.a和头文件。
~/zhoulu/curl-8.13.0$ ./configure --host=arm-none-linux-gnueabi --prefix ~/zhoulu/ --without-ssl --without-libpsl --without-zlib --disable-shared --enable-static
~/zhoulu/curl-8.13.0$make
~/zhoulu/curl-8.13.0$make install
2.使用百度AI写的接口代码,稍微修改了一下直接使用。代码如下:
#include <stdio.h>
#include <curl/curl.h>
// 写入数据的回调函数,将接收到的数据保存到文件
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
return fwrite(ptr, size, nmemb, stream);
}
int url_resource_get(char *resource_url, char *resource_name)
{
CURL *curl;
FILE *fp;
CURLcode res;
// 全局初始化libcurl
curl_global_init(CURL_GLOBAL_DEFAULT);
// 初始化CURL句柄
curl = curl_easy_init();
if (!curl) {
fprintf(stderr, "Error: Failed to initialize CURL.\n");
return 1;
}
// 以二进制写入模式打开文件
fp = fopen(resource_name, "wb");
if (!fp) {
fprintf(stderr, "Error: Failed to open file %s\n", resource_name);
curl_easy_cleanup(curl); // 清理CURL句柄
curl_global_cleanup(); // 全局清理
return 1;
}
// 设置CURL选项
curl_easy_setopt(curl, CURLOPT_URL, resource_url); // 设置URL
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); // 回调函数
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); // 文件指针
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // 跟随重定向
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); // 设置User-Agent
// 执行下载操作
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
fprintf(stderr, "Error: %s\n", curl_easy_strerror(res));
}
// 清理资源
fclose(fp);
curl_easy_cleanup(curl);
curl_global_cleanup();
return 0;
}
3.使用之前百度AI写的多线程的main.c,来调用功能接口进行测试。代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>
#include <signal.h>
#define NUM_THREADS 1
extern int url_resource_get(char *resource_url, char *resource_name);
bool g_program_stop_flag = false;
// 统一的线程函数
void* thread_function(void* arg)
{
int thread_num = *(int*)arg; // 获取线程编号
while (1)
{
switch (thread_num)
{
case 1:
url_resource_get("http://192.168.8.2:8000/Makefile", "Makefile");
sleep(3);
break;
default:
break;
}
if (g_program_stop_flag)
break;
}
return NULL;
}
static void signal_handler(int sig)
{
const char *sig_name;
switch (sig) {
case SIGINT: sig_name = "SIGINT"; break;
case SIGTERM: sig_name = "SIGTERM"; break;
case SIGQUIT: sig_name = "SIGQUIT"; break;
case SIGSEGV: sig_name = "SIGSEGV"; break;
case SIGFPE: sig_name = "SIGFPE"; break;
default: sig_name = "Unknown"; break;
}
// 输出信息(注意:此处用stdio函数不安全,仅用于演示)
fprintf(stderr, "\nCaught signal: %s (%d)\n", sig_name, sig);
// 针对不同信号的逻辑
switch (sig) {
case SIGSEGV:
// 段错误:记录信息并终止(无法安全恢复)
fprintf(stderr, "Segmentation fault! Exiting...\n");
break;
case SIGFPE:
// 浮点异常:记录信息并终止
fprintf(stderr, "Arithmetic error! Exiting...\n");
break;
default:
// SIGINT/SIGTERM/SIGQUIT:标记退出循环
fprintf(stderr, "Graceful shutdown...\n");
g_program_stop_flag = true;
break;
}
// 注意:SIGSEGV/SIGFPE处理后应直接终止,避免未定义行为
if (sig == SIGSEGV || sig == SIGFPE) {
signal(sig, SIG_DFL); // 恢复默认行为
raise(sig); // 重新触发信号以生成核心转储(如果需要)
}
}
static void setup_signal_handlers()
{
struct sigaction sa;
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART; // 自动重启被中断的系统调用
// 注册需要处理的信号
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
signal(SIGPIPE,SIG_IGN);
}
int main(int argc, char *argv[])
{
int i;
pthread_t threads[NUM_THREADS];
int thread_nums[NUM_THREADS]; // 存储线程编号
setup_signal_handlers();
// 逐个创建线程
for (i = 0; i < NUM_THREADS; i++)
{
thread_nums[i] = i + 1; // 线程编号从1开始
int rc = pthread_create(&threads[i], NULL, thread_function, &thread_nums[i]);
if (rc) {
fprintf(stderr, "Error creating thread %d: %d\n", i+1, rc);
exit(EXIT_FAILURE);
}
fprintf(stdout, "jl_v2x_app_obu start task Thread-%d (ID: %lu) \n", i+1, threads[i]);
}
// 逐个等待线程
for (i = 0; i < NUM_THREADS; i++)
{
pthread_join(threads[i], NULL);
fprintf(stdout, "jl_v2x_app_obu task Thread-%d (ID: %lu) stop\n", thread_nums[i], threads[i]);
}
fprintf(stdout, "jl_v2x_app_obu Graceful shutdown\n");
return 0;
}
4.编译生成可执行程序。
~/zhoulu$ arm-linux-gcc appv_main.c appv_url_get.c -o appv_main -I./include -L./lib -lcurl -lpthread -lrt
5.搭建测试使用的http服务端。
在Windows11系统中安装python,直接使用python内置的简单http服务器功能。建立了http服务目录python_http_server并启动http服务。放置了资源文件Makefile到目录中。
PS C:\Users\liudo\python_http_server> python.exe -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...
6.在JLKJ天线控制器上运行程序进行接口功能测试。截图如下: