/** * KFile read/write subtest. * Try to write/read in the same \a f file location \a size bytes. * \return true if all is ok, false otherwise * \note Restore file position at exit (if no error) * \note Test buffer \a buf must be filled with * the following statement: * \code * buf[i] = i & 0xff * \endcode */ static bool kfile_rwTest(KFile *f, uint8_t *buf, size_t size) { /* * Write test buffer */ if (kfile_write(f, buf, size) != size) { LOG_ERR("error writing buf"); return false; } kfile_seek(f, -(kfile_off_t)size, KSM_SEEK_CUR); /* * Reset test buffer */ memset(buf, 0, size); /* * Read file in test buffer */ if (kfile_read(f, buf, size) != size) { LOG_ERR("error reading buf"); return false; } kfile_seek(f, -(kfile_off_t)size, KSM_SEEK_CUR); /* * Check test result */ for (size_t i = 0; i < size; i++) { if (buf[i] != (i & 0xff)) { LOG_ERR("error comparing at index [%d] read [%02x] expected [%02x]\n", i, buf[i], i); return false; } } return true; }
/** * Reopen file \a fd. * This is a generic implementation that only flush file * and reset seek_pos to 0. */ struct KFile * kfile_genericReopen(struct KFile *fd) { kfile_flush(fd); kfile_seek(fd, 0, KSM_SEEK_SET); return fd; }
/** * KFile read/write test. * This function write and read \a test_buf long \a size * on \a fd handler. * \a save_buf can be NULL or a buffer where to save previous file content. */ int kfile_testRunGeneric(KFile *fd, uint8_t *test_buf, uint8_t *save_buf, size_t size) { /* * Part of test buf size that you would write. * This var is used in test 3 to check kfile_write * when writing beyond filesize limit. */ kfile_off_t len = size / 2; /* Fill test buffer */ for (size_t i = 0; i < size; i++) test_buf[i] = (i & 0xff); /* * If necessary, user can save content, * for later restore. */ if (save_buf) { LOG_INFO("Saved content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + size); kfile_read(fd, save_buf, size); } /* TEST 1 BEGIN. */ LOG_INFO("Test 1: write from pos 0 to [%ld]\n", (long)size); /* * Seek to addr 0. */ if (kfile_seek(fd, 0, KSM_SEEK_SET) != 0) goto kfile_test_end; /* * Test read/write to address 0..size */ if (!kfile_rwTest(fd, test_buf, size)) goto kfile_test_end; LOG_INFO("Test 1: ok!\n"); /* * Restore previous read content. */ if (save_buf) { kfile_seek(fd, 0, KSM_SEEK_SET); if (kfile_write(fd, save_buf, size) != size) goto kfile_test_end; LOG_INFO("Restore content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + size); } /* TEST 1 END. */ /* TEST 2 BEGIN. */ LOG_INFO("Test 2: write from pos [%ld] to [%ld]\n", fd->size/2 , fd->size/2 + size); /* * Go to half test size. */ kfile_seek(fd, (fd->size / 2), KSM_SEEK_SET); /* * If necessary, user can save content * for later restore. */ if (save_buf) { kfile_read(fd, save_buf, size); kfile_seek(fd, -(kfile_off_t)size, KSM_SEEK_CUR); LOG_INFO("Saved content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + size); } /* * Test read/write to address filesize/2 ... filesize/2 + size */ if (!kfile_rwTest(fd, test_buf, size)) goto kfile_test_end; LOG_INFO("Test 2: ok!\n"); /* * Restore previous content. */ if (save_buf) { kfile_seek(fd, -(kfile_off_t)size, KSM_SEEK_CUR); if (kfile_write(fd, save_buf, size) != size) goto kfile_test_end; LOG_INFO("Restore content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + size); } /* TEST 2 END. */ /* TEST 3 BEGIN. */ LOG_INFO("Test 3: write outside of fd->size limit [%ld]\n", fd->size); /* * Go to the Flash end */ kfile_seek(fd, -len, KSM_SEEK_END); /* * If necessary, user can save content, * for later restore. */ if (save_buf) { kfile_read(fd, save_buf, len); kfile_seek(fd, -len, KSM_SEEK_CUR); LOG_INFO("Saved content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + len); } /* * Test read/write to address (filesize - size) ... filesize */ if (kfile_rwTest(fd, test_buf, size)) goto kfile_test_end; kprintf("Test 3: ok!\n"); /* * Restore previous read content */ if (save_buf) { kfile_seek(fd, -len, KSM_SEEK_END); if ((kfile_off_t)kfile_write(fd, save_buf, len) != len) goto kfile_test_end; LOG_INFO("Restore content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + len); } /* TEST 3 END. */ kfile_close(fd); return 0; kfile_test_end: kfile_close(fd); LOG_ERR("One kfile_test failed!\n"); return EOF; }
int main(void) { // SD fat filesystem context FATFS fs; // Context files that we would manage FatFile ini_file; FatFile log_file; init(); LOG_INFO("SD fat example project %s: %d times\n", VERS_HOST, VERS_BUILD); while (1) { bool sd_ok = true; FRESULT result; // Setting info INISetting ini_set; memset(&ini_set, 0, sizeof(ini_set)); sd_ok = sd_init(&spi_dma.fd); if (sd_ok) { LOG_INFO("Mount FAT filesystem.\n"); if ((result = f_mount(0, &fs)) != FR_OK) { LOG_ERR("Mounting FAT volumes error[%d]\n", result); sd_ok = false; } LOG_INFO("Read setting from ini file: %s\n", INI_FILE_NAME); if (sd_ok && ((result = fatfile_open(&ini_file, INI_FILE_NAME, FA_READ)) != FR_OK)) { LOG_ERR("Could not open ini file: %s error[%d,]\n", INI_FILE_NAME, result); sd_ok = false; } if (sd_ok) { /* * If sd is ok, we read all setting from INI file. * NOTE: if one ini key or section was not found into INI * file, the iniparser return the defaul value. */ ini_getString(&ini_file.fd, LOG_SECTION, LOG_NAME_KEY, "default.log", ini_set.name, sizeof(ini_set.name)); LOG_INFO("Log file name [%s]\n", ini_set.name); char tmp[25]; ini_getString(&ini_file.fd, LOG_SECTION, LOG_ON_SERIAL, "1", tmp, sizeof(tmp)); ini_set.log_on_serial = atoi(tmp); LOG_INFO("Log serial [%d]\n", ini_set.log_on_serial); ini_getString(&ini_file.fd, LOG_SECTION, LOG_ON_FILE, "1", tmp, sizeof(tmp)); ini_set.log_on_file = atoi(tmp); LOG_INFO("Log sd [%d]\n", ini_set.log_on_file); ini_getString(&ini_file.fd, LOG_SECTION, LOG_SAMPLE_TIME, "500", tmp, sizeof(tmp)); ini_set.sample_time = atoi(tmp); LOG_INFO("Sample time [%ld]\n", ini_set.sample_time); ini_getString(&ini_file.fd, SERIAL_LOG, SERIAL_PORT, "0", tmp, sizeof(tmp)); ini_set.port = atoi(tmp); LOG_INFO("Serial port [%d]\n", ini_set.port); ini_getString(&ini_file.fd, SERIAL_LOG, SERIAL_BAUD, "115200", tmp, sizeof(tmp)); ini_set.baud = atoi(tmp); LOG_INFO("Serial buad [%d]\n", ini_set.baud); ini_getString(&ini_file.fd, LOG_FORMAT_SEC, FORMAT_LINE_HEADER, "BeRTOS: ", ini_set.line_header, sizeof(ini_set.line_header)); LOG_INFO("Serial line header[%s]\n", ini_set.line_header); ini_getString(&ini_file.fd, LOG_FORMAT_SEC, FORMAT_FIELD_SEP, ",", ini_set.field_sep, sizeof(ini_set.field_sep)); LOG_INFO("Serial char sep[%s]\n", ini_set.field_sep); ini_getString(&ini_file.fd, TEMPERATURE, TEMP_UNIT_LABEL, "C", ini_set.temp_unit_label, sizeof(ini_set.temp_unit_label)); LOG_INFO("Temp unit label[%s]\n", ini_set.temp_unit_label); ini_getString(&ini_file.fd, PRESSURE, PRESS_UNIT_LABEL, "hPa", ini_set.press_unit_label, sizeof(ini_set.press_unit_label)); LOG_INFO("Press unit label[%s]\n", ini_set.press_unit_label); ini_getString(&ini_file.fd, VOLTAGE, VOLTAGE_UNIT_LABEL, "V", ini_set.voltage_unit_label, sizeof(ini_set.voltage_unit_label)); LOG_INFO("Press unit label[%s]\n", ini_set.voltage_unit_label); } } if (ini_set.log_on_serial) { // Init serial log port ser_init(&log_port, ini_set.port); ser_setbaudrate(&log_port, ini_set.baud); LOG_INFO("SERIAL init..port[%d] buad[%d]\n", ini_set.port, ini_set.baud); } char log_string[160]; memset(log_string, 0, sizeof(log_string)); // Supplay voltage uint16_t vdd = ADC_RANGECONV(adc_read(SUPPLAY_VOLTAGE_CH), 0, ADC_SUPPLAY_VOLTAGE); // Read temperature int16_t tmp = tmp123_read(&temp_sensor_bus.fd); // Read pressure uint16_t vout = ADC_RANGECONV(adc_read(PRESSURE_SENSOR_CH), 0, vdd); int16_t press = mpxx6115a_press(vout, vdd); /* * Format string whit read data * line_header + temp + temp_unit_label + field_sep + press + press_unit_label + field_sep + vdd + voltage_unit_label */ int wr_len = sprintf(log_string, "%s%d.%01d%s%s%d%s%s%d.%d%s\r\n", ini_set.line_header, tmp / 10, ABS(tmp % 10), ini_set.temp_unit_label, ini_set.field_sep, press, ini_set.press_unit_label, ini_set.field_sep, vdd / 1000, ABS(vdd % 1000), ini_set.voltage_unit_label); /* * if SD is ok, try to open log file and write our data and, only * if by configuration we have enable the log on file */ if (sd_ok && ini_set.log_on_file) { // Open log file and do not overwrite the previous log file result = fatfile_open(&log_file, ini_set.name, FA_OPEN_EXISTING | FA_WRITE); // If the log file there isn't we create the new one if (result == FR_NO_FILE) { result = fatfile_open(&log_file, ini_set.name, FA_CREATE_NEW | FA_WRITE); LOG_INFO("Create the log file: %s\n", ini_set.name); } if ( result == FR_OK) { LOG_INFO("Opened log file '%s' size %ld\n", ini_set.name, log_file.fat_file.fsize); // To append data we should go to end of file before to start to write kfile_seek(&log_file.fd, 0, KSM_SEEK_END); int len = kfile_write(&log_file.fd, log_string, wr_len); // Flush data and close the files. kfile_flush(&log_file.fd); kfile_close(&log_file.fd); // Unmount always to prevent accidental sd remove. f_mount(0, NULL); LOG_INFO("Wrote [%d]\n", len); } else { LOG_ERR("Unable to open file: '%s' error[%d]\n", ini_set.name, result); } } // If by configuration we have enable the log on serial, we log it if (ini_set.log_on_serial) kfile_write(&log_port.fd, log_string, wr_len); timer_delay(ini_set.sample_time); } return 0; }