1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-20 10:54:14 +01:00

Add missing header on some files.

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@2595 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
edouard 2011-01-26 16:49:21 +00:00 committed by edouard
parent 549e92f9c0
commit dce3c25771
11 changed files with 2524 additions and 2313 deletions

View File

@ -1,18 +1,43 @@
#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
/**
******************************************************************************
*
* @file common.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
* @{
* @brief The USB and Serial protocol uploader plugin
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/#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

@ -1,46 +1,72 @@
#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();
}
/**
******************************************************************************
*
* @file port.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
* @{
* @brief The USB and Serial protocol uploader plugin
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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

@ -1,49 +1,75 @@
#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
/**
******************************************************************************
*
* @file port.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
* @{
* @brief The USB and Serial protocol uploader plugin
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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

@ -1,781 +1,807 @@
#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];
}
/**
******************************************************************************
*
* @file qssp.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
* @{
* @brief The USB and Serial protocol uploader plugin
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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

@ -1,96 +1,122 @@
#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
/**
******************************************************************************
*
* @file qssp.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
* @{
* @brief The USB and Serial protocol uploader plugin
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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

@ -1,76 +1,102 @@
#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);
}
/**
******************************************************************************
*
* @file qsspt.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
* @{
* @brief The USB and Serial protocol uploader plugin
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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

@ -1,33 +1,59 @@
#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
/**
******************************************************************************
*
* @file qsspt.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
* @{
* @brief The USB and Serial protocol uploader plugin
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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

@ -1,2 +1,17 @@
#include "delay.h"
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "delay.h"

View File

@ -1,13 +1,28 @@
#ifndef DELAY_H
#define DELAY_H
#include <QThread>
class delay : public QThread
{
public:
static void msleep(unsigned long msecs)
{
QThread::msleep(msecs);
}
};
#endif // DELAY_H
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef DELAY_H
#define DELAY_H
#include <QThread>
class delay : public QThread
{
public:
static void msleep(unsigned long msecs)
{
QThread::msleep(msecs);
}
};
#endif // DELAY_H

View File

@ -1,991 +1,991 @@
/**
******************************************************************************
*
* @file op_dfu.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Uploader Plugin
* @{
* @brief The uploader plugin
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "op_dfu.h"
#include <cmath>
#include <qwaitcondition.h>
#include <QMetaType>
using namespace OP_DFU;
DFUObject::DFUObject(bool _debug,bool _use_serial,QString portname): debug(_debug),use_serial(_use_serial),mready(true)
{
info = NULL;
qRegisterMetaType<OP_DFU::Status>("Status");
if(use_serial)
{
PortSettings settings;
settings.BaudRate=BAUD57600;
settings.DataBits=DATA_8;
settings.FlowControl=FLOW_OFF;
settings.Parity=PAR_NONE;
settings.StopBits=STOP_1;
settings.Timeout_Millisec=1000;
info = new port(settings,portname);
info->rxBuf = sspRxBuf;
info->rxBufSize = MAX_PACKET_DATA_LEN;
info->txBuf = sspTxBuf;
info->txBufSize = MAX_PACKET_DATA_LEN;
info->max_retry = 10;
info->timeoutLen = 1000;
if(info->status()!=port::open)
{
cout << "Could not open serial port\n";
mready = false;
return;
}
serialhandle = new qsspt(info,debug);
int count = 0;
while((serialhandle->ssp_Synchronise()==false) && (count < 10))
{
if (debug)
qDebug()<<"SYNC failed, resending";
count++;
}
if (count == 10) {
mready = false;
return;
}
qDebug() << "SYNC Succeded";
serialhandle->start();
}
else
{
send_delay=10;
use_delay=true;
int numDevices=0;
int count=0;
while((numDevices==0) && count < 10)
{
if (debug)
qDebug() << ".";
delay::msleep(500);
numDevices = hidHandle.open(1,0x20a0,0x4117,0,0); //0xff9c,0x0001);
count++;
}
if(debug)
qDebug() << numDevices << " device(s) opened";
}
}
DFUObject::~DFUObject()
{
if (use_serial) {
if (mready) {
delete serialhandle;
delete info;
}
} else {
hidHandle.close(0);
}
}
bool DFUObject::SaveByteArrayToFile(QString const & sfile, const QByteArray &array)
{
QFile file(sfile);
if (!file.open(QIODevice::WriteOnly))
{
if(debug)
qDebug()<<"Can't open file";
return false;
}
file.write(array);
file.close();
return true;
}
/**
Tells the mainboard to enter DFU Mode.
*/
bool DFUObject::enterDFU(int const &devNumber)
{
char buf[BUF_LEN];
buf[0] =0x02; //reportID
buf[1] = OP_DFU::EnterDFU; //DFU Command
buf[2] = 0; //DFU Count
buf[3] = 0; //DFU Count
buf[4] = 0; //DFU Count
buf[5] = 0; //DFU Count
buf[6] = devNumber; //DFU Data0
buf[7] = 1; //DFU Data1
buf[8] = 1; //DFU Data2
buf[9] = 1; //DFU Data3
int result = sendData(buf, BUF_LEN);
// int result = hidHandle.send(0,buf, BUF_LEN, 500);
if(result<1)
return false;
if(debug)
qDebug() << "EnterDFU: " << result << " bytes sent";
return true;
}
/**
Tells the board to get ready for an upload. It will in particular
erase the memory to make room for the data. You will have to query
its status to wait until erase is done before doing the actual upload.
*/
bool DFUObject::StartUpload(qint32 const & numberOfBytes, TransferTypes const & type,quint32 crc)
{
int lastPacketCount;
qint32 numberOfPackets=numberOfBytes/4/14;
int pad=(numberOfBytes-numberOfPackets*4*14)/4;
if(pad==0)
{
lastPacketCount=14;
}
else
{
++numberOfPackets;
lastPacketCount=pad;
}
char buf[BUF_LEN];
buf[0] =0x02;//reportID
buf[1] = setStartBit(OP_DFU::Upload);//DFU Command
buf[2] = numberOfPackets>>24;//DFU Count
buf[3] = numberOfPackets>>16;//DFU Count
buf[4] = numberOfPackets>>8;//DFU Count
buf[5] = numberOfPackets;//DFU Count
buf[6] = (int)type;//DFU Data0
buf[7] = lastPacketCount;//DFU Data1
buf[8] = crc>>24;
buf[9] = crc>>16;
buf[10] = crc>>8;
buf[11] = crc;
if(debug)
qDebug()<<"Number of packets:"<<numberOfPackets<<" Size of last packet:"<<lastPacketCount;
int result = sendData(buf, BUF_LEN);
delay::msleep(1000);
// int result = hidHandle.send(0,buf, BUF_LEN, 5000);
if(debug)
qDebug() << result << " bytes sent";
if(result>0)
{
return true;
}
return false;
}
/**
Does the actual data upload to the board. Needs to be called once the
board is ready to accept data following a StartUpload command, and it is erased.
*/
bool DFUObject::UploadData(qint32 const & numberOfBytes, QByteArray & data)
{
int lastPacketCount;
qint32 numberOfPackets=numberOfBytes/4/14;
int pad=(numberOfBytes-numberOfPackets*4*14)/4;
if(pad==0)
{
lastPacketCount=14;
}
else
{
++numberOfPackets;
lastPacketCount=pad;
}
if(debug)
qDebug()<<"Start Uploading:"<<numberOfPackets<<"4Bytes";
char buf[BUF_LEN];
buf[0] =0x02;//reportID
buf[1] = OP_DFU::Upload;//DFU Command
int packetsize;
float percentage;
int laspercentage;
for(qint32 packetcount=0;packetcount<numberOfPackets;++packetcount)
{
percentage=(float)(packetcount+1)/numberOfPackets*100;
if(laspercentage!=(int)percentage)
printProgBar((int)percentage,"UPLOADING");
laspercentage=(int)percentage;
if(packetcount==numberOfPackets)
packetsize=lastPacketCount;
else
packetsize=14;
// qDebug()<<packetcount;
buf[2] = packetcount>>24;//DFU Count
buf[3] = packetcount>>16;//DFU Count
buf[4] = packetcount>>8;//DFU Count
buf[5] = packetcount;//DFU Count
char *pointer=data.data();
pointer=pointer+4*14*packetcount;
// qDebug()<<"Packet Number="<<packetcount<<"Data0="<<(int)data[0]<<" Data1="<<(int)data[1]<<" Data0="<<(int)data[2]<<" Data0="<<(int)data[3]<<" buf6="<<(int)buf[6]<<" buf7="<<(int)buf[7]<<" buf8="<<(int)buf[8]<<" buf9="<<(int)buf[9];
CopyWords(pointer,buf+6,packetsize*4);
// for (int y=0;y<packetsize*4;++y)
// {
// qDebug()<<y<<":"<<(int)data[packetcount*14*4+y]<<"---"<<(int)buf[6+y];
// }
// qDebug()<<" Data0="<<(int)data[0]<<" Data0="<<(int)data[1]<<" Data0="<<(int)data[2]<<" Data0="<<(int)data[3]<<" buf6="<<(int)buf[6]<<" buf7="<<(int)buf[7]<<" buf8="<<(int)buf[8]<<" buf9="<<(int)buf[9];
//delay::msleep(send_delay);
//if(StatusRequest()!=OP_DFU::uploading) return false;
int result = sendData(buf, BUF_LEN);
// qDebug()<<"sent:"<<result;
if(result<1)
{
return false;
}
// qDebug() << "UPLOAD:"<<"Data="<<(int)buf[6]<<(int)buf[7]<<(int)buf[8]<<(int)buf[9]<<";"<<result << " bytes sent";
}
cout<<"\n";
// while(true){}
return true;
}
/**
Sends the firmware description to the device
*/
OP_DFU::Status DFUObject::UploadDescription(QString description)
{
cout<<"Starting uploading description\n";
if(description.length()%4!=0)
{
int pad=description.length()/4;
pad=(pad+1)*4;
pad=pad-description.length();
QString padding;
padding.fill(' ',pad);
description.append(padding);
}
if(!StartUpload(description.length(),OP_DFU::Descript,0))
return OP_DFU::abort;
QByteArray array=description.toAscii();
if(!UploadData(description.length(),array))
{
return OP_DFU::abort;
}
if(!EndOperation())
{
return OP_DFU::abort;
}
OP_DFU::Status ret = StatusRequest();
if(debug)
qDebug() << "Upload description Status=" << StatusToString(ret);
return ret;
}
/**
Downloads the description string for the current device.
You have to call enterDFU before calling this function.
*/
QString DFUObject::DownloadDescription(int const & numberOfChars)
{
QByteArray arr;
StartDownloadT(&arr, numberOfChars,OP_DFU::Descript);
QString str(arr);
return str;
}
/**
Starts a firmware download
@param firmwareArray: pointer to the location where we should store the firmware
@package device: the device to use for the download
*/
bool DFUObject::DownloadFirmware(QByteArray *firmwareArray, int device)
{
if (isRunning())
return false;
requestedOperation = OP_DFU::Download;
requestSize = devices[device].SizeOfCode;
requestTransferType = OP_DFU::FW;
requestStorage = firmwareArray;
start();
return true;
}
/**
Runs the upload or download operations.
*/
void DFUObject::run()
{
switch (requestedOperation) {
case OP_DFU::Download:
StartDownloadT(requestStorage, requestSize, requestTransferType);
emit(downloadFinished());
break;
case OP_DFU::Upload: {
OP_DFU::Status ret = UploadFirmwareT(requestFilename, requestVerify, requestDevice);
emit(uploadFinished(ret));
break;
}
default:
break;
}
return;
}
/**
Downloads a certain number of bytes from a certain location, and stores in an array whose
pointer is passed as an argument
*/
bool DFUObject::StartDownloadT(QByteArray *fw, qint32 const & numberOfBytes, TransferTypes const & type)
{
int lastPacketCount;
// First of all, work out the number of DFU packets we should ask for:
qint32 numberOfPackets = numberOfBytes/4/14;
int pad = (numberOfBytes-numberOfPackets*4*14)/4;
if(pad == 0) {
lastPacketCount=14;
}
else {
++numberOfPackets;
lastPacketCount=pad;
}
char buf[BUF_LEN];
buf[0] = 0x02; //reportID
buf[1] = OP_DFU::Download_Req; //DFU Command
buf[2] = numberOfPackets>>24; //DFU Count
buf[3] = numberOfPackets>>16; //DFU Count
buf[4] = numberOfPackets>>8; //DFU Count
buf[5] = numberOfPackets; //DFU Count
buf[6] = (int)type; //DFU Data0
buf[7] = lastPacketCount; //DFU Data1
buf[8] = 1; //DFU Data2
buf[9] = 1; //DFU Data3
int result = sendData(buf, BUF_LEN);
//int result = hidHandle.send(0,buf, BUF_LEN, 500);
if(debug)
qDebug() << "StartDownload:"<<numberOfPackets<<"packets"<<" Last Packet Size="<<lastPacketCount<<" "<<result << " bytes sent";
float percentage;
int laspercentage;
// Now get those packets:
for(qint32 x=0;x<numberOfPackets;++x)
{
int size;
percentage=(float)(x+1)/numberOfPackets*100;
if(laspercentage!=(int)percentage)
printProgBar((int)percentage,"DOWNLOADING");
laspercentage=(int)percentage;
result = receiveData(buf,BUF_LEN);
//result = hidHandle.receive(0,buf,BUF_LEN,5000);
if(debug)
qDebug() << result << " bytes received"<<" Count="<<x<<"-"<<(int)buf[2]<<";"<<(int)buf[3]<<";"<<(int)buf[4]<<";"<<(int)buf[5]<<" Data="<<(int)buf[6]<<";"<<(int)buf[7]<<";"<<(int)buf[8]<<";"<<(int)buf[9];
if(x==numberOfPackets-1)
size=lastPacketCount*4;
else
size=14*4;
fw->append(buf+6,size);
}
StatusRequest();
return true;
}
/**
Resets the device
*/
int DFUObject::ResetDevice(void)
{
char buf[BUF_LEN];
buf[0] =0x02; //reportID
buf[1] = OP_DFU::Reset; //DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
return sendData(buf, BUF_LEN);
//return hidHandle.send(0,buf, BUF_LEN, 500);
}
int DFUObject::AbortOperation(void)
{
char buf[BUF_LEN];
buf[0] =0x02;//reportID
buf[1] = OP_DFU::Abort_Operation;//DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
return sendData(buf, BUF_LEN);
//return hidHandle.send(0,buf, BUF_LEN, 500);
}
/**
Starts the firmware (leaves bootloader and boots the main software)
*/
int DFUObject::JumpToApp()
{
char buf[BUF_LEN];
buf[0] =0x02;//reportID
buf[1] = OP_DFU::JumpFW;//DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
return sendData(buf, BUF_LEN);
//return hidHandle.send(0,buf, BUF_LEN, 500);
}
OP_DFU::Status DFUObject::StatusRequest()
{
char buf[BUF_LEN];
buf[0] =0x02; //reportID
buf[1] = OP_DFU::Status_Request; //DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
int result = sendData(buf, BUF_LEN);
//int result = hidHandle.send(0,buf, BUF_LEN, 10000);
if(debug)
qDebug() << "StatusRequest: " << result << " bytes sent";
result = receiveData(buf,BUF_LEN);
// result = hidHandle.receive(0,buf,BUF_LEN,10000);
if(debug)
qDebug() << "StatusRequest: " << result << " bytes received";
if(buf[1]==OP_DFU::Status_Rep)
{
return (OP_DFU::Status)buf[6];
}
else
return OP_DFU::abort;
}
/**
Ask the bootloader for the list of devices available
*/
bool DFUObject::findDevices()
{
devices.clear();
char buf[BUF_LEN];
buf[0] =0x02; //reportID
buf[1] = OP_DFU::Req_Capabilities; //DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
int result = sendData(buf, BUF_LEN);
//int result = hidHandle.send(0,buf, BUF_LEN, 5000);
if(result<1)
{
return false;
}
result = receiveData(buf,BUF_LEN);
//result = hidHandle.receive(0,buf,BUF_LEN,5000);
if(result<1)
{
return false;
}
numberOfDevices=buf[7];
RWFlags=buf[8];
RWFlags=RWFlags<<8 | buf[9];
if(buf[1]==OP_DFU::Rep_Capabilities)
{
for(int x=0;x<numberOfDevices;++x)
{
device dev;
dev.Readable=(bool)(RWFlags>>(x*2) & 1);
dev.Writable=(bool)(RWFlags>>(x*2+1) & 1);
devices.append(dev);
buf[0] =0x02; //reportID
buf[1] = OP_DFU::Req_Capabilities; //DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = x+1;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
int result = sendData(buf, BUF_LEN);
result = receiveData(buf,BUF_LEN);
// int result = hidHandle.send(0,buf, BUF_LEN, 5000);
// result = hidHandle.receive(0,buf,BUF_LEN,5000);
//devices[x].ID=buf[9];
devices[x].ID=buf[14];
devices[x].ID=devices[x].ID<<8 | (quint8)buf[15];
devices[x].BL_Version=buf[7];
devices[x].SizeOfDesc=buf[8];
quint32 aux;
aux=(quint8)buf[10];
aux=aux<<8 |(quint8)buf[11];
aux=aux<<8 |(quint8)buf[12];
aux=aux<<8 |(quint8)buf[13];
devices[x].FW_CRC=aux;
aux=(quint8)buf[2];
aux=aux<<8 |(quint8)buf[3];
aux=aux<<8 |(quint8)buf[4];
aux=aux<<8 |(quint8)buf[5];
devices[x].SizeOfCode=aux;
}
if(debug)
{
qDebug() << "Found " << numberOfDevices << " devices";
for(int x=0;x<numberOfDevices;++x)
{
qDebug()<<"Device #"<<x+1;
qDebug()<<"Device ID="<<devices[x].ID;
qDebug()<<"Device Readable="<<devices[x].Readable;
qDebug()<<"Device Writable="<<devices[x].Writable;
qDebug()<<"Device SizeOfCode="<<devices[x].SizeOfCode;
qDebug()<<"Device SizeOfDesc="<<devices[x].SizeOfDesc;
qDebug()<<"BL Version="<<devices[x].BL_Version;
qDebug()<<"FW CRC="<<devices[x].FW_CRC;
}
}
}
return true;
}
bool DFUObject::EndOperation()
{
char buf[BUF_LEN];
buf[0] =0x02;//reportID
buf[1] = OP_DFU::Op_END;//DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
int result = sendData(buf, BUF_LEN);
// int result = hidHandle.send(0,buf, BUF_LEN, 5000);
// hidHandle.receive(0,buf,BUF_LEN,5000);
if(debug)
qDebug() << result << " bytes sent";
if(result>0)
return true;
return false;
}
//
/**
Starts a firmware upload (asynchronous)
*/
bool DFUObject::UploadFirmware(const QString &sfile, const bool &verify,int device)
{
if (isRunning())
return false;
requestedOperation = OP_DFU::Upload;
requestFilename = sfile;
requestDevice = device;
requestVerify = verify;
start();
return true;
}
OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &verify,int device)
{
OP_DFU::Status ret;
if (debug)
qDebug() <<"Starting Firmware Uploading...";
QFile file(sfile);
if (!file.open(QIODevice::ReadOnly))
{
if(debug)
qDebug()<<"Cant open file";
return OP_DFU::abort;
}
QByteArray arr = file.readAll();
if(debug)
qDebug()<<"Bytes Loaded="<<arr.length();
if(arr.length()%4!=0)
{
int pad=arr.length()/4;
++pad;
pad=pad*4;
pad=pad-arr.length();
arr.append(QByteArray(pad,255));
}
if( devices[device].SizeOfCode < arr.length())
{
if (debug)
qDebug() << "ERROR file to big for device";
return OP_DFU::abort;;
}
quint32 crc=CRCFromQBArray(arr,devices[device].SizeOfCode);
if (debug)
qDebug() << "NEW FIRMWARE CRC=" << crc;
if( !StartUpload(arr.length(), OP_DFU::FW, crc))
{
ret = StatusRequest();
if(debug)
{
qDebug() << "StartUpload failed";
qDebug() << "StartUpload returned:" << StatusToString(ret);
}
return ret;
}
emit operationProgress(QString("Erasing memory, please wait..."));
if (debug) qDebug() << "Erasing memory";
if( StatusRequest() == OP_DFU::abort) return OP_DFU::abort;
// TODO: why is there a loop there? The "if" statement
// will cause a break or return anyway!!
for (int x = 0; x < 3; ++x) {
ret = StatusRequest();
if (debug) qDebug() << "Erase returned: " << StatusToString(ret);
if (ret == OP_DFU::uploading)
break;
else
return ret;
}
emit operationProgress(QString("Uploading firmware"));
if( !UploadData(arr.length(),arr))
{
ret = StatusRequest();
if(debug)
{
qDebug()<<"Upload failed (upload data)";
qDebug()<<"UploadData returned:"<<StatusToString(ret);
}
return ret;
}
if(!EndOperation())
{
ret = StatusRequest();
if(debug)
{
qDebug()<<"Upload failed (end operation)";
qDebug()<<"EndOperation returned:"<<StatusToString(ret);
}
return ret;
}
ret = StatusRequest();
if(ret != OP_DFU::Last_operation_Success)
return ret;
if(verify) {
emit operationProgress(QString("Verifying firmware"));
cout<<"Starting code verification\n";
QByteArray arr2;
StartDownloadT(&arr2, arr.length(),OP_DFU::FW);
if (arr != arr2 ) {
cout<<"Verify:FAILED\n";
return OP_DFU::abort;
}
}
if(debug)
qDebug()<<"Status="<<ret;
cout<<"Firmware Uploading succeeded\n";
return ret;
}
OP_DFU::Status DFUObject::CompareFirmware(const QString &sfile, const CompareType &type,int device)
{
cout<<"Starting Firmware Compare...\n";
QFile file(sfile);
if (!file.open(QIODevice::ReadOnly))
{
if(debug)
qDebug()<<"Cant open file";
return OP_DFU::abort;
}
QByteArray arr=file.readAll();
if(debug)
qDebug()<<"Bytes Loaded="<<arr.length();
if(arr.length()%4!=0)
{
int pad=arr.length()/4;
++pad;
pad=pad*4;
pad=pad-arr.length();
arr.append(QByteArray(pad,255));
}
if(type==OP_DFU::crccompare)
{
quint32 crc=CRCFromQBArray(arr,devices[device].SizeOfCode);
if(crc==devices[device].FW_CRC)
{
cout<<"Compare Successfull CRC MATCH!\n";
}
else
{
cout<<"Compare failed CRC DONT MATCH!\n";
}
return StatusRequest();
}
else
{
QByteArray arr2;
StartDownloadT(&arr2, arr.length(), OP_DFU::FW);
if(arr == arr2)
{
cout<<"Compare Successfull ALL Bytes MATCH!\n";
}
else
{
cout<<"Compare failed Bytes DONT MATCH!\n";
}
return StatusRequest();
}
}
void DFUObject::CopyWords(char *source, char *destination, int count)
{
for (int x=0;x<count;x=x+4)
{
*(destination+x)=source[x+3];
*(destination+x+1)=source[x+2];
*(destination+x+2)=source[x+1];
*(destination+x+3)=source[x+0];
}
}
QString DFUObject::StatusToString(OP_DFU::Status const & status)
{
switch(status)
{
case DFUidle:
return "DFUidle";
case uploading:
return "";
case wrong_packet_received:
return "wrong_packet_received";
case too_many_packets:
return "too_many_packets";
case too_few_packets:
return "too_few_packets";
case Last_operation_Success:
return "Last_operation_Success";
case downloading:
return "downloading";
case idle:
return "idle";
case Last_operation_failed:
return "Last_operation_failed";
case outsideDevCapabilities:
return "outsideDevCapabilities";
case CRC_Fail:
return "CRC check FAILED";
case failed_jump:
return "Jmp to user FW failed";
case abort:
return "abort";
case uploadingStarting:
return "Uploading Starting";
default:
return "unknown";
}
}
/**
Prints a progress bar with percentage & label during an operation.
Also outputs to stdout if we are in debug mode.
*/
void DFUObject::printProgBar( int const & percent,QString const& label){
std::string bar;
emit(progressUpdated(percent));
if (debug) {
for(int i = 0; i < 50; i++){
if( i < (percent/2)){
bar.replace(i,1,"=");
}else if( i == (percent/2)){
bar.replace(i,1,">");
}else{
bar.replace(i,1," ");
}
}
std::cout<< "\r"<<label.toLatin1().data()<< "[" << bar << "] ";
std::cout.width( 3 );
std::cout<< percent << "% " << std::flush;
}
}
/**
Utility function
*/
quint32 DFUObject::CRC32WideFast(quint32 Crc, quint32 Size, quint32 *Buffer)
{
//Size = Size >> 2; // /4 Size passed in as a byte count, assumed to be a multiple of 4
while(Size--)
{
static const quint32 CrcTable[16] = { // Nibble lookup table for 0x04C11DB7 polynomial
0x00000000,0x04C11DB7,0x09823B6E,0x0D4326D9,0x130476DC,0x17C56B6B,0x1A864DB2,0x1E475005,
0x2608EDB8,0x22C9F00F,0x2F8AD6D6,0x2B4BCB61,0x350C9B64,0x31CD86D3,0x3C8EA00A,0x384FBDBD };
Crc = Crc ^ *((quint32 *)Buffer); // Apply all 32-bits
Buffer += 1;
// Process 32-bits, 4 at a time, or 8 rounds
Crc = (Crc << 4) ^ CrcTable[Crc >> 28]; // Assumes 32-bit reg, masking index to 4-bits
Crc = (Crc << 4) ^ CrcTable[Crc >> 28]; // 0x04C11DB7 Polynomial used in STM32
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
}
return(Crc);
}
/**
Utility function
*/
quint32 DFUObject::CRCFromQBArray(QByteArray array, quint32 Size)
{
int pad=Size-array.length();
array.append(QByteArray(pad,255));
quint32 t[Size/4];
for(int x=0;x<array.length()/4;x++)
{
quint32 aux=0;
aux=(char)array[x*4+3]&0xFF;
aux=aux<<8;
aux+=(char)array[x*4+2]&0xFF;
aux=aux<<8;
aux+=(char)array[x*4+1]&0xFF;
aux=aux<<8;
aux+=(char)array[x*4+0]&0xFF;
t[x]=aux;
}
return CRC32WideFast(0xFFFFFFFF,Size/4,(quint32*)t);
}
/**
Send data to the bootloader, either through the serial port
of through the HID handle, depending on the mode we're using
*/
int DFUObject::sendData(void * data,int size)
{
if(!use_serial)
return hidHandle.send(0,data, size, 5000);
// Serial Mode:
if(serialhandle->sendData((uint8_t*)data+1,size-1))
{
if (debug)
qDebug() << "packet sent" << "data0" << ((uint8_t*)data+1)[0];
return size;
}
if(debug)
qDebug() << "Serial send OVERRUN";
return -1;
}
/**
Receive data from the bootloader, either through the serial port
of through the HID handle, depending on the mode we're using
*/
int DFUObject::receiveData(void * data,int size)
{
if(!use_serial)
return hidHandle.receive(0,data, size, 10000);
// Serial Mode:
int x;
QTime time;
time.start();
while(true)
{
if((x=serialhandle->read_Packet(((char *) data)+1)!=-1) || time.elapsed()>10000)
{
if(time.elapsed()>10000)
qDebug()<<"____timeout";
return x;
}
}
}
/**
******************************************************************************
*
* @file op_dfu.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Uploader Plugin
* @{
* @brief The uploader plugin
*****************************************************************************/
/*
* 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, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "op_dfu.h"
#include <cmath>
#include <qwaitcondition.h>
#include <QMetaType>
using namespace OP_DFU;
DFUObject::DFUObject(bool _debug,bool _use_serial,QString portname): debug(_debug),use_serial(_use_serial),mready(true)
{
info = NULL;
qRegisterMetaType<OP_DFU::Status>("Status");
if(use_serial)
{
PortSettings settings;
settings.BaudRate=BAUD57600;
settings.DataBits=DATA_8;
settings.FlowControl=FLOW_OFF;
settings.Parity=PAR_NONE;
settings.StopBits=STOP_1;
settings.Timeout_Millisec=1000;
info = new port(settings,portname);
info->rxBuf = sspRxBuf;
info->rxBufSize = MAX_PACKET_DATA_LEN;
info->txBuf = sspTxBuf;
info->txBufSize = MAX_PACKET_DATA_LEN;
info->max_retry = 10;
info->timeoutLen = 1000;
if(info->status()!=port::open)
{
cout << "Could not open serial port\n";
mready = false;
return;
}
serialhandle = new qsspt(info,debug);
int count = 0;
while((serialhandle->ssp_Synchronise()==false) && (count < 10))
{
if (debug)
qDebug()<<"SYNC failed, resending";
count++;
}
if (count == 10) {
mready = false;
return;
}
qDebug() << "SYNC Succeded";
serialhandle->start();
}
else
{
send_delay=10;
use_delay=true;
int numDevices=0;
int count=0;
while((numDevices==0) && count < 10)
{
if (debug)
qDebug() << ".";
delay::msleep(500);
numDevices = hidHandle.open(1,0x20a0,0x4117,0,0); //0xff9c,0x0001);
count++;
}
if(debug)
qDebug() << numDevices << " device(s) opened";
}
}
DFUObject::~DFUObject()
{
if (use_serial) {
if (mready) {
delete serialhandle;
delete info;
}
} else {
hidHandle.close(0);
}
}
bool DFUObject::SaveByteArrayToFile(QString const & sfile, const QByteArray &array)
{
QFile file(sfile);
if (!file.open(QIODevice::WriteOnly))
{
if(debug)
qDebug()<<"Can't open file";
return false;
}
file.write(array);
file.close();
return true;
}
/**
Tells the mainboard to enter DFU Mode.
*/
bool DFUObject::enterDFU(int const &devNumber)
{
char buf[BUF_LEN];
buf[0] =0x02; //reportID
buf[1] = OP_DFU::EnterDFU; //DFU Command
buf[2] = 0; //DFU Count
buf[3] = 0; //DFU Count
buf[4] = 0; //DFU Count
buf[5] = 0; //DFU Count
buf[6] = devNumber; //DFU Data0
buf[7] = 1; //DFU Data1
buf[8] = 1; //DFU Data2
buf[9] = 1; //DFU Data3
int result = sendData(buf, BUF_LEN);
// int result = hidHandle.send(0,buf, BUF_LEN, 500);
if(result<1)
return false;
if(debug)
qDebug() << "EnterDFU: " << result << " bytes sent";
return true;
}
/**
Tells the board to get ready for an upload. It will in particular
erase the memory to make room for the data. You will have to query
its status to wait until erase is done before doing the actual upload.
*/
bool DFUObject::StartUpload(qint32 const & numberOfBytes, TransferTypes const & type,quint32 crc)
{
int lastPacketCount;
qint32 numberOfPackets=numberOfBytes/4/14;
int pad=(numberOfBytes-numberOfPackets*4*14)/4;
if(pad==0)
{
lastPacketCount=14;
}
else
{
++numberOfPackets;
lastPacketCount=pad;
}
char buf[BUF_LEN];
buf[0] =0x02;//reportID
buf[1] = setStartBit(OP_DFU::Upload);//DFU Command
buf[2] = numberOfPackets>>24;//DFU Count
buf[3] = numberOfPackets>>16;//DFU Count
buf[4] = numberOfPackets>>8;//DFU Count
buf[5] = numberOfPackets;//DFU Count
buf[6] = (int)type;//DFU Data0
buf[7] = lastPacketCount;//DFU Data1
buf[8] = crc>>24;
buf[9] = crc>>16;
buf[10] = crc>>8;
buf[11] = crc;
if(debug)
qDebug()<<"Number of packets:"<<numberOfPackets<<" Size of last packet:"<<lastPacketCount;
int result = sendData(buf, BUF_LEN);
delay::msleep(1000);
// int result = hidHandle.send(0,buf, BUF_LEN, 5000);
if(debug)
qDebug() << result << " bytes sent";
if(result>0)
{
return true;
}
return false;
}
/**
Does the actual data upload to the board. Needs to be called once the
board is ready to accept data following a StartUpload command, and it is erased.
*/
bool DFUObject::UploadData(qint32 const & numberOfBytes, QByteArray & data)
{
int lastPacketCount;
qint32 numberOfPackets=numberOfBytes/4/14;
int pad=(numberOfBytes-numberOfPackets*4*14)/4;
if(pad==0)
{
lastPacketCount=14;
}
else
{
++numberOfPackets;
lastPacketCount=pad;
}
if(debug)
qDebug()<<"Start Uploading:"<<numberOfPackets<<"4Bytes";
char buf[BUF_LEN];
buf[0] =0x02;//reportID
buf[1] = OP_DFU::Upload;//DFU Command
int packetsize;
float percentage;
int laspercentage;
for(qint32 packetcount=0;packetcount<numberOfPackets;++packetcount)
{
percentage=(float)(packetcount+1)/numberOfPackets*100;
if(laspercentage!=(int)percentage)
printProgBar((int)percentage,"UPLOADING");
laspercentage=(int)percentage;
if(packetcount==numberOfPackets)
packetsize=lastPacketCount;
else
packetsize=14;
// qDebug()<<packetcount;
buf[2] = packetcount>>24;//DFU Count
buf[3] = packetcount>>16;//DFU Count
buf[4] = packetcount>>8;//DFU Count
buf[5] = packetcount;//DFU Count
char *pointer=data.data();
pointer=pointer+4*14*packetcount;
// qDebug()<<"Packet Number="<<packetcount<<"Data0="<<(int)data[0]<<" Data1="<<(int)data[1]<<" Data0="<<(int)data[2]<<" Data0="<<(int)data[3]<<" buf6="<<(int)buf[6]<<" buf7="<<(int)buf[7]<<" buf8="<<(int)buf[8]<<" buf9="<<(int)buf[9];
CopyWords(pointer,buf+6,packetsize*4);
// for (int y=0;y<packetsize*4;++y)
// {
// qDebug()<<y<<":"<<(int)data[packetcount*14*4+y]<<"---"<<(int)buf[6+y];
// }
// qDebug()<<" Data0="<<(int)data[0]<<" Data0="<<(int)data[1]<<" Data0="<<(int)data[2]<<" Data0="<<(int)data[3]<<" buf6="<<(int)buf[6]<<" buf7="<<(int)buf[7]<<" buf8="<<(int)buf[8]<<" buf9="<<(int)buf[9];
//delay::msleep(send_delay);
//if(StatusRequest()!=OP_DFU::uploading) return false;
int result = sendData(buf, BUF_LEN);
// qDebug()<<"sent:"<<result;
if(result<1)
{
return false;
}
// qDebug() << "UPLOAD:"<<"Data="<<(int)buf[6]<<(int)buf[7]<<(int)buf[8]<<(int)buf[9]<<";"<<result << " bytes sent";
}
cout<<"\n";
// while(true){}
return true;
}
/**
Sends the firmware description to the device
*/
OP_DFU::Status DFUObject::UploadDescription(QString description)
{
cout<<"Starting uploading description\n";
if(description.length()%4!=0)
{
int pad=description.length()/4;
pad=(pad+1)*4;
pad=pad-description.length();
QString padding;
padding.fill(' ',pad);
description.append(padding);
}
if(!StartUpload(description.length(),OP_DFU::Descript,0))
return OP_DFU::abort;
QByteArray array=description.toAscii();
if(!UploadData(description.length(),array))
{
return OP_DFU::abort;
}
if(!EndOperation())
{
return OP_DFU::abort;
}
OP_DFU::Status ret = StatusRequest();
if(debug)
qDebug() << "Upload description Status=" << StatusToString(ret);
return ret;
}
/**
Downloads the description string for the current device.
You have to call enterDFU before calling this function.
*/
QString DFUObject::DownloadDescription(int const & numberOfChars)
{
QByteArray arr;
StartDownloadT(&arr, numberOfChars,OP_DFU::Descript);
QString str(arr);
return str;
}
/**
Starts a firmware download
@param firmwareArray: pointer to the location where we should store the firmware
@package device: the device to use for the download
*/
bool DFUObject::DownloadFirmware(QByteArray *firmwareArray, int device)
{
if (isRunning())
return false;
requestedOperation = OP_DFU::Download;
requestSize = devices[device].SizeOfCode;
requestTransferType = OP_DFU::FW;
requestStorage = firmwareArray;
start();
return true;
}
/**
Runs the upload or download operations.
*/
void DFUObject::run()
{
switch (requestedOperation) {
case OP_DFU::Download:
StartDownloadT(requestStorage, requestSize, requestTransferType);
emit(downloadFinished());
break;
case OP_DFU::Upload: {
OP_DFU::Status ret = UploadFirmwareT(requestFilename, requestVerify, requestDevice);
emit(uploadFinished(ret));
break;
}
default:
break;
}
return;
}
/**
Downloads a certain number of bytes from a certain location, and stores in an array whose
pointer is passed as an argument
*/
bool DFUObject::StartDownloadT(QByteArray *fw, qint32 const & numberOfBytes, TransferTypes const & type)
{
int lastPacketCount;
// First of all, work out the number of DFU packets we should ask for:
qint32 numberOfPackets = numberOfBytes/4/14;
int pad = (numberOfBytes-numberOfPackets*4*14)/4;
if(pad == 0) {
lastPacketCount=14;
}
else {
++numberOfPackets;
lastPacketCount=pad;
}
char buf[BUF_LEN];
buf[0] = 0x02; //reportID
buf[1] = OP_DFU::Download_Req; //DFU Command
buf[2] = numberOfPackets>>24; //DFU Count
buf[3] = numberOfPackets>>16; //DFU Count
buf[4] = numberOfPackets>>8; //DFU Count
buf[5] = numberOfPackets; //DFU Count
buf[6] = (int)type; //DFU Data0
buf[7] = lastPacketCount; //DFU Data1
buf[8] = 1; //DFU Data2
buf[9] = 1; //DFU Data3
int result = sendData(buf, BUF_LEN);
//int result = hidHandle.send(0,buf, BUF_LEN, 500);
if(debug)
qDebug() << "StartDownload:"<<numberOfPackets<<"packets"<<" Last Packet Size="<<lastPacketCount<<" "<<result << " bytes sent";
float percentage;
int laspercentage;
// Now get those packets:
for(qint32 x=0;x<numberOfPackets;++x)
{
int size;
percentage=(float)(x+1)/numberOfPackets*100;
if(laspercentage!=(int)percentage)
printProgBar((int)percentage,"DOWNLOADING");
laspercentage=(int)percentage;
result = receiveData(buf,BUF_LEN);
//result = hidHandle.receive(0,buf,BUF_LEN,5000);
if(debug)
qDebug() << result << " bytes received"<<" Count="<<x<<"-"<<(int)buf[2]<<";"<<(int)buf[3]<<";"<<(int)buf[4]<<";"<<(int)buf[5]<<" Data="<<(int)buf[6]<<";"<<(int)buf[7]<<";"<<(int)buf[8]<<";"<<(int)buf[9];
if(x==numberOfPackets-1)
size=lastPacketCount*4;
else
size=14*4;
fw->append(buf+6,size);
}
StatusRequest();
return true;
}
/**
Resets the device
*/
int DFUObject::ResetDevice(void)
{
char buf[BUF_LEN];
buf[0] =0x02; //reportID
buf[1] = OP_DFU::Reset; //DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
return sendData(buf, BUF_LEN);
//return hidHandle.send(0,buf, BUF_LEN, 500);
}
int DFUObject::AbortOperation(void)
{
char buf[BUF_LEN];
buf[0] =0x02;//reportID
buf[1] = OP_DFU::Abort_Operation;//DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
return sendData(buf, BUF_LEN);
//return hidHandle.send(0,buf, BUF_LEN, 500);
}
/**
Starts the firmware (leaves bootloader and boots the main software)
*/
int DFUObject::JumpToApp()
{
char buf[BUF_LEN];
buf[0] =0x02;//reportID
buf[1] = OP_DFU::JumpFW;//DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
return sendData(buf, BUF_LEN);
//return hidHandle.send(0,buf, BUF_LEN, 500);
}
OP_DFU::Status DFUObject::StatusRequest()
{
char buf[BUF_LEN];
buf[0] =0x02; //reportID
buf[1] = OP_DFU::Status_Request; //DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
int result = sendData(buf, BUF_LEN);
//int result = hidHandle.send(0,buf, BUF_LEN, 10000);
if(debug)
qDebug() << "StatusRequest: " << result << " bytes sent";
result = receiveData(buf,BUF_LEN);
// result = hidHandle.receive(0,buf,BUF_LEN,10000);
if(debug)
qDebug() << "StatusRequest: " << result << " bytes received";
if(buf[1]==OP_DFU::Status_Rep)
{
return (OP_DFU::Status)buf[6];
}
else
return OP_DFU::abort;
}
/**
Ask the bootloader for the list of devices available
*/
bool DFUObject::findDevices()
{
devices.clear();
char buf[BUF_LEN];
buf[0] =0x02; //reportID
buf[1] = OP_DFU::Req_Capabilities; //DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
int result = sendData(buf, BUF_LEN);
//int result = hidHandle.send(0,buf, BUF_LEN, 5000);
if(result<1)
{
return false;
}
result = receiveData(buf,BUF_LEN);
//result = hidHandle.receive(0,buf,BUF_LEN,5000);
if(result<1)
{
return false;
}
numberOfDevices=buf[7];
RWFlags=buf[8];
RWFlags=RWFlags<<8 | buf[9];
if(buf[1]==OP_DFU::Rep_Capabilities)
{
for(int x=0;x<numberOfDevices;++x)
{
device dev;
dev.Readable=(bool)(RWFlags>>(x*2) & 1);
dev.Writable=(bool)(RWFlags>>(x*2+1) & 1);
devices.append(dev);
buf[0] =0x02; //reportID
buf[1] = OP_DFU::Req_Capabilities; //DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = x+1;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
int result = sendData(buf, BUF_LEN);
result = receiveData(buf,BUF_LEN);
// int result = hidHandle.send(0,buf, BUF_LEN, 5000);
// result = hidHandle.receive(0,buf,BUF_LEN,5000);
//devices[x].ID=buf[9];
devices[x].ID=buf[14];
devices[x].ID=devices[x].ID<<8 | (quint8)buf[15];
devices[x].BL_Version=buf[7];
devices[x].SizeOfDesc=buf[8];
quint32 aux;
aux=(quint8)buf[10];
aux=aux<<8 |(quint8)buf[11];
aux=aux<<8 |(quint8)buf[12];
aux=aux<<8 |(quint8)buf[13];
devices[x].FW_CRC=aux;
aux=(quint8)buf[2];
aux=aux<<8 |(quint8)buf[3];
aux=aux<<8 |(quint8)buf[4];
aux=aux<<8 |(quint8)buf[5];
devices[x].SizeOfCode=aux;
}
if(debug)
{
qDebug() << "Found " << numberOfDevices << " devices";
for(int x=0;x<numberOfDevices;++x)
{
qDebug()<<"Device #"<<x+1;
qDebug()<<"Device ID="<<devices[x].ID;
qDebug()<<"Device Readable="<<devices[x].Readable;
qDebug()<<"Device Writable="<<devices[x].Writable;
qDebug()<<"Device SizeOfCode="<<devices[x].SizeOfCode;
qDebug()<<"Device SizeOfDesc="<<devices[x].SizeOfDesc;
qDebug()<<"BL Version="<<devices[x].BL_Version;
qDebug()<<"FW CRC="<<devices[x].FW_CRC;
}
}
}
return true;
}
bool DFUObject::EndOperation()
{
char buf[BUF_LEN];
buf[0] =0x02;//reportID
buf[1] = OP_DFU::Op_END;//DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
buf[7] = 0;
buf[8] = 0;
buf[9] = 0;
int result = sendData(buf, BUF_LEN);
// int result = hidHandle.send(0,buf, BUF_LEN, 5000);
// hidHandle.receive(0,buf,BUF_LEN,5000);
if(debug)
qDebug() << result << " bytes sent";
if(result>0)
return true;
return false;
}
//
/**
Starts a firmware upload (asynchronous)
*/
bool DFUObject::UploadFirmware(const QString &sfile, const bool &verify,int device)
{
if (isRunning())
return false;
requestedOperation = OP_DFU::Upload;
requestFilename = sfile;
requestDevice = device;
requestVerify = verify;
start();
return true;
}
OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &verify,int device)
{
OP_DFU::Status ret;
if (debug)
qDebug() <<"Starting Firmware Uploading...";
QFile file(sfile);
if (!file.open(QIODevice::ReadOnly))
{
if(debug)
qDebug()<<"Cant open file";
return OP_DFU::abort;
}
QByteArray arr = file.readAll();
if(debug)
qDebug()<<"Bytes Loaded="<<arr.length();
if(arr.length()%4!=0)
{
int pad=arr.length()/4;
++pad;
pad=pad*4;
pad=pad-arr.length();
arr.append(QByteArray(pad,255));
}
if( devices[device].SizeOfCode < arr.length())
{
if (debug)
qDebug() << "ERROR file to big for device";
return OP_DFU::abort;;
}
quint32 crc=CRCFromQBArray(arr,devices[device].SizeOfCode);
if (debug)
qDebug() << "NEW FIRMWARE CRC=" << crc;
if( !StartUpload(arr.length(), OP_DFU::FW, crc))
{
ret = StatusRequest();
if(debug)
{
qDebug() << "StartUpload failed";
qDebug() << "StartUpload returned:" << StatusToString(ret);
}
return ret;
}
emit operationProgress(QString("Erasing memory, please wait..."));
if (debug) qDebug() << "Erasing memory";
if( StatusRequest() == OP_DFU::abort) return OP_DFU::abort;
// TODO: why is there a loop there? The "if" statement
// will cause a break or return anyway!!
for (int x = 0; x < 3; ++x) {
ret = StatusRequest();
if (debug) qDebug() << "Erase returned: " << StatusToString(ret);
if (ret == OP_DFU::uploading)
break;
else
return ret;
}
emit operationProgress(QString("Uploading firmware"));
if( !UploadData(arr.length(),arr))
{
ret = StatusRequest();
if(debug)
{
qDebug()<<"Upload failed (upload data)";
qDebug()<<"UploadData returned:"<<StatusToString(ret);
}
return ret;
}
if(!EndOperation())
{
ret = StatusRequest();
if(debug)
{
qDebug()<<"Upload failed (end operation)";
qDebug()<<"EndOperation returned:"<<StatusToString(ret);
}
return ret;
}
ret = StatusRequest();
if(ret != OP_DFU::Last_operation_Success)
return ret;
if(verify) {
emit operationProgress(QString("Verifying firmware"));
cout<<"Starting code verification\n";
QByteArray arr2;
StartDownloadT(&arr2, arr.length(),OP_DFU::FW);
if (arr != arr2 ) {
cout<<"Verify:FAILED\n";
return OP_DFU::abort;
}
}
if(debug)
qDebug()<<"Status="<<ret;
cout<<"Firmware Uploading succeeded\n";
return ret;
}
OP_DFU::Status DFUObject::CompareFirmware(const QString &sfile, const CompareType &type,int device)
{
cout<<"Starting Firmware Compare...\n";
QFile file(sfile);
if (!file.open(QIODevice::ReadOnly))
{
if(debug)
qDebug()<<"Cant open file";
return OP_DFU::abort;
}
QByteArray arr=file.readAll();
if(debug)
qDebug()<<"Bytes Loaded="<<arr.length();
if(arr.length()%4!=0)
{
int pad=arr.length()/4;
++pad;
pad=pad*4;
pad=pad-arr.length();
arr.append(QByteArray(pad,255));
}
if(type==OP_DFU::crccompare)
{
quint32 crc=CRCFromQBArray(arr,devices[device].SizeOfCode);
if(crc==devices[device].FW_CRC)
{
cout<<"Compare Successfull CRC MATCH!\n";
}
else
{
cout<<"Compare failed CRC DONT MATCH!\n";
}
return StatusRequest();
}
else
{
QByteArray arr2;
StartDownloadT(&arr2, arr.length(), OP_DFU::FW);
if(arr == arr2)
{
cout<<"Compare Successfull ALL Bytes MATCH!\n";
}
else
{
cout<<"Compare failed Bytes DONT MATCH!\n";
}
return StatusRequest();
}
}
void DFUObject::CopyWords(char *source, char *destination, int count)
{
for (int x=0;x<count;x=x+4)
{
*(destination+x)=source[x+3];
*(destination+x+1)=source[x+2];
*(destination+x+2)=source[x+1];
*(destination+x+3)=source[x+0];
}
}
QString DFUObject::StatusToString(OP_DFU::Status const & status)
{
switch(status)
{
case DFUidle:
return "DFUidle";
case uploading:
return "";
case wrong_packet_received:
return "wrong_packet_received";
case too_many_packets:
return "too_many_packets";
case too_few_packets:
return "too_few_packets";
case Last_operation_Success:
return "Last_operation_Success";
case downloading:
return "downloading";
case idle:
return "idle";
case Last_operation_failed:
return "Last_operation_failed";
case outsideDevCapabilities:
return "outsideDevCapabilities";
case CRC_Fail:
return "CRC check FAILED";
case failed_jump:
return "Jmp to user FW failed";
case abort:
return "abort";
case uploadingStarting:
return "Uploading Starting";
default:
return "unknown";
}
}
/**
Prints a progress bar with percentage & label during an operation.
Also outputs to stdout if we are in debug mode.
*/
void DFUObject::printProgBar( int const & percent,QString const& label){
std::string bar;
emit(progressUpdated(percent));
if (debug) {
for(int i = 0; i < 50; i++){
if( i < (percent/2)){
bar.replace(i,1,"=");
}else if( i == (percent/2)){
bar.replace(i,1,">");
}else{
bar.replace(i,1," ");
}
}
std::cout<< "\r"<<label.toLatin1().data()<< "[" << bar << "] ";
std::cout.width( 3 );
std::cout<< percent << "% " << std::flush;
}
}
/**
Utility function
*/
quint32 DFUObject::CRC32WideFast(quint32 Crc, quint32 Size, quint32 *Buffer)
{
//Size = Size >> 2; // /4 Size passed in as a byte count, assumed to be a multiple of 4
while(Size--)
{
static const quint32 CrcTable[16] = { // Nibble lookup table for 0x04C11DB7 polynomial
0x00000000,0x04C11DB7,0x09823B6E,0x0D4326D9,0x130476DC,0x17C56B6B,0x1A864DB2,0x1E475005,
0x2608EDB8,0x22C9F00F,0x2F8AD6D6,0x2B4BCB61,0x350C9B64,0x31CD86D3,0x3C8EA00A,0x384FBDBD };
Crc = Crc ^ *((quint32 *)Buffer); // Apply all 32-bits
Buffer += 1;
// Process 32-bits, 4 at a time, or 8 rounds
Crc = (Crc << 4) ^ CrcTable[Crc >> 28]; // Assumes 32-bit reg, masking index to 4-bits
Crc = (Crc << 4) ^ CrcTable[Crc >> 28]; // 0x04C11DB7 Polynomial used in STM32
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
}
return(Crc);
}
/**
Utility function
*/
quint32 DFUObject::CRCFromQBArray(QByteArray array, quint32 Size)
{
int pad=Size-array.length();
array.append(QByteArray(pad,255));
quint32 t[Size/4];
for(int x=0;x<array.length()/4;x++)
{
quint32 aux=0;
aux=(char)array[x*4+3]&0xFF;
aux=aux<<8;
aux+=(char)array[x*4+2]&0xFF;
aux=aux<<8;
aux+=(char)array[x*4+1]&0xFF;
aux=aux<<8;
aux+=(char)array[x*4+0]&0xFF;
t[x]=aux;
}
return CRC32WideFast(0xFFFFFFFF,Size/4,(quint32*)t);
}
/**
Send data to the bootloader, either through the serial port
of through the HID handle, depending on the mode we're using
*/
int DFUObject::sendData(void * data,int size)
{
if(!use_serial)
return hidHandle.send(0,data, size, 5000);
// Serial Mode:
if(serialhandle->sendData((uint8_t*)data+1,size-1))
{
if (debug)
qDebug() << "packet sent" << "data0" << ((uint8_t*)data+1)[0];
return size;
}
if(debug)
qDebug() << "Serial send OVERRUN";
return -1;
}
/**
Receive data from the bootloader, either through the serial port
of through the HID handle, depending on the mode we're using
*/
int DFUObject::receiveData(void * data,int size)
{
if(!use_serial)
return hidHandle.receive(0,data, size, 10000);
// Serial Mode:
int x;
QTime time;
time.start();
while(true)
{
if((x=serialhandle->read_Packet(((char *) data)+1)!=-1) || time.elapsed()>10000)
{
if(time.elapsed()>10000)
qDebug()<<"____timeout";
return x;
}
}
}

