Initiate version
This commit is contained in:
parent
89d39daeb4
commit
6c5fc45750
197
decode.c
Normal file
197
decode.c
Normal file
@ -0,0 +1,197 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
// 定义缓冲区大小(可以根据实际需求调整)
|
||||
#define BUFFER_SIZE 1024 // 每次读取1024条记录
|
||||
|
||||
// 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;
|
||||
|
||||
// 完整的数据记录结构
|
||||
#pragma pack(1)
|
||||
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 print_usage() {
|
||||
printf("用法:\n");
|
||||
printf("decode.exe -f <文件名> [-o <输出文件名>]\n");
|
||||
printf("选项:\n");
|
||||
printf(" -f <文件名> 指定输入文件\n");
|
||||
printf(" -o <文件名> 指定输出文件(可选,默认输出到与输入同名的.csv文件)\n");
|
||||
printf(" -h 显示帮助信息\n");
|
||||
printf("\n示例:\n");
|
||||
printf("decode.exe -f 20241112.BIN\n");
|
||||
printf("decode.exe -f 20241112.BIN -o output.csv\n");
|
||||
}
|
||||
|
||||
// 原有的decode函数保持不变
|
||||
void decode(char *filename) {
|
||||
FILE *file = fopen(filename, "rb");
|
||||
if (!file) {
|
||||
fprintf(stderr, "无法打开文件\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取文件大小
|
||||
fseek(file, 0, SEEK_END);
|
||||
long fileSize = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
// 计算记录数量
|
||||
int 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++) {
|
||||
// 直接使用小端序数据,无需转换
|
||||
// 单字节数据:y, month, d, h, m, s
|
||||
// 双字节数据:ms, deepth, ax, ay, az, gx, gy, gz 已经是正确的小端序
|
||||
printf("%04d,%02d,%02d,%02d,%02d,%02d,%03d,%04d,%d,%d,%d,%d,%d,%d\n",
|
||||
buffer[i].y + 2000, // 年份偏移2000
|
||||
buffer[i].month, // 月
|
||||
buffer[i].d, // 日
|
||||
buffer[i].h, // 时
|
||||
buffer[i].m, // 分
|
||||
buffer[i].s, // 秒
|
||||
buffer[i].ms, // 毫秒,uint16_t
|
||||
buffer[i].deepth, // 深度,uint16_t
|
||||
buffer[i].data.ax, // 加速度计x,int16_t
|
||||
buffer[i].data.ay, // 加速度计y,int16_t
|
||||
buffer[i].data.az, // 加速度计z,int16_t
|
||||
buffer[i].data.gx, // 陀螺仪x,int16_t
|
||||
buffer[i].data.gy, // 陀螺仪y,int16_t
|
||||
buffer[i].data.gz // 陀螺仪z,int16_t
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
|
||||
fprintf(stderr, "共解析 %d 条记录\n", recordCount);
|
||||
}
|
||||
|
||||
// 生成输出文件名
|
||||
char* generate_output_filename(const char* input_file) {
|
||||
size_t len = strlen(input_file);
|
||||
char* output = (char*)malloc(len + 5); // +5 为了容纳 .csv 和结束符
|
||||
|
||||
// 复制输入文件名
|
||||
strcpy(output, input_file);
|
||||
|
||||
// 找到最后一个点的位置
|
||||
char* dot = strrchr(output, '.');
|
||||
if (dot != NULL) {
|
||||
// 如果找到点,在点的位置替换后缀
|
||||
strcpy(dot, ".csv");
|
||||
} else {
|
||||
// 如果没有找到点,直接在末尾添加.csv
|
||||
strcat(output, ".csv");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// 设置控制台输出代码页为 UTF-8
|
||||
SetConsoleOutputCP(65001);
|
||||
|
||||
char *input_file = NULL;
|
||||
char *output_file = NULL;
|
||||
|
||||
// 解析命令行参数
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0) {
|
||||
print_usage();
|
||||
return 0;
|
||||
}
|
||||
else if (strcmp(argv[i], "-f") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
input_file = argv[i + 1];
|
||||
i++;
|
||||
} else {
|
||||
printf("错误:-f 参数后需要指定文件名\n");
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "-o") == 0) {
|
||||
if (i + 1 < argc) {
|
||||
output_file = argv[i + 1];
|
||||
i++;
|
||||
} else {
|
||||
printf("错误:-o 参数后需要指定文件名\n");
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "错误:未知参数 %s\n", argv[i]);
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查必需参数
|
||||
if (input_file == NULL) {
|
||||
fprintf(stderr, "错误:未指定输入文件\n");
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 检查输入文件是否存在
|
||||
FILE *file = fopen(input_file, "rb");
|
||||
if (!file) {
|
||||
printf("错误:无法打开输入文件 %s\n", input_file);
|
||||
return 1;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
// 如果没有指定输出文件,生成默认的输出文件名
|
||||
char *auto_output_file = NULL;
|
||||
if (output_file == NULL) {
|
||||
auto_output_file = generate_output_filename(input_file);
|
||||
output_file = auto_output_file;
|
||||
}
|
||||
|
||||
// 重定向标准输出到文件
|
||||
if (freopen(output_file, "w", stdout) == NULL) {
|
||||
printf("错误:无法创建输出文件 %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;
|
||||
}
|
93
deepth.c
Normal file
93
deepth.c
Normal file
@ -0,0 +1,93 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h> // 包含 strtof()
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define START_CMD 'start()'
|
||||
#define STOP_CMD 'stop()'
|
||||
|
||||
/**
|
||||
压力
|
||||
接口协议: $P=XXX.XXX空格;<回车><换行>
|
||||
压力整数位部分固定三位,位数不够前面补零,小数部分固定三位;单位 dbar。
|
||||
负(-)号占一位,正(+)号不显示。
|
||||
例如:$P=005.000 ;
|
||||
$P=-01.000 ;
|
||||
注:压力小于 1000dbar,整数部分是 3 位,小数部分是 3 位;超过或等于 1000dabr,整数部分是 4 位,小数
|
||||
部分是 3 位。
|
||||
例如:$P=999.999;
|
||||
$P=1000.000
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* @brief 通过字符串获取压力值,单位dbar
|
||||
* 1dbar=1.02m
|
||||
* @param str 传入的字符串,例如"$P=6999.454 ;"
|
||||
* @return dbar数值对应的深度值,单位m
|
||||
* 成功返回深度值,失败返回INT16_MIN
|
||||
*/
|
||||
int16_t dbar2Deepth(char *str)
|
||||
{
|
||||
//char str[] = "$P=6999.454 ;";
|
||||
char *start, *end;
|
||||
float num;
|
||||
int8_t err;
|
||||
|
||||
// 查找等号后的字符位置
|
||||
start = strchr(str, '='); // 找到 '=' 的位置
|
||||
if (start != NULL)
|
||||
{
|
||||
start++; // 跳过 '='
|
||||
|
||||
// 使用 strtof() 函数从字符串中提取浮点数
|
||||
num = strtof(start, &end);
|
||||
|
||||
// 检查转换是否成功,并且确保后面是分号 ' '
|
||||
if (*end == ' ')
|
||||
{
|
||||
printf("提取的dbar数值: %f\n", num);
|
||||
err = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = 1;
|
||||
printf("转换失败,剩余未转换的字符: %s\n", end);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err = -1;
|
||||
printf("没有找到等号。\n");
|
||||
}
|
||||
|
||||
if (err == 0 || err == 1)
|
||||
{
|
||||
//1dbar=1.02m
|
||||
return (int16_t)(num * 1.02);
|
||||
}
|
||||
if (err == -1)
|
||||
{
|
||||
return INT16_MIN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取当前深度值
|
||||
* 通过 dbar2Deepth() 函数将字符串 "$P=6999.454 ;" 转换为
|
||||
* 压力值对应的深度值,单位m
|
||||
* @return 深度值,单位m
|
||||
*/
|
||||
int16_t getDeepth() {
|
||||
char str[] = "$P= 6999.454 ;";
|
||||
return dbar2Deepth(str);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// char str[] = "$P=-1999.454 ;";
|
||||
|
||||
|
||||
printf("当前深度:%d\n", getDeepth());
|
||||
}
|
109
demo/hamming.c
Normal file
109
demo/hamming.c
Normal file
@ -0,0 +1,109 @@
|
||||
#include "hamming.h"
|
||||
|
||||
/**
|
||||
* @brief 计算一个字节中1的个数
|
||||
* @param byte 输入字节
|
||||
* @return 返回字节中1的个数
|
||||
*/
|
||||
static inline int countOnes(unsigned char byte) {
|
||||
static const unsigned char ones[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
|
||||
return ones[byte & 0x0F] + ones[byte >> 4];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 计算汉明码的校验位
|
||||
* @param data 输入数据数组
|
||||
* @param size 数据大小
|
||||
* @param parity 输出的校验位数组(3字节)
|
||||
* @note 校验位计算包括:
|
||||
* - 对每个数据位进行异或运算生成校验位
|
||||
* - 最后一个校验字节的最高位用于总体奇偶校验
|
||||
*/
|
||||
void calculateParity(const unsigned char *data, int size, unsigned char *parity) {
|
||||
// 初始化校验位数组
|
||||
memset(parity, 0, PARITY_BYTES);
|
||||
int totalOnes = 0;
|
||||
|
||||
// 对每个数据字节
|
||||
for(int i = 0; i < size; i++) {
|
||||
unsigned char byte = data[i];
|
||||
totalOnes += countOnes(byte);
|
||||
|
||||
// 对字节中的每一位
|
||||
for(int j = 0; j < 8; j++) {
|
||||
if(byte & (1 << j)) {
|
||||
// 计算该位在整个数据中的位置
|
||||
int bitPos = i * 8 + j;
|
||||
|
||||
// 更新相应的校验位
|
||||
for(int k = 0; k < 20; k++) {
|
||||
if(bitPos & (1 << k)) {
|
||||
if(k < 8)
|
||||
parity[0] ^= (1 << k);
|
||||
else if(k < 16)
|
||||
parity[1] ^= (1 << (k - 8));
|
||||
else
|
||||
parity[2] ^= (1 << (k - 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加总体奇偶校验
|
||||
if(totalOnes % 2) {
|
||||
parity[2] |= 0x08; // 设置最高位
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检测并纠正数据中的错误
|
||||
* @param data 需要检查的数据
|
||||
* @param size 数据大小
|
||||
* @param parity 原始校验位
|
||||
* @return 返回检测结果:
|
||||
* 0 - 无错误
|
||||
* 1 - 检测到并纠正了单比特错误
|
||||
* -1 - 校验位错误
|
||||
* -2 - 检测到多位错误
|
||||
*/
|
||||
int detectAndCorrect(unsigned char *data, int size, const unsigned char *parity) {
|
||||
unsigned char currentParity[PARITY_BYTES];
|
||||
calculateParity(data, size, currentParity);
|
||||
// printf("parity: %02X %02X %02X\n", parity[2], parity[1], parity[0]);
|
||||
// printf("currentParity: %02X %02X %02X\n", currentParity[2], currentParity[1], currentParity[0]);
|
||||
|
||||
// 计算syndrome
|
||||
unsigned int syndrome = 0;
|
||||
syndrome |= (currentParity[0] ^ parity[0]);
|
||||
syndrome |= (currentParity[1] ^ parity[1]) << 8;
|
||||
syndrome |= ((currentParity[2] ^ parity[2]) & 0x07) << 16;
|
||||
|
||||
// 检查总体奇偶校验
|
||||
int parityError = ((currentParity[2] ^ parity[2]) & 0x08) ? 1 : 0;
|
||||
|
||||
if(syndrome == 0) {
|
||||
if(parityError) {
|
||||
return -2; // 检测到多位错误
|
||||
}
|
||||
return 0; // 无错误
|
||||
}
|
||||
|
||||
if(!parityError) {
|
||||
return -1; // 校验位错误(syndrome不为0但奇偶校验正确)
|
||||
}
|
||||
|
||||
// 单比特错误
|
||||
int bitPos = syndrome;
|
||||
int bytePos = bitPos / 8;
|
||||
int bitInByte = bitPos % 8;
|
||||
|
||||
if(bytePos < size) {
|
||||
data[bytePos] ^= (1 << bitInByte);
|
||||
// printf("纠正位置:字节 %d,位 %d\n", bytePos, bitInByte);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -2; // 检测到多位错误
|
||||
}
|
14
demo/hamming.h
Normal file
14
demo/hamming.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef HAMMING_H
|
||||
#define HAMMING_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define PARITY_BYTES 3 // 3字节校验位
|
||||
|
||||
// 函数声明
|
||||
void calculateParity(const unsigned char *data, int size, unsigned char *parity);
|
||||
int detectAndCorrect(unsigned char *data, int size, const unsigned char *parity);
|
||||
|
||||
#endif // HAMMING_H
|
64
demo/main.c
Normal file
64
demo/main.c
Normal file
@ -0,0 +1,64 @@
|
||||
#include "hamming.h"
|
||||
#define DATA_SIZE 10231
|
||||
|
||||
int mainn() {
|
||||
unsigned char data[DATA_SIZE], newData[DATA_SIZE];
|
||||
unsigned char parity[3] = {0};
|
||||
|
||||
// 初始化测试数据
|
||||
for(int i = 0; i < DATA_SIZE; i++) {
|
||||
data[i] = i & 0xff;
|
||||
newData[i] = data[i];
|
||||
}
|
||||
|
||||
// 计算校验位
|
||||
calculateParity(data, DATA_SIZE, parity);
|
||||
size_t k = 0;
|
||||
for (size_t i = 0; i < DATA_SIZE; i++)
|
||||
{
|
||||
|
||||
// 注入错误
|
||||
newData[i] ^= (1 << 7);
|
||||
|
||||
// 检测并纠正错误
|
||||
int result = detectAndCorrect(newData, DATA_SIZE, parity);
|
||||
|
||||
// 输出结果
|
||||
// printf("错误检测结果: ");
|
||||
switch(result) {
|
||||
case 0:
|
||||
printf("无错误\n");
|
||||
break;
|
||||
case 1:
|
||||
// printf("错误已纠正\n");
|
||||
k++;
|
||||
break;
|
||||
case -1:
|
||||
// printf("校验位错误\n");
|
||||
k=-1;
|
||||
break;
|
||||
case -2:
|
||||
printf("检测到多位错误\n");
|
||||
k=-1;
|
||||
break;
|
||||
}
|
||||
if (k == -1)
|
||||
{
|
||||
printf("数据恢复失败\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (memcmp(newData, data, DATA_SIZE) == 0) {
|
||||
// printf("恢复后数据与原始数据一致\n");
|
||||
} else {
|
||||
printf("恢复后数据与原始数据不一致\n");
|
||||
}
|
||||
if ( i == DATA_SIZE - 1)
|
||||
{
|
||||
printf("数据恢复完毕,k=%d\n",k);
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user