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

235 lines
8.6 KiB
C++
Raw Normal View History

2024-06-07 11:12:56 +03:00
/*
* 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_ */