MotorControlModuleSDFM_TMS3.../Projects/EFC_Communication/UMLibrary/driver/SpiBus.hh
2024-06-07 11:12:56 +03:00

174 lines
5.8 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.

/*
* SpiBus.h
*
* Created on: 6 июн. 2019 г.
* Author: krugliy
*/
#ifndef SOURCE_DRIVER_SPIBUS_H_
#define SOURCE_DRIVER_SPIBUS_H_
#include <cstddef>
#include "../common/Link.hpp"
#include "DiscreteOutput_OnePin.hh"
#include "../peripheral/ISerialPort.hh"
#include "../peripheral/ISerialPortConfigurator.hh"
namespace driver {
//serial port buffered driver
class ISerialPortBuff {
public:
virtual bool buff_transmite( const void * bit_stream, int bit_count ) = 0;
virtual bool receive( void * data ) = 0;
virtual ~ISerialPortBuff() = default;
};
//
class SpiBusAbonentConfig {
public:
struct Setting {
unsigned short clk_scheme;
unsigned short cs_polarity;
unsigned short transfer_delay;
unsigned long baud_rate;
bool rx_inv; //признак необходимости инвертировать принимаемые данные
bool tx_inv; //признак необходимости инвертировать данные на отправку
bool loop_back_enable;
bool isValid() {
return true; //todo: baud_rate должен быть ограничен,
//причем максимальная частота клоцирования должна быть прописана в настройках периферии
}
bool operator==( const Setting & other ) {
return ( clk_scheme == other.clk_scheme )
&& ( baud_rate == other.baud_rate )
&& ( loop_back_enable == other.loop_back_enable );
}
bool operator!=( const Setting & other ) { return not (*this == other ); }
};
bool configure( Setting & set ) {
if( not set.isValid() ) return false;
abonent_setting = set;
return true;
}
const Setting & getAbonentSetting() const { return abonent_setting; }
bool getCsActiveLevel() const { return abonent_setting.cs_polarity ==
1; }
private:
Setting abonent_setting;
};
class SpiBus {
public:
class SpiAbonent;
static const unsigned short max_links = 32; //должно быть равно max_spi_bus_abonents
static const unsigned short fifo_buff_size = 16; //размер внутреннего буфера в 16-ти битных словах
static const unsigned short fifo_buff_word_bit_len = 16;
static const unsigned short max_delay_cycle_count = 255;
peripheral::ISerialPort * createAbonent( peripheral::IGpio & chip_select,
const SpiBusAbonentConfig & abon_config,
std::pmr::memory_resource* allocator );
SpiBus( peripheral::ISerialPort & _serial_port,
peripheral::ISerialPortConfigurator & _serial_configurator,
std::size_t _max_spi_abonents );
virtual ~SpiBus() = default;
private:
const std::size_t max_spi_bus_abonents;
short num_spi_abonent;
class SpiBusMaster {
private:
peripheral::ISerialPort & serial_port;
peripheral::ISerialPortConfigurator & serial_configurator;
SpiAbonent * active_abonent;
SpiBusAbonentConfig::Setting active_abon_setting;
Link<SpiAbonent, max_links> collision;
public:
//запрос на передачу
//если порт свободен, возвращается указатель на интерфейс
//в противном случае 0, а абонент который заблокировал доступ к порту
//повторно не получит порт пока им не воспользуется абонент, получивший 0 на вызов функции
peripheral::ISerialPort * transfer_request( SpiAbonent * spi_abonent );
//проверка готовности ответа
bool is_response_ready( SpiAbonent * spi_abonent );
//отмена запроса на передачу
void cancel_request( SpiAbonent * spi_abonent );
SpiBusMaster( peripheral::ISerialPort & _serial_port, peripheral::ISerialPortConfigurator & _serial_configurator );
} spiBusMaster;
};
class SpiBus::SpiAbonent : public peripheral::ISerialPort {
private:
SpiBus::SpiBusMaster & serial_bus;
const SpiBusAbonentConfig abon_config;
driver::detail::DiscreteOutput_OnePin chip_select;
unsigned char rx_buff[fifo_buff_size]; //буфферизация фрейма, не данных
bool data_ready = false; //буфер rx_buff - не прочитан
short num_words;
public:
//мастер использует эти функции абонента:
const SpiBusAbonentConfig::Setting & getSetting() const { return abon_config.getAbonentSetting(); }
// bool transmite_handler( peripheral::ISerialPort & serial_port ); //тут должно возможным быть только чтение порта
// //либо рассматривать эту функцию как завершение частичной передачи данных,
// //тогда ее можно использовать для до передачи из внутреннего fifo буфера
//
//
void transmite_complete_handler( peripheral::ISerialPort & serial_port );
// bool transmite_complete_handler( CircularBuffer<spi_rx_buff_size, uint16_t> & master_rx_buff )
bool transmite( const void * bit_stream, int bit_count ) override;
bool receive( void * data ) override;
bool isDataReady();
SpiAbonent( SpiBusMaster & _bus_master, peripheral::IGpio & _chip_select,
const SpiBusAbonentConfig & _abon_config );
virtual ~SpiAbonent();
};
} /* namespace driver */
#endif /* SOURCE_DRIVER_SPIBUS_H_ */