added settings

master
Yorick GEOFFRE 2 years ago
parent e6ae8a3487
commit b75ef82d2e

@ -0,0 +1,34 @@
#include "imagemaster.h"
#include <QImage>
#include <QColor>
#include <QVector>
#include <QBuffer>
#include <QFile>
#include <QDir>
#include <QStandardPaths>
#include <QDebug>
#include <QDateTime>
void saveImageFromColorArray(const QVector<QColor> &colorArray, int width, int height, int scale) {
QImage image(width, height, QImage::Format_ARGB32);
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
int index = y * width + x;
image.setPixelColor(x, y, colorArray.at(index));
}
}
QImage scaledImage = image.scaled(width * scale, height * scale, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
QString path = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
QString currentDateTime = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss");
QString fileName = QDir(path).filePath(currentDateTime + ".png");
if (scaledImage.save(fileName)) {
qDebug() << "Image saved successfully";
} else {
qDebug() << "Failed to save image";
}
}

@ -0,0 +1,9 @@
#ifndef IMAGEMASTER_H
#define IMAGEMASTER_H
#include <QVector>
#include <QColor>
void saveImageFromColorArray(const QVector<QColor> &colorArray, int width, int height, int scale);
#endif // IMAGEMASTER_H

@ -11,6 +11,7 @@
class PollingTimer : public QObject
{
Q_OBJECT
Q_PROPERTY(unsigned int timeout READ getTimeout WRITE setTimeout NOTIFY timeoutChanged)
protected:
std::atomic<bool> shouldRun;
std::thread* myThread = nullptr;
@ -24,7 +25,15 @@ public:
PollingTimer(Command* c) : shouldRun(false), _c(c){}
Q_INVOKABLE void start();
Q_INVOKABLE void stop();
Q_INVOKABLE inline void setDelay(const unsigned int& timeout) {this->timeout = timeout;}
unsigned int getTimeout() const {return timeout;}
void setTimeout(const unsigned int& t) {
if (t != timeout) {
timeout = t;
emit timeoutChanged();
}
}
signals:
void timeoutChanged();
};
#endif // POLLINGTIMER_H

