sdrangel/liblimesuite/srcmw/ConnectionSTREAM/ConnectionSTREAMImages.cpp

185 lines
6.6 KiB
C++

/**
@file ConnectionSTREAMImages.cpp
@author Lime Microsystems
@brief Image updating and version checking
*/
#include "ConnectionSTREAM.h"
#include "ErrorReporting.h"
#include "SystemResources.h"
#include "LMS64CProtocol.h"
#include "LMSBoards.h"
#include "Logger.h"
#include <fstream>
#include <ciso646>
using namespace lime;
/*!
* The entry structure that describes a board revision and its fw/gw images
*/
struct ConnectionSTREAMImageEntry
{
eLMS_DEV dev;
int hw_rev;
int fw_ver;
const char *fw_img;
int gw_ver;
int gw_rev;
const char *gw_rbf;
};
/*!
* Lookup the board information given hardware type and revision.
* Edit each entry for supported hardware and image updates.
*/
static const ConnectionSTREAMImageEntry &lookupImageEntry(const LMS64CProtocol::LMSinfo &info)
{
static const std::vector<ConnectionSTREAMImageEntry> imageEntries = {
ConnectionSTREAMImageEntry({LMS_DEV_UNKNOWN, -1, -1, "Unknown-USB.img", -1, -1, "Unknown-USB.rbf"}),
ConnectionSTREAMImageEntry({LMS_DEV_LIMESDR, 4, 3, "LimeSDR-USB_HW_1.3_r3.0.img", 2, 8, "LimeSDR-USB_HW_1.4_r2.8.rbf"}),
ConnectionSTREAMImageEntry({LMS_DEV_LIMESDR, 3, 3, "LimeSDR-USB_HW_1.3_r3.0.img", 1, 20, "LimeSDR-USB_HW_1.1_r1.20.rbf"}),
ConnectionSTREAMImageEntry({LMS_DEV_LIMESDR, 2, 3, "LimeSDR-USB_HW_1.2_r3.0.img", 1, 20, "LimeSDR-USB_HW_1.1_r1.20.rbf"}),
ConnectionSTREAMImageEntry({LMS_DEV_LIMESDR, 1, 7, "LimeSDR-USB_HW_1.1_r7.0.img", 1, 20, "LimeSDR-USB_HW_1.1_r1.20.rbf"}),
ConnectionSTREAMImageEntry({LMS_DEV_STREAM, 3, 8, "STREAM-USB_HW_1.1_r8.0.img", 1, 2, "STREAM-USB_HW_1.3_r1.2.rbf"})};
for(const auto &iter : imageEntries)
{
if (info.device == iter.dev and info.hardware == iter.hw_rev)
{
return iter;
}
}
return imageEntries.front(); //the -1 unknown entry
}
void ConnectionSTREAM::VersionCheck(void)
{
const auto info = this->GetInfo();
const auto &entry = lookupImageEntry(info);
//an entry match was not found
if (entry.dev == LMS_DEV_UNKNOWN)
{
lime::error("Unsupported hardware connected: %s[HW=%d]", GetDeviceName(info.device), info.hardware);
return;
}
//check and warn about firmware mismatch problems
if (info.firmware != entry.fw_ver) lime::warning(
"Firmware version mismatch!\n"
" Expected firmware version %d, but found version %d\n"
" Follow the FW and FPGA upgrade instructions:\n"
" http://wiki.myriadrf.org/Lime_Suite#Flashing_images\n"
" Or run update on the command line: LimeUtil --update\n",
entry.fw_ver, info.firmware);
//check and warn about gateware mismatch problems
const auto fpgaInfo = this->GetFPGAInfo();
if (fpgaInfo.gatewareVersion != entry.gw_ver
|| fpgaInfo.gatewareRevision != entry.gw_rev) lime::warning(
"Gateware version mismatch!\n"
" Expected gateware version %d, revision %d\n"
" But found version %d, revision %d\n"
" Follow the FW and FPGA upgrade instructions:\n"
" http://wiki.myriadrf.org/Lime_Suite#Flashing_images\n"
" Or run update on the command line: LimeUtil --update\n",
entry.gw_ver, entry.gw_rev, fpgaInfo.gatewareVersion, fpgaInfo.gatewareRevision);
}
static bool programmingCallbackStream(
int bsent, int btotal, const char* progressMsg,
const std::string &image,
IConnection::ProgrammingCallback callback)
{
const auto msg = std::string(progressMsg) + " (" + image + ")";
return callback(bsent, btotal, msg.c_str());
}
int ConnectionSTREAM::ProgramUpdate(const bool download, IConnection::ProgrammingCallback callback)
{
const auto info = this->GetInfo();
const auto &entry = lookupImageEntry(info);
//an entry match was not found
if (entry.dev == LMS_DEV_UNKNOWN)
{
return lime::ReportError("Unsupported hardware connected: %s[HW=%d]", GetDeviceName(info.device), info.hardware);
}
//download images when missing
if (download)
{
const std::vector<std::string> images = {entry.fw_img, entry.gw_rbf};
for (const auto &image : images)
{
if (not lime::locateImageResource(image).empty()) continue;
const std::string msg("Downloading: " + image);
if (callback) callback(0, 1, msg.c_str());
int ret = lime::downloadImageResource(image);
if (ret != 0) return ret; //error set by download call
if (callback) callback(1, 1, "Done!");
}
}
//load firmware into flash
{
//open file
std::ifstream file;
const auto path = lime::locateImageResource(entry.fw_img);
file.open(path.c_str(), std::ios::in | std::ios::binary);
if (not file.good()) return lime::ReportError("Error opening %s", path.c_str());
//read file
std::streampos fileSize;
file.seekg(0, std::ios::end);
fileSize = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> progData(fileSize, 0);
file.read(progData.data(), fileSize);
int device = LMS64CProtocol::FX3; //FX3
int progMode = 2; //Firmware to FLASH
using namespace std::placeholders;
const auto cb = std::bind(&programmingCallbackStream, _1, _2, _3, path, callback);
auto status = this->ProgramWrite(progData.data(), progData.size(), progMode, device, cb);
if (status != 0) return status;
}
//load gateware into flash
{
//open file
std::ifstream file;
const auto path = lime::locateImageResource(entry.gw_rbf);
file.open(path.c_str(), std::ios::in | std::ios::binary);
if (not file.good()) return lime::ReportError("Error opening %s", path.c_str());
//read file
std::streampos fileSize;
file.seekg(0, std::ios::end);
fileSize = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> progData(fileSize, 0);
file.read(progData.data(), fileSize);
int device = LMS64CProtocol::FPGA; //Altera FPGA
int progMode = 1; //Bitstream to FLASH
using namespace std::placeholders;
const auto cb = std::bind(&programmingCallbackStream, _1, _2, _3, path, callback);
auto status = this->ProgramWrite(progData.data(), progData.size(), progMode, device, cb);
if (status != 0) return status;
}
//Reset FX3, FPGA should be reloaded on boot
{
int device = LMS64CProtocol::FX3; //FX3
auto status = this->ProgramWrite(nullptr, 0, 0, device, nullptr);
if (status != 0) return status;
}
return 0;
}