174 lines
5.8 KiB
C++
174 lines
5.8 KiB
C++
/*
|
||
* 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_ */
|