1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-29 07:24:13 +01:00

3rd attempt to add files!

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@2506 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
pip 2011-01-21 13:09:04 +00:00 committed by pip
parent aec73a209d
commit 0d912d130d
8 changed files with 1329 additions and 0 deletions

View File

@ -0,0 +1,18 @@
#ifndef COMMON_H
#define COMMON_H
enum decodeState_ {
decode_len1_e = 0,
decode_seqNo_e,
decode_data_e,
decode_crc1_e,
decode_crc2_e,
decode_idle_e
};
enum ReceiveState {
state_escaped_e = 0,
state_unescaped_e
};
#endif // COMMON_H

View File

@ -0,0 +1,46 @@
#include "port.h"
#include "delay.h"
port::port(PortSettings settings,QString name):mstatus(port::closed)
{
timer.start();
sport = new QextSerialPort(name,settings, QextSerialPort::Polling);
if(sport->open(QIODevice::ReadWrite|QIODevice::Unbuffered))
{
mstatus=port::open;
// sport->setDtr();
}
else
mstatus=port::error;
}
port::~port() {
sport->close();
}
port::portstatus port::status()
{
return mstatus;
}
int16_t port::pfSerialRead(void)
{
char c[1];
if( sport->bytesAvailable() )
{
sport->read(c,1);
}
else return -1;
return (uint8_t)c[0];
}
void port::pfSerialWrite(uint8_t c)
{
char cc[1];
cc[0]=c;
sport->write(cc,1);
}
uint32_t port::pfGetTime(void)
{
return timer.elapsed();
}

View File

@ -0,0 +1,49 @@
#ifndef PORT_H
#define PORT_H
#include <stdint.h>
#include <qextserialport/src/qextserialport.h>
#include <QTime>
#include <QDebug>
#include "common.h"
class port
{
public:
enum portstatus{open,closed,error};
virtual int16_t pfSerialRead(void); // function to read a character from the serial input stream
virtual void pfSerialWrite( uint8_t ); // function to write a byte to be sent out the serial port
virtual uint32_t pfGetTime(void);
uint8_t retryCount; // how many times have we tried to transmit the 'send' packet
uint8_t maxRetryCount; // max. times to try to transmit the 'send' packet
uint16_t max_retry; // Maximum number of retrys for a single transmit.
int32_t timeoutLen; // how long to wait for each retry to succeed
int32_t timeout; // current timeout. when 'time' reaches this point we have timed out
uint8_t txSeqNo; // current 'send' packet sequence number
uint16_t rxBufPos; // current buffer position in the receive packet
uint16_t rxBufLen; // number of 'data' bytes in the buffer
uint8_t rxSeqNo; // current 'receive' packet number
uint16_t rxBufSize; // size of the receive buffer.
uint16_t txBufSize; // size of the transmit buffer.
uint8_t *txBuf; // transmit buffer. REquired to store a copy of packet data in case a retry is needed.
uint8_t *rxBuf; // receive buffer. Used to store data as a packet is received.
uint16_t sendSynch; // flag to indicate that we should send a synchronize packet to the host
// this is required when switching from the application to the bootloader
// and vice-versa. This fixes the firwmare download timeout.
// when this flag is set to true, the next time we send a packet we will first // send a synchronize packet.
ReceiveState InputState;
decodeState_ DecodeState;
uint16_t SendState;
uint16_t crc;
uint32_t RxError;
uint32_t TxError;
uint16_t flags;
port(PortSettings settings,QString name);
~port();
portstatus status();
private:
portstatus mstatus;
QTime timer;
QextSerialPort *sport;
};
#endif // PORT_H

View File

