/** ******************************************************************************* * @file modbus_oscil.c * @brief Модуль для реализации осциллографа через MODBUS. ******************************************************************************* * @details * Файл содержит реализацию функций для работы с буфером осциллографа. * * @section oscil_functions Функции * - MB_Oscil_Init() — Инициализация структуры осциллографа * - MB_Oscil_Add() — Добавление данных в буфер * - MB_Oscil_UpdateTail() — Обновление указателя Tail ******************************************************************************/ #include "modbus_oscil.h" #ifdef MODBUS_ENABLE_OSCIL /** * @brief Инициализация структуры осциллографа * @param oscil Указатель на структуру осциллографа * @param BufferSize Размер буфера в Modbus регистрах (max 125) * @param NumbOfChannels Количество каналов (должно быть четным) * @param SampleTime Период дискретизации * @return HAL Status */ HAL_StatusTypeDef MB_Oscil_Init(MB_OscilTypeDef *oscil, uint8_t BufferSize, uint8_t NumbOfChannels, uint16_t SampleTime) { if(!oscil || (BufferSize >= MbData_size) || (NumbOfChannels > 15) || !SampleTime) return HAL_ERROR; if(NumbOfChannels % 2 != 0) return HAL_ERROR; oscil->Config.BufferSize = BufferSize; oscil->Config.NumbOfChannels = NumbOfChannels; oscil->Config.SampleTime = SampleTime; oscil->Config.LastTick = 0; oscil->Preamble.Head = 0; oscil->Preamble.Tail = 0; oscil->Config.Overrun = 0; return HAL_OK; } /** * @brief Инициализация структуры осциллографа * @param oscil Указатель на структуру осциллографа * @param BufferSize Размер буфера в Modbus регистрах (max 125) * @param NumbOfChannels Количество каналов (должно быть четным) * @param SampleTime Период дискретизации * @return HAL Status */ HAL_StatusTypeDef MB_Oscil_Set_SampleTime(MB_OscilTypeDef *oscil, uint16_t SampleTime) { if(!oscil || !SampleTime) return HAL_ERROR; oscil->Config.SampleTime = SampleTime; return HAL_OK; } /** * @brief Добавление данных всех каналов в буфер * @param oscil Указатель на структуру осциллографа * @param Data Массив с данными каналов (длина = NumbOfChannels) * @return HAL Status */ HAL_StatusTypeDef MB_Oscil_Add(MB_OscilTypeDef *oscil, uint8_t *Data) { if(!oscil || !Data) return HAL_ERROR; if(local_time() - oscil->Config.LastTick < oscil->Config.SampleTime) return HAL_BUSY; oscil->Config.LastTick = local_time(); uint8_t head_max = oscil->Config.BufferSize * 2; uint8_t start_pos = oscil->Preamble.Head; uint8_t channels = oscil->Config.NumbOfChannels; uint8_t tail = oscil->Preamble.Tail; // Пишем данные for(uint8_t i = 0; i < channels; i++) { uint8_t write_pos = (start_pos + i) % head_max; oscil->Data[write_pos] = Data[i]; } // Новое положение Head uint8_t new_head = (start_pos + channels) % head_max; // Проверяем, есть ли непрочитанные данные (Tail != Head) // if(tail != start_pos) { // Если есть непрочитанные данные, проверяем не перетерли ли мы их if(start_pos < new_head) { // Линейный случай if(tail > start_pos && tail <= new_head) { oscil->Preamble.Tail = (new_head + 1) % head_max; oscil->Config.Overrun = 1; } } else if(start_pos > new_head) { // Кольцевой случай (было переполнение) if(tail > start_pos || tail <= new_head) { oscil->Preamble.Tail = (new_head + 1) % head_max; oscil->Config.Overrun = 1; } } // } oscil->Preamble.Head = new_head; return HAL_OK; } /** * @brief Обновление указателя Tail * @param oscil Указатель на структуру осциллографа * @return HAL Status * * @details Вызывается после того, как данные были прочитаны через Modbus. * Tail устанавливается на следующий байт за Head. */ HAL_StatusTypeDef MB_Oscil_UpdateTail(MB_OscilTypeDef *oscil) { if(!oscil) return HAL_ERROR; // Сдвигаем Tail на следующий байт за Head uint8_t head_max = oscil->Config.BufferSize * 2; oscil->Preamble.Tail = oscil->Preamble.Head; if(oscil->Preamble.Tail >= head_max) oscil->Preamble.Tail = 0; oscil->Config.Overrun = 0; return HAL_OK; } #endif //MODBUS_ENABLE_OSCIL