MotorControlModuleSDFM_TMS3.../Projects/EFC_Application/UMLibrary/driver/SerialAdapterWithCheck.hh

235 lines
7.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* SerialPortAdapterWithCheck.hpp
*
* Created on: 23 августа. 2023 г.
* Author: titov
*/
#ifndef SOURCE_DRIVER_SERIALPORTADAPTERWITHCHECK_HPP_
#define SOURCE_DRIVER_SERIALPORTADAPTERWITHCHECK_HPP_
#include "../systemic/IHoldingRegister.hpp"
#include "SpiPortRoutineOperation.hpp"
#include "../peripheral/ISerialPort.hh"
#include "../systemic/Timer.hh"
#include <cstddef>
namespace driver {
/**
* @brief Адаптер последовательного порта с дополнительной проверкой корректности отправленных данных
* и выставлением соответствующего статуса.
*
* @tparam Frame Тип контейнера для данных
* @tparam Latency Задержка
* @tparam AutoSet отправлять ли данные, если они не были изменены
* False - будут отправляться только измененные данные.
* True - данные будут отправляться по таймеру. независимо от того, изменились ли они
*/
template<typename Frame, typename Latency = unsigned int, bool AutoSet = false>
class SerialPortAdapterWithCheck : public systemic::IHoldingRegister<Frame> {
public:
// Задержка
static Latency temp;
/**
* @param port Последовательный интерфейс для обмена данными
* @param frame_size Размер кадра
* @param period_time Период отправки/чтения данных
* @param request_frame Фрейм для передачи заголовка
* @param default_set_frame Фрейм для передачи данных
* @param default_get_frame Фрейм для получения данных
* @param check_sending_value_mask Маска для проверки корректности отправленных данных
* @param locked Заблокироать выполнение обработки данных
* @param lset Задержка на отправку данных
* @param lget Задержка на чтение данных
*/
SerialPortAdapterWithCheck( peripheral::ISerialPort & port, std::size_t frame_size, systemic::time_t period_time,
Frame request_frame, Frame default_set_frame, Frame default_get_frame, Frame check_sending_value_mask,
bool locked = false,
Latency & lset = temp, Latency & lget = temp );
/**
* @brief Отправить фрейм в последовательный порт.
* @param frame фрейм данных
*/
void set( Frame frame ) final;
/**
* @brief Прочитать последний полученный ответ из последовательного порта.
* @result Фрейм данных
*/
Frame get() const final;
/**
* @brief Заблокировать операции отправки/приема данных.
*/
void lock() final;
/**
* @brief Разблокировать операции отправки/приема данных.
*/
void unlock() final;
/**
* @brief Перезагружает адаптер.
*/
void reset();
/**
* @brief Запуск процесса чтения/отправки данных по последовательному порту.
*/
void process();
/**
* @brief Завершилась ли последняя отправка ошибкой.
* @return Результат последней отправки:
* true - данные были испорчены при отправке
* false - отправка завершилась успешно
*/
bool is_last_sending_error() const;
~SerialPortAdapterWithCheck() = default;
private:
enum { SET, GET, SWITCH, LOCKED } op, prev_op, stash_op;
// Статус последней отправки по последовательному порту
enum { SUCCESS, FAILURE } last_sending_status_ = SUCCESS;
// Набор операций для драйвера SPI.
typedef SpiOperationPack<Frame, Latency> Operation;
// Набор операций для отправки данных по SPI
Operation set_op;
// Набор операций для чтения данных по SPI
Operation get_op;
// Фрейм для передачи данных
Frame new_set_value;
// Фрейм для получения данных
Frame new_get_value;
// Период между операциями
systemic::time_t period_time;
// Отвечает за обработку операций, связанных с периодом
systemic::Timer periodizator;
// Маска для проверки корректности последней отправки данных
Frame check_sending_value_mask_;
};
}
template<typename Frame, typename Latency, bool AutoSet>
Latency driver::SerialPortAdapterWithCheck<Frame, Latency, AutoSet>::temp = 0;
template<typename Frame, typename Latency, bool AutoSet>
inline driver::SerialPortAdapterWithCheck<Frame, Latency, AutoSet>::SerialPortAdapterWithCheck(
peripheral::ISerialPort & port, std::size_t frame_size, systemic::time_t period_time,
Frame request_frame, Frame default_set_frame, Frame default_get_frame, Frame check_sending_value_mask,
bool locked,
Latency & _lset, Latency & _lget ) :
set_op( port, frame_size, default_set_frame, _lset ), get_op( port, frame_size, request_frame, _lget ), new_set_value(default_set_frame), new_get_value(default_get_frame), period_time(period_time),
op( locked ? LOCKED : GET ), prev_op(SWITCH), stash_op(GET), check_sending_value_mask_(check_sending_value_mask) {
periodizator.start( period_time );
}
template<typename Frame, typename Latency, bool AutoSet>
inline void driver::SerialPortAdapterWithCheck<Frame, Latency, AutoSet>::set( Frame set_value ) {
new_set_value = set_value;
}
template<typename Frame, typename Latency, bool AutoSet>
inline Frame driver::SerialPortAdapterWithCheck<Frame, Latency, AutoSet>::get() const {
return new_get_value;
}
template<typename Frame, typename Latency, bool AutoSet>
inline void driver::SerialPortAdapterWithCheck<Frame, Latency, AutoSet>::lock() {
stash_op = op;
op = LOCKED;
periodizator.stop();
}
template<typename Frame, typename Latency, bool AutoSet>
inline void driver::SerialPortAdapterWithCheck<Frame, Latency, AutoSet>::unlock() {
periodizator.start(period_time);
op = stash_op;
}
template<typename Frame, typename Latency, bool AutoSet>
inline void driver::SerialPortAdapterWithCheck<Frame, Latency, AutoSet>::reset() {
op = LOCKED;
periodizator.stop();
prev_op = SWITCH;
stash_op = GET;
periodizator.start( period_time );
op = GET;
}
template<typename Frame, typename Latency, bool AutoSet>
inline void driver::SerialPortAdapterWithCheck<Frame, Latency, AutoSet>::process() {
switch(op) {
case SET: {
if( set_op() ) {
prev_op = op;
op = SWITCH;
}
} break;
case GET: {
if( get_op() ) {
prev_op = op;
op = SWITCH;
new_get_value = get_op.output;
}
} break;
case SWITCH: {
if( periodizator.delayElapsed() ) {
periodizator.start(period_time);
// Проверка на ошибку записи:
if( prev_op == GET ) {
last_sending_status_ =
// Проверка по маске - накладываем маску на поля и сравниваем их
(set_op.input & check_sending_value_mask_) == (new_get_value & check_sending_value_mask_)
// Стартовая проверка - чтобы исключить ложное срабатывание в начале работы
|| (get_op.output == 0x00) ? SUCCESS : FAILURE;
}
if( prev_op == GET &&
( FAILURE == last_sending_status_ || set_op.input != new_set_value || AutoSet ) ) {
set_op.input = new_set_value;
op = SET;
} else
op = GET;
}
} break;
case LOCKED: {
} break;
}
}
template<typename Frame, typename Latency, bool AutoSet>
inline bool driver::SerialPortAdapterWithCheck<Frame, Latency, AutoSet>::is_last_sending_error() const {
return last_sending_status_ != SUCCESS;
}
#endif /* SOURCE_DRIVER_SERIALPORTADAPTERWITHCHECK_HPP_ */