/* * 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 namespace driver { /** * @brief Адаптер последовательного порта с дополнительной проверкой корректности отправленных данных * и выставлением соответствующего статуса. * * @tparam Frame Тип контейнера для данных * @tparam Latency Задержка * @tparam AutoSet отправлять ли данные, если они не были изменены * False - будут отправляться только измененные данные. * True - данные будут отправляться по таймеру. независимо от того, изменились ли они */ template class SerialPortAdapter : public systemic::IHoldingRegister { 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 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 Latency driver::SerialPortAdapter::temp = 0; template inline driver::SerialPortAdapter::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 inline void driver::SerialPortAdapter::set( Frame set_value ) { new_set_value = set_value; } template inline Frame driver::SerialPortAdapter::get() const { return new_get_value; } template inline void driver::SerialPortAdapter::lock() { stash_op = op; op = LOCKED; periodizator.stop(); } template inline void driver::SerialPortAdapter::unlock() { periodizator.start(period_time); op = stash_op; } template inline void driver::SerialPortAdapter::reset() { op = LOCKED; periodizator.stop(); prev_op = SWITCH; stash_op = GET; periodizator.start( period_time ); op = GET; } template inline void driver::SerialPortAdapter::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_ */