MotorControlModuleSDFM_TMS3.../Projects/EFC_Application/UMLibrary/driver/I2cEeprom24LCxxB.cpp

263 lines
7.2 KiB
C++

/*
* I2cEeprom24LCxxB.cpp
*
* Created on: 14 àïð. 2018 ã.
* Author: Pair programming
*/
#include <cmath>
#include "I2cEeprom24LCxxB.hh"
#include "../systemic/SharedData.hh"
#include <mutex>
#include <shared_mutex>
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<systemic::SharedData> 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<systemic::ProtectedDataView> 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;
}