263 lines
7.6 KiB
C++
263 lines
7.6 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;
|
||
}
|
||
|