207 lines
6.7 KiB
C++
207 lines
6.7 KiB
C++
|
|
/*
|
|||
|
|
* SerialPortAdapter.hpp
|
|||
|
|
*
|
|||
|
|
* Created on: 17 пїЅпїЅпїЅ. 2019 пїЅ.
|
|||
|
|
* Author: titov
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#ifndef SOURCE_DRIVER_SERIALPORTADAPTER_HPP_
|
|||
|
|
#define SOURCE_DRIVER_SERIALPORTADAPTER_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 SerialPortAdapter : 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 locked Заблокироать выполнение обработки данных
|
|||
|
|
* @param lset Задержка на отправку данных
|
|||
|
|
* @param lget Задержка на чтение данных
|
|||
|
|
*/
|
|||
|
|
SerialPortAdapter( peripheral::ISerialPort & port, std::size_t frame_size, systemic::time_t period_time,
|
|||
|
|
Frame request_frame, Frame default_set_frame, Frame default_get_frame,
|
|||
|
|
bool locked = false,
|
|||
|
|
Latency & lset = temp, Latency & lget = temp );
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief Отправить фрейм в последовательный порт.
|
|||
|
|
* @param frame фрейм данных
|
|||
|
|
*/
|
|||
|
|
void set( Frame frame ) final;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief Прочитать последний полученный ответ из последовательного порта.
|
|||
|
|
* @result Фрейм данных
|
|||
|
|
*/
|
|||
|
|
Frame get() const final;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Заблокировать операции отправки/приема данных.
|
|||
|
|
*/
|
|||
|
|
void lock() final;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Разблокировать операции отправки/приема данных.
|
|||
|
|
*/
|
|||
|
|
void unlock() final;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Перезагружает адаптер.
|
|||
|
|
*/
|
|||
|
|
void reset();
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Запуск процесса чтения/отправки данных по последовательному порту.
|
|||
|
|
*/
|
|||
|
|
void process();
|
|||
|
|
|
|||
|
|
~SerialPortAdapter() = default;
|
|||
|
|
private:
|
|||
|
|
enum { SET, GET, SWITCH, LOCKED } op, prev_op, stash_op;
|
|||
|
|
|
|||
|
|
// Набор операций для драйвера 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;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename Frame, typename Latency, bool AutoSet>
|
|||
|
|
Latency driver::SerialPortAdapter<Frame, Latency, AutoSet>::temp = 0;
|
|||
|
|
|
|||
|
|
template<typename Frame, typename Latency, bool AutoSet>
|
|||
|
|
inline driver::SerialPortAdapter<Frame, Latency, AutoSet>::SerialPortAdapter(
|
|||
|
|
peripheral::ISerialPort & port, std::size_t frame_size, systemic::time_t period_time,
|
|||
|
|
Frame request_frame, Frame default_set_frame, Frame default_get_frame,
|
|||
|
|
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) {
|
|||
|
|
|
|||
|
|
periodizator.start( period_time );
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
template<typename Frame, typename Latency, bool AutoSet>
|
|||
|
|
inline void driver::SerialPortAdapter<Frame, Latency, AutoSet>::set( Frame set_value ) {
|
|||
|
|
|
|||
|
|
new_set_value = set_value;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename Frame, typename Latency, bool AutoSet>
|
|||
|
|
inline Frame driver::SerialPortAdapter<Frame, Latency, AutoSet>::get() const {
|
|||
|
|
|
|||
|
|
return new_get_value;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename Frame, typename Latency, bool AutoSet>
|
|||
|
|
inline void driver::SerialPortAdapter<Frame, Latency, AutoSet>::lock() {
|
|||
|
|
|
|||
|
|
stash_op = op;
|
|||
|
|
op = LOCKED;
|
|||
|
|
periodizator.stop();
|
|||
|
|
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename Frame, typename Latency, bool AutoSet>
|
|||
|
|
inline void driver::SerialPortAdapter<Frame, Latency, AutoSet>::unlock() {
|
|||
|
|
|
|||
|
|
periodizator.start(period_time);
|
|||
|
|
op = stash_op;
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
template<typename Frame, typename Latency, bool AutoSet>
|
|||
|
|
inline void driver::SerialPortAdapter<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::SerialPortAdapter<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 && ( set_op.input != new_set_value || AutoSet ) ) {
|
|||
|
|
set_op.input = new_set_value;
|
|||
|
|
op = SET;
|
|||
|
|
} else {
|
|||
|
|
op = GET;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} break;
|
|||
|
|
case LOCKED: {
|
|||
|
|
} break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif /* SOURCE_DRIVER_SERIALPORTADAPTER_HPP_ */
|