260 lines
7.2 KiB
C
260 lines
7.2 KiB
C
#include <stdio.h>
|
||
#include <stdint.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
|
||
// 操作系统相关头文件
|
||
#ifdef _WIN32
|
||
#include <windows.h>
|
||
#define PATH_SEPARATOR '\\'
|
||
#else
|
||
#include <unistd.h>
|
||
#include <locale.h>
|
||
#define PATH_SEPARATOR '/'
|
||
#endif
|
||
|
||
|
||
#define BUFFER_SIZE 1024
|
||
|
||
// 平台无关的结构体定义
|
||
#pragma pack(1)
|
||
// MPU传感器数据结构
|
||
typedef struct {
|
||
int16_t ax; // 加速度计 X轴
|
||
int16_t ay; // 加速度计 Y轴
|
||
int16_t az; // 加速度计 Z轴
|
||
int16_t gx; // 陀螺仪 X轴
|
||
int16_t gy; // 陀螺仪 Y轴
|
||
int16_t gz; // 陀螺仪 Z轴
|
||
} sensor_data_t;
|
||
|
||
// 完整的数据记录结构
|
||
typedef struct {
|
||
uint8_t y; // 年(相对值,需要加上2000)
|
||
uint8_t month; // 月
|
||
uint8_t d; // 日
|
||
uint8_t h; // 时
|
||
uint8_t m; // 分
|
||
uint8_t s; // 秒
|
||
uint16_t ms; // 毫秒
|
||
int16_t deepth; // 深度
|
||
sensor_data_t data; // MPU传感器数据
|
||
} info_t;
|
||
#pragma pack()
|
||
|
||
// 平台相关的函数封装
|
||
void platform_init(void) {
|
||
#ifdef _WIN32
|
||
// Windows: 设置控制台代码页为UTF-8
|
||
SetConsoleOutputCP(65001);
|
||
#else
|
||
// Linux: 设置locale为UTF-8
|
||
setlocale(LC_ALL, "en_US.UTF-8");
|
||
#endif
|
||
}
|
||
|
||
// 生成输出文件名
|
||
char* generate_output_filename(const char* input_file) {
|
||
size_t len = strlen(input_file);
|
||
char* output = (char*)malloc(len + 5); // +5 for ".csv\0"
|
||
if (!output) return NULL;
|
||
|
||
strcpy(output, input_file);
|
||
|
||
// 找到最后一个点的位置
|
||
char* dot = strrchr(output, '.');
|
||
if (dot != NULL) {
|
||
strcpy(dot, ".csv");
|
||
} else {
|
||
strcat(output, ".csv");
|
||
}
|
||
|
||
return output;
|
||
}
|
||
|
||
// 检测系统字节序
|
||
static uint8_t is_little_endian(void) {
|
||
uint16_t test = 0x0001;
|
||
return *(uint8_t *)&test;
|
||
}
|
||
|
||
// 字节序转换函数
|
||
static uint16_t swap_uint16(uint16_t val) {
|
||
return (val << 8) | (val >> 8);
|
||
}
|
||
|
||
static int16_t swap_int16(int16_t val) {
|
||
return (val << 8) | ((val >> 8) & 0xFF);
|
||
}
|
||
|
||
void decode(char *filename) {
|
||
uint8_t sys_is_le = is_little_endian();
|
||
|
||
#ifdef _WIN32
|
||
fprintf(stderr, "系统类型: Windows\n");
|
||
#else
|
||
fprintf(stderr, "系统类型: Linux\n");
|
||
#endif
|
||
fprintf(stderr, "系统字节序: %s\n", sys_is_le ? "小端序" : "大端序");
|
||
|
||
FILE *file = fopen(filename, "rb");
|
||
if (!file) {
|
||
fprintf(stderr, "无法打开文件: %s\n", filename);
|
||
return;
|
||
}
|
||
|
||
|
||
// 获取文件大小
|
||
fseek(file, 0, SEEK_END);
|
||
long fileSize = ftell(file);
|
||
fseek(file, 0, SEEK_SET);
|
||
|
||
// 计算记录数量
|
||
size_t recordCount = fileSize / sizeof(info_t);
|
||
|
||
// 打印CSV格式的表头
|
||
printf("年,月,日,时,分,秒,毫秒,深度,ax,ay,az,gx,gy,gz\n");
|
||
|
||
// 使用缓冲区读取以提高效率
|
||
info_t buffer[BUFFER_SIZE];
|
||
size_t records_read;
|
||
|
||
while ((records_read = fread(buffer, sizeof(info_t), BUFFER_SIZE, file)) > 0) {
|
||
for (size_t i = 0; i < records_read; i++) {
|
||
// 如果系统是大端序,需要转换所有16位数据
|
||
uint16_t ms = buffer[i].ms;
|
||
int16_t depth = buffer[i].deepth;
|
||
int16_t ax = buffer[i].data.ax;
|
||
int16_t ay = buffer[i].data.ay;
|
||
int16_t az = buffer[i].data.az;
|
||
int16_t gx = buffer[i].data.gx;
|
||
int16_t gy = buffer[i].data.gy;
|
||
int16_t gz = buffer[i].data.gz;
|
||
|
||
if (!sys_is_le) {
|
||
// 系统是大端序,需要转换
|
||
ms = swap_uint16(ms);
|
||
depth = swap_int16(depth);
|
||
ax = swap_int16(ax);
|
||
ay = swap_int16(ay);
|
||
az = swap_int16(az);
|
||
gx = swap_int16(gx);
|
||
gy = swap_int16(gy);
|
||
gz = swap_int16(gz);
|
||
}
|
||
|
||
printf("%04d,%02d,%02d,%02d,%02d,%02d,%03d,%04d,%d,%d,%d,%d,%d,%d\n",
|
||
buffer[i].y + 2000, // 单字节数据不需要转换
|
||
buffer[i].month,
|
||
buffer[i].d,
|
||
buffer[i].h,
|
||
buffer[i].m,
|
||
buffer[i].s,
|
||
ms, // 使用可能转换过的值
|
||
depth,
|
||
ax, ay, az,
|
||
gx, gy, gz
|
||
);
|
||
}
|
||
}
|
||
|
||
fclose(file);
|
||
|
||
fprintf(stderr, "共解析 %zu 条记录\n", recordCount);
|
||
}
|
||
|
||
void print_usage(const char* program_name) {
|
||
fprintf(stderr, "用法:\n");
|
||
#ifdef _WIN32
|
||
fprintf(stderr, "%s -f <文件名> [-o <输出文件名>]\n", program_name);
|
||
#else
|
||
fprintf(stderr, "./%s -f <文件名> [-o <输出文件名>]\n", program_name);
|
||
#endif
|
||
fprintf(stderr, "选项:\n");
|
||
fprintf(stderr, " -f <文件名> 指定输入文件\n");
|
||
fprintf(stderr, " -o <文件名> 指定输出文件(可选,默认输出到与输入同名的.csv文件)\n");
|
||
fprintf(stderr, " -h 显示帮助信息\n");
|
||
fprintf(stderr, "\n示例:\n");
|
||
#ifdef _WIN32
|
||
fprintf(stderr, "%s -f 20241112.BIN\n", program_name);
|
||
fprintf(stderr, "%s -f 20241112.BIN -o output.csv\n", program_name);
|
||
#else
|
||
fprintf(stderr, "./%s -f 20241112.BIN\n", program_name);
|
||
fprintf(stderr, "./%s -f 20241112.BIN -o output.csv\n", program_name);
|
||
#endif
|
||
}
|
||
|
||
int main(int argc, char *argv[]) {
|
||
// 平台初始化
|
||
platform_init();
|
||
|
||
char *input_file = NULL;
|
||
char *output_file = NULL;
|
||
|
||
// 解析命令行参数
|
||
for (int i = 1; i < argc; i++) {
|
||
if (strcmp(argv[i], "-h") == 0) {
|
||
print_usage(argv[0]);
|
||
return 0;
|
||
}
|
||
else if (strcmp(argv[i], "-f") == 0) {
|
||
if (i + 1 < argc) {
|
||
input_file = argv[i + 1];
|
||
i++;
|
||
} else {
|
||
fprintf(stderr, "错误:-f 参数后需要指定文件名\n");
|
||
print_usage(argv[0]);
|
||
return 1;
|
||
}
|
||
}
|
||
else if (strcmp(argv[i], "-o") == 0) {
|
||
if (i + 1 < argc) {
|
||
output_file = argv[i + 1];
|
||
i++;
|
||
} else {
|
||
fprintf(stderr, "错误:-o 参数后需要指定文件名\n");
|
||
print_usage(argv[0]);
|
||
return 1;
|
||
}
|
||
}
|
||
else {
|
||
fprintf(stderr, "错误:未知参数 %s\n", argv[i]);
|
||
print_usage(argv[0]);
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
// 检查必需参数
|
||
if (input_file == NULL) {
|
||
fprintf(stderr, "错误:未指定输入文件\n");
|
||
print_usage(argv[0]);
|
||
return 1;
|
||
}
|
||
|
||
// 如果没有指定输出文件,生成默认的输出文件名
|
||
char *auto_output_file = NULL;
|
||
if (output_file == NULL) {
|
||
auto_output_file = generate_output_filename(input_file);
|
||
output_file = auto_output_file;
|
||
}
|
||
|
||
// 重定向标准输出到文件
|
||
if (output_file != NULL) {
|
||
if (freopen(output_file, "w", stdout) == NULL) {
|
||
fprintf(stderr, "错误:无法创建输出文件 %s\n", output_file);
|
||
if (auto_output_file) free(auto_output_file);
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
// 解析文件
|
||
decode(input_file);
|
||
|
||
// 清理
|
||
if (auto_output_file) {
|
||
free(auto_output_file);
|
||
}
|
||
|
||
return 0;
|
||
}
|