437 lines
9.6 KiB
C++
437 lines
9.6 KiB
C++
/*
|
||
* SlipCommunication.cpp
|
||
*
|
||
* Created on: 31 марта 2017 г.
|
||
* Author: titov
|
||
*/
|
||
|
||
#include "SlipCommunication.hh"
|
||
//#include "../common/Literals.hh"
|
||
|
||
namespace driver {
|
||
|
||
//!< Объединение для конвертации двухбайтовых велечин в побайтовые
|
||
union TUShortToBytes
|
||
{
|
||
unsigned short UShortValue; //!<Двубайтовая целочисленная переменная
|
||
//!<Массив из двух байт.
|
||
struct
|
||
{
|
||
unsigned short Lo:8; //!<Младшая часть двубайтовой переменной
|
||
unsigned short Hi:8; //!<Старшая часть двубайтовой переменной
|
||
} byteValue; //!<массив из двух байт
|
||
};
|
||
|
||
void SlipCommunication::recieve_restart() {
|
||
count_head_byte = count_data_byte = count_crc16_byte = 0;
|
||
receive_mode = TReceiveMode::HEAD;
|
||
data_ready = false;
|
||
}
|
||
|
||
void SlipCommunication::create_packet() {
|
||
if(crc16rec.get() == packet_crc16 ) {
|
||
//В этот момент пакет полностью принят.
|
||
totalRecLength = packet_head.packet_size;
|
||
incoming_packet++;
|
||
//Прием пакета закончен, ожидаем новый пакет.
|
||
recieve_restart();
|
||
} else {
|
||
//Сбрасываем неправильные данные.
|
||
recieveReset();
|
||
}
|
||
|
||
}
|
||
|
||
bool SlipCommunication::packet_end() const {
|
||
return !(count_head_byte || count_data_byte || count_crc16_byte) || (receive_mode == TReceiveMode::STOP);
|
||
}
|
||
|
||
bool SlipCommunication::data_collection(char byte) {
|
||
switch(receive_mode) {
|
||
case TReceiveMode::HEAD: {
|
||
crc16rec.calcPartial(&byte, 1, !count_head_byte);
|
||
|
||
head_buff[count_head_byte] = byte;
|
||
count_head_byte++;
|
||
|
||
if(count_head_byte == head_size) {
|
||
packet_head.deserialize(head_buff);
|
||
|
||
bool addressed = (packet_head.hw_address == hw_address || packet_head.hw_address == 0xFFFFU);
|
||
|
||
if(!addressed)
|
||
receive_mode = TReceiveMode::SLEEP;
|
||
else if(packet_head.packet_size > 0 && packet_head.packet_size < max_datasize)
|
||
receive_mode = TReceiveMode::DATA;
|
||
else if(packet_head.packet_size == 0)
|
||
receive_mode = TReceiveMode::CRC16;
|
||
else
|
||
recieve_restart();
|
||
}
|
||
break;
|
||
}
|
||
case TReceiveMode::DATA: {
|
||
crc16rec.calcPartial(&byte, 1 , false);
|
||
|
||
receiveBuffer.put(byte);
|
||
count_data_byte++;
|
||
|
||
if(count_data_byte == packet_head.packet_size) {
|
||
|
||
receive_mode = TReceiveMode::CRC16;
|
||
}
|
||
break;
|
||
}
|
||
case TReceiveMode::CRC16: {
|
||
crc16_buff[count_crc16_byte] = byte;
|
||
count_crc16_byte++;
|
||
|
||
if(count_crc16_byte == crc16_size) {
|
||
deserialize_crc16();
|
||
|
||
receive_mode = TReceiveMode::STOP;
|
||
}
|
||
break;
|
||
}
|
||
default: break;
|
||
}
|
||
|
||
return receive_mode == TReceiveMode::STOP;
|
||
}
|
||
|
||
unsigned short SlipCommunication::slip_decode(char byte) {
|
||
if(byte_db_recived) {
|
||
byte_db_recived = false;
|
||
switch(byte) {
|
||
case TSlipDecode::DC:
|
||
return 0xC0u;//(TSlipDecode::C0 & 0xFFu);
|
||
case TSlipDecode::DD:
|
||
return 0xDBu;//(TSlipDecode::DB & 0xFFu);
|
||
default:
|
||
return TSlipDecode::ERROR;
|
||
}
|
||
} else {
|
||
switch(byte) {
|
||
case TSlipDecode::DB:
|
||
byte_db_recived = true;
|
||
return TSlipDecode::NOTBYTE;
|
||
case TSlipDecode::C0:
|
||
return TSlipDecode::END;
|
||
default:
|
||
return byte;
|
||
}
|
||
}
|
||
}
|
||
|
||
bool SlipCommunication::byte_processing(char byte) {
|
||
unsigned short symbol = slip_decode(byte); //Декодируем байт.
|
||
|
||
switch(symbol) { //Обрабатываем байт ->
|
||
case TSlipDecode::ERROR:
|
||
recieveReset(); //Сбрасываем данные.
|
||
break;
|
||
case TSlipDecode::NOTBYTE:
|
||
break; //Пропускаем байт.
|
||
case TSlipDecode::END:
|
||
if(data_ready) create_packet(); //Оформляем пакет.
|
||
else recieveReset(); //Сбрасываем данные.
|
||
break;
|
||
default:
|
||
if(data_ready) recieveReset(); //Сбрасываем данные.
|
||
else data_ready = data_collection(symbol); //Собираем данные.
|
||
break;
|
||
}
|
||
|
||
return packet_end(); //Возращаем признак окончания пакета.
|
||
}
|
||
|
||
bool SlipCommunication::slip_send(char byte) {
|
||
bool result;
|
||
char tmpByte[2];
|
||
|
||
switch( byte ) {
|
||
case TSlipDecode::C0:
|
||
tmpByte[0] = 0xDBu;//TSlipDecode::DB;
|
||
tmpByte[1] = 0xDCu;//TSlipDecode::DC;
|
||
|
||
result = bus.send( tmpByte, 2 );
|
||
break;
|
||
|
||
case TSlipDecode::DB:
|
||
tmpByte[0] = 0xDBu;//TSlipDecode::DB;
|
||
tmpByte[1] = 0xDDu;//TSlipDecode::DD;
|
||
|
||
result = bus.send( tmpByte, 2 );
|
||
break;
|
||
|
||
default:
|
||
|
||
result = bus.send( &byte, 1 );
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
bool SlipCommunication::send_word_without_crc(unsigned short word) {
|
||
bool result;
|
||
TUShortToBytes convert;
|
||
char tmpc;
|
||
|
||
convert.UShortValue = word;
|
||
|
||
tmpc = convert.byteValue.Lo;
|
||
result = slip_send(tmpc);
|
||
|
||
tmpc = convert.byteValue.Hi;
|
||
result = result && slip_send(tmpc);
|
||
|
||
return result;
|
||
}
|
||
|
||
bool SlipCommunication::send_word_with_crc(unsigned short word) {
|
||
bool result;
|
||
TUShortToBytes convert;
|
||
char tmpc;
|
||
|
||
convert.UShortValue = word;
|
||
|
||
tmpc = convert.byteValue.Lo;
|
||
crc16send.calcPartial( &tmpc, 1, false );
|
||
result = slip_send(tmpc);
|
||
|
||
tmpc = convert.byteValue.Hi;
|
||
crc16send.calcPartial( &tmpc, 1, false );
|
||
result = result && slip_send( tmpc );
|
||
|
||
return result;
|
||
}
|
||
|
||
void SlipCommunication::deserialize_crc16() {
|
||
TUShortToBytes converter;
|
||
converter.byteValue.Lo = crc16_buff[0];
|
||
converter.byteValue.Hi = crc16_buff[1];
|
||
packet_crc16 = converter.UShortValue;
|
||
}
|
||
|
||
void SlipCommunication::recieveReset() {
|
||
|
||
// while(count_data_byte--) {
|
||
// char temp;
|
||
// receiveBuffer->Pop(&temp);
|
||
// }
|
||
|
||
receiveBuffer.clear();
|
||
incoming_packet = 0;
|
||
recieve_restart();
|
||
}
|
||
|
||
bool SlipCommunication::sendHead(unsigned short id, unsigned short size) noexcept {
|
||
bool result;
|
||
|
||
packet_start = true;
|
||
|
||
de.on();
|
||
|
||
crc16send.calcPartial( 0, 0, true );
|
||
|
||
result = send_word_with_crc(size);
|
||
result = result && send_word_with_crc(id);
|
||
result = result && send_byte_with_crc(hw_address);
|
||
|
||
return result;
|
||
}
|
||
|
||
bool SlipCommunication::sendEnd() noexcept {
|
||
char tmpc = TSlipDecode::C0;
|
||
|
||
packet_start = false;
|
||
|
||
return send_word_without_crc(crc16send.get()) && bus.send( &tmpc, 1 );
|
||
}
|
||
|
||
void SlipCommunication::send_reset() {
|
||
char tmpc = TSlipDecode::C0;
|
||
bus.reset();
|
||
bus.send( &tmpc, 1 );
|
||
}
|
||
|
||
SlipCommunication::SlipCommunication(
|
||
peripheral::IUartPort & bus,
|
||
driver::IDiscreteOutput & de ) :
|
||
bus(bus), de(de),
|
||
|
||
receiveBuffer(),
|
||
|
||
error_count(0),
|
||
max_error(1000u),
|
||
bus_enable(true),
|
||
|
||
hw_address(0),
|
||
|
||
packet_crc16(0),
|
||
|
||
max_datasize(128),
|
||
|
||
incoming_packet(0),
|
||
|
||
totalRecLength(0),
|
||
byte_db_recived(false),
|
||
|
||
count_crc16_byte(0),
|
||
count_data_byte(0),
|
||
count_head_byte(0),
|
||
|
||
data_ready(false),
|
||
|
||
packet_head(),
|
||
receive_mode(TReceiveMode::HEAD),
|
||
timeout() {
|
||
|
||
recieve_restart();
|
||
|
||
}
|
||
|
||
SlipCommunication::~SlipCommunication() {}
|
||
|
||
unsigned short SlipCommunication::recieve_word() {
|
||
char tmpc;
|
||
TUShortToBytes converter;
|
||
|
||
tmpc = receiveBuffer.push();
|
||
converter.byteValue.Lo = tmpc;
|
||
tmpc = receiveBuffer.push();
|
||
converter.byteValue.Hi = tmpc;
|
||
|
||
return converter.UShortValue;
|
||
}
|
||
|
||
void SlipCommunication::setAddress(unsigned short address) {
|
||
hw_address = address;
|
||
}
|
||
|
||
bool SlipCommunication::send_byte_with_crc(unsigned char byte) {
|
||
bool result;
|
||
|
||
char tmpc = byte;
|
||
|
||
crc16send.calcPartial( &tmpc, 1, false );
|
||
result = slip_send(tmpc);
|
||
|
||
return result;
|
||
}
|
||
|
||
void SlipCommunication::process() {
|
||
bool error = bus.isRecieptionError();
|
||
|
||
if( bus_enable && error )
|
||
++error_count;
|
||
|
||
if( error )
|
||
bus.reset();
|
||
|
||
// if(bus_enable && error_count > max_error) {
|
||
// bus.receivedReset();
|
||
// bus.intDisable();
|
||
// bus_enable = false;
|
||
// }
|
||
|
||
int i = 32;
|
||
char byte;
|
||
|
||
while(!incoming_packet && i-- && bus.receive(&byte, 1)) {
|
||
|
||
error_count = 0;
|
||
|
||
byte_processing(byte);
|
||
|
||
}
|
||
|
||
if( ( bus.isDataSent() and not packet_start ) )
|
||
de.off();
|
||
|
||
}
|
||
|
||
void SlipCommunication::THead::deserialize(char (&buff)[head_size]) {
|
||
|
||
TUShortToBytes converter;
|
||
converter.byteValue.Lo = buff[0];
|
||
converter.byteValue.Hi = buff[1];
|
||
packet_size = converter.UShortValue;
|
||
converter.byteValue.Lo = buff[2];
|
||
converter.byteValue.Hi = buff[3];
|
||
packet_id = converter.UShortValue;
|
||
hw_address = buff[4];
|
||
|
||
}
|
||
|
||
|
||
bool SlipCommunication::recieve_data(char * data, short length) {
|
||
bool result = incoming_packet;
|
||
|
||
if( incoming_packet ) {
|
||
|
||
char * ptr_data = reinterpret_cast<char *>(data);
|
||
|
||
int i;
|
||
for(i = 0; i < length && totalRecLength; i++, totalRecLength-- )
|
||
ptr_data[i] = recieve_byte();
|
||
|
||
if( totalRecLength == 0 && i != length ) result = false;
|
||
if( totalRecLength == 0 ) incoming_packet--;
|
||
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
bool SlipCommunication::send_packet(unsigned short id, const char * data, short length) {
|
||
return sendHead(id, length) && send(data, length) && sendEnd();
|
||
}
|
||
|
||
char SlipCommunication::recieve_byte() {
|
||
return receiveBuffer.push();
|
||
}
|
||
|
||
bool driver::SlipCommunication::send( const char * data, std::size_t size ) {
|
||
bool result = true;
|
||
const unsigned short * ptr_data = reinterpret_cast<const unsigned short *>(data);
|
||
|
||
for( int i = 0; i < size; i++ )
|
||
result = result && send_word_with_crc(ptr_data[i]);
|
||
|
||
return result;
|
||
}
|
||
|
||
bool driver::SlipCommunication::receive( char * data, std::size_t size ) {
|
||
bool result = incoming_packet;
|
||
|
||
if( incoming_packet )
|
||
{
|
||
unsigned short * ptr_data = reinterpret_cast<unsigned short *>(data);
|
||
|
||
int i;
|
||
for(i = 0; i < size && totalRecLength; i++, totalRecLength -= 2 )
|
||
ptr_data[i] = recieve_word();
|
||
|
||
if( totalRecLength == 0 && i != size ) result = false;
|
||
if( totalRecLength == 0 ) incoming_packet--;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
}
|
||
|
||
std::pair<bool, unsigned short> driver::SlipCommunication::isPacketAvailable() const {
|
||
|
||
return std::pair<bool, unsigned short>( incoming_packet, packet_head.packet_id );
|
||
|
||
}
|
||
|
||
bool driver::SlipCommunication::isPacketSent() const {
|
||
|
||
return bus.isDataSent() and not packet_start;
|
||
|
||
}
|