#include "log.h" #include "rtc.h" #include "ringfs.h" #include "spi_flash.h" #include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include "rtc.h" #include "settings_api.h" #include #include #include #undef DBG #define DBG if(1) static bool archive_state = false; static bool log_state = true; static bool log_init_f = false; static bool archive_init_f = false; struct ringfs fs_log; struct ringfs fs_archive; SemaphoreHandle_t log_mutex; xQueueHandle log_queue; uint16_t log_entries_capacity; uint16_t archive_entries_capacity; void archive_task(void *params); void log_task(void *params); // static int op_sector_erase(struct ringfs_flash_partition *flash, int address) { (void)flash; int ret; ret = spi_flash_erase_sector(address, 0); return ret; } // static ssize_t op_program(struct ringfs_flash_partition *flash, int address, const void *data, size_t size) { (void)flash; int ret; ret = spi_flash_write(address, data, size, 0); return ret; } // static ssize_t op_read(struct ringfs_flash_partition *flash, int address, void *data, size_t size) { (void)flash; int ret; ret = spi_flash_read(address, data, size, 0); return ret; } // static struct ringfs_flash_partition ringfs_flash_log = { .sector_offset = LOG_FLASH_SECTOR_OFFSET, .sector_erase = op_sector_erase, .program = op_program, .read = op_read, }; // static struct ringfs_flash_partition ringfs_flash_archive = { .sector_offset = ARCHIVE_FLASH_SECTOR_OFFSET, .sector_erase = op_sector_erase, .program = op_program, .read = op_read, }; // void log_init(bool format) { DBG printf("[LOG] Init...\r\n"); if (!spi_flash_desc.present) return; // ---------------------------------------------------------------------- // // Журнал ringfs_flash_log.sector_size = spi_flash_desc.sector_size; ringfs_flash_log.sector_count = LOG_FLASH_SECTOR_COUNT; ringfs_init(&fs_log, &ringfs_flash_log, LOG_ENTRY_VERSION, sizeof(log_entry_t)); if (format || ringfs_scan(&fs_log) != 0) { DBG printf("FAT1 false\r\n"); ringfs_format(&fs_log); } DBG printf("FAT1 true\r\n"); // ---------------------------------------------------------------------- // // Архив ringfs_flash_archive.sector_size = spi_flash_desc.sector_size; ringfs_flash_archive.sector_count = ARCHIVE_FLASH_SECTOR_COUNT; ringfs_init(&fs_archive, &ringfs_flash_archive, ARCHIV_ENTRY_VERSION, sizeof(archive_entry_t)); if (format || ringfs_scan(&fs_archive) != 0) { DBG printf("FAT2 false\r\n"); ringfs_format(&fs_archive); } DBG printf("FAT2 true\r\n"); log_mutex = xSemaphoreCreateMutex(); log_entries_capacity = ringfs_capacity(&fs_log); archive_entries_capacity = ringfs_capacity(&fs_archive); xTaskCreate(archive_task, "archive_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL); log_queue = xQueueCreate(10, sizeof(log_entry_t)); xTaskCreate(log_task, "log_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL); log_init_f = true; archive_init_f = true; } // int log_fetch(void *entry, entry_type_t entry_type, uint32_t timeout) { int ret; ret = xSemaphoreTake(log_mutex, (TickType_t)timeout); if (ret == pdFALSE) return ret; if (entry_type == LOG_ENTRY) ret = ringfs_fetch(&fs_log, entry); else if (entry_type == ARCHIVE_ENTRY) ret = ringfs_fetch(&fs_archive, entry); else ret = -1; xSemaphoreGive(log_mutex); return ret; } // int log_discard(void *entry, entry_type_t entry_type, uint32_t timeout) { int ret; ret = xSemaphoreTake(log_mutex, (TickType_t)timeout); if (ret == pdFALSE) return ret; if (entry_type == LOG_ENTRY) ret = ringfs_discard(&fs_log); else if (entry_type == ARCHIVE_ENTRY) ret = ringfs_discard(&fs_archive); else ret = -1; xSemaphoreGive(log_mutex); return ret; } // int log_append(void *entry, entry_type_t entry_type) { int ret; TM_RTC_t time; common_entry_t *entry_ptr = entry; log_entry_t *log_etnry_ptr; archive_entry_t *archive_etnry_ptr; ret = xSemaphoreTake(log_mutex, portMAX_DELAY); if (ret == pdFALSE) return ret; if (entry_ptr->timestamp == 0) entry_ptr->timestamp = rtc_get_ms(); if (entry_type == LOG_ENTRY) { log_etnry_ptr = (log_entry_t*)entry; log_etnry_ptr->crc = crc_8(entry, sizeof(log_entry_t) - 1); ret = ringfs_append(&fs_log, entry); } else if (entry_type == ARCHIVE_ENTRY) { archive_etnry_ptr = (archive_entry_t*)entry; archive_etnry_ptr->crc = crc_8(entry, sizeof(archive_entry_t) - 1); ret = ringfs_append(&fs_archive, entry); } else ret = -1; xSemaphoreGive(log_mutex); return ret; } // uint16_t log_capacity(void) { //return ringfs_count_estimate(&fs_log); return ringfs_count_exact(&fs_log); } // uint16_t log_arch_capacity(void) { //return ringfs_count_estimate(&fs_archive); return ringfs_count_exact(&fs_archive); } // -------------------------------------------------------------------------- // // misc uint8_t crc_8(uint8_t *data, int length) { uint8_t crc = 0x00; uint8_t extract; uint8_t sum; for (int i = 0; i < length; i++) { extract = *data; for (uint8_t tmp = 8; tmp; tmp--) { sum = (crc ^ extract) & 0x01; crc >>= 1; if (sum) crc ^= 0x8C; extract >>= 1; } data++; } return crc; } // -------------------------------------------------------------------------- // // Tests // val - 0 - журнал // val - 1 - архив void log_info(uint8_t val) { if (val > 1) return; struct ringfs *fs = val == 0 ? &fs_log : &fs_archive; int capacity_flash = 0; int count_flash = 0; int count_estimate = 0; capacity_flash = ringfs_capacity(fs); count_flash = ringfs_count_exact(fs); count_estimate = ringfs_count_estimate(fs); if (val == 0) { DBG printf("Log partition capacity: %u\r\n", capacity_flash); DBG printf("Count log entry: %u\r\n", count_flash); DBG printf("Estimate count: %u\r\n", count_estimate); } else { DBG printf("Archive partition capacity: %u\r\n", capacity_flash); DBG printf("Count archive entry: %u\r\n", count_flash); DBG printf("Estimate count: %u\r\n", count_estimate); } } // val - 0 - журнал // val - 1 - архив void log_format(uint8_t val) { if (val == 0) { DBG printf("Formating log partition...\r\n"); ringfs_format(&fs_log); } else if (val == 1) { DBG printf("Formating archive partition...\r\n"); ringfs_format(&fs_archive); } } // Добавить n записей журнала int log_add_random_entry(uint8_t val, uint32_t cnt_entry) { int ret; log_entry_t log_entry = {0}; archive_entry_t archive_entry = {0}; static uint8_t log_index = 0; static uint32_t archive_index = 0; if (val == 0) { DBG printf("Appending %u archive entries\r\n", cnt_entry); for (uint32_t i = 0; i < cnt_entry; i++) { log_entry.code_type = log_index; log_entry.code_state = log_index; log_entry.channel_number = log_index; log_entry.value = (float)log_index++; ret = log_append((void*)&log_entry, LOG_ENTRY); } DBG printf("Result: %u\r\n", ret); } if (val == 1) { DBG printf("Appending %u archive entries\r\n", cnt_entry); for (uint32_t i = 0; i < cnt_entry; i++) { archive_entry.input_value = archive_index++; ret = log_append((void*)&archive_entry, ARCHIVE_ENTRY); } DBG printf("Result: %u\r\n", ret); } return ret; } // int log_add_entry(log_event_type_t type, log_event_state_t state, uint8_t channel_number, float value) { log_entry_t entry; if (!log_init_f) return -1; entry.timestamp = rtc_get_ms(); entry.code_type = (uint8_t)type; entry.code_state = (uint8_t)state; entry.channel_number = channel_number; entry.value = value; xQueueSend(log_queue, &entry, 0); return 0; } // void test_fetch(void) { archive_entry_t entry = {0}; log_fetch(&entry, ARCHIVE_ENTRY, portMAX_DELAY); //printf("\r\n%" PRId64 " [ms]\r\n", rtc_get_ms()); printf("[entry] timestamp = % " PRId64 ", value = %u, crc = %u\r\n", entry.timestamp, entry.input_value, entry.crc); } // void log_archive_state(bool state) { archive_state = state; } // void log_log_state(bool state) { log_state = state; } void archive_task(void *params) { int ret = 0; archive_entry_t entry = {0}; for (;;) { if ((!archive_state) || (!archive_init_f)) { vTaskDelay(1000); continue; } entry.timestamp = 0; entry.input_value = (uint8_t)input_state_bit; DBG printf("Append archive entry..."); ret = log_append((void*)&entry, ARCHIVE_ENTRY); if (ret != 0) { DBG printf("FAIL\r\n"); } else { DBG printf("OK\r\n"); } vTaskDelay(settings.period_archive*1000); } } // void log_task(void *params) { int ret; log_entry_t entry; for (;;) { if (xQueueReceive(log_queue, &entry, portMAX_DELAY) == pdTRUE) { DBG printf("Try append LOG entry... "); ret = log_append((void*)&entry, LOG_ENTRY); DBG printf("Result: %i\r\n", ret); } } }