Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,18 @@ C:\Qt\6.6.0\msvc2019_64\bin\windeployqt.exe solum.exe
```

This copies all required dependencies into the same folder. **The solum.dll file though needs to be copied manually in addition.**

## Developer startup


### Windows

1. Download and install Qt creator
2. Ensure you use a msvc compiler (Qt.bluetooth is not supported with the mingw
compiler)
- I none is installed on your machine download it via the microsoft build
tools
3. Open the `solum_qt.pro` with qt creator
4. Run the application
5. Make sure that you add the necessary certificates. You can find the
necessary token to claim them on the [clarius user website](https://cloud.clarius.com/login/)
232 changes: 113 additions & 119 deletions examples/solum_qt/solum/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,132 +57,126 @@ int main(int argc, char *argv[])

_solum = std::make_unique<Solum>();

if (solumInit(argc, argv, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString().c_str(),
// connection callback
[](CusConnection res, int port, const char* msg)
{
QApplication::postEvent(_solum.get(), new event::Connection(res, port, QString::fromLatin1(msg)));
},
// cert callback
[](int daysValid)
{
QApplication::postEvent(_solum.get(), new event::Cert(daysValid));
},
// power down callback
[](CusPowerDown res, int tm)
{
QApplication::postEvent(_solum.get(), new event::PowerDown(res, tm));
},
// new image callback
[](const void* img, const CusProcessedImageInfo* nfo, int npos, const CusPosInfo* pos)
{
size_t sz = nfo->imageSize;
// we need to perform a deep copy of the image data since we have to post the event (yes this happens a lot with this api)
if (_image.size() < static_cast<size_t>(sz))
_image.resize(sz);
memcpy(_image.data(), img, sz);
QQuaternion imu;
if (npos && pos)
imu = QQuaternion(static_cast<float>(pos[0].qw), static_cast<float>(pos[0].qx), static_cast<float>(pos[0].qy), static_cast<float>(pos[0].qz));

SolumImage solumImage = {
.img_ = { reinterpret_cast<uint8_t *>(_image.data()), sz },
.width_ = nfo->width,
.height_ = nfo->height,
.bpp_ = nfo->bitsPerPixel,
.format_ = nfo->format,
};

QApplication::postEvent(_solum.get(), new event::ProcessedImage(
IMAGE_EVENT, solumImage, nfo->overlay, imu, nfo->micronsPerPixel, nfo->originX, nfo->originY
));
},
// new raw data callback
[](const void* data, const CusRawImageInfo* nfo, int, const CusPosInfo*)
{
SolumImage solumImage = {
.width_ = nfo->lines,
.height_ = nfo->samples,
.bpp_ = nfo->bitsPerSample,
.format_ = nfo->jpeg ? Jpeg : Uncompressed8Bit,
};

// we need to perform a deep copy of the image data since we have to post the event (yes this happens a lot with this api)
size_t sz = nfo->lines * nfo->samples * (nfo->bitsPerSample / 8);
if (nfo->rf)
{
if (_rfData.size() < static_cast<size_t>(sz))
_rfData.resize(sz);
memcpy(_rfData.data(), data, sz);
solumImage.img_ = { reinterpret_cast<uint8_t *>(_rfData.data()), sz },
CusInitParams initParams = solumDefaultInitParams();
initParams.args = {argc, argv};

const std::string security_key_dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toStdString();
initParams.storeDir = security_key_dir.c_str();

initParams.connectFn = [](CusConnection res, int port, const char* msg) {
QApplication::postEvent(_solum.get(), new event::Connection(res, port, QString::fromLatin1(msg)));
};

initParams.certFn = [](int daysValid) {
QApplication::postEvent(_solum.get(), new event::Cert(daysValid));
};

initParams.powerDownFn = [](CusPowerDown res, int tm) {
QApplication::postEvent(_solum.get(), new event::PowerDown(res, tm));
};

initParams.newProcessedImageFn =
[](const void* img, const CusProcessedImageInfo* nfo, int npos, const CusPosInfo* pos) {
size_t sz = nfo->imageSize;
// we need to perform a deep copy of the image data since we have to post the event (yes this happens a lot with this api)
if (_image.size() < static_cast<size_t>(sz))
_image.resize(sz);
memcpy(_image.data(), img, sz);
QQuaternion imu;
if (npos && pos)
imu = QQuaternion(static_cast<float>(pos[0].qw), static_cast<float>(pos[0].qx), static_cast<float>(pos[0].qy), static_cast<float>(pos[0].qz));

SolumImage solumImage = {
.img_ = { reinterpret_cast<uint8_t *>(_image.data()), sz },
.width_ = nfo->width,
.height_ = nfo->height,
.bpp_ = nfo->bitsPerPixel,
.format_ = nfo->format,
};

QApplication::postEvent(_solum.get(), new event::ProcessedImage(
IMAGE_EVENT, solumImage, nfo->overlay, imu, nfo->micronsPerPixel, nfo->originX, nfo->originY
));
};


initParams.buttonFn = [](CusButton btn, int clicks) {
// post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread
QApplication::postEvent(_solum.get(), new event::Button(btn, clicks));
};

initParams.errorFn = [](CusErrorCode code, const char* msg) {
// post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread
QApplication::postEvent(_solum.get(), new event::Error(msg));
};

initParams.imagingFn = [](CusImagingState state, int imaging) {
// post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread
QApplication::postEvent(_solum.get(), new event::Imaging(state, imaging ? true : false));
};


initParams.newRawImageFn = [](const void* data, const CusRawImageInfo* nfo, int, const CusPosInfo*) {
SolumImage solumImage = {
.width_ = nfo->lines,
.height_ = nfo->samples,
.bpp_ = nfo->bitsPerSample,
.format_ = nfo->jpeg ? Jpeg : Uncompressed8Bit,
};

// we need to perform a deep copy of the image data since we have to post the event (yes this happens a lot with this api)
size_t sz = nfo->lines * nfo->samples * (nfo->bitsPerSample / 8);
if (nfo->rf) {
if (_rfData.size() < static_cast<size_t>(sz))
_rfData.resize(sz);
memcpy(_rfData.data(), data, sz);
solumImage.img_ = { reinterpret_cast<uint8_t *>(_rfData.data()), sz },
QApplication::postEvent(_solum.get(), new event::RfImage(solumImage, nfo->lateralSize, nfo->axialSize));
}
else
{
// image may be a jpeg, adjust the size
if (nfo->jpeg)
sz = nfo->jpeg;
if (_prescanImage.size() < static_cast<size_t>(sz))
_prescanImage.resize(sz);
memcpy(_prescanImage.data(), data, sz);
solumImage.img_ = { reinterpret_cast<uint8_t *>(_prescanImage.data()), sz },
}
else {
// image may be a jpeg, adjust the size
if (nfo->jpeg) { sz = nfo->jpeg; }
if (_prescanImage.size() < static_cast<size_t>(sz))
_prescanImage.resize(sz);
memcpy(_prescanImage.data(), data, sz);
solumImage.img_ = { reinterpret_cast<uint8_t *>(_prescanImage.data()), sz },
QApplication::postEvent(_solum.get(), new event::Image(PRESCAN_EVENT, solumImage, false));
}
},
// new spectrum callback
[](const void* img, const CusSpectralImageInfo* nfo)
{
size_t sz = nfo->lines * nfo->samples * (nfo->bitsPerSample / 8);
// we need to perform a deep copy of the spectrum data since we have to post the event (yes this happens a lot with this api)
if (_spectrum.size() < sz)
_spectrum.resize(sz);
memcpy(_spectrum.data(), img, sz);
QApplication::postEvent(_solum.get(), new event::SpectrumImage(_spectrum.data(), nfo->lines, nfo->samples, nfo->bitsPerSample));
},
// new imu port callback
[](int port)
{
QApplication::postEvent(_solum.get(), new event::ImuPort(port));
},
// new imu data callback
[](const CusPosInfo* pos)
{
QQuaternion imu;
if (pos)
imu = QQuaternion(static_cast<float>(pos->qw), static_cast<float>(pos->qx), static_cast<float>(pos->qy), static_cast<float>(pos->qz));
QApplication::postEvent(_solum.get(), new event::Imu(IMU_EVENT, imu));
},
// imaging state change callback
[](CusImagingState state, int imaging)
{
// post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread
QApplication::postEvent(_solum.get(), new event::Imaging(state, imaging ? true : false));
},
// button press callback
[](CusButton btn, int clicks)
{
// post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread
QApplication::postEvent(_solum.get(), new event::Button(btn, clicks));
},
// error message callback
[](const char* err)
{
// post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread
QApplication::postEvent(_solum.get(), new event::Error(err));
},
width, height) != 0)
}
};

initParams.newSpectralImageFn = [](const void* img, const CusSpectralImageInfo* nfo) {
size_t sz = nfo->lines * nfo->samples * (nfo->bitsPerSample / 8);
// we need to perform a deep copy of the spectrum data since we have to post the event (yes this happens a lot with this api)
if (_spectrum.size() < sz) { _spectrum.resize(sz); }
memcpy(_spectrum.data(), img, sz);
QApplication::postEvent(_solum.get(), new event::SpectrumImage(_spectrum.data(), nfo->lines, nfo->samples, nfo->bitsPerSample));
};

initParams.newImuPortFn = [](int port) {
QApplication::postEvent(_solum.get(), new event::ImuPort(port));
};

initParams.newImuDataFn = [](const CusPosInfo* pos) {
QQuaternion imu;
if (pos)
imu = QQuaternion(static_cast<float>(pos->qw), static_cast<float>(pos->qx), static_cast<float>(pos->qy), static_cast<float>(pos->qz));
QApplication::postEvent(_solum.get(), new event::Imu(IMU_EVENT, imu));
};

initParams.width = width;
initParams.height = height;

if (solumInit(&initParams) != 0)
{
qDebug() << "error initializing listener";
return -1;
}

solumSetTeeFn(
[](bool connected, const char* serial, double timeRemaining, const char* id, const char* name, const char* exam)
{
// post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread
QApplication::postEvent(_solum.get(), new event::Tee(connected, QString::fromLatin1(serial), timeRemaining,
QString::fromLatin1(id), QString::fromLatin1(name), QString::fromLatin1(exam)));
});
solumSetTeeFn( [](bool connected, const char* serial, double timeRemaining, const char* id, const char* name, const char* exam) {
// post event here, as the gui (statusbar) will be updated directly, and it needs to come from the application thread
QApplication::postEvent(_solum.get(), new event::Tee(connected, QString::fromLatin1(serial), timeRemaining,
QString::fromLatin1(id), QString::fromLatin1(name), QString::fromLatin1(exam)));
});

print_firmware_version();

Expand Down
11 changes: 10 additions & 1 deletion examples/solum_qt/solum/solumqt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "display.h"
#include "3d.h"
#include <solum/solum.h>
#include <string>

static Solum* _me;

Expand Down Expand Up @@ -843,7 +844,15 @@ void Solum::onTcpConnect()
{
if (!tcpConnected_)
{
if (solumConnect(ui_.ip->text().toStdString().c_str(), ui_.port->text().toInt()) < 0)

const std::string ip = ui_.ip->text().toStdString();
const CusConnectionParams connectionParams = {
ip.c_str(),
ui_.port->text().toUInt(),
0
};

if (solumConnect(&connectionParams) < 0)
addStatus(tr("Connection failed"));
else
addStatus(tr("Trying connection"));
Expand Down
Loading