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

207 lines
5.5 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.

#include "../memories/memories.hh"
/*
* SpiBus.cpp
*
* Created on: 6 июн. 2019 г.
* Author: krugliy
*/
#include "SpiBus.hh"
#include <climits>
#include <stdint.h>
peripheral::ISerialPort* driver::SpiBus::SpiBusMaster::transfer_request(
SpiAbonent* spi_abonent) {
if( active_abonent && serial_port.isDataReady() ) {
active_abonent->transmite_complete_handler( serial_port );
cancel_request( active_abonent );
}
// ITransferHandler * volatile prev_handler = active_handler;
SpiAbonent * volatile prev_abonenet = active_abonent;
if( !prev_abonenet && !collision.isTiedTo( spi_abonent ) ) {
while( collision.popLink( static_cast<SpiAbonent *>( spi_abonent ) ) );
// spi.reset();
// interrupt_ctrl.enable();
if( active_abon_setting != spi_abonent->getSetting() ) {
serial_configurator.applySetting(
spi_abonent->getSetting().baud_rate,
spi_abonent->getSetting().clk_scheme,
spi_abonent->getSetting().transfer_delay,
spi_abonent->getSetting().loop_back_enable
);
active_abon_setting = spi_abonent->getSetting();
}
active_abonent = spi_abonent;
return & serial_port;
} else if( static_cast<SpiAbonent *>( prev_abonenet ) != spi_abonent && prev_abonenet ) {
collision.putLink( static_cast<SpiAbonent *>( spi_abonent ), prev_abonenet );
}
return nullptr;
}
void driver::SpiBus::SpiBusMaster::cancel_request(SpiAbonent* spi_abonent) {
while( collision.popLink( spi_abonent ) );
if( active_abonent == spi_abonent ) {
// interrupt_ctrl.disable();
// spi.reset();
active_abonent = nullptr;
}
}
driver::SpiBus::SpiBusMaster::SpiBusMaster(
peripheral::ISerialPort& _serial_port,
peripheral::ISerialPortConfigurator& _serial_configurator) :
serial_port(_serial_port), active_abonent( nullptr ),
serial_configurator(_serial_configurator),
active_abon_setting(), collision() {}
peripheral::ISerialPort * driver::SpiBus::createAbonent(
peripheral::IGpio& chip_select,
const SpiBusAbonentConfig& abon_config,
std::pmr::memory_resource* allocator ) {
if( num_spi_abonent < max_spi_bus_abonents ) {
num_spi_abonent++;
//todo: использовать алокатор
return memories::instance_object<SpiAbonent>( *allocator, spiBusMaster, chip_select, abon_config );
}
return nullptr;
}
driver::SpiBus::SpiBus(peripheral::ISerialPort& _serial_port,
peripheral::ISerialPortConfigurator& _serial_configurator,
std::size_t _max_spi_abonents ) :
max_spi_bus_abonents( _max_spi_abonents ),
num_spi_abonent( 0 ),
spiBusMaster( _serial_port, _serial_configurator ) {}
bool driver::SpiBus::SpiAbonent::transmite(const void* bit_stream,
int bit_count) {
if( peripheral::ISerialPort * port = serial_bus.transfer_request( this ) ) {
num_words = bit_count / CHAR_BIT;
if( bit_count % CHAR_BIT ) num_words += 1;
chip_select.on();
if( not abon_config.getAbonentSetting().tx_inv ) {
if( not port->transmite( bit_stream, bit_count ) ) {
chip_select.off();
} else return true;
} else {
char tx_buff[fifo_buff_size];
for( int i = 0; i < num_words; i++ ) {
tx_buff[i] = ~*static_cast<const char*>(bit_stream);
bit_stream = static_cast<const char*>(bit_stream) + 1;
}
if( not port->transmite( tx_buff, bit_count ) ) {
chip_select.off();
} else return true;
}
}
return false;
}
bool driver::SpiBus::SpiAbonent::receive(void* data) {
if( isDataReady() ) {
if( abon_config.getAbonentSetting().rx_inv ) {
for( int i = 0; i < num_words; i++ )
static_cast<unsigned char *>(data)[i] = ~rx_buff[i];
} else {
for( int i = 0; i < num_words; i++ )
static_cast<unsigned char *>(data)[i] = rx_buff[i];
}
serial_bus.cancel_request( this );
data_ready = false;
return true;
}
return false;
}
driver::SpiBus::SpiAbonent::SpiAbonent(SpiBusMaster& _bus_master,
peripheral::IGpio& _chip_select,
const SpiBusAbonentConfig& _abon_config) :
serial_bus(_bus_master),
abon_config(_abon_config),
chip_select(_chip_select, _abon_config.getCsActiveLevel()),
rx_buff(), num_words(0) {}
bool driver::SpiBus::SpiAbonent::isDataReady() {
return serial_bus.is_response_ready( this ) || data_ready;
}
driver::SpiBus::SpiAbonent::~SpiAbonent() {
//надо сказать мастеру, что мы удаляемся - приемные буфера больше не действительны
}
void driver::SpiBus::SpiAbonent::transmite_complete_handler(
peripheral::ISerialPort& serial_port) {
chip_select.off();
data_ready = ( sizeof( rx_buff ) >= num_words )
&& serial_port.receive( rx_buff );
}
bool driver::SpiBus::SpiBusMaster::is_response_ready( SpiAbonent* spi_abonent ) {
if( active_abonent && active_abonent == spi_abonent ) {
return serial_port.isDataReady() ? spi_abonent->transmite_complete_handler( serial_port ), true : false;
}
return false;
}