#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 #include #include #undef DBG #define DBG if(1) static struct ringfs fs_log; struct ringfs fs_archive; SemaphoreHandle_t log_mutex; // 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 = 4; //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"); // ---------------------------------------------------------------------- // //fLogInit = true; log_mutex = xSemaphoreCreateMutex(); //xTaskCreate(log_task, ( char * ) "log_task", configMINIMAL_STACK_SIZE * 2, NULL, tskIDLE_PRIORITY, NULL); } // 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; entry_ptr->timestamp = rtc_get_ms(); if (entry_type == LOG_ENTRY) { log_etnry_ptr = 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 = 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; } // -------------------------------------------------------------------------- // // 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 #if 0 // fs_log int log_test(void) { int ret; } #endif // fs_archive int test_archive(void) { int ret; archive_entry_t entry; int capacity_flash = 0; int count_flash = 0; capacity_flash = ringfs_capacity(&fs_archive); count_flash = ringfs_count_exact(&fs_archive); DBG printf("Fetching...\r\n"); if (log_fetch(&entry, ARCHIVE_ENTRY, portMAX_DELAY)) { printf("%" PRId64 "\n", entry.timestamp); } else { DBG printf("fail\r\n"); } #if 0 DBG printf("Discarding\r\n"); if (log_discard) #endif return 0; } // Добавить n архивных записей int test_add_random_archive_entry(uint32_t cnt_entry) { int ret; archive_entry_t entry = {0}; static uint32_t index = 0; DBG printf("Try append %u archive entry\r\n", cnt_entry); for (uint32_t i = 0; i < cnt_entry; i++) { //entry.input_value = ringfs_count_exact(&fs_archive); entry.input_value = index++; ret = log_append(&entry, ARCHIVE_ENTRY); } return ret; } // 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 test_archive_info(void) { int capacity_flash = 0; int count_flash = 0; int count_estimate = 0; capacity_flash = ringfs_capacity(&fs_archive); count_flash = ringfs_count_exact(&fs_archive); count_estimate = ringfs_count_estimate(&fs_archive); printf("Archive partition capasity: %u\r\n", capacity_flash); printf("Count archive entry: %u\r\n", count_flash); printf("Estimate count: %u\r\n", count_estimate); } // void test_archive_format(void) { ringfs_format(&fs_archive); } // void test_print_all_archive(void) { test_archive_info(); } #if 0 char logFileBuf[FILE_BUF_MAX_LEN]; char name_login[50]; extern const char* logsStrShortRu[]; bool flUpdateLog = false; static bool fLogInit = false; // Флаг инициализации журнала #define LOG_TIME 1000*60*10 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 = { .sector_offset = LOG_FLASH_SECTOR_OFFSET, .sector_erase = op_sector_erase, .program = op_program, .read = op_read, }; static struct ringfs fs; static struct ringfs_flash_partition ringfs_flash2 = { .sector_offset = ALARM_LOG_FLASH_SECTOR_OFFSET, .sector_erase = op_sector_erase, .program = op_program, .read = op_read, }; static struct ringfs fs2; static SemaphoreHandle_t log_mutex; /** * @brief Отключает журнал для безопасной перезагрузки */ bool LOG_Disable(void) { if (fLogInit) { /* Ожидаем завершения работы с журнал */ if ( xSemaphoreTake(log_mutex, 10000) == pdTRUE ) { //fLogInit = false; //xSemaphoreGive(logMutex); return true; } else { return false; } } else { return true; } } void log_task(void* params) { for(;;){ flUpdateLog = true; vTaskDelay(LOG_TIME); /*vTaskDelay(50); log_event_data(LOG_SYSTEM_BOOT, "Администратор"); log_add(")215.7;215.7;220.5;000;50.1;2.30;25.0;00000001;");*/ } } void log_init(bool format) { DBG printf(">>> Event log\n"); if (!spi_flash_desc.present) return; ringfs_flash.sector_size = spi_flash_desc.sector_size; ringfs_flash.sector_count = SECTOR_COUNT; ringfs_init(&fs, &ringfs_flash, LOG_ENTRY_VERSION, sizeof(log_entry_t)); if (format || ringfs_scan(&fs) != 0){ DBG printf("FAT1 false\r\n"); ringfs_format(&fs); } DBG printf("FAT1 true\r\n"); ringfs_flash2.sector_size = spi_flash_desc.sector_size; ringfs_flash2.sector_count = SECTOR_COUNT; ringfs_init(&fs2, &ringfs_flash2, LOG_ENTRY_VERSION, sizeof(log_entry_t)); if (format || ringfs_scan(&fs2) != 0){ DBG printf("FAT2 false\r\n"); ringfs_format(&fs2); } DBG printf("FAT2 true\r\n"); fLogInit = true; log_mutex = xSemaphoreCreateMutex(); xTaskCreate(log_task, ( char * ) "log_task", configMINIMAL_STACK_SIZE * 2, NULL, tskIDLE_PRIORITY, NULL); } int capacity_flash = 0; int count_flash = 0; int log_test(void) { int ret; log_entry_t entry; log_init(false); capacity_flash = ringfs_capacity(&fs); count_flash = ringfs_count_exact(&fs); DBG printf("\tCapacity: %d\n", capacity_flash); DBG printf("\tCount: %d\n", count_flash); DBG printf("\tAppending "); // ret = log_event(LOG_SYSTEM_DEFCONFIG, 0, 0); DBG printf("%s\n", ret == 0 ? "ok" : "error"); if (ret == 0) return -1; // ret = log_event(LOG_SYSTEM_DEFCONFIG, 0, 512); entry.timestamp = 0; entry.type = 0; DBG printf("\tFetching "); if (log_fetch(&entry, portMAX_DELAY) == 0){ DBG printf("ok, time=%d, type=%d\n", entry.timestamp, entry.type); log_fetch(&entry, portMAX_DELAY); entry.timestamp = 0; entry.type = 0; log_fetch(&entry, portMAX_DELAY); entry.timestamp = 0; entry.type = 0; log_fetch(&entry, portMAX_DELAY); entry.timestamp = 0; entry.type = 0; log_fetch(&entry, portMAX_DELAY); return 0; } else { DBG printf("fail\n"); return -1; } DBG printf("\tDiscarding "); if (log_discard(&entry,portMAX_DELAY) == 0) DBG printf("ok\n"); else { DBG printf("fail\n"); return -1; } return 0; } int log_append(log_entry_t *entry) { int ret; TM_RTC_t data; ret = xSemaphoreTake( log_mutex, portMAX_DELAY ); if (ret == pdFALSE) return ret; if (!entry->timestamp){ TM_RTC_GetDateTime(&data, TM_RTC_Format_BIN); entry->timestamp = data.unix; } if(entry->type == LOG_VALUE) ringfs_append(&fs, entry); else ringfs_append(&fs2, entry); xSemaphoreGive(log_mutex); return ret; } int log_fetch(log_entry_t *entry, uint32_t timeout) { int ret; ret = xSemaphoreTake( log_mutex, (TickType_t)timeout ); if (ret == pdFALSE) return ret; if(entry->type == LOG_VALUE) ret = ringfs_fetch(&fs, entry); else ret = ringfs_fetch(&fs2, entry); xSemaphoreGive(log_mutex); return ret; } int log_rewind(log_entry_t *entry, uint32_t timeout) { int ret; ret = xSemaphoreTake( log_mutex, (TickType_t)timeout ); if (ret == pdFALSE) return ret; if(entry->type == LOG_VALUE) ret = ringfs_rewind(&fs); else ret = ringfs_rewind(&fs2); xSemaphoreGive(log_mutex); return ret; } int log_discard(log_entry_t *entry, uint32_t timeout) { int ret; ret = xSemaphoreTake( log_mutex, (TickType_t)timeout ); if (ret == pdFALSE) return ret; if(entry->type == LOG_VALUE) ret = ringfs_discard(&fs); else ret = ringfs_discard(&fs2); xSemaphoreGive(log_mutex); return ret; } void log_event_data(log_type_t type, char *data) { log_entry_t entry_data; entry_data.timestamp = 0; entry_data.type = type; strncpy(entry_data.data, data, 49); if (fLogInit) log_append(&entry_data); } void log_add(char *log_data) { char buf_value[50]; uint8_t i, len; memset(buf_value, 0, 50); len = strlen(log_data); if (len != UPS_DATA_STRING_SIZE) { //len = UPS_DATA_STRING_SIZE; return; } strncpy(buf_value, log_data, len); DBG printf("UPS log data: %s\r\n", log_data); buf_value[0] = '\"'; for(i = 0; i < len; i++) { if(buf_value[i] == ' ') buf_value[i] = ';'; } buf_value[len - 1] = ';'; if(fLogInit){ if(fs.write.slot>67) { log_entry_t entry_data; entry_data.timestamp = 0; log_event_data(LOG_VALUE, buf_value); } else log_event_data(LOG_VALUE, buf_value); } } /** * @brief Возвращает true если журнал проинициализирован */ bool LOG_IsInit() { return fLogInit; } /** * @brief Возвращает общее количество страниц */ uint32_t LOG_GetPageCount(void) { return (((ringfs_count_estimate(&fs)) / 10) + 1); } uint32_t LOG_GetTotalSTRCount(void) { return ringfs_count_estimate(&fs); } void LOG_GetPage_tabs(char *str, uint32_t page) { TM_RTC_t rtc_data; log_entry_t entry; char buf[20]; uint8_t i; int start =LOG_GetTotalSTRCount();//(fs.write.sector*fs.slots_per_sector + fs.write.slot); memset(buf, 0, 20); for(i=0; i < 10; i++){ fs.cursor_position = start - 10*(page-1) - 1 - i; if(fs.cursor_position < 0) break; else{ fs.cursor.sector = (fs.read.sector + fs.cursor_position/fs.slots_per_sector)%fs.flash->sector_count; fs.cursor.slot = fs.cursor_position%fs.slots_per_sector; } entry.type = LOG_VALUE; log_fetch(&entry, portMAX_DELAY); entry.data[49] = 0; strncat(str, entry.data, strlen(entry.data)); TM_RTC_GetDateTimeFromUnix(&rtc_data, entry.timestamp); sprintf(buf, "%02i.%02i.%02i %02i:%02i:%02i", rtc_data.date, rtc_data.month, rtc_data.year, rtc_data.hours, rtc_data.minutes, rtc_data.seconds); strcat(str, buf); strcat(str, "\","); strcat(str, "\r\n"); } } void LOG_GetPage(char *str, uint32_t page) { TM_RTC_t rtc_data; log_entry_t entry; char buf[20]; uint8_t i; int start =LOG_GetTotalSTRCount();//(fs.write.sector*fs.slots_per_sector + fs.write.slot); memset(buf, 0, 20); for(i=0; i < 10; i++){ fs.cursor_position = start - 10*(page-1) - 1 - i; if(fs.cursor_position < 0) break; else{ fs.cursor.sector = (fs.read.sector + fs.cursor_position/fs.slots_per_sector)%fs.flash->sector_count; fs.cursor.slot = fs.cursor_position%fs.slots_per_sector; } entry.type = LOG_VALUE; log_fetch(&entry, portMAX_DELAY); entry.data[49] = 0; strncat(str, entry.data, strlen(entry.data)); TM_RTC_GetDateTimeFromUnix(&rtc_data, entry.timestamp); sprintf(buf, "%02i.%02i.%02i %02i:%02i:%02i", rtc_data.date, rtc_data.month, rtc_data.year, rtc_data.hours, rtc_data.minutes, rtc_data.seconds); strcat(str, buf); strcat(str, "\","); } } uint32_t LOG_GetData(int ptr, char *str, uint32_t size, bool start) { TM_RTC_t rtc_data; log_entry_t entry; char buf[20]; uint8_t i; entry.type = LOG_VALUE; if(start) log_rewind(&entry, portMAX_DELAY); fs.cursor_position = ptr/STRING_SIZE; fs.cursor.sector = (fs.read.sector + fs.cursor_position/fs.slots_per_sector)%fs.flash->sector_count; fs.cursor.slot = fs.cursor_position%fs.slots_per_sector; for(i = 0; i < size/STRING_SIZE; i++) { entry.type = LOG_VALUE; log_fetch(&entry, portMAX_DELAY); entry.data[49] = 0; strncat(str, &entry.data[1], (strlen(entry.data) - 1)); TM_RTC_GetDateTimeFromUnix(&rtc_data, entry.timestamp); sprintf(buf, "%02i.%02i.%02i %02i:%02i:%02i", rtc_data.date, rtc_data.month, rtc_data.year, rtc_data.hours, rtc_data.minutes, rtc_data.seconds); strcat(str, buf); strcat(str, "\n"); } return strlen(str); } #endif