/* * I2cEeprom24LCxxB.cpp * * Created on: 14 апр. 2018 г. * Author: Pair programming */ #include #include "I2cEeprom24LCxxB.hh" #include "../systemic/SharedData.hh" #include #include using driver::detail::I2cEeprom24LCxxB; I2cEeprom24LCxxB::DiscreteOutputDummy I2cEeprom24LCxxB::write_protect; systemic::ProcCtrl dummy_proc_ctrl; I2cEeprom24LCxxB::I2cEeprom24LCxxB( peripheral::II2c & i2c, const Setting & config, IDiscreteOutput & write_protect) : i2c(i2c), write_protected(write_protect), proc_ctrl(&dummy_proc_ctrl), polling_time(config.polling_time), size(config.size), address(config.address), baud_rate(config.baud_rate), timer(), index(0), failed_request(false), read_p(0), write_p(0), current_step(0), page_size(config.page_size), error_counter(0), result(nullptr), page_buff(), start_index(0), stop_index(0) {} void I2cEeprom24LCxxB::init( systemic::IProcessControl * pc, float Ts ) { proc_ctrl = pc; } void I2cEeprom24LCxxB::process() { if( read_p ) { //Ожидаем результата транзакции. if( result ) { //Успешное завершение операции. if( result->isComplete() ) { char page_buff_rx[frame_step]; while( current_step = result->getRequestedData( page_buff_rx ) ) { uint32_t data_offset = index - start_index; { systemic::SharedData portion( read_p + data_offset, current_step ); std::lock_guard guard(portion); for( int i = 0; i < current_step; i = i + bytes_in_char ) read_p[data_offset++] = page_buff_rx[i] | ( page_buff_rx[i+1] << 8u ); } index += current_step / bytes_in_char, timer.start( polling_time ); error_counter = 0; if( index == stop_index ) { read_p = 0; timer.stop(); proc_ctrl->disable(); } } i2c.discard(result); } else if( result->isError() ) //Завершили операцию с ошибкой. i2c.discard(result); //Ожидаем получения возможности осуществить транзакцию. } else if( peripheral::II2c::ITransaction * transaction = i2c.request( baud_rate, 8 ) ) { uint32_t address_data = index * bytes_in_char; char address_in_block[address_bytes_count]; address_in_block[0] = ( address_data >> 8u ) & 0xFFu ; //Формирование старшего байта адресации. address_in_block[1] = address_data & 0xFFu; //Формирование младшего байта адресации. current_step = ( bytes_in_char * (stop_index - index) > frame_step ? frame_step : bytes_in_char * (stop_index - index) ); transaction->addWriteRequest(address, address_in_block, address_bytes_count); transaction->addReadRequest( address, current_step); transaction->addStopCondition(); result = i2c.perform(transaction); } } else if( write_p ) { //Ожидаем результата. if( result ) { //Операция выполнена успешно. if( result->isComplete() ) { index += current_step / bytes_in_char, timer.start( polling_time ); error_counter = 0; if( index == stop_index ) { write_p = 0; timer.stop(); proc_ctrl->disable(); } i2c.discard(result); } else if( result->isError() ) //Операция завершилась ошибкой. i2c.discard(result); } else if( peripheral::II2c::ITransaction * transaction = i2c.request( baud_rate, 8 ) ) { uint32_t address_data = index * bytes_in_char; uint16_t byte_step = ( bytes_in_char * (stop_index - index) > frame_step ? frame_step : bytes_in_char * (stop_index - index) ); uint16_t start_page = address_data / page_size; uint16_t stop_page = ( address_data + byte_step ) / page_size; if( start_page != stop_page ) current_step = stop_page * page_size - address_data; else current_step = byte_step; uint32_t data_offset = index - start_index; uint16_t send_byte = current_step + address_bytes_count; page_buff[0] = ( address_data >> 8u ) & 0xFFu; //Формирование старшего байта адресации. page_buff[1] = address_data & 0xFFu; //Формирование младшего байта адресации. { systemic::ProtectedDataView portion( write_p + data_offset, current_step ); std::shared_lock guard(portion); for( int i = 0; i < current_step; i = i + bytes_in_char ) { page_buff[i + address_bytes_count] = write_p[data_offset] & 0xFF; page_buff[i+1 + address_bytes_count] = write_p[data_offset++] >> 8u; } } transaction->addWriteRequest( address, page_buff, send_byte ); transaction->addStopCondition(); result = i2c.perform(transaction); } } if( timer.delayFinished() ) { index = start_index; failed_request = false; if( error_counter < error_counter_failure ) error_counter++; i2c.discard(result), result = nullptr; i2c.reset(); timer.start( polling_time ); } } bool I2cEeprom24LCxxB::read( char * data, size_t start, size_t data_size ) { if( !proc_ctrl ) return false; if( read_p || write_p ) return false; if( data && start < size && data_size < size && start + data_size < size ) { if( not data_size ) return true; result = nullptr; read_p = data; start_index = start; index = start; stop_index = start + data_size; failed_request = false; proc_ctrl->enable(); timer.start( polling_time ); return true; } return false; } bool I2cEeprom24LCxxB::write( const char * data, size_t start, size_t data_size ) { if( !proc_ctrl ) return false; if( read_p || write_p ) return false; if( data && start < size && data_size < size && start + data_size < size ) { if( not data_size ) return true; result = nullptr; write_p = data; start_index = start; index = start; stop_index = start + data_size; failed_request = false; proc_ctrl->enable(); timer.start( polling_time ); return true; } return false; } bool I2cEeprom24LCxxB::isReadComplete() const { return not read_p; } bool I2cEeprom24LCxxB::isWriteComplete() const { return not write_p; } std::size_t driver::detail::I2cEeprom24LCxxB::getCapacity() const { return size; } bool I2cEeprom24LCxxB::isError() const { return error_counter >= error_counter_failure; }