View File

@ -1,208 +1,208 @@
#ifndef OP_DFU_H
#define OP_DFU_H
#include <QByteArray>
#include <rawhid/pjrc_rawhid.h>
#include <QDebug>
#include <QFile>
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
#include <QMetaType>
#include <QCryptographicHash>
#include <QList>
#include <iostream>
#include "delay.h"
#include <qextserialport/src/qextserialport.h>
#include <QTime>
#include "SSP/qssp.h"
#include "SSP/port.h"
#include "SSP/qsspt.h"
using namespace std;
#define BUF_LEN 64
#define MAX_PACKET_DATA_LEN 255
#define MAX_PACKET_BUF_SIZE (1+1+MAX_PACKET_DATA_LEN+2)
namespace OP_DFU {
enum TransferTypes
{
FW,
Descript
};
enum CompareType
{
crccompare,
bytetobytecompare
};
Q_ENUMS(Status)
enum Status
{
DFUidle,//0
uploading,//1
wrong_packet_received,//2
too_many_packets,//3
too_few_packets,//4
Last_operation_Success,//5
downloading,//6
idle,//7
Last_operation_failed,//8
uploadingStarting,//9
outsideDevCapabilities,//10
CRC_Fail,//11
failed_jump,//12
abort//13
};
enum Actions
{
actionProgram,
actionProgramAndVerify,
actionDownload,
actionCompareAll,
actionCompareCrc,
actionListDevs,
actionStatusReq,
actionReset,
actionJump
};
enum Commands
{
Reserved,//0
Req_Capabilities,//1
Rep_Capabilities,//2
EnterDFU,//3
JumpFW,//4
Reset,//5
Abort_Operation,//6
Upload,//7
Op_END,//8
Download_Req,//9
Download,//10
Status_Request,//11
Status_Rep,//12
};
struct device
{
int ID;
quint32 FW_CRC;
int BL_Version;
int SizeOfDesc;
quint32 SizeOfCode;
bool Readable;
bool Writable;
};
class DFUObject : public QThread
{
Q_OBJECT;
public:
//DFUObject(bool debug);
DFUObject(bool debug,bool use_serial,QString port);
~DFUObject();
// Service commands:
bool enterDFU(int const &devNumber);
bool findDevices();
int JumpToApp();
int ResetDevice(void);
OP_DFU::Status StatusRequest();
bool EndOperation();
int AbortOperation(void);
bool ready() { return mready; }
// Upload (send to device) commands
OP_DFU::Status UploadDescription(QString description);
bool UploadFirmware(const QString &sfile, const bool &verify,int device);
// Download (get from device) commands:
// DownloadDescription is synchronous
QString DownloadDescription(int const & numberOfChars);
// Asynchronous firmware download: initiates fw download,
// and a downloadFinished signal is emitted when download
// if finished:
bool DownloadFirmware(QByteArray *byteArray, int device);
// Comparison functions (is this needed?)
OP_DFU::Status CompareFirmware(const QString &sfile, const CompareType &type,int device);
bool SaveByteArrayToFile(QString const & file,QByteArray const &array);
// Variables:
QList<device> devices;
int numberOfDevices;
int send_delay;
bool use_delay;
// Helper functions:
QString StatusToString(OP_DFU::Status const & status);
quint32 CRC32WideFast(quint32 Crc, quint32 Size, quint32 *Buffer);
signals:
void progressUpdated(int);
void downloadFinished();
void uploadFinished(OP_DFU::Status);
void operationProgress(QString status);
private:
// Generic variables:
bool debug;
bool use_serial;
bool mready;
int RWFlags;
qsspt * serialhandle;
int sendData(void*,int);
int receiveData(void * data,int size);
uint8_t sspTxBuf[MAX_PACKET_BUF_SIZE];
uint8_t sspRxBuf[MAX_PACKET_BUF_SIZE];
port * info;
// USB Bootloader:
pjrc_rawhid hidHandle;
int setStartBit(int command){ return command|0x20; }
quint32 CRCFromQBArray(QByteArray array, quint32 Size);
void CopyWords(char * source, char* destination, int count);
void printProgBar( int const & percent,QString const& label);
bool StartUpload(qint32 const &numberOfBytes, TransferTypes const & type,quint32 crc);
bool UploadData(qint32 const & numberOfPackets,QByteArray & data);
// Thread management:
// Same as startDownload except that we store in an external array:
bool StartDownloadT(QByteArray *fw, qint32 const & numberOfBytes, TransferTypes const & type);
OP_DFU::Status UploadFirmwareT(const QString &sfile, const bool &verify,int device);
QMutex mutex;
OP_DFU::Commands requestedOperation;
qint32 requestSize;
OP_DFU::TransferTypes requestTransferType;
QByteArray *requestStorage;
QString requestFilename;
bool requestVerify;
int requestDevice;
protected:
void run();// Executes the upload or download operations
};
}
Q_DECLARE_METATYPE(OP_DFU::Status)
#endif // OP_DFU_H
#ifndef OP_DFU_H
#define OP_DFU_H
#include <QByteArray>
#include <rawhid/pjrc_rawhid.h>
#include <QDebug>
#include <QFile>
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
#include <QMetaType>
#include <QCryptographicHash>
#include <QList>
#include <iostream>
#include "delay.h"
#include <qextserialport/src/qextserialport.h>
#include <QTime>
#include "SSP/qssp.h"
#include "SSP/port.h"
#include "SSP/qsspt.h"
using namespace std;
#define BUF_LEN 64
#define MAX_PACKET_DATA_LEN 255
#define MAX_PACKET_BUF_SIZE (1+1+MAX_PACKET_DATA_LEN+2)
namespace OP_DFU {
enum TransferTypes
{
FW,
Descript
};
enum CompareType
{
crccompare,
bytetobytecompare
};
Q_ENUMS(Status)
enum Status
{
DFUidle,//0
uploading,//1
wrong_packet_received,//2
too_many_packets,//3
too_few_packets,//4
Last_operation_Success,//5
downloading,//6
idle,//7
Last_operation_failed,//8
uploadingStarting,//9
outsideDevCapabilities,//10
CRC_Fail,//11
failed_jump,//12
abort//13
};
enum Actions
{
actionProgram,
actionProgramAndVerify,
actionDownload,
actionCompareAll,
actionCompareCrc,
actionListDevs,
actionStatusReq,
actionReset,
actionJump
};
enum Commands
{
Reserved,//0
Req_Capabilities,//1
Rep_Capabilities,//2
EnterDFU,//3
JumpFW,//4
Reset,//5
Abort_Operation,//6
Upload,//7
Op_END,//8
Download_Req,//9
Download,//10
Status_Request,//11
Status_Rep,//12
};
struct device
{
int ID;
quint32 FW_CRC;
int BL_Version;
int SizeOfDesc;
quint32 SizeOfCode;
bool Readable;
bool Writable;
};
class DFUObject : public QThread
{
Q_OBJECT;
public:
//DFUObject(bool debug);
DFUObject(bool debug,bool use_serial,QString port);
~DFUObject();
// Service commands:
bool enterDFU(int const &devNumber);
bool findDevices();
int JumpToApp();
int ResetDevice(void);
OP_DFU::Status StatusRequest();
bool EndOperation();
int AbortOperation(void);
bool ready() { return mready; }
// Upload (send to device) commands
OP_DFU::Status UploadDescription(QString description);
bool UploadFirmware(const QString &sfile, const bool &verify,int device);
// Download (get from device) commands:
// DownloadDescription is synchronous
QString DownloadDescription(int const & numberOfChars);
// Asynchronous firmware download: initiates fw download,
// and a downloadFinished signal is emitted when download
// if finished:
bool DownloadFirmware(QByteArray *byteArray, int device);
// Comparison functions (is this needed?)
OP_DFU::Status CompareFirmware(const QString &sfile, const CompareType &type,int device);
bool SaveByteArrayToFile(QString const & file,QByteArray const &array);
// Variables:
QList<device> devices;
int numberOfDevices;
int send_delay;
bool use_delay;
// Helper functions:
QString StatusToString(OP_DFU::Status const & status);
quint32 CRC32WideFast(quint32 Crc, quint32 Size, quint32 *Buffer);
signals:
void progressUpdated(int);
void downloadFinished();
void uploadFinished(OP_DFU::Status);
void operationProgress(QString status);
private:
// Generic variables:
bool debug;
bool use_serial;
bool mready;
int RWFlags;
qsspt * serialhandle;
int sendData(void*,int);
int receiveData(void * data,int size);
uint8_t sspTxBuf[MAX_PACKET_BUF_SIZE];
uint8_t sspRxBuf[MAX_PACKET_BUF_SIZE];
port * info;
// USB Bootloader:
pjrc_rawhid hidHandle;
int setStartBit(int command){ return command|0x20; }
quint32 CRCFromQBArray(QByteArray array, quint32 Size);
void CopyWords(char * source, char* destination, int count);
void printProgBar( int const & percent,QString const& label);
bool StartUpload(qint32 const &numberOfBytes, TransferTypes const & type,quint32 crc);
bool UploadData(qint32 const & numberOfPackets,QByteArray & data);
// Thread management:
// Same as startDownload except that we store in an external array:
bool StartDownloadT(QByteArray *fw, qint32 const & numberOfBytes, TransferTypes const & type);
OP_DFU::Status UploadFirmwareT(const QString &sfile, const bool &verify,int device);
QMutex mutex;
OP_DFU::Commands requestedOperation;
qint32 requestSize;
OP_DFU::TransferTypes requestTransferType;
QByteArray *requestStorage;
QString requestFilename;
bool requestVerify;
int requestDevice;
protected:
void run();// Executes the upload or download operations
};
}
Q_DECLARE_METATYPE(OP_DFU::Status)
#endif // OP_DFU_H