/*! \file piprotocol.h * \brief Highly configurable from file I/O channel */ /* PIP - Platform Independent Primitives Protocol, input/output channel (COM, UDP) Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com, Bychkov Andrey wapmobil@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef PIPROTOCOL_H #define PIPROTOCOL_H #include "piserial.h" #include "piethernet.h" #include "pipacketextractor.h" #include "pitimer.h" #include "piconfig.h" #include "math.h" class PIProtocol; class PIP_EXPORT PIMultiProtocolBase: protected PIObject { PIOBJECT(PIMultiProtocolBase) friend class PIProtocol; public: PIMultiProtocolBase() {;} virtual ~PIMultiProtocolBase() {;} protected: virtual void received(PIProtocol * prot, bool corrected, uchar * data, int size) {;} private: static void receiveEvent(PIMultiProtocolBase * p, PIProtocol * prot, bool corrected, uchar * data, int size) {p->mutex_receive.lock(); p->received(prot, corrected, data, size); p->mutex_receive.unlock();} PIMutex mutex_receive; }; typedef void (*ReceiveFunc)(void * ); /// events: /// void receiverStarted() /// void receiverStopped() /// void senderStarted() /// void senderStopped() /// void received(bool validate_is_ok) /// void qualityChanged(PIProtocol::Quality old_quality, PIProtocol::Quality new_quality) /// /// handlers: /// void startReceive(float exp_frequency = -1.f) /// void stopReceive() /// void startSend(float frequency = -1.f) /// void stopSend() /// void start() /// void stop() /// void send() /// void send(const void * data, int size, bool direct = false) class PIP_EXPORT PIProtocol: public PIObject { PIOBJECT(PIProtocol) friend class PIMultiProtocolBase; friend class PIMultiProtocol; enum Type {None, Serial, Ethernet}; public: //! Contructs an empty unconfigured protocol PIProtocol(): PIObject() {init();} //! Contructs protocol configured from file "config", config file section "name" PIProtocol(const PIString & config, const PIString & name, void * recHeaderPtr = 0, int recHeaderSize = 0, void * recDataPtr = 0, int recDataSize = 0, void * sendDataPtr = 0, int sendDataSize = 0); // from config virtual ~PIProtocol(); //! Connection quality enum Quality { Unknown /** Unknown, no one packet received yet */ = 1, Failure /** No connection, no one correct packet received for last period */ = 2, Bad /** Bad connection, correct packets received <= 20% */ = 3, Average /** Average connection, correct packets received > 20% and <= 80% */ = 4, Good /** Good connection, correct packets received > 80% */ = 5 }; EVENT_HANDLER0(void, startReceive) {startReceive(-1.f);} EVENT_HANDLER1(void, startReceive, float, exp_frequency); // if "frequency = -1" used last passed value EVENT_HANDLER0(void, stopReceive); void setExpectedFrequency(float frequency); // for connection quality diagnostic void setReceiverDevice(const PIString & device, PISerial::Speed speed, bool force = false); // for Serial void setReceiverData(void * dataPtr, int dataSize) {this->dataPtr = (uchar * )dataPtr; this->dataSize = dataSize; packet_ext->setPacketData(headerPtr, headerSize, dataSize);} void setReceiverDataHeader(void * headerPtr, int headerSize) {this->headerPtr = (uchar * )headerPtr; this->headerSize = headerSize; packet_ext->setPacketData(headerPtr, headerSize, dataSize);} void setReceiverAddress(const PIString & ip, int port, bool force = false); // for Ethernet void setReceiverParameters(PIFlags parameters) {if (type_rec == PIProtocol::Serial || type_send == PIProtocol::Serial) ser->setParameters(parameters);} // for Serial void setReceiveSlot(ReceiveFunc slot) {ret_func = slot;} float expectedFrequency() const {return exp_freq;} EVENT_HANDLER0(void, startSend) {startSend(-1.f);} // if "frequency = -1" used last passed value EVENT_HANDLER1(void, startSend, float, frequency); // if "frequency = -1" used last passed value EVENT_HANDLER0(void, stopSend) {sendTimer->stop(); senderStopped();} void setSenderFrequency(float frequency) {send_freq = frequency;} void setSenderDevice(const PIString & device, PISerial::Speed speed, bool force = false); // for Serial void setSenderData(void * dataPtr, int dataSize) {sendDataPtr = (uchar * )dataPtr; sendDataSize = dataSize;} void setSenderAddress(const PIString & ip, int port, bool force = false); // for Ethernet void setSenderIP(const PIString & ip, bool force = false); // for Ethernet void setSenderPort(int port, bool force = false); // for Ethernet void setSenderParameters(PIFlags parameters) {if (type_send == PIProtocol::Serial) ser->setParameters(parameters);} // for Serial float senderFrequency() const {return send_freq;} EVENT_HANDLER0(void, start) {startReceive(); startSend();} EVENT_HANDLER0(void, stop) {stopReceive(); stopSend();} EVENT_HANDLER0(void, send); EVENT_HANDLER2(void, send, const void *, data, int, size) {send(data, size, false);} EVENT_HANDLER3(void, send, const void *, data, int, size, bool, direct); void setName(const PIString & name) {protName = name; PIObject::setName(name);} PIString name() const {return protName;} void setDisconnectTimeout(float timeout) {timeout_ = timeout; changeDisconnectTimeout();} float disconnectTimeout() const {return timeout_;} const float * disconnectTimeout_ptr() const {return &timeout_;} float immediateFrequency() const {return immediate_freq;} float integralFrequency() const {return integral_freq;} const float * immediateFrequency_ptr() const {return &immediate_freq;} const float * integralFrequency_ptr() const {return &integral_freq;} ullong receiveCountPerSec() const {return packets_in_sec;} const ullong * receiveCountPerSec_ptr() const {return &packets_in_sec;} ullong sendCountPerSec() const {return packets_out_sec;} const ullong * sendCountPerSec_ptr() const {return &packets_out_sec;} ullong receiveBytesPerSec() const {return bytes_in_sec;} const ullong * receiveBytesPerSec_ptr() const {return &bytes_in_sec;} ullong sendBytesPerSec() const {return bytes_out_sec;} const ullong * sendBytesPerSec_ptr() const {return &bytes_out_sec;} ullong receiveCount() const {return receive_count;} const ullong * receiveCount_ptr() const {return &receive_count;} ullong wrongCount() const {return wrong_count;} const ullong * wrongCount_ptr() const {return &wrong_count;} ullong sendCount() const {return send_count;} const ullong * sendCount_ptr() const {return &send_count;} ullong missedCount() const {return missed_count;} const ullong * missedCount_ptr() const {return &missed_count;} PIProtocol::Quality quality() const {return net_diag;} // receive quality const int * quality_ptr() const {return (int * )&net_diag;} // receive quality pointer PIString receiverDeviceName() const {return devReceiverName;} PIString senderDeviceName() const {return devSenderName;} PIString receiverDeviceState() const {return devReceiverState;} const PIString * receiverDeviceState_ptr() const {return &devReceiverState;} PIString senderDeviceState() const {return devSenderState;} const PIString * senderDeviceState_ptr() const {return &devSenderState;} PIString receiveSpeed() const {return speedIn;} const PIString * receiveSpeed_ptr() const {return &speedIn;} PIString sendSpeed() const {return speedOut;} const PIString * sendSpeed_ptr() const {return &speedOut;} PIString receiverHistorySize() const {return history_rsize_rec;} const PIString * receiverHistorySize_ptr() const {return &history_rsize_rec;} PIString senderHistorySize() const {return history_rsize_send;} const PIString * senderHistorySize_ptr() const {return &history_rsize_send;} bool writeReceiverHistory() const {return history_write_rec;} const bool * writeReceiverHistory_ptr() const {return &history_write_rec;} bool writeSenderHistory() const {return history_write_send;} const bool * writeSenderHistory_ptr() const {return &history_write_send;} void * receiveData() {return dataPtr;} void * sendData() {return sendDataPtr;} PIPacketExtractor * packetExtractor() {return packet_ext;} PIByteArray lastHeader() {return packet_ext->lastHeader();} EVENT0(receiverStarted) EVENT0(receiverStopped) EVENT0(senderStarted) EVENT0(senderStopped) EVENT1(received, bool, validate_is_ok) EVENT2(qualityChanged, PIProtocol::Quality, new_quality, PIProtocol::Quality, old_quality) protected: virtual bool receive(uchar * data, int size) {if (dataPtr != 0) memcpy(dataPtr, data, size); return true;} // executed when raw data received, break if 'false' return virtual bool validate() {return true;} // function for validate algorithm and save data from dataPtr to external struct virtual bool headerValidate(uchar * src, uchar * rec, int size) {for (int i = 0; i < size; ++i) if (src[i] != rec[i]) return false; return true;} // function for validate header (COM-port and headerSize > 0) virtual uint checksum_i(void * data, int size) { // function for checksum (uint) uint c = 0; for (int i = 0; i < size; ++i) c += ((uchar*)data)[i]; return ~(c + 1); } virtual uchar checksum_c(void * data, int size) { // function for checksum (uchar) uchar c = 0; for (int i = 0; i < size; ++i) c += ((uchar*)data)[i]; return ~(c + 1); } virtual bool aboutSend() {return true;} // executed before send data, if return 'false' then data is not sending void init(); void init_sender(PIConfig::Entry & b, PIConfig::Entry & sb, const PIString & config); void init_receiver(PIConfig::Entry & b, PIConfig::Entry & rb, const PIString & config); void check_state(); void calc_freq(); void calc_diag(); PISerial * ser; PIEthernet * eth; uint dataSize, headerSize, sendDataSize; uchar * dataPtr, * headerPtr, * sendDataPtr; private: static void sendEvent(void * e, int) {((PIProtocol * )e)->send();} static bool receiveEvent(void * t, uchar * data, int size); static bool headerValidateEvent(void * t, uchar * src, uchar * rec, int size) {return ((PIProtocol * )t)->headerValidate(src, rec, size);} static void diagEvent(void * t, int); static void secEvent(void * t, int); void setMultiProtocolOwner(PIMultiProtocolBase * mp) {mp_owner = mp;} PIMultiProtocolBase * multiProtocolOwner() const {return mp_owner;} void changeDisconnectTimeout(); ReceiveFunc ret_func; PIPacketExtractor * packet_ext; PITimer * diagTimer, * sendTimer, * secTimer; PIMultiProtocolBase * mp_owner; PIProtocol::Type type_send, type_rec; PIProtocol::Quality net_diag; PIDeque last_freq; PIDeque last_packets; PIString protName, devReceiverName, devReceiverState, devSenderName, devSenderState, speedIn, speedOut; PIString history_path_rec, history_path_send, history_rsize_rec, history_rsize_send; PIFile history_file_rec, history_file_send; ushort history_id_rec, history_id_send; bool work, new_mp_prot, history_write_rec, history_write_send; float exp_freq, send_freq, ifreq, immediate_freq, integral_freq, timeout_; int packets[2], pckt_cnt, pckt_cnt_max; char cur_pckt; ullong wrong_count, receive_count, send_count, missed_count, packets_in_sec, packets_out_sec, bytes_in_sec, bytes_out_sec; }; #endif // PIPROTOCOL_H