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

LP-458 uploadtool: reconcile gcs uploader with uploadtool

ssp is entirely copied from uploadtool (as it works there)
dfu still has some small differences due to "quirks" in tool or gcs
This commit is contained in:
Philippe Renon 2017-02-01 23:08:27 +01:00
parent 6f806b6c49
commit 131842724e
24 changed files with 1470 additions and 316 deletions

View File

@ -2,7 +2,8 @@
******************************************************************************
*
* @file common.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
@ -23,10 +24,11 @@
* 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
*/
#ifndef COMMON_H
#define COMMON_H
enum decodeState_ {
enum DecodeState {
decode_len1_e = 0,
decode_seqNo_e,
decode_data_e,
@ -34,10 +36,10 @@ enum decodeState_ {
decode_crc2_e,
decode_idle_e
};
enum ReceiveState {
state_escaped_e = 0,
state_unescaped_e
};
#endif // COMMON_H

View File

@ -0,0 +1,97 @@
/**
******************************************************************************
*
* @file main.cpp
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* 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 "port.h"
#include "qsspt.h"
#include "../../../libs/qextserialport/src/qextserialport.h"
#include <QtCore/QCoreApplication>
#include <QTime>
#include <QDebug>
#define MAX_PACKET_DATA_LEN 255
#define MAX_PACKET_BUF_SIZE (1 + 1 + 255 + 2)
int main(int argc, char *argv[])
{
uint8_t sspTxBuf[MAX_PACKET_BUF_SIZE];
uint8_t sspRxBuf[MAX_PACKET_BUF_SIZE];
port *info;
PortSettings settings;
settings.BaudRate = BAUD57600;
settings.DataBits = DATA_8;
settings.FlowControl = FLOW_OFF;
settings.Parity = PAR_NONE;
settings.StopBits = STOP_1;
settings.Timeout_Millisec = 5000;
info = new port(settings, "COM3");
info->rxBuf = sspRxBuf;
info->rxBufSize = MAX_PACKET_DATA_LEN;
info->txBuf = sspTxBuf;
info->txBufSize = 255;
info->max_retry = 3;
info->timeoutLen = 5000;
// qssp b(info);
qsspt bb(info);
uint8_t buf[1000];
QCoreApplication a(argc, argv);
while (!bb.ssp_Synchronise()) {
qDebug() << "trying sync";
}
bb.start();
qDebug() << "sync complete";
buf[0] = 0;
buf[1] = 1;
buf[2] = 2;
while (true) {
if (bb.sendData(buf, 63)) {
qDebug() << "send OK";
}
// else
// qDebug()<<"send NOK";
////bb.ssp_SendData(buf,63);
}
while (true) {
if (bb.packets_Available() > 0) {
bb.read_Packet(buf);
qDebug() << "receive=" << (int)buf[0] << (int)buf[1] << (int)buf[2];
++buf[0];
++buf[1];
++buf[2];
// bb.ssp_SendData(buf,63);
bb.sendData(buf, 63);
}
// bb.ssp_ReceiveProcess();
// bb.ssp_SendProcess();
}
return a.exec();
}

View File

@ -2,7 +2,8 @@
******************************************************************************
*
* @file port.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
@ -25,21 +26,24 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "port.h"
#include "delay.h"
port::port(QString name) : mstatus(port::closed)
#include <QSerialPort>
#include <QDebug>
port::port(QString name, bool debug) : mstatus(port::closed), debug(debug)
{
timer.start();
sport = new QSerialPort(name);
if (sport->open(QIODevice::ReadWrite | QIODevice::Unbuffered)) {
if (sport->setBaudRate(57600)
sport = new QSerialPort(name, this);
if (sport->open(QIODevice::ReadWrite)) {
if (sport->setBaudRate(QSerialPort::Baud57600)
&& sport->setDataBits(QSerialPort::Data8)
&& sport->setParity(QSerialPort::NoParity)
&& sport->setStopBits(QSerialPort::OneStop)
&& sport->setFlowControl(QSerialPort::NoFlowControl)) {
mstatus = port::open;
}
// sport->setDtr();
} else {
qDebug() << sport->error();
mstatus = port::error;
}
}
@ -53,13 +57,25 @@ port::portstatus port::status()
{
return mstatus;
}
int16_t port::pfSerialRead(void)
{
char c[1];
if (sport->bytesAvailable()) {
// TODO why the wait ? (gcs uploader dfu does not have it)
sport->waitForBytesWritten(1);
if (sport->bytesAvailable() || sport->waitForReadyRead(0)) {
sport->read(c, 1);
} else { return -1; }
if (debug) {
if (((uint8_t)c[0]) == 0xe1 || rxDebugBuff.count() > 50) {
qDebug() << "PORT R " << rxDebugBuff.toHex();
rxDebugBuff.clear();
}
rxDebugBuff.append(c[0]);
}
} else {
return -1;
}
return (uint8_t)c[0];
}
@ -69,6 +85,15 @@ void port::pfSerialWrite(uint8_t c)
cc[0] = c;
sport->write(cc, 1);
if (debug) {
if (((uint8_t)cc[0]) == 0xe1 || rxDebugBuff.count() > 50) {
qDebug() << "PORT T " << txDebugBuff.toHex();
txDebugBuff.clear();
}
txDebugBuff.append(cc[0]);
}
// TODO why the wait ? (gcs uploader dfu does not have it)
sport->waitForBytesWritten(1);
}
uint32_t port::pfGetTime(void)

View File

@ -2,7 +2,8 @@
******************************************************************************
*
* @file port.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
@ -26,19 +27,30 @@
*/
#ifndef PORT_H
#define PORT_H
#include <stdint.h>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QTime>
#include <QDebug>
#include "common.h"
class port {
#include <QObject>
#include <QTime>
#include <stdint.h>
class QSerialPort;
class port : public QObject {
Q_OBJECT;
public:
enum portstatus { open, closed, error };
port(QString name, bool debug);
virtual ~port();
portstatus status();
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.
@ -54,22 +66,25 @@ public:
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.
// and vice-versa. This fixes the firmware 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;
DecodeState DecodeState;
uint16_t SendState;
uint16_t crc;
uint32_t RxError;
uint32_t TxError;
uint16_t flags;
port(QString name);
virtual ~port();
portstatus status();
private:
portstatus mstatus;
QTime timer;
QSerialPort *sport;
bool debug;
QByteArray rxDebugBuff;
QByteArray txDebugBuff;
};
#endif // PORT_H

View File

@ -2,7 +2,8 @@
******************************************************************************
*
* @file qssp.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
@ -26,12 +27,12 @@
*/
#include "qssp.h"
#include <QDebug>
#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
@ -144,7 +145,7 @@ void qssp::ssp_Init(const PortConfig_t *const info)
thisport->txSeqNo = 255;
thisport->SendState = SSP_IDLE;
thisport->InputState = (ReceiveState)0;
thisport->DecodeState = (decodeState_)0;
thisport->DecodeState = (DecodeState)0;
thisport->TxError = 0;
thisport->RxError = 0;
thisport->txSeqNo = 0;
@ -174,7 +175,7 @@ int16_t qssp::ssp_SendProcess()
sf_SetSendTimeout();
value = SSP_TX_WAITING;
} else {
// Give up, # of trys has exceded the limit
// Give up, # of tries has exceeded the limit
value = SSP_TX_TIMEOUT;
CLEARBIT(thisport->flags, ACK_RECEIVED);
thisport->SendState = SSP_IDLE;
@ -258,6 +259,7 @@ uint16_t qssp::ssp_SendDataBlock(uint8_t *data, uint16_t length)
uint16_t retval = FALSE;
packet_status = ssp_SendData(data, length); // send the data
// TODO the loop is non blocking and will spin as fast as the CPU allows
while (packet_status == SSP_TX_WAITING) { // check the status
(void)ssp_ReceiveProcess(); // process any bytes received.
packet_status = ssp_SendProcess(); // check the send status
@ -343,7 +345,7 @@ int16_t qssp::ssp_SendData(const uint8_t *data, const uint16_t length)
}
/*!
* \brief Attempts to synchronize the sequence numbers with the other end of the connectin.
* \brief Attempts to synchronize the sequence numbers with the other end of the connection.
* \param thisport = which port to use
* \return true = success
* \return false = failed to receive an ACK to our synch request
@ -374,7 +376,7 @@ uint16_t qssp::ssp_Synchronise()
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
ssp_ReceiveProcess(); // do the receive process
packet_status = ssp_SendProcess(); // do the send process
}
thisport->sendSynch = FALSE;
@ -391,7 +393,6 @@ uint16_t qssp::ssp_Synchronise()
retval = FALSE;
break;
}
;
return retval;
}
@ -417,7 +418,6 @@ void qssp::sf_SendPacket()
thisport->retryCount++;
}
/*!
* \brief converts data to transport layer protocol packet format.
* \param txbuf = buffer to use when forming the packet
@ -523,9 +523,18 @@ void qssp::sf_write_byte(uint8_t c)
uint16_t qssp::sf_crc16(uint16_t crc, uint8_t data)
{
#ifdef SPP_USES_CRC
return (crc >> 8) ^ CRC_TABLE[(crc ^ data) & 0x00FF];
}
#else
uint8_t cka = crc & 0xff;
uint8_t ckb = (crc >> 8) & 0xff;
cka += data;
ckb += cka;
return cka | ckb << 8;
#endif
}
/*!
* \brief sets the timeout for the given packet
@ -651,6 +660,12 @@ int16_t qssp::sf_DecodeState(uint8_t c)
retval = SSP_RX_IDLE;
break;
case decode_len1_e:
if (c == 0) {
thisport->DecodeState = decode_idle_e;
thisport->RxError++;
retval = SSP_RX_IDLE;
break;
}
thisport->rxBuf[LENGTH] = c;
thisport->rxBufLen = c;
if (thisport->rxBufLen <= thisport->rxBufSize) {
@ -785,6 +800,7 @@ int16_t qssp::sf_ReceivePacket()
}
return value;
}
qssp::qssp(port *info, bool debug) : debug(debug)
{
thisport = info;
@ -800,12 +816,13 @@ qssp::qssp(port *info, bool debug) : debug(debug)
thisport->txSeqNo = 255;
thisport->SendState = SSP_IDLE;
thisport->InputState = (ReceiveState)0;
thisport->DecodeState = (decodeState_)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)
{
Q_UNUSED(size);

View File

@ -2,7 +2,8 @@
******************************************************************************
*
* @file qssp.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
@ -26,9 +27,12 @@
*/
#ifndef QSSP_H
#define QSSP_H
#include <stdint.h>
#include "port.h"
#include "common.h"
#include "port.h"
#include <stdint.h>
/** LOCAL DEFINITIONS **/
#ifndef TRUE
#define TRUE 1
@ -38,6 +42,8 @@
#define FALSE 0
#endif
#define SPP_USES_CRC
#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.
@ -55,7 +61,6 @@
#define SSP_RX_ACK 6
#define SSP_RX_SYNCH 7
typedef struct {
uint8_t *pbuff;
uint16_t length;
@ -73,42 +78,41 @@ typedef struct {
// 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 **/
bool debug;
// static void sf_SendSynchPacket( Port_t *thisport );
uint16_t sf_crc16(uint16_t crc, uint8_t data);
uint16_t sf_crc16(uint16_t crc, uint8_t data);
void sf_write_byte(uint8_t c);
void sf_SetSendTimeout();
uint16_t sf_CheckTimeout();
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);
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;
uint16_t ssp_SendDataBlock(uint8_t *data, uint16_t length);
public:
/** PUBLIC FUNCTIONS **/
virtual void pfCallBack(uint8_t *, uint16_t); // call back function that is called when a full packet has been received
qssp(port *info, bool debug);
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();
int16_t ssp_ReceiveByte();
uint16_t ssp_Synchronise();
qssp(port *info, bool debug);
virtual void pfCallBack(uint8_t *, uint16_t); // call back function that is called when a full packet has been received
};
#endif // QSSP_H

View File

@ -2,7 +2,8 @@
******************************************************************************
*
* @file qsspt.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
@ -26,18 +27,27 @@
*/
#include "qsspt.h"
#include <QDebug>
qsspt::qsspt(port *info, bool debug) : qssp(info, debug), endthread(false), datapending(false), debug(debug)
{}
qsspt::~qsspt()
{
endthread = true;
// TODO bad...
wait(1000);
}
void qsspt::run()
{
// TODO the loop is non blocking and will spin as fast as the CPU allows
while (!endthread) {
receivestatus = this->ssp_ReceiveProcess();
sendstatus = this->ssp_SendProcess();
msleep(1);
receivestatus = ssp_ReceiveProcess();
sendstatus = ssp_SendProcess();
sendbufmutex.lock();
if (datapending && receivestatus == SSP_TX_IDLE) {
this->ssp_SendData(mbuf, msize);
ssp_SendData(mbuf, msize);
datapending = false;
}
sendbufmutex.unlock();
@ -46,8 +56,13 @@ void qsspt::run()
}
}
}
bool qsspt::sendData(uint8_t *buf, uint16_t size)
{
if (debug) {
QByteArray data((const char *)buf, size);
qDebug() << "SSP TX " << data.toHex();
}
if (datapending) {
return false;
}
@ -56,6 +71,8 @@ bool qsspt::sendData(uint8_t *buf, uint16_t size)
mbuf = buf;
msize = size;
sendbufmutex.unlock();
// TODO why do we wait 10 seconds ? why do we then ignore the timeout ?
// There is a ssp_SendDataBlock method...
msendwait.lock();
sendwait.wait(&msendwait, 10000);
msendwait.unlock();
@ -65,21 +82,19 @@ bool qsspt::sendData(uint8_t *buf, uint16_t size)
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]);
qDebug() << "receive callback" << buf[0] << buf[1] << buf[2] << buf[3] << buf[4] << "queue size=" << queue.count();
}
QByteArray data((const char *)buf, size);
mutex.lock();
queue.enqueue(array);
// queue.enqueue((const char *)&buf);
queue.enqueue(data);
mutex.unlock();
}
int qsspt::packets_Available()
{
return queue.count();
}
int qsspt::read_Packet(void *data)
{
mutex.lock();
@ -89,11 +104,9 @@ int qsspt::read_Packet(void *data)
}
QByteArray arr = queue.dequeue();
memcpy(data, (uint8_t *)arr.data(), arr.length());
if (debug) {
qDebug() << "SSP RX " << arr.toHex();
}
mutex.unlock();
return arr.length();
}
qsspt::~qsspt()
{
endthread = true;
wait(1000);
}

