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