@ -0,0 +1,781 @@
#include "qssp.h"
#include <stdint.h>
#include <string.h>
#include <stdio.h>
/** PRIVATE DEFINITIONS **/
#define SYNC 225 // Sync character used in Serial Protocol
#define ESC 224 // ESC character used in Serial Protocol
#define ESC_SYNC 1 // ESC_SYNC character used in Serial Protocol
#define ACK_BIT 0x80 // Ack bit, bit 7 of sequence number, 1 = Acknowledge, 0 =
// new packet
// packet location definitions.
#define LENGTH 0
#define SEQNUM 1
#define DATA 2
// Make larger sized integers from smaller sized integers
#define MAKEWORD16( ub, lb ) ((uint16_t)0x0000 | ((uint16_t)(ub) << 8) | (uint16_t)(lb) )
#define MAKEWORD32( uw, lw ) ((uint32_t)(0x0UL | ((uint32_t)(uw) << 16) | (uint32_t)(lw)) )
#define MAKEWORD32B( b3, b2, b1, b0 ) ((uint32_t)((uint32_t)(b3)<< 24) | ((uint32_t)(b2)<<16) | ((uint32_t)(b1)<<8) | ((uint32_t)(b0) )
// Used to extract smaller integers from larger sized intergers
#define LOWERBYTE( w ) (uint8_t)((w) & 0x00ff )
#define UPPERBYTE( w ) (uint8_t)(((w) & 0xff00) >> 8 )
#define UPPERWORD(lw) (uint16_t)(((lw) & 0xffff0000) >> 16 )
#define LOWERWORD(lw) (uint16_t)((lw) & 0x0000ffff)
// Macros to operate on a target and bitmask.
#define CLEARBIT( a, b ) ((a) = (a) & ~(b))
#define SETBIT( a, b ) ((a) = (a) | (b) )
#define TOGGLEBIT(a,b) ((a) = (a) ^ (b) )
// test bit macros operate using a bit mask.
#define ISBITSET( a, b ) ( ((a) & (b)) == (b) ? TRUE : FALSE )
#define ISBITCLEAR( a, b) ( (~(a) & (b)) == (b) ? TRUE : FALSE )
/* Flag bit masks...*/
#define SENT_SYNCH (0x01)
#define ACK_RECEIVED (0x02)
#define ACK_EXPECTED (0x04)
#define SSP_AWAITING_ACK 0
#define SSP_ACKED 1
#define SSP_IDLE 2
/** PRIVATE DATA **/
static const uint16_t CRC_TABLE[] = {
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
/** EXTERNAL DATA **/
/** EXTERNAL FUNCTIONS **/
/** VERIFICATION FUNCTIONS **/
/***********************************************************************************************************/
/*!
* \brief Initializes the communication port for use
* \param thisport = pointer to port structure to initialize
* \param info = config struct with default values.
* \return None.
*
* \note
* Must be called before calling the Send or REceive process functions.
*/
void qssp::ssp_Init(const PortConfig_t* const info)
{
thisport->maxRetryCount = info->max_retry;
thisport->timeoutLen = info->timeoutLen;
thisport->txBufSize = info->txBufSize;
thisport->rxBufSize = info->rxBufSize;
thisport->txBuf = info->txBuf;
thisport->rxBuf = info->rxBuf;
thisport->retryCount = 0;
thisport->sendSynch = FALSE; //TRUE;
thisport->rxSeqNo = 255;
thisport->txSeqNo = 255;
thisport->SendState = SSP_IDLE;
thisport->InputState =(ReceiveState)0;
thisport->DecodeState =(decodeState_)0;
thisport->TxError =0;
thisport->RxError =0;
thisport->txSeqNo =0;
thisport->rxSeqNo =0;
}
/*!
* \brief Runs the send process, checks for receipt of ack, timeouts and resends if needed.
* \param thisport = which port to use
* \return SSP_TX_WAITING - waiting for a valid ACK to arrive
* \return SSP_TX_TIMEOUT - failed to receive a valid ACK in the timeout period, after retrying.
* \return SSP_TX_IDLE - not expecting a ACK packet (no current transmissions in progress)
* \return SSP_TX_ACKED - valid ACK received before timeout period.
*
* \note
*
*/
int16_t qssp::ssp_SendProcess( )
{
int16_t value = SSP_TX_WAITING;
if (thisport->SendState == SSP_AWAITING_ACK ) {
if (sf_CheckTimeout() == TRUE) {
if (thisport->retryCount < thisport->maxRetryCount) {
// Try again
sf_SendPacket();
sf_SetSendTimeout();
value = SSP_TX_WAITING;
} else {
// Give up, # of trys has exceded the limit
value = SSP_TX_TIMEOUT;
CLEARBIT( thisport->flags, ACK_RECEIVED);
thisport->SendState = SSP_IDLE;
if (debug)
qDebug()<<"Send TimeOut!";
}
} else {
value = SSP_TX_WAITING;
}
} else if( thisport->SendState == SSP_ACKED ) {
SETBIT( thisport->flags, ACK_RECEIVED);
value = SSP_TX_ACKED;
thisport->SendState = SSP_IDLE;
} else {
thisport->SendState = SSP_IDLE;
value = SSP_TX_IDLE;
}
return value;
}
/*!
* \brief Runs the receive process. fetches a byte at a time and runs the byte through the protocol receive state machine.
* \param thisport - which port to use.
* \return receive status.
*
* \note
*
*/
int16_t qssp::ssp_ReceiveProcess()
{
int16_t b;
int16_t packet_status = SSP_RX_IDLE;
do {
b = thisport->pfSerialRead(); // attempt to read a char from the serial buffer
if (b != -1) {
packet_status = sf_ReceiveState(b); // process the newly received byte in the receive state machine
}
// keep going until either we received a full packet or there are no more bytes to process
} while (packet_status != SSP_RX_COMPLETE && b != -1);
return packet_status;
}
/*!
* \brief processes a single byte through the receive state machine.
* \param thisport = which port to use
* \return current receive status
*
* \note
*
*/
int16_t qssp::ssp_ReceiveByte()
{
int16_t b;
int16_t packet_status = SSP_RX_IDLE;
b = thisport->pfSerialRead();
if( b != -1 ) {
packet_status = sf_ReceiveState(b);
}
return packet_status;
}
/*!
* \brief Sends a data packet and blocks until timeout or ack is received.
* \param thisport = which port to use
* \param data = pointer to data to send
* \param length = number of data bytes to send. Must be less than 254
* \return true = ack was received within number of retries
* \return false = ack was not received.
*
* \note
*
*/
uint16_t qssp::ssp_SendDataBlock(uint8_t *data, uint16_t length )
{
int16_t packet_status = SSP_TX_WAITING;
uint16_t retval = FALSE;
packet_status = ssp_SendData(data, length ); // send the data
while( packet_status == SSP_TX_WAITING ) { // check the status
(void)ssp_ReceiveProcess(); // process any bytes received.
packet_status = ssp_SendProcess(); // check the send status
}
if( packet_status == SSP_TX_ACKED ) { // figure out what happened to the packet
retval = TRUE;
} else {
retval = FALSE;
}
return retval;
}
/*!
* \brief sends a chunk of data and does not block
* \param thisport = which port to use
* \param data = pointer to data to send
* \param length = number of bytes to send
* \return SSP_TX_BUFOVERRUN = tried to send too much data
* \return SSP_TX_WAITING = data sent and waiting for an ack to arrive
* \return SSP_TX_BUSY = a packet has already been sent, but not yet acked
*
* \note
*
*/
int16_t qssp::ssp_SendData(const uint8_t *data, const uint16_t length )
{
int16_t value = SSP_TX_WAITING;
if( (length + 2) > thisport->txBufSize ) {
// TRYING to send too much data.
value = SSP_TX_BUFOVERRUN;
} else if( thisport->SendState == SSP_IDLE ) {
#ifdef ACTIVE_SYNCH
if( thisport->sendSynch == TRUE ) {
sf_SendSynchPacket();
}
#endif
#ifdef SYNCH_SEND
if( length == 0 ) {
// TODO this method could allow a task/user to start a synchronisation step if a zero is mistakenly passed to this function.
// could add a check for a NULL data pointer, or use some sort of static flag that can only be accessed by a static function
// that must be called before calling this function.
// we are attempting to send a synch packet
thisport->txSeqNo = 0; // make this zero to cause the other end to re-synch with us
SETBIT(thisport->flags, SENT_SYNCH);
} else {
// we are sending a data packet
CLEARBIT( thisport->txSeqNo, ACK_BIT ); // make sure we are not sending a ACK packet
thisport->txSeqNo++; // update the sequence number.
if( thisport->txSeqNo > 0x7F) { // check for sequence number rollover
thisport->txSeqNo = 1; // if we do have rollover then reset to 1 not zero,
// zero is reserviced for synchronization requests
}
}
#else
CLEARBIT( thisport->txSeqNo, ACK_BIT ); // make sure we are not sending a ACK packet
thisport->txSeqNo++; // update the sequence number.
if( thisport->txSeqNo > 0x7F) { // check for sequence number rollover
thisport->txSeqNo = 1; // if we do have rollover then reset to 1 not zero,
// zero is reserved for synchronization requests
}
#endif
CLEARBIT( thisport->flags, ACK_RECEIVED);
thisport->SendState = SSP_AWAITING_ACK;
value = SSP_TX_WAITING;
thisport->retryCount = 0; // zero out the retry counter for this transmission
sf_MakePacket( thisport->txBuf, data, length, thisport->txSeqNo );
sf_SendPacket( ); // punch out the packet to the serial port
sf_SetSendTimeout( ); // do the timeout values
if (debug)
qDebug()<<"Sent DATA PACKET:"<<thisport->txSeqNo;
} else {
// error we are already sending a packet. Need to wait for the current packet to be acked or timeout.
value = SSP_TX_BUSY;
if (debug)
qDebug()<<"Error sending TX was busy";
}
return value;
}
/*!
* \brief Attempts to synchronize the sequence numbers with the other end of the connectin.
* \param thisport = which port to use
* \return true = success
* \return false = failed to receive an ACK to our synch request
*
* \note
* A. send a packet with a sequence number equal to zero
* B. if timed out then:
* send synch packet again
* increment try counter
* if number of tries exceed maximum try limit then exit
* C. goto A
*/
uint16_t qssp::ssp_Synchronise( )
{
int16_t packet_status;
uint16_t retval = FALSE;
#ifndef USE_SENDPACKET_DATA
thisport->txSeqNo = 0; // make this zero to cause the other end to re-synch with us
SETBIT(thisport->flags, SENT_SYNCH);
// TODO - should this be using ssp_SendPacketData()??
sf_MakePacket( thisport->txBuf, NULL, 0, thisport->txSeqNo ); // construct the packet
sf_SendPacket( );
sf_SetSendTimeout( );
thisport->SendState = SSP_AWAITING_ACK;
packet_status = SSP_TX_WAITING;
#else
packet_status = ssp_SendData( NULL, 0 );
#endif
while( packet_status == SSP_TX_WAITING ) { // we loop until we time out.
(void)ssp_ReceiveProcess( ); // do the receive process
packet_status = ssp_SendProcess( ); // do the send process
}
thisport->sendSynch = FALSE;
switch( packet_status ) {
case SSP_TX_ACKED:
retval = TRUE;
break;
case SSP_TX_BUSY: // intentional fall through.
case SSP_TX_TIMEOUT: // intentional fall through.
case SSP_TX_BUFOVERRUN:
retval = FALSE;
break;
default:
retval = FALSE;
break;
};
return retval;
}
/*!
* \brief sends out a preformatted packet for a give port
* \param thisport = which port to use.
* \return none.
*
* \note
* Packet should be formed through the use of sf_MakePacket before calling this function.
*/
void qssp::sf_SendPacket()
{
// add 3 to packet data length for: 1 length + 2 CRC (packet overhead)
uint8_t packetLen = thisport->txBuf[LENGTH] + 3;
// use the raw serial write function so the SYNC byte does not get 'escaped'
thisport->pfSerialWrite(SYNC);
for( uint8_t x = 0; x < packetLen; x++ ) {
sf_write_byte(thisport->txBuf[x] );
}
thisport->retryCount++;
}
/*!
* \brief converts data to transport layer protocol packet format.
* \param txbuf = buffer to use when forming the packet
* \param pdata = pointer to data to use
* \param length = number of bytes to use
* \param seqNo = sequence number of this packet
* \return none.
*
* \note
* 1. This function does not try to interpret ACK or SYNCH packets. This should
* be done by the caller of this function.
* 2. This function will attempt to format all data upto the size of the tx buffer.
* Any extra data beyond that will be ignored.
* 3. TODO: Should this function return an error if data length to be sent is greater th tx buffer size?
*
*/
void qssp::sf_MakePacket( uint8_t *txBuf, const uint8_t * pdata, uint16_t length, uint8_t seqNo )
{
uint16_t crc = 0xffff;
uint16_t bufPos = 0;
uint8_t b;
// add 1 for the seq. number
txBuf[LENGTH] = length + 1;
txBuf[SEQNUM] = seqNo;
crc = sf_crc16( crc, seqNo );
length = length + 2; // add two for the length and seqno bytes which are added before the loop.
for( bufPos = 2; bufPos < length; bufPos++ ) {
b = *pdata++;
txBuf[bufPos] = b;
crc = sf_crc16( crc, b ); // update CRC value
}
txBuf[bufPos++] = LOWERBYTE(crc);
txBuf[bufPos] = UPPERBYTE(crc);
}
/*!
* \brief sends out an ack packet to given sequence number
* \param thisport = which port to use
* \param seqNumber = sequence number of the packet we would like to ack
* \return none.
*
* \note
*
*/
void qssp::sf_SendAckPacket(uint8_t seqNumber)
{
uint8_t AckSeqNumber = SETBIT( seqNumber, ACK_BIT );
// create the packet, note we pass AckSequenceNumber directly
sf_MakePacket( thisport->txBuf, NULL, 0, AckSeqNumber );
sf_SendPacket( );
if (debug)
qDebug()<<"Sent ACK PACKET:"<<seqNumber;
// we don't set the timeout for an ACK because we don't ACK our ACKs in this protocol
}
/*!
* \brief writes a byte out the output channel. Adds escape byte where needed
* \param thisport = which port to use
* \param c = byte to send
* \return none.
*
* \note
*
*/
void qssp::sf_write_byte(uint8_t c )
{
if( c == SYNC ) { // check for SYNC byte
thisport->pfSerialWrite( ESC ); // since we are not starting a packet we must ESCAPE the SYNCH byte
thisport->pfSerialWrite( ESC_SYNC ); // now send the escaped synch char
} else if( c == ESC ) { // Check for ESC character
thisport->pfSerialWrite( ESC ); // if it is, we need to send it twice
thisport->pfSerialWrite( ESC );
} else {
thisport->pfSerialWrite( c ); // otherwise write the byte to serial port
}
}
/************************************************************************************************************
*
* NAME: uint16_t ssp_crc16( uint16_t crc, uint16_t data )
* DESCRIPTION: Uses crc_table to calculate new crc
* ARGUMENTS:
* arg1: crc
* arg2: data - byte to calculate into CRC
* RETURN: New crc
* CREATED: 5/8/02
*
*************************************************************************************************************/
/*!
* \brief calculates the new CRC value for 'data'
* \param crc = current CRC value
* \param data = new byte
* \return updated CRC value
*
* \note
*
*/
uint16_t qssp::sf_crc16( uint16_t crc, uint8_t data )
{
return (crc >> 8) ^ CRC_TABLE[( crc ^ data ) & 0x00FF ];
}
/*!
* \brief sets the timeout for the given packet
* \param thisport = which port to use
* \return none.
*
* \note
*
*/
void qssp::sf_SetSendTimeout()
{
uint32_t timeout;
timeout = thisport->pfGetTime() + thisport->timeoutLen;
thisport->timeout = timeout;
}
/*!
* \brief checks to see if a timeout occured
* \param thisport = which port to use
* \return true = a timeout has occurred
* \return false = has not timed out
*
* \note
*
*/
uint16_t qssp::sf_CheckTimeout()
{
uint16_t retval = FALSE;
uint32_t current_time;
current_time = thisport->pfGetTime();
if( current_time > thisport->timeout ) {
retval = TRUE;
}
if(retval)
if (debug)
qDebug()<<"timeout "<<current_time<<thisport->timeout;
return retval;
}
/****************************************************************************
* NAME: sf_ReceiveState
* DESC: Implements the receive state handling code for escaped and unescaped data
* ARGS: thisport - which port to operate on
* c - incoming byte
* RETURN:
* CREATED:
* NOTES:
* 1. change from using pointer to functions.
****************************************************************************/
/*!
* \brief implements the receive state handling code for escaped and unescaped data
* \param thisport = which port to use
* \param c = byte to process through the receive state machine
* \return receive status
*
* \note
*
*/
int16_t qssp::sf_ReceiveState(uint8_t c )
{
int16_t retval = SSP_RX_RECEIVING;
switch( thisport->InputState ) {
case state_unescaped_e:
if( c == SYNC ) {
thisport->DecodeState = decode_len1_e;
} else if ( c == ESC ) {
thisport->InputState = state_escaped_e;
} else {
retval = sf_DecodeState(c);
}
break; // end of unescaped state.
case state_escaped_e:
thisport->InputState = state_unescaped_e;
if( c == SYNC ) {
thisport->DecodeState = decode_len1_e;
} else if (c == ESC_SYNC ) {
retval = sf_DecodeState(SYNC);
} else {
retval = sf_DecodeState(c);
}
break; // end of the escaped state.
default:
break;
}
return retval;
}
/****************************************************************************
* NAME: sf_DecodeState
* DESC: Implements the receive state finite state machine
* ARGS: thisport - which port to operate on
* c - incoming byte
* RETURN:
* CREATED:
* NOTES:
* 1. change from using pointer to functions.
****************************************************************************/
/*!
* \brief implements the receiving decoding state machine
* \param thisport = which port to use
* \param c = byte to process
* \return receive status
*
* \note
*
*/
int16_t qssp::sf_DecodeState( uint8_t c )
{
int16_t retval;
switch( thisport->DecodeState ) {
case decode_idle_e:
// 'c' is ignored in this state as the only way to leave the idle state is
// recognition of the SYNC byte in the sf_ReceiveState function.
retval = SSP_RX_IDLE;
break;
case decode_len1_e:
thisport->rxBuf[LENGTH]= c;
thisport->rxBufLen = c;
if( thisport->rxBufLen <= thisport->rxBufSize ) {
thisport->DecodeState = decode_seqNo_e;
retval = SSP_RX_RECEIVING;
} else {
thisport->DecodeState = decode_idle_e;
retval = SSP_RX_IDLE;
}
break;
case decode_seqNo_e:
thisport->rxBuf[SEQNUM] = c;
thisport->crc = 0xffff;
thisport->rxBufLen--; // subtract 1 for the seq. no.
thisport->rxBufPos = 2;
thisport->crc = sf_crc16( thisport->crc, c );
if( thisport->rxBufLen > 0 ) {
thisport->DecodeState = decode_data_e;
} else {
thisport->DecodeState = decode_crc1_e;
}
retval = SSP_RX_RECEIVING;
break;
case decode_data_e:
thisport->rxBuf[ (thisport->rxBufPos)++] = c;
thisport->crc = sf_crc16( thisport->crc, c );
if( thisport->rxBufPos == (thisport->rxBufLen+2) ) {
thisport->DecodeState = decode_crc1_e;
}
retval = SSP_RX_RECEIVING;
break;
case decode_crc1_e:
thisport->crc = sf_crc16( thisport->crc, c );
thisport->DecodeState = decode_crc2_e;
retval = SSP_RX_RECEIVING;
break;
case decode_crc2_e:
thisport->DecodeState = decode_idle_e;
// verify the CRC value for the packet
if( sf_crc16( thisport->crc, c) == 0) {
// TODO shouldn't the return value of sf_ReceivePacket() be checked?
sf_ReceivePacket();
retval = SSP_RX_COMPLETE;
} else {
thisport->RxError++;
retval = SSP_RX_IDLE;
}
break;
default:
thisport->DecodeState = decode_idle_e; // unknown state so reset to idle state and wait for the next start of a packet.
retval = SSP_RX_IDLE;
break;
}
return retval;
}
/************************************************************************************************************
*
* NAME: int16_t sf_ReceivePacket( )
* DESCRIPTION: Receive one packet, assumed that data is in rec.buff[]
* ARGUMENTS:
* RETURN: 0 . no new packet was received, could be ack or same packet
* 1 . new packet received
* SSP_PACKET_?
* SSP_PACKET_COMPLETE
* SSP_PACKET_ACK
* CREATED: 5/8/02
*
*************************************************************************************************************/
/*!
* \brief receive one packet. calls the callback function if needed.
* \param thisport = which port to use
* \return true = valid data packet received.
* \return false = otherwise
*
* \note
*
* Created: Oct 7, 2010 12:07:22 AM by joe
*/
int16_t qssp::sf_ReceivePacket()
{
int16_t value = FALSE;
if( ISBITSET(thisport->rxBuf[SEQNUM], ACK_BIT ) ) {
// Received an ACK packet, need to check if it matches the previous sent packet
if( ( thisport->rxBuf[SEQNUM] & 0x7F) == (thisport->txSeqNo & 0x7f)) {
// It matches the last packet sent by us
SETBIT( thisport->txSeqNo, ACK_BIT );
thisport->SendState = SSP_ACKED;
value = FALSE;
if (debug)
qDebug()<<"Received ACK:"<<(thisport->txSeqNo & 0x7F);
}
// else ignore the ACK packet
} else {
// Received a 'data' packet, figure out what type of packet we received...
if( thisport->rxBuf[SEQNUM] == 0 ) {
if (debug)
qDebug()<<"Received SYNC Request";
// Synchronize sequence number with host
#ifdef ACTIVE_SYNCH
thisport->sendSynch = TRUE;
#endif
sf_SendAckPacket(thisport->rxBuf[SEQNUM] );
thisport->rxSeqNo = 0;
value = FALSE;
} else if( thisport->rxBuf[SEQNUM] == thisport->rxSeqNo ) {
// Already seen this packet, just ack it, don't act on the packet.
sf_SendAckPacket(thisport->rxBuf[SEQNUM] );
value = FALSE;
} else {
//New Packet
thisport->rxSeqNo = thisport->rxBuf[SEQNUM];
// Let the application do something with the data/packet.
// skip the first two bytes (length and seq. no.) in the buffer.
if (debug)
qDebug()<<"Received DATA PACKET seq="<<thisport->rxSeqNo<<"Data="<<(uint8_t)thisport->rxBuf[2]<<(uint8_t)thisport->rxBuf[3]<<(uint8_t)thisport->rxBuf[4];
pfCallBack( &(thisport->rxBuf[2]), thisport->rxBufLen);
// after we send the ACK, it is possible for the host to send a new packet.
// Thus the application needs to copy the data and reset the receive buffer
// inside of thisport->pfCallBack()
sf_SendAckPacket(thisport->rxBuf[SEQNUM] );
value = TRUE;
}
}
return value;
}
qssp::qssp(port * info,bool debug):debug(debug)
{
thisport=info;
thisport->maxRetryCount = info->max_retry;
thisport->timeoutLen = info->timeoutLen;
thisport->txBufSize = info->txBufSize;
thisport->rxBufSize = info->rxBufSize;
thisport->txBuf = info->txBuf;
thisport->rxBuf = info->rxBuf;
thisport->retryCount = 0;
thisport->sendSynch = FALSE; //TRUE;
thisport->rxSeqNo = 255;
thisport->txSeqNo = 255;
thisport->SendState = SSP_IDLE;
thisport->InputState =(ReceiveState)0;
thisport->DecodeState =(decodeState_)0;
thisport->TxError =0;
thisport->RxError =0;
thisport->txSeqNo =0;
thisport->rxSeqNo =0;
}
void qssp::pfCallBack( uint8_t * buf, uint16_t size)
{
if (debug)
qDebug()<<"receive callback"<<buf[0]<<buf[1]<<buf[2]<<buf[3]<<buf[4];
}

View File

@ -0,0 +1,96 @@
#ifndef QSSP_H
#define QSSP_H
#include <stdint.h>
#include "port.h"
#include "common.h"
/** LOCAL DEFINITIONS **/
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define SSP_TX_IDLE 0 // not expecting a ACK packet (no current transmissions in progress)
#define SSP_TX_WAITING 1 // waiting for a valid ACK to arrive
#define SSP_TX_TIMEOUT 2 // failed to receive a valid ACK in the timeout period, after retrying.
#define SSP_TX_ACKED 3 // valid ACK received before timeout period.
#define SSP_TX_BUFOVERRUN 4 // amount of data to send execeds the transmission buffer sizeof
#define SSP_TX_BUSY 5 // Attempted to start a transmission while a transmission was already in progress.
//#define SSP_TX_FAIL - failure...
#define SSP_RX_IDLE 0
#define SSP_RX_RECEIVING 1
#define SSP_RX_COMPLETE 2
// types of packet that can be received
#define SSP_RX_DATA 5
#define SSP_RX_ACK 6
#define SSP_RX_SYNCH 7
typedef struct
{
uint8_t *pbuff;
uint16_t length;
uint16_t crc;
uint8_t seqNo;
} Packet_t;
typedef struct {
uint8_t *rxBuf; // Buffer used to store rcv data
uint16_t rxBufSize; // rcv buffer size.
uint8_t *txBuf; // Length of data in buffer
uint16_t txBufSize; // CRC for data in Packet buff
uint16_t max_retry; // Maximum number of retrys for a single transmit.
int32_t timeoutLen; // how long to wait for each retry to succeed
// function returns time in number of seconds that has elapsed from a given reference point
} PortConfig_t;
/** Public Data **/
/** EXTERNAL FUNCTIONS **/
class qssp
{
private:
port * thisport;
decodeState_ DecodeState_t;
/** PRIVATE FUNCTIONS **/
//static void sf_SendSynchPacket( Port_t *thisport );
uint16_t sf_crc16( uint16_t crc, uint8_t data );
void sf_write_byte(uint8_t c );
void sf_SetSendTimeout();
uint16_t sf_CheckTimeout();
int16_t sf_DecodeState(uint8_t c );
int16_t sf_ReceiveState(uint8_t c );
void sf_SendPacket();
void sf_SendAckPacket(uint8_t seqNumber);
void sf_MakePacket( uint8_t *buf, const uint8_t * pdata, uint16_t length, uint8_t seqNo );
int16_t sf_ReceivePacket();
uint16_t ssp_SendDataBlock(uint8_t *data, uint16_t length );
bool debug;
public:
/** PUBLIC FUNCTIONS **/
virtual void pfCallBack( uint8_t *, uint16_t); // call back function that is called when a full packet has been received
int16_t ssp_ReceiveProcess();
int16_t ssp_SendProcess();
uint16_t ssp_SendString(char *str );
int16_t ssp_SendData( const uint8_t * data,const uint16_t length );
void ssp_Init( const PortConfig_t* const info);
int16_t ssp_ReceiveByte( );
uint16_t ssp_Synchronise( );
qssp(port * info,bool debug);
};
#endif // QSSP_H

View File

@ -0,0 +1,76 @@
#include "qsspt.h"
qsspt::qsspt(port * info,bool debug):qssp(info,debug),endthread(false),datapending(false),debug(debug)
{
}
void qsspt::run()
{
while(!endthread)
{
receivestatus=this->ssp_ReceiveProcess();
sendstatus=this->ssp_SendProcess();
msleep(1);
sendbufmutex.lock();
if(datapending && receivestatus==SSP_TX_IDLE)
{
this->ssp_SendData(mbuf,msize);
datapending=false;
}
sendbufmutex.unlock();
if(sendstatus==SSP_TX_ACKED)
sendwait.wakeAll();
}
}
bool qsspt::sendData(uint8_t * buf,uint16_t size)
{
if(datapending)
return false;
sendbufmutex.lock();
datapending=true;
mbuf=buf;
msize=size;
sendbufmutex.unlock();
msendwait.lock();
sendwait.wait(&msendwait,10000);
msendwait.unlock();
return true;
}
void qsspt::pfCallBack( uint8_t * buf, uint16_t size)
{
if (debug)
qDebug()<<"receive callback"<<buf[0]<<buf[1]<<buf[2]<<buf[3]<<buf[4]<<"array size="<<queue.count();
QByteArray array;
for(int x=0;x<size;x++)
{
array.append(buf[x]);
}
mutex.lock();
queue.enqueue(array);
// queue.enqueue((const char *)&buf);
mutex.unlock();
}
int qsspt::packets_Available()
{
return queue.count();
}
int qsspt::read_Packet(void * data)
{
mutex.lock();
if(queue.size()==0)
{
mutex.unlock();
return -1;
}
QByteArray arr=queue.dequeue();
memcpy(data,(uint8_t*)arr.data(),arr.length());
mutex.unlock();
return arr.length();
}
qsspt::~qsspt()
{
endthread=true;
wait(1000);
}

View File

@ -0,0 +1,33 @@
#ifndef QSSPT_H
#define QSSPT_H
#include "qssp.h"
#include <QThread>
#include <QQueue>
#include <QWaitCondition>
class qsspt:public qssp, public QThread
{
public:
qsspt(port * info,bool debug);
void run();
int packets_Available();
int read_Packet(void *);
~qsspt();
bool sendData(uint8_t * buf,uint16_t size);
private:
virtual void pfCallBack( uint8_t *, uint16_t);
uint8_t * mbuf;
uint16_t msize;
QQueue<QByteArray> queue;
QMutex mutex;
QMutex sendbufmutex;
bool datapending;
bool endthread;
uint16_t sendstatus;
uint16_t receivestatus;
QWaitCondition sendwait;
QMutex msendwait;
bool debug;
};
#endif // QSSPT_H

View File

@ -0,0 +1,230 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
width="48"
height="48"
id="svg2474">
<metadata
id="metadata33">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs2476">
<linearGradient
id="linearGradient3533">
<stop
id="stop3535"
style="stop-color:#93b9dd;stop-opacity:1"
offset="0" />
<stop
id="stop3545"
style="stop-color:#6396cd;stop-opacity:1"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3266">
<stop
id="stop3268"
style="stop-color:#387ab8;stop-opacity:1"
offset="0" />
<stop
id="stop3270"
style="stop-color:#387ab8;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient3276">
<stop
id="stop3278"
style="stop-color:#6396cd;stop-opacity:1"
offset="0" />
<stop
id="stop3280"
style="stop-color:#83acd5;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="108.5625"
y1="102.78125"
x2="108.5625"
y2="71.78125"
id="linearGradient5497"
xlink:href="#linearGradient5491"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-95.99949,-49.00038)" />
<linearGradient
id="linearGradient5491">
<stop
id="stop5493"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop5495"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="102.5625"
y1="49.78125"
x2="103.5625"
y2="72.78125"
id="linearGradient5480"
xlink:href="#linearGradient5474"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-95.99949,-49.00038)" />
<linearGradient
id="linearGradient5474">
<stop
id="stop5476"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop5478"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="118.47968"
y1="55.060318"
x2="118.47968"
y2="91.941895"
id="linearGradient4593-5-8-1-5-2"
xlink:href="#linearGradient3533"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-100.99949,-49.00038)" />
<linearGradient
x1="34.980953"
y1="53.837799"
x2="35.996098"
y2="83.57618"
id="linearGradient4593-5-8-1-5-2-3"
xlink:href="#linearGradient3533"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-5,0)" />
<radialGradient
cx="33.875"
cy="197.29688"
r="4.84375"
fx="33.875"
fy="197.29688"
id="radialGradient5147-5"
xlink:href="#linearGradient6462-6-8-548-9-2-7"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.33870968,0,130.47051)" />
<linearGradient
id="linearGradient6462-6-8-548-9-2-7">
<stop
id="stop6464-5-9-94-5-4-4"
style="stop-color:#000000;stop-opacity:1"
offset="0" />
<stop
id="stop6466-3-6-1-7-2-8"
style="stop-color:#000000;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
id="linearGradient6462-6-8-548-9-5">
<stop
id="stop6464-5-9-94-5-8"
style="stop-color:#000000;stop-opacity:1"
offset="0" />
<stop
id="stop6466-3-6-1-7-5"
style="stop-color:#000000;stop-opacity:0"
offset="1" />
</linearGradient>
<radialGradient
cx="33.875"
cy="197.29688"
r="4.84375"
fx="33.875"
fy="197.29688"
id="radialGradient6081"
xlink:href="#linearGradient6462-6-8-548-9-5"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.33870968,0,130.47051)" />
<linearGradient
x1="42.030777"
y1="84.719109"
x2="53.808601"
y2="73.263672"
id="linearGradient4008"
xlink:href="#linearGradient3276"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-5,0)" />
<linearGradient
x1="39.843277"
y1="83.781609"
x2="50.683601"
y2="75.138672"
id="linearGradient4018"
xlink:href="#linearGradient3266"
gradientUnits="userSpaceOnUse" />
</defs>
<path
d="m 38.71875,197.29687 a 4.84375,1.640625 0 1 1 -9.6875,0 4.84375,1.640625 0 1 1 9.6875,0 z"
transform="matrix(3.3032251,0,0,1.6761866,-89.458749,-288.73764)"
id="path6460-6-4-4-3-3"
style="opacity:0.2;color:#000000;fill:url(#radialGradient5147-5);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
<path
d="M 46.405989,78.610714 A 13.125,13.125 0 0 1 33.62701,84.097034"
transform="matrix(1.0666665,0,0,1.0666665,-14.49949,-51.367037)"
id="path4010"
style="color:#000000;fill:none;stroke:url(#linearGradient4018);stroke-width:8.43750095;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
<path
d="m 38.71875,197.29687 a 4.84375,1.640625 0 1 1 -9.6875,0 4.84375,1.640625 0 1 1 9.6875,0 z"
transform="matrix(4.541935,0,0,1.9809503,-131.42005,-348.86656)"
id="path6460-6-4-4-4"
style="opacity:0.1;color:#000000;fill:url(#radialGradient6081);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
<path
d="M 35.542313,84.24974 A 13.125,13.125 0 1 1 47.171703,64.884866"
transform="matrix(1.0666665,0,0,1.0666665,-14.49949,-51.367037)"
id="path4788-6"
style="color:#000000;fill:none;stroke:#387ab8;stroke-width:8.43750095;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
<path
d="m 38.50051,9.4996196 0,11.0000004 -11,0"
id="path4847"
style="color:#000000;fill:none;stroke:#387ab8;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
<path
d="m 46.386659,78.638476 a 13.125,13.125 0 0 1 -13.412517,5.34104"
transform="matrix(1.0666665,0,0,1.0666665,-14.49949,-51.367037)"
id="path4006"
style="color:#000000;fill:none;stroke:url(#linearGradient4008);stroke-width:6.56250095;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
<path
d="m 37.320778,84.13999 a 13.125,13.125 0 1 1 9.33779,-20.123155"
transform="matrix(1.0666665,0,0,1.0666665,-14.49949,-51.367037)"
id="path4788"
style="color:#000000;fill:none;stroke:url(#linearGradient4593-5-8-1-5-2-3);stroke-width:6.56250095;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
<path
d="m 38.50051,9.4996196 0,11.0000004 -11,0"
id="path4847-1"
style="color:#000000;fill:none;stroke:url(#linearGradient4593-5-8-1-5-2);stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
<path
d="m 29.740794,33.593555 c -3.674085,2.533277 -8.663315,2.652831 -12.552784,-0.06269 -5.010358,-3.498088 -6.216831,-10.333397 -2.718751,-15.34375 3.498091,-5.010353 10.3334,-6.216833 15.343751,-2.71875 1.16116,0.810688 2.10377,1.843969 2.875,3.03125 l -5.1875,0 c -1.056625,-0.01494 -2.028484,0.943269 -2.028484,2 0,1.056731 0.971859,2.014943 2.028484,2 l 11,0 c 1.062499,0.28125 2.062499,-0.71875 2,-2 l 0,-11.0000004 c 0.01671,-1.0680358 -0.963214,-2.0479629 -2.03125,-2.0312505 -0.06245,-0.00293 -0.125046,-0.00293 -0.1875,0 -0.982752,0.107995 -1.802514,1.0428108 -1.78125,2.0312505 l 0,4.0625004 c -0.9534,-1.127853 -2.06667,-2.152011 -3.28125,-3 l -0.09375,-0.0625 c -2.85203,-1.9610889 -6.0733,-2.9220479 -9.312501,-2.9687509 -5.46224,-0.07875 -10.90353,2.4568065 -14.2500005,7.2500009 -5.354351,7.669111 -3.450361,18.3019 4.2187505,23.65625 6.255407,4.367344 14.482569,3.905673 20.208772,-0.574695"
id="path4788-2"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.23999999;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" />
<path
d="m 36.50052,13.562118 c -0.9534,-1.127853 -2.06667,-2.152011 -3.28125,-3 l -0.0937,-0.0625 c -2.85203,-1.9610889 -6.0733,-2.9220479 -9.312501,-2.9687509 -5.46224,-0.07875 -10.90354,2.4568065 -14.2500105,7.2500009 -5.354351,7.669111 -3.450361,18.3019 4.2187505,23.65625"
id="path4788-2-3"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.3;color:#000000;fill:none;stroke:url(#linearGradient5480);stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" />
<path
d="M 32.53183,30.81212 C 29.03374,35.822473 22.198429,37.028952 17.18808,33.53087 12.177699,30.032787 10.971229,23.197473 14.469309,18.18712 17.96742,13.176767 24.802729,11.970287 29.81308,15.46837"
id="path4788-2-3-4"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.3;color:#000000;fill:none;stroke:url(#linearGradient5497);stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" />
</svg>

After

Width:  |  Height:  |  Size: 12 KiB