View File

@ -2,7 +2,8 @@
******************************************************************************
*
* @file qsspt.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Serial and USB Uploader Plugin
@ -28,20 +29,24 @@
#define QSSPT_H
#include "qssp.h"
#include <QThread>
#include <QQueue>
#include <QWaitCondition>
#include <QMutex>
class qsspt : public qssp, public QThread {
public:
qsspt(port *info, bool debug);
~qsspt();
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;
@ -54,6 +59,8 @@ private:
QWaitCondition sendwait;
QMutex msendwait;
bool debug;
virtual void pfCallBack(uint8_t *, uint16_t);
};
#endif // QSSPT_H

View File

@ -0,0 +1,816 @@
/***********************************************************************************************************
*
* NAME: ssp.c
* DESCRIPTION: simple serial protocol - packet based serial transport layer.
* AUTHOR: Joe Hlebasko
* HISTORY: Created 1/1/2010
*
* Packet Formats
* Format:
* +------+----+------+---------------------------+--------+
* | 225 | L1 | S# | App Data (0-254 bytes) | CRC 16 |
* +------+----+------+---------------------------+--------+
*
* 225 = sync byte, indicates start of a packet
* L1 = 1 byte for size of data payload. (sequence number is part of data payload.)
* S# = 1 byte for sequence number.
* Seq of 0 = seq # synchronise request, forces other end to reset receive sequence number to 1.
* sender of synchronise request will reset the tx seq number to 1
* Seq # of 1..127 = normal data packets. Sequence number is incremented by for each transmitted
* packet. Rolls over from 127 to 1.
* if most sig. bit is set then the packet is an ACK packet of data packet sequence number of the
* lower 7 bits (1..127)
* App Data may contain 0..254 bytes. The sequence number is consider part of the payload.
* CRC 16 - 16 bits of CRC values of Sequence # and data bytes.
*
* Protocol has two types of packets: data and ack packets. ACK packets have the most sig. bit set in the
* sequence number, this implies that valid sequence numbers are 1..127
*
* This protocol uses the concept of sequences numbers to determine if a given packet has been received. This
* requires both devices to be able to synchronize sequence numbers. This is accomplished by sending a packet
* length 1 and sequence number = 0. The receive then resets it's transmit sequence number to 1.
*
* ACTIVE_SYNCH is a version that will automatically send a synch request if it receives a synch packet. Only
* one device in the communication should do otherwise you end up with an endless loops of synchronization.
* Right now each side needs to manually issues a synch request.
*
* This protocol is best used in cases where one device is the master and the other is the slave, or a don't
* speak unless spoken to type of approach.
*
* The following are items are required to initialize a port for communications:
* 1. The number attempts for each packet
* 2. time to wait for an ack.
* 3. pointer to buffer to be used for receiving.
* 4. pointer to a buffer to be used for transmission
* 5. length of each buffer (rx and tx)
* 6. Four functions:
* 1. write byte = writes a byte out the serial port (or other comm device)
* 2. read byte = retrieves a byte from the serial port. Returns -1 if a byte is not available
* 3. callback = function to call when a valid data packet has been received. This function is responsible
* to do what needs to be done with the data when it is received. The primary mission of this function
* should be to copy the data to a private buffer out of the working receive buffer to prevent overrun.
* processing should be kept to a minimum.
* 4. get time = function should return the current time. Note that time units are not specified it just
* needs to be some measure of time that increments as time passes by. The timeout values for a given
* port should the units used/returned by the get time function.
*
* All of the state information of a communication port is contained in a Port_t structure. This allows this
* module to operature on multiple communication ports with a single code base.
*
* The ssp_ReceiveProcess and ssp_SendProcess functions need to be called to process data through the
* respective state machines. Typical implementation would have a serial ISR to pull bytes out of the UART
* and place into a circular buffer. The serial read function would then pull bytes out this buffer
* processing. The TX side has the write function placing bytes into a circular buffer with the TX ISR
* pulling bytes out of the buffer and putting into the UART. It is possible to run the receive process from
* the receive ISR but care must be taken on processing data when it is received to avoid holding up the ISR
* and sending ACK packets from the receive ISR.
*
***********************************************************************************************************/
/** INCLUDE FILES **/
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "ssp.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)
/** PRIVATE FUNCTIONS **/
// static void sf_SendSynchPacket( Port_t *thisport );
static uint16_t sf_crc16(uint16_t crc, uint8_t data);
static void sf_write_byte(Port_t *thisport, uint8_t c);
static void sf_SetSendTimeout(Port_t *thisport);
static uint16_t sf_CheckTimeout(Port_t *thisport);
static int16_t sf_DecodeState(Port_t *thisport, uint8_t c);
static int16_t sf_ReceiveState(Port_t *thisport, uint8_t c);
static void sf_SendPacket(Port_t *thisport);
static void sf_SendAckPacket(Port_t *thisport, uint8_t seqNumber);
static void sf_MakePacket(uint8_t *buf, const uint8_t *pdata, uint16_t length, uint8_t seqNo);
static int16_t sf_ReceivePacket(Port_t *thisport);
/* 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 ssp_Init(Port_t *thisport, const PortConfig_t *const info)
{
thisport->pfCallBack = info->pfCallBack;
thisport->pfSerialRead = info->pfSerialRead;
thisport->pfSerialWrite = info->pfSerialWrite;
thisport->pfGetTime = info->pfGetTime;
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;
}
/*!
* \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 ssp_SendProcess(Port_t *thisport)
{
int16_t value = SSP_TX_WAITING;
if (thisport->SendState == SSP_AWAITING_ACK) {
if (sf_CheckTimeout(thisport) == TRUE) {
if (thisport->retryCount < thisport->maxRetryCount) {
// Try again
sf_SendPacket(thisport);
sf_SetSendTimeout(thisport);
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;
}
} 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 ssp_ReceiveProcess(Port_t *thisport)
{
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(thisport, 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 ssp_ReceiveByte(Port_t *thisport)
{
int16_t b;
int16_t packet_status = SSP_RX_IDLE;
b = thisport->pfSerialRead();
if (b != -1) {
packet_status = sf_ReceiveState(thisport, 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 ssp_SendDataBlock(Port_t *thisport, uint8_t *data, uint16_t length)
{
int16_t packet_status = SSP_TX_WAITING;
uint16_t retval = FALSE;
packet_status = ssp_SendData(thisport, data, length); // send the data
while (packet_status == SSP_TX_WAITING) { // check the status
(void)ssp_ReceiveProcess(thisport); // process any bytes received.
packet_status = ssp_SendProcess(thisport); // 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 ssp_SendData(Port_t *thisport, 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(thisport);
}
#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 // ifdef SYNCH_SEND
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(thisport); // punch out the packet to the serial port
sf_SetSendTimeout(thisport); // do the timeout values
} else {
// error we are already sending a packet. Need to wait for the current packet to be acked or timeout.
value = SSP_TX_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 ssp_Synchronise(Port_t *thisport)
{
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(thisport);
sf_SetSendTimeout(thisport);
thisport->SendState = SSP_AWAITING_ACK;
packet_status = SSP_TX_WAITING;
#else
packet_status = ssp_SendData(thisport, NULL, 0);
#endif
while (packet_status == SSP_TX_WAITING) { // we loop until we time out.
(void)ssp_ReceiveProcess(thisport); // do the receive process
packet_status = ssp_SendProcess(thisport); // 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.
*/
static void sf_SendPacket(Port_t *thisport)
{
// 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, 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 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
*
*/
static void sf_SendAckPacket(Port_t *thisport, 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(thisport);
// 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
*
*/
static void sf_write_byte(Port_t *thisport, 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
*
*/
static uint16_t 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
*
*/
static void sf_SetSendTimeout(Port_t *thisport)
{
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
*
*/
static uint16_t sf_CheckTimeout(Port_t *thisport)
{
uint16_t retval = FALSE;
uint32_t current_time;
current_time = thisport->pfGetTime();
if (current_time > thisport->timeout) {
retval = TRUE;
}
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
*
*/
static int16_t sf_ReceiveState(Port_t *thisport, 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(thisport, 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(thisport, SYNC);
} else {
retval = sf_DecodeState(thisport, 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
*
*/
static int16_t sf_DecodeState(Port_t *thisport, 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(thisport);
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
*/
static int16_t sf_ReceivePacket(Port_t *thisport)
{
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;
}
// else ignore the ACK packet
} else {
// Received a 'data' packet, figure out what type of packet we received...
if (thisport->rxBuf[SEQNUM] == 0) {
// Synchronize sequence number with host
#ifdef ACTIVE_SYNCH
thisport->sendSynch = TRUE;
#endif
sf_SendAckPacket(thisport, 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, thisport->rxBuf[SEQNUM]);
value = FALSE;
} else {
// New Packet
thisport->rxSeqNo = thisport->rxBuf[SEQNUM];
// Let the application do something with the data/packet.
if (thisport->pfCallBack != NULL) {
// skip the first two bytes (length and seq. no.) in the buffer.
thisport->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, thisport->rxBuf[SEQNUM]);
value = TRUE;
}
}
return value;
}

View File

@ -0,0 +1,118 @@
/*******************************************************************
*
* NAME: ssp.h
*
*
*******************************************************************/
#ifndef SSP_H
#define SSP_H
/** INCLUDE FILES **/
#include <stdint.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 enum decodeState_ {
decode_len1_e = 0,
decode_seqNo_e,
decode_data_e,
decode_crc1_e,
decode_crc2_e,
decode_idle_e
} DecodeState_t;
typedef enum ReceiveState {
state_escaped_e = 0,
state_unescaped_e
} ReceiveState_t;
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
void (*pfCallBack)(uint8_t *, uint16_t); // call back function that is called when a full packet has been received
int16_t (*pfSerialRead)(void); // function to call to read a byte from serial hardware
void (*pfSerialWrite)(uint8_t); // function used to write a byte to serial hardware for transmission
uint32_t (*pfGetTime)(void); // function returns time in number of seconds that has elapsed from a given reference point
} PortConfig_t;
typedef struct Port_tag {
void (*pfCallBack)(uint8_t *, uint16_t); // call back function that is called when a full packet has been received
int16_t (*pfSerialRead)(void); // function to read a character from the serial input stream
void (*pfSerialWrite)(uint8_t); // function to write a byte to be sent out the serial port
uint32_t (*pfGetTime)(void); // function returns time in number of seconds that has elapsed from a given reference point
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
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_t InputState;
DecodeState_t DecodeState;
uint16_t SendState;
uint16_t crc;
uint32_t RxError;
uint32_t TxError;
uint16_t flags;
} Port_t;
/** Public Data **/
/** PUBLIC FUNCTIONS **/
int16_t ssp_ReceiveProcess(Port_t *thisport);
int16_t ssp_SendProcess(Port_t *thisport);
uint16_t ssp_SendString(Port_t *thisport, char *str);
int16_t ssp_SendData(Port_t *thisport, const uint8_t *data, const uint16_t length);
void ssp_Init(Port_t *thisport, const PortConfig_t *const info);
int16_t ssp_ReceiveByte(Port_t *thisport);
uint16_t ssp_Synchronise(Port_t *thisport);
/** EXTERNAL FUNCTIONS **/
#endif // ifndef SSP_H

View File

@ -0,0 +1,50 @@
#-------------------------------------------------
#
# Project created by QtCreator 2010-07-24T11:26:38
#
#-------------------------------------------------
TEMPLATE = app
TARGET = ssp_test
QT += core
QT -= gui
CONFIG += console
CONFIG -= app_bundle
DEFINES += QEXTSERIALPORT_LIBRARY
SOURCES += \
main.cpp \
qssp.cpp \
port.cpp \
qsspt.cpp
HEADERS += \
../../../libs/qextserialport/src/qextserialport.h \
../../../libs/qextserialport/src/qextserialenumerator.h \
../../../libs/qextserialport/src/qextserialport_global.h \
qssp.h \
port.h \
common.h \
qsspt.h
SOURCES += ../../../libs/qextserialport/src/qextserialport.cpp
unix:SOURCES += ../../../libs/qextserialport/src/posix_qextserialport.cpp
unix:!macx:SOURCES += ../../../libs/qextserialport/src/qextserialenumerator_unix.cpp
macx {
SOURCES += ../../../libs/qextserialport/src/qextserialenumerator_osx.cpp
LIBS += -framework IOKit -framework CoreFoundation
}
win32 {
SOURCES += \
../../../libs/qextserialport/src/win_qextserialport.cpp \
../../../libs/qextserialport/src/qextserialenumerator_win.cpp
# needed for mingw to pull in appropriate dbt business...probably a better way to do this
DEFINES += WINVER=0x0501
LIBS += -lsetupapi
}

View File

@ -1,16 +0,0 @@
/*
* 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,27 +0,0 @@
/*
* 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

@ -27,6 +27,11 @@
*/
#include "devicewidget.h"
#include <QFileDialog>
#include <QDebug>
#include <QDir>
#include <QCryptographicHash>
DeviceWidget::DeviceWidget(QWidget *parent) :
QWidget(parent)
{
@ -132,7 +137,7 @@ void DeviceWidget::populate()
myDevice->lblMaxCode->setText(tr("Max code size: ") + QString::number(m_dfu->devices[deviceID].SizeOfCode));
myDevice->lblCRC->setText(QString::number(m_dfu->devices[deviceID].FW_CRC));
myDevice->lblBLVer->setText(tr("BL version: ") + QString::number(m_dfu->devices[deviceID].BL_Version));
int size = ((OP_DFU::device)m_dfu->devices[deviceID]).SizeOfDesc;
int size = ((DFU::device)m_dfu->devices[deviceID]).SizeOfDesc;
m_dfu->enterDFU(deviceID);
QByteArray desc = m_dfu->DownloadDescriptionAsBA(size);
@ -409,13 +414,13 @@ void DeviceWidget::uploadFirmware()
updateButtons(true);
return;
}
OP_DFU::Status ret = m_dfu->StatusRequest();
DFU::Status ret = m_dfu->StatusRequest();
qDebug() << m_dfu->StatusToString(ret);
m_dfu->AbortOperation(); // Necessary, otherwise I get random failures.
connect(m_dfu, SIGNAL(progressUpdated(int)), this, SLOT(setProgress(int)));
connect(m_dfu, SIGNAL(operationProgress(QString)), this, SLOT(dfuStatus(QString)));
connect(m_dfu, SIGNAL(uploadFinished(OP_DFU::Status)), this, SLOT(uploadFinished(OP_DFU::Status)));
connect(m_dfu, SIGNAL(uploadFinished(DFU::Status)), this, SLOT(uploadFinished(DFU::Status)));
bool retstatus = m_dfu->UploadFirmware(filename, verify, deviceID);
if (!retstatus) {
emit uploadEnded(false);
@ -478,7 +483,7 @@ void DeviceWidget::downloadFinished()
disconnect(m_dfu, SIGNAL(downloadFinished()), this, SLOT(downloadFinished()));
disconnect(m_dfu, SIGNAL(progressUpdated(int)), this, SLOT(setProgress(int)));
// Now save the result (use the utility function from OP_DFU)
// Now save the result (use the utility function from DFU)
m_dfu->SaveByteArrayToFile(filename, downloadedFirmware);
emit downloadEnded(true);
@ -489,13 +494,13 @@ void DeviceWidget::downloadFinished()
/**
Callback for the firmware upload result
*/
void DeviceWidget::uploadFinished(OP_DFU::Status retstatus)
void DeviceWidget::uploadFinished(DFU::Status retstatus)
{
disconnect(m_dfu, SIGNAL(uploadFinished(OP_DFU::Status)), this, SLOT(uploadFinished(OP_DFU::Status)));
disconnect(m_dfu, SIGNAL(uploadFinished(DFU::Status)), this, SLOT(uploadFinished(DFU::Status)));
disconnect(m_dfu, SIGNAL(progressUpdated(int)), this, SLOT(setProgress(int)));
disconnect(m_dfu, SIGNAL(operationProgress(QString)), this, SLOT(dfuStatus(QString)));
if (retstatus != OP_DFU::Last_operation_Success) {
if (retstatus != DFU::Last_operation_Success) {
emit uploadEnded(false);
status(QString("Upload failed with code: ") + m_dfu->StatusToString(retstatus).toLatin1().data(), STATUSICON_FAIL);
updateButtons(true);
@ -505,7 +510,7 @@ void DeviceWidget::uploadFinished(OP_DFU::Status retstatus)
status(QString("Updating description"), STATUSICON_RUNNING);
repaint(); // Make sure the text above shows right away
retstatus = m_dfu->UploadDescription(descriptionArray);
if (retstatus != OP_DFU::Last_operation_Success) {
if (retstatus != DFU::Last_operation_Success) {
emit uploadEnded(false);
status(QString("Upload failed with code: ") + m_dfu->StatusToString(retstatus).toLatin1().data(), STATUSICON_FAIL);
updateButtons(true);
@ -516,7 +521,7 @@ void DeviceWidget::uploadFinished(OP_DFU::Status retstatus)
status(QString("Updating description"), STATUSICON_RUNNING);
repaint(); // Make sure the text above shows right away
retstatus = m_dfu->UploadDescription(myDevice->description->text());
if (retstatus != OP_DFU::Last_operation_Success) {
if (retstatus != DFU::Last_operation_Success) {
emit uploadEnded(false);
status(QString("Upload failed with code: ") + m_dfu->StatusToString(retstatus).toLatin1().data(), STATUSICON_FAIL);
updateButtons(true);

View File

@ -29,22 +29,18 @@
#define DEVICEWIDGET_H
#include "ui_devicewidget.h"
#include "uploader_global.h"
#include "uploadergadgetwidget.h"
#include "op_dfu.h"
#include <QWidget>
#include <QFileDialog>
#include <QErrorMessage>
#include <QByteArray>
#include <QtSvg/QGraphicsSvgItem>
#include <QtSvg/QSvgRenderer>
#include <QCryptographicHash>
#include "dfu.h"
#include "uavobjectutilmanager.h"
#include "devicedescriptorstruct.h"
#include <QDir>
#include <QCoreApplication>
#include "uploader_global.h"
using namespace OP_DFU;
#include <QWidget>
#include <QByteArray>
using namespace DFU;
class UPLOADER_EXPORT DeviceWidget : public QWidget {
Q_OBJECT
public:
@ -87,7 +83,7 @@ public slots:
void downloadFirmware();
void setProgress(int);
void downloadFinished();
void uploadFinished(OP_DFU::Status);
void uploadFinished(DFU::Status);
void dfuStatus(QString);
void confirmCB(int);

View File

@ -1,8 +1,9 @@
/**
******************************************************************************
*
* @file op_dfu.cpp
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @file dfu.cpp
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup Uploader Uploader Plugin
@ -24,25 +25,37 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "dfu.h"
#include "op_dfu.h"
#include "SSP/port.h"
#include "SSP/qsspt.h"
#include <ophid/inc/ophid_hidapi.h>
#include <ophid/inc/ophid_usbmon.h>
#include <ophid/inc/ophid_usbsignal.h>
#include <QEventLoop>
#include <QFile>
#include <QTimer>
#include <QDebug>
#include <iostream>
#include <cmath>
#include <qwaitcondition.h>
#include <QMetaType>
#include <QtWidgets/QApplication>
using namespace OP_DFU;
using namespace std;
using namespace DFU;
DFUObject::DFUObject(bool _debug, bool _use_serial, QString portname) :
debug(_debug), use_serial(_use_serial), mready(true)
{
info = NULL;
numberOfDevices = 0;
serialhandle = NULL;
port *info = NULL;
qRegisterMetaType<OP_DFU::Status>("Status");
qRegisterMetaType<DFU::Status>("Status");
if (use_serial) {
info = new port(portname);
info = new port(portname, false);
info->rxBuf = sspRxBuf;
info->rxBufSize = MAX_PACKET_DATA_LEN;
info->txBuf = sspTxBuf;
@ -54,42 +67,50 @@ DFUObject::DFUObject(bool _debug, bool _use_serial, QString portname) :
mready = false;
return;
}
serialhandle = new qsspt(info, debug);
serialhandle = new qsspt(info, false /*debug*/);
int count = 0;
while ((serialhandle->ssp_Synchronise() == false) && (count < 10)) {
while (!serialhandle->ssp_Synchronise() && (count < 10)) {
if (debug) {
qDebug() << "SYNC failed, resending";
qDebug() << "SYNC failed, resending...";
}
count++;
}
if (count == 10) {
mready = false;
qDebug() << "SYNC failed";
return;
}
qDebug() << "SYNC Succeded";
// transfer ownership of port to serialhandle thread
info->moveToThread(serialhandle);
connect(serialhandle, SIGNAL(finished()), info, SLOT(deleteLater()));
// start the serialhandle thread
serialhandle->start();
} else {
mready = false;
hidHandle = new opHID_hidapi();
mready = false;
QEventLoop m_eventloop;
QTimer::singleShot(200, &m_eventloop, SLOT(quit()));
m_eventloop.exec();
QList<USBPortInfo> devices;
devices = USBMonitor::instance()->availableDevices(0x20a0, -1, -1, USBMonitor::Bootloader);
if (devices.length() == 1) {
if (hidHandle.open(1, devices.first().vendorID, devices.first().productID, 0, 0) == 1) {
if (hidHandle->open(1, devices.first().vendorID, devices.first().productID, 0, 0) == 1) {
mready = true;
QTimer::singleShot(200, &m_eventloop, SLOT(quit()));
m_eventloop.exec();
} else {
hidHandle.close(0);
hidHandle->close(0);
}
} else {
// Wait for the board to appear on the USB bus:
USBSignalFilter filter(0x20a0, -1, -1, USBMonitor::Bootloader);
connect(&filter, SIGNAL(deviceDiscovered()), &m_eventloop, SLOT(quit()));
for (int x = 0; x < 4; ++x) {
qDebug() << "OP_DFU trying to detect bootloader:" << x;
qDebug() << "DFU trying to detect bootloader:" << x;
if (x == 0) {
QTimer::singleShot(10000, &m_eventloop, SLOT(quit()));
@ -101,15 +122,15 @@ DFUObject::DFUObject(bool _debug, bool _use_serial, QString portname) :
qDebug() << "Devices length: " << devices.length();
if (devices.length() == 1) {
qDebug() << "Opening device";
if (hidHandle.open(1, devices.first().vendorID, devices.first().productID, 0, 0) == 1) {
if (hidHandle->open(1, devices.first().vendorID, devices.first().productID, 0, 0) == 1) {
QTimer::singleShot(200, &m_eventloop, SLOT(quit()));
m_eventloop.exec();
qDebug() << "OP_DFU detected after delay";
qDebug() << "DFU detected after delay";
mready = true;
qDebug() << "Detected";
break;
} else {
hidHandle.close(0);
hidHandle->close(0);
}
} else {
qDebug() << devices.length() << " device(s) detected, don't know what to do!";
@ -123,12 +144,12 @@ DFUObject::DFUObject(bool _debug, bool _use_serial, QString portname) :
DFUObject::~DFUObject()
{
if (use_serial) {
if (mready) {
delete serialhandle;
delete info;
}
delete serialhandle;
} else {
hidHandle.close(0);
if (hidHandle) {
hidHandle->close(0);
delete hidHandle;
}
}
}
@ -138,7 +159,7 @@ bool DFUObject::SaveByteArrayToFile(QString const & sfile, const QByteArray &arr
if (!file.open(QIODevice::WriteOnly)) {
if (debug) {
qDebug() << "Can't open file";
qDebug() << "Can't open file" << sfile;
}
return false;
}
@ -155,7 +176,7 @@ bool DFUObject::enterDFU(int const &devNumber)
char buf[BUF_LEN];
buf[0] = 0x02; // reportID
buf[1] = OP_DFU::EnterDFU; // DFU Command
buf[1] = DFU::EnterDFU; // DFU Command
buf[2] = 0; // DFU Count
buf[3] = 0; // DFU Count
buf[4] = 0; // DFU Count
@ -194,7 +215,7 @@ bool DFUObject::StartUpload(qint32 const & numberOfBytes, TransferTypes const &
}
char buf[BUF_LEN];
buf[0] = 0x02; // reportID
buf[1] = setStartBit(OP_DFU::Upload); // DFU Command
buf[1] = setStartBit(DFU::Upload); // DFU Command
buf[2] = numberOfPackets >> 24; // DFU Count
buf[3] = numberOfPackets >> 16; // DFU Count
buf[4] = numberOfPackets >> 8; // DFU Count
@ -210,7 +231,7 @@ bool DFUObject::StartUpload(qint32 const & numberOfBytes, TransferTypes const &
}
int result = sendData(buf, BUF_LEN);
delay::msleep(1000);
QThread::msleep(1000);
if (debug) {
qDebug() << result << " bytes sent";
@ -221,7 +242,6 @@ bool DFUObject::StartUpload(qint32 const & numberOfBytes, TransferTypes const &
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.
@ -243,7 +263,7 @@ bool DFUObject::UploadData(qint32 const & numberOfBytes, QByteArray & data)
}
char buf[BUF_LEN];
buf[0] = 0x02; // reportID
buf[1] = OP_DFU::Upload; // DFU Command
buf[1] = DFU::Upload; // DFU Command
int packetsize;
float percentage;
int laspercentage = 0;
@ -265,40 +285,43 @@ bool DFUObject::UploadData(qint32 const & numberOfBytes, QByteArray & data)
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];
// if (debug) {
// 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)
// {
// 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);
// QThread::msleep(send_delay);
// if(StatusRequest()!=OP_DFU::uploading) return false;
// if (StatusRequest() != DFU::uploading) {
// return false;
// }
int result = sendData(buf, BUF_LEN);
// qDebug()<<"sent:"<<result;
// if (debug) {
// 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";
// if (debug) {
// 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(QVariant desc)
DFU::Status DFUObject::UploadDescription(QVariant desc)
{
cout << "Starting uploading description\n";
QByteArray array;
emit operationProgress("Uploading description");
QByteArray array;
if (desc.type() == QVariant::String) {
QString description = desc.toString();
if (description.length() % 4 != 0) {
@ -314,17 +337,16 @@ OP_DFU::Status DFUObject::UploadDescription(QVariant desc)
array = desc.toByteArray();
}
if (!StartUpload(array.length(), OP_DFU::Descript, 0)) {
return OP_DFU::abort;
if (!StartUpload(array.length(), DFU::Descript, 0)) {
return DFU::abort;
}
if (!UploadData(array.length(), array)) {
return OP_DFU::abort;
return DFU::abort;
}
if (!EndOperation()) {
return OP_DFU::abort;
return DFU::abort;
}
OP_DFU::Status ret = StatusRequest();
DFU::Status ret = StatusRequest();
if (debug) {
qDebug() << "Upload description Status=" << StatusToString(ret);
@ -341,7 +363,7 @@ QString DFUObject::DownloadDescription(int const & numberOfChars)
{
QByteArray arr;
StartDownloadT(&arr, numberOfChars, OP_DFU::Descript);
StartDownloadT(&arr, numberOfChars, DFU::Descript);
int index = arr.indexOf(255);
return QString((index == -1) ? arr : arr.left(index));
@ -351,7 +373,7 @@ QByteArray DFUObject::DownloadDescriptionAsBA(int const & numberOfChars)
{
QByteArray arr;
StartDownloadT(&arr, numberOfChars, OP_DFU::Descript);
StartDownloadT(&arr, numberOfChars, DFU::Descript);
return arr;
}
@ -366,28 +388,27 @@ bool DFUObject::DownloadFirmware(QByteArray *firmwareArray, int device)
if (isRunning()) {
return false;
}
requestedOperation = OP_DFU::Download;
requestedOperation = DFU::Download;
requestSize = devices[device].SizeOfCode;
requestTransferType = OP_DFU::FW;
requestTransferType = DFU::FW;
requestStorage = firmwareArray;
start();
return true;
}
/**
Runs the upload or download operations.
*/
void DFUObject::run()
{
switch (requestedOperation) {
case OP_DFU::Download:
case DFU::Download:
StartDownloadT(requestStorage, requestSize, requestTransferType);
emit(downloadFinished());
break;
case OP_DFU::Upload:
case DFU::Upload:
{
OP_DFU::Status ret = UploadFirmwareT(requestFilename, requestVerify, requestDevice);
DFU::Status ret = UploadFirmwareT(requestFilename, requestVerify, requestDevice);
emit(uploadFinished(ret));
break;
}
@ -418,7 +439,7 @@ bool DFUObject::StartDownloadT(QByteArray *fw, qint32 const & numberOfBytes, Tra
char buf[BUF_LEN];
buf[0] = 0x02; // reportID
buf[1] = OP_DFU::Download_Req; // DFU Command
buf[1] = DFU::Download_Req; // DFU Command
buf[2] = numberOfPackets >> 24; // DFU Count
buf[3] = numberOfPackets >> 16; // DFU Count
buf[4] = numberOfPackets >> 8; // DFU Count
@ -460,7 +481,6 @@ bool DFUObject::StartDownloadT(QByteArray *fw, qint32 const & numberOfBytes, Tra
return true;
}
/**
Resets the device
*/
@ -469,7 +489,7 @@ int DFUObject::ResetDevice(void)
char buf[BUF_LEN];
buf[0] = 0x02; // reportID
buf[1] = OP_DFU::Reset; // DFU Command
buf[1] = DFU::Reset; // DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
@ -480,7 +500,7 @@ int DFUObject::ResetDevice(void)
buf[9] = 0;
return sendData(buf, BUF_LEN);
// return hidHandle.send(0,buf, BUF_LEN, 500);
// return hidHandle->send(0,buf, BUF_LEN, 500);
}
int DFUObject::AbortOperation(void)
@ -488,7 +508,7 @@ int DFUObject::AbortOperation(void)
char buf[BUF_LEN];
buf[0] = 0x02; // reportID
buf[1] = OP_DFU::Abort_Operation; // DFU Command
buf[1] = DFU::Abort_Operation; // DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
@ -500,6 +520,7 @@ int DFUObject::AbortOperation(void)
return sendData(buf, BUF_LEN);
}
/**
Starts the firmware (leaves bootloader and boots the main software)
*/
@ -508,7 +529,7 @@ int DFUObject::JumpToApp(bool safeboot, bool erase)
char buf[BUF_LEN];
buf[0] = 0x02; // reportID
buf[1] = OP_DFU::JumpFW; // DFU Command
buf[1] = DFU::JumpFW; // DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
@ -559,12 +580,12 @@ int DFUObject::JumpToApp(bool safeboot, bool erase)
return sendData(buf, BUF_LEN);
}
OP_DFU::Status DFUObject::StatusRequest()
DFU::Status DFUObject::StatusRequest()
{
char buf[BUF_LEN];
buf[0] = 0x02; // reportID
buf[1] = OP_DFU::Status_Request; // DFU Command
buf[1] = DFU::Status_Request; // DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
@ -580,13 +601,13 @@ OP_DFU::Status DFUObject::StatusRequest()
while (result < 0 && retry_cnt < MaxSendRetry) {
retry_cnt++;
qWarning() << "StatusRequest failed, sleeping" << SendRetryIntervalMS << "ms";
delay::msleep(SendRetryIntervalMS);
QThread::msleep(SendRetryIntervalMS);
qWarning() << "StatusRequest retry attempt" << retry_cnt;
result = sendData(buf, BUF_LEN);
}
if (retry_cnt >= MaxSendRetry) {
qWarning() << "StatusRequest failed too many times, aborting";
return OP_DFU::abort;
return DFU::abort;
}
if (debug) {
qDebug() << "StatusRequest: " << result << " bytes sent";
@ -595,10 +616,10 @@ OP_DFU::Status DFUObject::StatusRequest()
if (debug) {
qDebug() << "StatusRequest: " << result << " bytes received";
}
if (buf[1] == OP_DFU::Status_Rep) {
return (OP_DFU::Status)buf[6];
if (buf[1] == DFU::Status_Rep) {
return (DFU::Status)buf[6];
} else {
return OP_DFU::abort;
return DFU::abort;
}
}
@ -610,7 +631,7 @@ bool DFUObject::findDevices()
devices.clear();
char buf[BUF_LEN];
buf[0] = 0x02; // reportID
buf[1] = OP_DFU::Req_Capabilities; // DFU Command
buf[1] = DFU::Req_Capabilities; // DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
@ -634,14 +655,14 @@ bool DFUObject::findDevices()
RWFlags = buf[8];
RWFlags = RWFlags << 8 | buf[9];
if (buf[1] == OP_DFU::Rep_Capabilities) {
if (buf[1] == 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[1] = DFU::Req_Capabilities; // DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
@ -689,13 +710,12 @@ bool DFUObject::findDevices()
return true;
}
bool DFUObject::EndOperation()
{
char buf[BUF_LEN];
buf[0] = 0x02; // reportID
buf[1] = OP_DFU::Op_END; // DFU Command
buf[1] = DFU::END; // DFU Command
buf[2] = 0;
buf[3] = 0;
buf[4] = 0;
@ -715,8 +735,6 @@ bool DFUObject::EndOperation()
return false;
}
//
/**
Starts a firmware upload (asynchronous)
*/
@ -725,7 +743,7 @@ bool DFUObject::UploadFirmware(const QString &sfile, const bool &verify, int dev
if (isRunning()) {
return false;
}
requestedOperation = OP_DFU::Upload;
requestedOperation = DFU::Upload;
requestFilename = sfile;
requestDevice = device;
requestVerify = verify;
@ -733,9 +751,9 @@ bool DFUObject::UploadFirmware(const QString &sfile, const bool &verify, int dev
return true;
}
OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &verify, int device)
DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &verify, int device)
{
OP_DFU::Status ret;
DFU::Status ret;
if (debug) {
qDebug() << "Starting Firmware Uploading...";
@ -745,9 +763,9 @@ OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &veri
if (!file.open(QIODevice::ReadOnly)) {
if (debug) {
qDebug() << "Cant open file";
qDebug() << "Failed to open file" << sfile;
}
return OP_DFU::abort;
return DFU::abort;
}
QByteArray arr = file.readAll();
@ -766,7 +784,7 @@ OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &veri
if (debug) {
qDebug() << "ERROR file to big for device";
}
return OP_DFU::abort;;
return DFU::abort;;
}
quint32 crc = DFUObject::CRCFromQBArray(arr, devices[device].SizeOfCode);
@ -774,7 +792,7 @@ OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &veri
qDebug() << "NEW FIRMWARE CRC=" << crc;
}
if (!StartUpload(arr.length(), OP_DFU::FW, crc)) {
if (!StartUpload(arr.length(), DFU::FW, crc)) {
ret = StatusRequest();
if (debug) {
qDebug() << "StartUpload failed";
@ -783,13 +801,13 @@ OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &veri
return ret;
}
emit operationProgress(QString("Erasing, please wait..."));
emit operationProgress("Erasing, please wait...");
if (debug) {
qDebug() << "Erasing memory";
}
if (StatusRequest() == OP_DFU::abort) {
return OP_DFU::abort;
if (StatusRequest() == DFU::abort) {
return DFU::abort;
}
// TODO: why is there a loop there? The "if" statement
@ -799,14 +817,14 @@ OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &veri
if (debug) {
qDebug() << "Erase returned: " << StatusToString(ret);
}
if (ret == OP_DFU::uploading) {
if (ret == DFU::uploading) {
break;
} else {
return ret;
}
}
emit operationProgress(QString("Uploading firmware"));
emit operationProgress("Uploading firmware");
if (!UploadData(arr.length(), arr)) {
ret = StatusRequest();
if (debug) {
@ -824,18 +842,18 @@ OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &veri
return ret;
}
ret = StatusRequest();
if (ret != OP_DFU::Last_operation_Success) {
if (ret != DFU::Last_operation_Success) {
return ret;
}
if (verify) {
emit operationProgress(QString("Verifying firmware"));
emit operationProgress("Verifying firmware");
cout << "Starting code verification\n";
QByteArray arr2;
StartDownloadT(&arr2, arr.length(), OP_DFU::FW);
StartDownloadT(&arr2, arr.length(), DFU::FW);
if (arr != arr2) {
cout << "Verify:FAILED\n";
return OP_DFU::abort;
return DFU::abort;
}
}
@ -846,8 +864,7 @@ OP_DFU::Status DFUObject::UploadFirmwareT(const QString &sfile, const bool &veri
return ret;
}
OP_DFU::Status DFUObject::CompareFirmware(const QString &sfile, const CompareType &type, int device)
DFU::Status DFUObject::CompareFirmware(const QString &sfile, const CompareType &type, int device)
{
cout << "Starting Firmware Compare...\n";
QFile file(sfile);
@ -855,7 +872,7 @@ OP_DFU::Status DFUObject::CompareFirmware(const QString &sfile, const CompareTyp
if (debug) {
qDebug() << "Cant open file";
}
return OP_DFU::abort;
return DFU::abort;
}
QByteArray arr = file.readAll();
@ -869,7 +886,7 @@ OP_DFU::Status DFUObject::CompareFirmware(const QString &sfile, const CompareTyp
pad = pad - arr.length();
arr.append(QByteArray(pad, 255));
}
if (type == OP_DFU::crccompare) {
if (type == DFU::crccompare) {
quint32 crc = DFUObject::CRCFromQBArray(arr, devices[device].SizeOfCode);
if (crc == devices[device].FW_CRC) {
cout << "Compare Successfull CRC MATCH!\n";
@ -879,7 +896,7 @@ OP_DFU::Status DFUObject::CompareFirmware(const QString &sfile, const CompareTyp
return StatusRequest();
} else {
QByteArray arr2;
StartDownloadT(&arr2, arr.length(), OP_DFU::FW);
StartDownloadT(&arr2, arr.length(), DFU::FW);
if (arr == arr2) {
cout << "Compare Successfull ALL Bytes MATCH!\n";
} else {
@ -898,7 +915,8 @@ void DFUObject::CopyWords(char *source, char *destination, int count)
*(destination + x + 3) = source[x + 0];
}
}
QString DFUObject::StatusToString(OP_DFU::Status const & status)
QString DFUObject::StatusToString(DFU::Status const & status)
{
switch (status) {
case DFUidle:
@ -955,11 +973,10 @@ QString DFUObject::StatusToString(OP_DFU::Status const & status)
*/
void DFUObject::printProgBar(int const & percent, QString const & label)
{
std::string bar;
emit(progressUpdated(percent));
if (debug) {
std::string bar;
for (int i = 0; i < 50; i++) {
if (i < (percent / 2)) {
bar.replace(i, 1, "=");
@ -984,7 +1001,8 @@ 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
// Nibble lookup table for 0x04C11DB7 polynomial
static const quint32 CrcTable[16] = {
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
};
@ -1016,7 +1034,7 @@ quint32 DFUObject::CRCFromQBArray(QByteArray array, quint32 Size)
quint32 pad = Size - array.length();
array.append(QByteArray(pad, 255));
quint32 *t = new quint32[Size / 4];
quint32 t[Size / 4];
for (int x = 0; x < array.length() / 4; x++) {
quint32 aux = 0;
aux = (char)array[x * 4 + 3] & 0xFF;
@ -1028,14 +1046,9 @@ quint32 DFUObject::CRCFromQBArray(QByteArray array, quint32 Size)
aux += (char)array[x * 4 + 0] & 0xFF;
t[x] = aux;
}
quint32 ret = DFUObject::CRC32WideFast(0xFFFFFFFF, Size / 4, t);
delete[] t;
return ret;
return DFUObject::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
@ -1043,7 +1056,7 @@ quint32 DFUObject::CRCFromQBArray(QByteArray array, quint32 Size)
int DFUObject::sendData(void *data, int size)
{
if (!use_serial) {
return hidHandle.send(0, data, size, 5000);
return hidHandle->send(0, data, size, 5000);
}
// Serial Mode:
@ -1059,7 +1072,6 @@ int DFUObject::sendData(void *data, int size)
return -1;
}
/**
Receive data from the bootloader, either through the serial port
of through the HID handle, depending on the mode we're using
@ -1067,18 +1079,24 @@ int DFUObject::sendData(void *data, int size)
int DFUObject::receiveData(void *data, int size)
{
if (!use_serial) {
return hidHandle.receive(0, data, size, 10000);
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) {
// QThread::msleep(10);
if (time.elapsed() > 10000) {
qDebug() << "____timeout";
}
if (x > size - 1) {
qDebug() << "Error buffer overrun";
Q_ASSERT(false);
}
return x;
}
}
@ -1094,9 +1112,9 @@ int DFUObject::receiveData(void *data, int size)
/**
Gets the type of board connected
*/
OP_DFU::eBoardType DFUObject::GetBoardType(int boardNum)
DFU::eBoardType DFUObject::GetBoardType(int boardNum)
{
OP_DFU::eBoardType brdType = eBoardUnkwn;
DFU::eBoardType brdType = eBoardUnkwn;
// First of all, check what Board type we are talking to
int board = devices[boardNum].ID;

View File

@ -1,36 +1,51 @@
#ifndef OP_DFU_H
#define OP_DFU_H
/**
******************************************************************************
*
* @file dfu.h
* @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
* 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
*/
#ifndef DFU_H
#define DFU_H
#include <QByteArray>
#include <ophid/inc/ophid_hidapi.h>
#include <ophid/inc/ophid_usbmon.h>
#include <ophid/inc/ophid_usbsignal.h>
#include <QDebug>
#include <QFile>
#include <QThread>
#include <QMutex>
#include <QMutexLocker>
#include <QMetaType>
#include <QCryptographicHash>
#include <QList>
#include <QVariant>
#include <iostream>
#include "delay.h"
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <QTime>
#include <QTimer>
#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 {
#define BUF_LEN 64
// serial
class qsspt;
// usb
class opHID_hidapi;
namespace DFU {
enum TransferTypes {
FW,
Descript
@ -81,7 +96,7 @@ enum Commands {
Reset, // 5
Abort_Operation, // 6
Upload, // 7
Op_END, // 8
END, // 8
Download_Req, // 9
Download, // 10
Status_Request, // 11
@ -108,13 +123,12 @@ struct device {
bool Writable;
};
class DFUObject : public QThread {
Q_OBJECT;
public:
static quint32 CRCFromQBArray(QByteArray array, quint32 Size);
// DFUObject(bool debug);
DFUObject(bool debug, bool use_serial, QString port);
virtual ~DFUObject();
@ -124,7 +138,7 @@ public:
bool findDevices();
int JumpToApp(bool safeboot, bool erase);
int ResetDevice(void);
OP_DFU::Status StatusRequest();
DFU::Status StatusRequest();
bool EndOperation();
int AbortOperation(void);
bool ready()
@ -133,7 +147,7 @@ public:
}
// Upload (send to device) commands
OP_DFU::Status UploadDescription(QVariant description);
DFU::Status UploadDescription(QVariant description);
bool UploadFirmware(const QString &sfile, const bool &verify, int device);
// Download (get from device) commands:
@ -146,11 +160,10 @@ public:
bool DownloadFirmware(QByteArray *byteArray, int device);
// Comparison functions (is this needed?)
OP_DFU::Status CompareFirmware(const QString &sfile, const CompareType &type, int device);
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;
@ -158,15 +171,14 @@ public:
bool use_delay;
// Helper functions:
QString StatusToString(OP_DFU::Status const & status);
QString StatusToString(DFU::Status const & status);
static quint32 CRC32WideFast(quint32 Crc, quint32 Size, quint32 *Buffer);
OP_DFU::eBoardType GetBoardType(int boardNum);
DFU::eBoardType GetBoardType(int boardNum);
signals:
void progressUpdated(int);
void downloadFinished();
void uploadFinished(OP_DFU::Status);
void uploadFinished(DFU::Status);
void operationProgress(QString status);
private:
@ -175,16 +187,18 @@ private:
bool use_serial;
bool mready;
int RWFlags;
// Serial
qsspt *serialhandle;
// USB
opHID_hidapi *hidHandle;
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:
opHID_hidapi hidHandle;
int setStartBit(int command)
{
return command | 0x20;
@ -198,11 +212,11 @@ private:
// 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);
DFU::Status UploadFirmwareT(const QString &sfile, const bool &verify, int device);
QMutex mutex;
OP_DFU::Commands requestedOperation;
DFU::Commands requestedOperation;
qint32 requestSize;
OP_DFU::TransferTypes requestTransferType;
DFU::TransferTypes requestTransferType;
QByteArray *requestStorage;
QString requestFilename;
bool requestVerify;
@ -213,7 +227,7 @@ protected:
};
}
Q_DECLARE_METATYPE(OP_DFU::Status)
Q_DECLARE_METATYPE(DFU::Status)
#endif // OP_DFU_H
#endif // DFU_H

View File

@ -23,8 +23,7 @@ HEADERS += \
uploadergadgetoptionspage.h \
uploadergadgetwidget.h \
uploaderplugin.h \
op_dfu.h \
delay.h \
dfu.h \
devicewidget.h \
SSP/port.h \
SSP/qssp.h \
@ -42,8 +41,7 @@ SOURCES += \
uploadergadgetoptionspage.cpp \
uploadergadgetwidget.cpp \
uploaderplugin.cpp \
op_dfu.cpp \
delay.cpp \
dfu.cpp \
devicewidget.cpp \
SSP/port.cpp \
SSP/qssp.cpp \

View File

@ -26,8 +26,8 @@
*/
#include "uploadergadgetconfiguration.h"
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
/**
* Loads a saved configuration or defaults if non exist.

View File

@ -28,11 +28,12 @@
#ifndef UPLOADERGADGETCONFIGURATION_H
#define UPLOADERGADGETCONFIGURATION_H
#include <coreplugin/iuavgadgetconfiguration.h>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include "uploader_global.h"
#include <coreplugin/iuavgadgetconfiguration.h>
#include <QtSerialPort/QSerialPort>
using namespace Core;
/**

View File

@ -40,7 +40,6 @@
#include <QtAlgorithms>
#include <QStringList>
UploaderGadgetOptionsPage::UploaderGadgetOptionsPage(UploaderGadgetConfiguration *config, QObject *parent) :
IOptionsPage(parent),
m_config(config)

View File

@ -30,14 +30,13 @@
#define UPLOADERGADGETOPTIONSPAGE_H
#include "uploader_global.h"
#include "coreplugin/dialogs/ioptionspage.h"
#include <QEventLoop>
#include <QString>
#include <QStringList>
#include <QDebug>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
class UploaderGadgetConfiguration;

View File

@ -29,8 +29,9 @@
#include "ui_uploader.h"
#include <ophid/inc/ophid_usbmon.h>
#include "flightstatus.h"
#include "delay.h"
#include "devicewidget.h"
#include "runningdevicewidget.h"
@ -45,6 +46,7 @@
#include <QDesktopServices>
#include <QMessageBox>
#include <QProgressBar>
#include <QtSerialPort/QSerialPortInfo>
#include <QDebug>
#define DFU_DEBUG true
@ -484,7 +486,7 @@ void UploaderGadgetWidget::goToBootloader(UAVObject *callerObj, bool success)
if (m_resetOnly) {
m_resetOnly = false;
delay::msleep(3500);
QThread::msleep(3500);
systemBoot();
break;
}
@ -804,7 +806,7 @@ bool UploaderGadgetWidget::autoUpdate(bool erase)
firmware = file.readAll();
QEventLoop eventLoop2;
connect(m_dfu, SIGNAL(progressUpdated(int)), this, SLOT(autoUpdateFlashProgress(int)));
connect(m_dfu, SIGNAL(uploadFinished(OP_DFU::Status)), &eventLoop2, SLOT(quit()));
connect(m_dfu, SIGNAL(uploadFinished(DFU::Status)), &eventLoop2, SLOT(quit()));
emit progressUpdate(UPLOADING_FW, QVariant());
if (!m_dfu->enterDFU(0)) {
emit progressUpdate(FAILURE, QVariant(tr("Could not enter direct firmware upload mode.")));
@ -820,7 +822,7 @@ bool UploaderGadgetWidget::autoUpdate(bool erase)
eventLoop2.exec();
QByteArray desc = firmware.right(100);
emit progressUpdate(UPLOADING_DESC, QVariant());
if (m_dfu->UploadDescription(desc) != OP_DFU::Last_operation_Success) {
if (m_dfu->UploadDescription(desc) != DFU::Last_operation_Success) {
emit progressUpdate(FAILURE, QVariant(tr("Failed to upload firmware description.")));
emit autoUpdateFailed();
return false;

View File

@ -30,13 +30,14 @@
#include "uploader_global.h"
#include "dfu.h"
#include "enums.h"
#include "op_dfu.h"
#include <QEventLoop>
#include <QProgressDialog>
#include <QTimer>
using namespace OP_DFU;
using namespace DFU;
using namespace uploader;
class Ui_UploaderWidget;