/****************************************************************/ /* TMS320C32 */ /* ====== BIOS, КЛАИН, КЛВСП ====== */ /* ЦНИИ СЭТ (с) 1998-2001г. */ /****************************************************************/ /* log_to_mem.c **************************************************************** * Запись логов в памyть * ****************************************************************/ #include "DSP2833x_Device.h" #include "filter_bat2.h" #include "measure.h" #include "package.h" #include "RS485.h" #include "message.h" #include "peripher.h" #include "DAC.h" #include "ADC.h" #include "log_to_mem.h" int no_write = 0, never_write = 0; // Флаги, чтобы не писать (если что) #pragma DATA_SECTION(logs_block,".logg"); unsigned int logs_block[0xFA00]; LOG Log; unsigned int flog=0; // Очищение памати, где логи лежат void clear_mem() { unsigned long i; Log.Start = LOG_PAGE_START; Log.Finis = LOG_PAGE_START + LOG_PAGE_LEN; Log.Adres = Log.Start; Log.Circl = 0; for (i=Log.Start; i= UMP_LOG_CAPACITY/2) ump_count = UMP_LOG_CAPACITY/2-1; ump_post_dropped = 0; ump_post = 1000; reason |= 0x100; } /* Последнее место оставляем для снимка конца постинтервала. При * переполнении честно отмечаем усечение битом 0x200 в конечной записи. */ if (ump_post && ump_count >= UMP_LOG_CAPACITY-1) { ump_post_dropped = 1; return; } if (reason == 5 && ump_post_dropped) reason |= 0x200; p = logs_block + ((unsigned long)ump_bank * UMP_LOG_CAPACITY + ump_next) * UMP_LOG_WORDS; p[0] = (unsigned int)ump_time; p[1] = (unsigned int)(ump_time >> 16); p[2] = reason; p[3] = commands; p[4] = ump_inputs(); p[5] = ump_outputs(); p[6] = (unsigned int)IMPowse; p[7] = (unsigned int)WAKEpowse; p[8] = modbus[0x7B]; p[9] = modbus[0x1C]; for (i = 0; i < 4; i++) { p[10+i] = sens_data[i]; p[14+i] = modbus[i]; } p[18] = ump_can_header; p[19] = ump_can_data[0]; p[20] = ump_can_data[1]; p[21] = ump_can_data[2]; p[22] = ump_can_count; p[23] = CanTimeOutErrorTR; /* Исходные уставки — мА; эффективные уставки после ограничений — 0.1 мА. * p[8] — отправленный код, а p[9] — расчётное задание, НЕ измерение тока. */ p[24] = DAC_go; p[25] = DAC_stop; p[26] = DAC_min(); p[27] = DAC_max(); p[28] = DAC_cal(); p[29] = DAC_04; p[30] = DAC_20; p[31] = ump_dac_ramp; p[32] = ump_dac_duration; p[33] = ump_dac_go10; p[34] = ump_dac_stop10; p[35] = ump_dac_position; for (i = 0; i < 4; i++) p[36+i] = ADC_table[i]; ump_prev_commands = commands; ump_prev_inputs = p[4]; ump_prev_outputs = p[5]; ump_next++; if (ump_next == UMP_LOG_CAPACITY) ump_next = 0; if (ump_count < UMP_LOG_CAPACITY) ump_count++; ump_sequence++; } /* Завершённый банк больше не изменяется до следующего отключения. * Номер поколения позволяет GUI обнаружить замену архива во время чтения. */ static void ump_freeze(void) { ump_archive_bank = ump_bank; ump_archive_count = ump_count; ump_archive_next = ump_next; ump_generation++; ump_bank ^= 1; ump_count = 0; ump_next = 0; ump_post = 0; } void ump_log_tick(void) { unsigned int saved = __disable_interrupts(); if (ump_state == 1) { ump_time++; if (++ump_divider >= ump_period) { ump_divider = 0; ump_capture(1); } if (ump_post && --ump_post == 0) { ump_capture(5); ump_freeze(); } } __restore_interrupts(saved); } /* Дополнительный снимок только при изменении команд, входов или выходов. * Это не заменяет периодическую запись аналоговых величин в таймере. */ void ump_log_io(void) { unsigned int saved; if (ump_state != 1 || Desk != dsk_LOAD) return; saved = __disable_interrupts(); if (Commands != ump_prev_commands || ump_inputs() != ump_prev_inputs || ump_outputs() != ump_prev_outputs) ump_capture(3); __restore_interrupts(saved); } /* Вызывается после применения слов принятого CAN-кадра: снимок содержит * новые команды, а также исходный адрес/маску и все три слова кадра. */ void ump_log_can(unsigned int header, unsigned int a, unsigned int b, unsigned int c) { unsigned int saved; if (ump_state != 1 || Desk != dsk_LOAD) return; saved = __disable_interrupts(); ump_can_header = header; ump_can_data[0] = a; ump_can_data[1] = b; ump_can_data[2] = c; ump_can_count++; ump_capture(2); __restore_interrupts(saved); } void ump_log_rs(void) { unsigned int saved = __disable_interrupts(); ump_capture(4); __restore_interrupts(saved); } /* Управление журналом отделено от технологических команд: начало записи * НЕ запускает УМП. Выбор архива не останавливает текущую запись. */ int ump_log_write(unsigned int address, unsigned int value) { unsigned int saved, valid = 1; saved = __disable_interrupts(); if (address == UMP_LOG_BASE && value == 0) { ump_state = 3; ump_post = 0; } else if (address == UMP_LOG_BASE && value == 1 && Desk == dsk_LOAD && READY && ump_state != 1) { ump_count = 0; ump_next = 0; ump_cursor = 0; ump_divider = 0; ump_post = 0; ump_source = 0; ump_prev_commands = Commands; no_write = 0; never_write = 0; ump_state = 1; ump_capture(1); } else if (address == UMP_LOG_BASE+1 && ump_state != 1 && value >= 1 && value <= 1000) ump_period = value; else if (address == UMP_LOG_BASE+2 && value < UMP_LOG_CAPACITY) ump_cursor = value; else if (address == UMP_LOG_BASE+3 && value <= 1) ump_source = value; else valid = 0; __restore_interrupts(saved); return valid; } /* Преобразование хронологического индекса в физическую позицию кольца. * Для архива сохранены собственные count/next, независимые от живого банка. */ static unsigned int ump_word(unsigned int archived, unsigned int record, unsigned int word) { unsigned int count = archived ? ump_archive_count : ump_count; unsigned int next = archived ? ump_archive_next : ump_next; unsigned int bank = archived ? ump_archive_bank : ump_bank; unsigned int slot; if (record >= count) return 0; slot = next + UMP_LOG_CAPACITY - count + record; while (slot >= UMP_LOG_CAPACITY) slot -= UMP_LOG_CAPACITY; return logs_block[((unsigned long)bank * UMP_LOG_CAPACITY + slot) * UMP_LOG_WORDS + word]; } /* Весь Modbus-блок читается вызывающим кодом под одной блокировкой IRQ. * Поэтому timestamp/данные и заголовок онлайн-блока относятся к одному * состоянию кольца, даже если в этот момент приходит новая CAN-команда. */ unsigned int ump_log_read(unsigned int address) { unsigned int offset, count; unsigned long first; switch (address) { case UMP_LOG_BASE: return 0x554D; case UMP_LOG_BASE+1: return 2; case UMP_LOG_BASE+2: return ump_source ? 3 : ump_state; case UMP_LOG_BASE+3: return ump_source ? ump_archive_count : ump_count; case UMP_LOG_BASE+4: return UMP_LOG_WORDS; case UMP_LOG_BASE+5: return UMP_LOG_CAPACITY; case UMP_LOG_BASE+6: return ump_period; case UMP_LOG_BASE+7: return (unsigned int)ump_time; case UMP_LOG_BASE+8: return (unsigned int)(ump_time >> 16); case UMP_LOG_BASE+9: return Desk; case UMP_LOG_BASE+10: return Mode; case UMP_LOG_BASE+11: return (unsigned int)READY_FREQ; case UMP_LOG_BASE+12: return ump_generation; case UMP_LOG_BASE+13: return ump_archive_count; case UMP_LOG_BASE+14: return ump_post; case UMP_LOG_BASE+15: return ump_state; } if (address >= UMP_LOG_DATA && address < UMP_LOG_DATA+120 && (ump_source || ump_state != 1)) { offset = address - UMP_LOG_DATA; return ump_word(ump_source, ump_cursor + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS); } /* Последние три записи для онлайн-графика, без остановки и без * изменения курсора архивного чтения. Первые два слова — их номер. */ if (address >= UMP_LOG_LIVE && address < UMP_LOG_LIVE+124) { count = ump_count < 3 ? ump_count : 3; first = ump_sequence - count; offset = address - UMP_LOG_LIVE; if (offset == 0) return (unsigned int)first; if (offset == 1) return (unsigned int)(first >> 16); if (offset == 2) return count; if (offset == 3) return ump_generation; offset -= 4; if (offset / UMP_LOG_WORDS < count) return ump_word(0, ump_count - count + offset / UMP_LOG_WORDS, offset % UMP_LOG_WORDS); } return 0; }