/* * SpiBus.h * * Created on: 6 июн. 2019 г. * Author: krugliy */ #ifndef SOURCE_DRIVER_SPIBUS_H_ #define SOURCE_DRIVER_SPIBUS_H_ #include #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 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 & 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_ */