@ -2,10 +2,12 @@ import Sailfish.Silica 1.0
import harbour.i2ctool.I2cif 1.0
import melexis.driver 1.0
import QtQuick 2.0
import QtQuick.Layouts 1.1
Page {
id: mainPage
property bool isInitialized: false
property bool isRunning: false
SilicaListView {
anchors.fill: parent
@ -24,11 +26,11 @@ Page {
}
}
}
Column {
ColumnLayout {
id: column
width: parent.width
spacing: Theme.paddingLarge
anchors.horizontalCenter: parent.horizontalCenter
PageHeader
{
title: "ThermI2C"
@ -49,12 +51,15 @@ Page {
id: startButton
text: mainPage.isInitialized ? "Stop" : "Start"
onClicked: {
if(mainPage.isInitialized){
mainPage.isInitialized = false;
if(mainPage.isRunning){
mainPage.isRunning = false;
polling_timer.stop();
}else{
mainPage.isInitialized = true;
mainPage.isRunning = true;
if(!mainPage.isInitialized){
mlx90640.fuzzyInit();
mainPage.isInitialized = true;
}
polling_timer.start();
}
}
@ -65,13 +70,9 @@ Page {
Row
{
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -100
Grid {
id: grid
columns: 32
y: parent.height + height
x: (parent.width + width) / 2
Repeater {
id: repeater
model: 768
@ -95,6 +96,31 @@ Page {
}
}
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.paddingLarge
Button {
id: photoButton
text: "📷"
width: 120
height: 120
onClicked: {
thermalRenderer.capture()
}
}
Button {
id: settingsButton
text: "⚙️"
width: 120
height: 120
onClicked: {
console.log("Settings button clicked.")
pageStack.push(Qt.resolvedUrl("SecondPage.qml"))
}
}
}
}
}
}

@ -1,30 +1,77 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import Sailfish.Pickers 1.0
import QtQuick.Layouts 1.1
Page {
id: page
// The effective value will be restricted by ApplicationWindow.allowedOrientations
allowedOrientations: Orientation.All
SilicaListView {
id: listView
model: 20
anchors.fill: parent
header: PageHeader {
title: qsTr("Nested Page")
PageHeader {
id: header
title: "Settings Page"
}
delegate: BackgroundItem {
id: delegate
Column {
width: parent.width
spacing: Theme.paddingLarge
anchors.left: parent.left
anchors.right: parent.right
anchors.top: header.bottom
anchors.topMargin: Theme.paddingLarge
SectionHeader { text: "Performance" }
Label {
x: Theme.horizontalPageMargin
text: qsTr("Item") + " " + index
anchors.verticalCenter: parent.verticalCenter
color: delegate.highlighted ? Theme.highlightColor : Theme.primaryColor
text: "FPS Limit"
anchors.left: parent.left
anchors.leftMargin: Theme.horizontalPageMargin
}
TextField {
id: fpsPicker
width: parent.width - Theme.horizontalPageMargin * 2
placeholderText: "Enter FPS limit(1-60)"
validator: IntValidator { bottom: 1; top: 60 }
onTextChanged: {
if (fpsPicker.acceptableInput) {
polling_timer.timeout = (1000/parseInt(text, 10))
}
}
}
SectionHeader { text: "Display" }
Label {
text: "Min-Max Value"
anchors.left: parent.left
anchors.leftMargin: Theme.horizontalPageMargin
}
Slider {
id: rangeSlider
width: parent.width - Theme.horizontalPageMargin * 2
stepSize: 1
value: 50
minimumValue: 0
maximumValue: 100
onValueChanged: {
// handle value change
}
}
SectionHeader { text: "Options" }
Label {
text: "Noise"
anchors.left: parent.left
anchors.leftMargin: Theme.horizontalPageMargin
}
Switch {
id: noiseToggle
anchors.right: parent.right
anchors.rightMargin: Theme.horizontalPageMargin
onCheckedChanged: {
mlx90640.stubMode = checked
}
onClicked: console.log("Clicked " + index)
}
VerticalScrollDecorator {}
}
}

@ -23,6 +23,15 @@ int MLX90640::mlx90640_DumpEE(uint8_t slaveAddr, uint16_t *eeData)
return mlx90640_I2CRead(slaveAddr, mlx90640_EEPROM_START_ADDRESS, mlx90640_EEPROM_DUMP_NUM, eeData);
}
void MLX90640::setStubMode(const bool& val)
{
if (m_stubMode != val) {
m_stubMode = val;
mlx90640_I2CSetStub(val);
emit stubModeChanged();
}
}
int MLX90640::mlx90640_SynchFrame(uint8_t slaveAddr)
{
uint16_t dataReady = 0;

@ -89,16 +89,26 @@
#include <stdint.h>
#define IGNORE_I2C_DISCONNECTS //comment out this line to enable noise generation / demo mode
//#define IGNORE_I2C_DISCONNECTS //comment out this line to enable noise generation / demo mode
class MLX90640 : public QObject
{
Q_OBJECT
protected:
bool m_stubMode = true;
public:
Q_PROPERTY(bool initialized READ getInitialized WRITE setInitialized NOTIFY initializedChanged)
Q_PROPERTY(QVector<float> imageVect READ getImageVect NOTIFY dataReady)
Q_PROPERTY(bool stubMode READ getStubMode WRITE setStubMode NOTIFY stubModeChanged)
bool getStubMode() {
return m_stubMode;
}
void setStubMode(const bool& val);
QVector<float> getImageVect() const {
return this->imageVect;
}
@ -176,6 +186,12 @@ public:
uint16_t eeMLX90640[832];
try{
status = mlx90640_SetRefreshRate (0x33,0x06); //32hz
if(status != 0 && m_stubMode){
perlin.fillWithPerlinNoise(imageVect, 32, 24, 1234567);
emit initializedChanged();
emit dataReady(imageVect);
return;
}
int curRR = mlx90640_GetRefreshRate (0x33);
fprintf(stderr, "refresh rate: %d\n", curRR);
status = mlx90640_SetResolution(0x33,0x00); //16 bit res
@ -188,31 +204,19 @@ public:
fprintf(stderr, "dump EEprom...\n");
status = mlx90640_DumpEE (slaveAddress, eeMLX90640);
usleep(1000);
#ifndef IGNORE_I2C_DISCONNECTS
if(status != 0){
perlin.fillWithPerlinNoise(imageVect, 32, 24, 1234567);
emit initializedChanged();
emit dataReady(imageVect);
return;
}
#endif
fprintf(stderr, "extract parameters...\n");
status = mlx90640_ExtractParameters(eeMLX90640, &mlx90640);
usleep(1000);
#ifndef IGNORE_I2C_DISCONNECTS
if(status == 0)
getData();
else{
if(status != 0 && m_stubMode){
perlin.fillWithPerlinNoise(imageVect, 32, 24, 1234567);
emit dataReady(imageVect);
}
#else
}else{
getData();
#endif
}
}catch(...){
#ifndef IGNORE_I2C_DISCONNECTS
if(m_stubMode)
perlin.fillWithPerlinNoise(imageVect, 32, 24, 1234567);
#endif
}
emit initializedChanged();
@ -236,9 +240,8 @@ public:
imageVect[i] = mlx90640Image[i];
}
} else {
#ifndef IGNORE_I2C_DISCONNECTS
if(m_stubMode)
perlin.fillWithPerlinNoise(imageVect, 32, 24, 1234567);
#endif
}
emit dataReady(imageVect);
@ -253,7 +256,6 @@ public:
}
MLX90640() : imageVect(768){
fuzzyInit();
}
QVector<float> imageVect;
@ -280,5 +282,6 @@ protected:
signals:
void dataReady(QVector<float> data);
void initializedChanged();
void stubModeChanged();
};
#endif

@ -36,3 +36,7 @@ int mlx90640_I2CWrite(uint8_t slaveAddr,uint16_t writeAddress, uint16_t data)
{
return i2cDriverSingleton::getinstance()->i2cWrite(slaveAddr, writeAddress, data);
}
void mlx90640_I2CSetStub(const bool& stubmode){
i2cDriverSingleton::getinstance()->stubMode = stubmode;
}

@ -25,4 +25,5 @@
extern int mlx90640_I2CWrite(uint8_t slaveAddr,uint16_t writeAddress, uint16_t data);
extern int mlx90640_I2CRead(uint8_t slaveAddr,uint16_t startAddress, uint16_t nMemAddressRead, uint16_t *data);
extern void mlx90640_I2CFreqSet(int freq);
extern void mlx90640_I2CSetStub(const bool& stubmode);
#endif

@ -38,6 +38,7 @@ public:
QString firstTimeDefault(QString index);
bool stubMode = false;
signals:
void i2cProbingChanged();
void i2cError();

@ -89,7 +89,7 @@ int main(int argc, char *argv[]) {
//when a frame is ready, pass it to the renderer
QObject::connect(thermal, SIGNAL(dataReady(QVector<float>)), thermalRenderer, SLOT(receiveNewData(QVector<float>)), Qt::ConnectionType::DirectConnection);
pt->setDelay(100);
pt->setTimeout(100);
view.rootContext()->setContextProperty("polling_timer",pt);
view.rootContext()->setContextProperty("mlx90640", thermal);

@ -1,4 +1,5 @@
#include "thermaldatarenderer.h"
#include "imagemaster.h"
#include <chrono>
void ThermalDataRenderer::receiveNewData(QVector<float> data) {
auto start = std::chrono::high_resolution_clock::now();
@ -13,9 +14,34 @@ void ThermalDataRenderer::receiveNewData(QVector<float> data) {
if(renderBuffer.size() < data.size())
renderBuffer = QVector<QColor>(data.size()+1);
QVector<float> sortedData = data;
std::sort(sortedData.begin(), sortedData.end());
const float lowerPercentile = 0.2f;
const float upperPercentile = 0.98f;
int lowerIndex = static_cast<int>(lowerPercentile * sortedData.size());
int upperIndex = static_cast<int>(upperPercentile * sortedData.size());
minValue = sortedData[lowerIndex];
maxValue = sortedData[upperIndex];
//fprintf(stderr, "minValue: %f\t", minValue);
//fprintf(stderr, "maxValue: %f\n", maxValue);
attributers[activeAttributer]->maxValue = maxValue;
attributers[activeAttributer]->minValue= minValue;
for (int i = 0; i < data.size() && i < renderBuffer.size(); ++i) {
renderBuffer[i] = attributers[activeAttributer]->encode(data[i]);
}
if(takeCapture){
saveImageFromColorArray(renderBuffer, 32, 24, 5); //5 times upscale from 32x24 to 160x120
takeCapture = false;
}
emit dataChanged();
auto end = std::chrono::high_resolution_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

@ -22,6 +22,7 @@ class ThermalDataRenderer : public QObject
unsigned int activeAttributer;
float minValue = 0.0f;
float maxValue = 1.0f;
bool takeCapture = false;
public:
Q_PROPERTY(QVector<std::shared_ptr<ColorAttributer>> attributers READ getAttributers NOTIFY attributersChanged)
Q_PROPERTY(QStringList attributerNames READ getAttributerNames NOTIFY attributerNamesChanged)
@ -44,6 +45,10 @@ public:
return QColor(0,0,0);
}
Q_INVOKABLE void capture(){
takeCapture = true;
}
inline void addAttributer(ColorAttributerPtr attributer) {
attributers.push_back(attributer);
emit attributerNamesChanged();

@ -17,6 +17,7 @@ CONFIG += sailfishapp
SOURCES += src/thermi2c.cpp \
colorattributer.cpp \
command.cpp \
imagemaster.cpp \
perlin.cpp \
pollingtimer.cpp \
src/mlx90640_API.cpp \
@ -52,6 +53,7 @@ HEADERS += \
colorattributer.h \
command.h \
datapollcommand.h \
imagemaster.h \
perlin.h \
pollingtimer.h \
src/mlx90640_API.h \

File diff suppressed because it is too large Load Diff

@ -8,15 +8,4 @@
<translation>Mein Cover</translation>
</message>
</context>
<context>
<name>SecondPage</name>
<message>
<source>Nested Page</source>
<translation>Unterseite</translation>
</message>
<message>
<source>Item</source>
<translation>Element</translation>
</message>
</context>
</TS>

@ -8,15 +8,4 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SecondPage</name>
<message>
<source>Nested Page</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Item</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

Loading…
Cancel
Save