FluxDC/components/FluxSD/FluxSD.c

349 lines
9.8 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file FluxSD.c
* @brief SD卡源文件
*
* 用于存储测试日志
*
* @author wang xiang en
* @date 2025-04-18
* @version 版本号
* @copyright 版权声明((C)2025, YUWELL MEDTECH Co.ltd
*/
#include "FluxSD.h"
/* 用于信息存储的SD卡结构体 */
struct SD_Data sdData;
/* SD卡配置 */
const static char *SD_TAG = "SD_TEST";
const char* names[] = {"CLK", "CMD", "D0", "D1", "D2", "D3"};
const int pins[] = {CONFIG_EXAMPLE_PIN_CLK,
CONFIG_EXAMPLE_PIN_CMD,
CONFIG_EXAMPLE_PIN_D0,
CONFIG_EXAMPLE_PIN_D1,
CONFIG_EXAMPLE_PIN_D2,
CONFIG_EXAMPLE_PIN_D3
};
const int pin_count = sizeof(pins)/sizeof(pins[0]);
pin_configuration_t config = {
.names = names,
.pins = pins,
};
/**
* @brief 等待SD引脚状态改变
*
* SD卡引脚检测子函数
*
* @param[in] i 序号值
* @param[in] level 检测的电平
* @param[in] timeout 超时时间
* @return 返回值说明
*/
static uint32_t get_cycles_until_pin_level(int i, int level, int timeout) {
uint32_t start = esp_cpu_get_cycle_count();
while(gpio_get_level(i) == !level && esp_cpu_get_cycle_count() - start < timeout) {
;
}
uint32_t end = esp_cpu_get_cycle_count();
return end - start;
}
/**
* @brief SD卡引脚检测
*
* 测试SD卡引脚驱动能力及配置情况
*
* @param[in] config 配置情况
* @param[in] pin_count 引脚数目
*/
static void check_sd_card_pins(pin_configuration_t *config, const int pin_count)
{
ESP_LOGI(SD_TAG, "Testing SD pin connections and pullup strength");
gpio_config_t io_conf = {};
for (int i = 0; i < pin_count; ++i) {
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD;
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL(config->pins[i]);
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config(&io_conf);
}
printf("\n**** PIN recovery time ****\n\n");
for (int i = 0; i < pin_count; ++i) {
gpio_set_direction(config->pins[i], GPIO_MODE_INPUT_OUTPUT_OD);
gpio_set_level(config->pins[i], 0);
usleep(100);
gpio_set_level(config->pins[i], 1);
uint32_t cycles = get_cycles_until_pin_level(config->pins[i], 1, 10000);
printf("PIN %2d %3s %"PRIu32" cycles\n", config->pins[i], config->names[i], cycles);
}
printf("\n**** PIN recovery time with weak pullup ****\n\n");
for (int i = 0; i < pin_count; ++i) {
gpio_set_direction(config->pins[i], GPIO_MODE_INPUT_OUTPUT_OD);
gpio_pullup_en(config->pins[i]);
gpio_set_level(config->pins[i], 0);
usleep(100);
gpio_set_level(config->pins[i], 1);
uint32_t cycles = get_cycles_until_pin_level(config->pins[i], 1, 10000);
printf("PIN %2d %3s %"PRIu32" cycles\n", config->pins[i], config->names[i], cycles);
gpio_pullup_dis(config->pins[i]);
}
}
/**
* @brief SD卡写测试
*
* 向特定路径写入一段字符串
*
* @param[in] path 需要写入的路径
* @param[in] data 要写入的数据
*/
static esp_err_t s_example_write_file(const char *path, char *data)
{
ESP_LOGI(SD_TAG, "Opening file %s", path);
FILE *f = fopen(path, "a");
if (f == NULL) {
ESP_LOGE(SD_TAG, "Failed to open file for writing");
return ESP_FAIL;
}
fprintf(f, data);
fclose(f);
ESP_LOGI(SD_TAG, "File written");
return ESP_OK;
}
/**
* @brief 向SD卡中写入日志
*
* 向已定路径写入一段字符串
*
* @param[in] data 要写入的数据
*/
esp_err_t example_write_log(char *data)
{
ESP_LOGI(SD_TAG, "Opening file %s", sdData.log_file_dir);
FILE *f = fopen(sdData.log_file_dir, "a+");
if (f == NULL) {
ESP_LOGE(SD_TAG, "Failed to open file for writing");
return ESP_FAIL;
}
fprintf(f, "%s - %s\n",sdData.strftime_buf,data);
fclose(f);
ESP_LOGI(SD_TAG, "File written to log file %s",sdData.log_file_dir);
return ESP_OK;
}
/**
* @brief SD卡读测试
*
* 读取一段字符串
*
* @param[in] path 读取的文件所在的路径
*/
static esp_err_t s_example_read_file(const char *path)
{
ESP_LOGI(SD_TAG, "Reading file %s", path);
/* 创建文件控制句柄 */
FILE *f = fopen(path, "r");
if (f == NULL) {
ESP_LOGE(SD_TAG, "Failed to open file for reading");
return ESP_FAIL;
}
char line[EXAMPLE_MAX_CHAR_SIZE];
fgets(line, sizeof(line), f);//整行读取
//fread(line, sizeof(line), f);
fclose(f);
// strip newline
char *pos = strchr(line, '\n');
if (pos) {
*pos = '\0';
}
ESP_LOGI(SD_TAG, "Read from file: '%s'", line);
return ESP_OK;
}
/**
* @brief SD卡初始化
*
* 初始化SD读写总线将文件系统挂载到固定挂载点。
*
*/
void flux_sd_init(void)
{
esp_err_t ret;
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
/* 初始化SD卡 */
sdmmc_card_t *card;
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(SD_TAG, "Initializing SD card");
ESP_LOGI(SD_TAG, "Using SDMMC peripheral");
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
slot_config.width = 4;
slot_config.clk = CONFIG_EXAMPLE_PIN_CLK;
slot_config.cmd = CONFIG_EXAMPLE_PIN_CMD;
slot_config.d0 = CONFIG_EXAMPLE_PIN_D0;
slot_config.d1 = CONFIG_EXAMPLE_PIN_D1;
slot_config.d2 = CONFIG_EXAMPLE_PIN_D2;
slot_config.d3 = CONFIG_EXAMPLE_PIN_D3;
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
ESP_LOGI(SD_TAG, "Mounting filesystem");
ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(SD_TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} else {
ESP_LOGE(SD_TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
check_sd_card_pins(&config, pin_count);
}
return;
}
ESP_LOGI(SD_TAG, "Filesystem mounted");
/* 打印SD卡信息 */
sdmmc_card_print_info(stdout, card);
#ifdef CONFIG_WRITE_TEST
/* File write test example */
const char *file_hello = MOUNT_POINT"/hello.txt";
char data[EXAMPLE_MAX_CHAR_SIZE];
snprintf(data, EXAMPLE_MAX_CHAR_SIZE, "%s %s!\n", "Hello how are you", card->cid.name);
ret = s_example_write_file(file_hello, data);
if (ret != ESP_OK) {
return;
}
#endif
}
/**
* @brief 获取文件索引
*
* 1.每次开机后重置当前文件索引值
* 以该索引值新建日志文件、测试结果输出文件
*
* 2.当用于存储索引的文件不存在时进行自动新建索引文件
*/
esp_err_t sd_current_fileIndex_get(void)
{
/* 读取当前文件索引值 */
ESP_LOGI(SD_TAG, "Opening file %s", INDEX_FILE_NAME);
/* 判断文件是否存在 */
if (access(INDEX_FILE_NAME, F_OK) == -1)
{
/*当文件不存在时创建文件*/
FILE *new_f = fopen(INDEX_FILE_NAME, "w");
fprintf(new_f, "0");
fclose(new_f);
sdData.file_index = 0;
ESP_LOGI(SD_TAG, "File not found, creating new file");
}else{
/* 当文件存在时直接获取当前索引值 */
FILE *f = fopen(INDEX_FILE_NAME, "r");
if (f == NULL) {
ESP_LOGE(SD_TAG, "Failed to open file for reading");
return ESP_FAIL;
}
char line[EXAMPLE_MAX_CHAR_SIZE];
fgets(line, sizeof(line), f);
fclose(f);
sdData.file_index = atoi(line);
ESP_LOGI(SD_TAG, "Read from file: '%s' , current Index = %d", line,sdData.file_index);
}
/* 重置索引值 */
FILE *new_index_f = fopen(INDEX_FILE_NAME, "w");
if (new_index_f == NULL)
{
return ESP_FAIL;
}
fprintf(new_index_f, "%d", sdData.file_index+1);
fclose(new_index_f);
return ESP_OK;
}
/**
* @brief 向SD卡中写入测试结果
*
* 1.文件头为 时间戳、设备类型、挡位、频率、流量体积
* 2.向总的测试结果文件写入测试结果
*/
esp_err_t sd_testData_write(void)
{
/* 打开当前测试文件 */
FILE *current_test_f = fopen(sdData.test_file_dir, "a+");
if (current_test_f == NULL)
{
ESP_LOGE(SD_TAG, "Failed to open file for writing");
return ESP_FAIL;
}
fprintf(current_test_f,"%lld,%s,%d,%d,%ld,%.3f\n",\
sdData.current_time,\
sdData.strftime_buf,\
sdData.flux_test_result.current_device_type,\
sdData.flux_test_result.current_stage,\
sdData.flux_test_result.current_rate,\
sdData.flux_test_result.current_test_result
);
fclose(current_test_f);
/* 打开总的测试结果文件 */
FILE *total_test_f = fopen(TEST_FILE_NAME, "a+");
if (total_test_f == NULL)
{
ESP_LOGE(SD_TAG, "Failed to open file for writing");
return ESP_FAIL;
}
fprintf(total_test_f,"%lld,%s,%d,%d,%ld,%.3f\n",\
sdData.current_time,\
sdData.strftime_buf,\
sdData.flux_test_result.current_device_type,\
sdData.flux_test_result.current_stage,\
sdData.flux_test_result.current_rate,\
sdData.flux_test_result.current_test_result
);
fclose(total_test_f);
return ESP_OK;
}