/** ****************************************************************************** * * @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 #include #include #include using namespace OP_DFU; DFUObject::DFUObject(bool _debug,bool _use_serial,QString portname): debug(_debug),use_serial(_use_serial),mready(true) { info = NULL; qRegisterMetaType("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; QList devices; int count=0; while((devices.length()==0) && count < 10) { if (debug) qDebug() << "."; delay::msleep(500); // processEvents enables XP to process the system // plug/unplug events, otherwise it will not process // those events before the end of the call! QApplication::processEvents(); devices = USBMonitor::instance()->availableDevices(0x20a0,-1,-1,USBMonitor::Bootloader); count++; } if (devices.length()==1) { hidHandle.open(1,devices.first().vendorID,devices.first().productID,0,0); } else { qDebug() << devices.length() << " device(s) detected, don't know what to do!"; mready = false; } } } 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:"<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:"<>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="<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>(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;x0) 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="<"); }else{ bar.replace(i,1," "); } } std::cout<< "\r"<> 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;xsendData((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; } } }