/* * 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(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(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(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 driver::SlipCommunication::isPacketAvailable() const { return std::pair( incoming_packet, packet_head.packet_id ); } bool driver::SlipCommunication::isPacketSent() const { return bus.isDataSent() and not packet_start; }