main
Daniel Gorbea 2022-03-06 23:15:49 -05:00
rodzic 78d468c5e0
commit 6b27a3a53d
6 zmienionych plików z 503 dodań i 172 usunięć

Wyświetl plik

@ -1,6 +1,6 @@
# Oscilloscope Serial
An oscilloscope application that reads the values at serial port generated by an Arduino board and based on the value of the analog pin A0
An oscilloscope application that reads the values at serial port generated by an Arduino board and based on the value of the analog pin A0 (A5 for Leonardo)
<p align="center"><img src="./images/img1.png" width="600"><br>
<i>Main window</i><br><br></p>
@ -17,7 +17,7 @@ Flash _oscilloscope_. In the Oscilloscope app configure the serial port. By defa
You can connect any signal up to 5 volts to the analog pin A0. For signals over 5V a voltage divider is needed.
For ATmega boards it is defined a PWM signal at pin OC1B. To test the Oscilloscope app connect pin OC1B to pin A0
For ATmega boards it is defined a PWM signal at pin OC1B. To test the Oscilloscope app connect pin OC1B to pin A0/A5
Adjust PWM signal with PWM_FREQ and PWM_DUTY. Default is 1000Hz, 50% duty.
Pin OC1B location:
@ -43,6 +43,9 @@ Supported OS:
## Change log:
v0.3
- Minor fixes
[v0.2](https://github.com/dgatf/Oscilloscope/releases/tag/v0.2)
- Upgrade to qml gui
- Add csv export

Wyświetl plik

@ -1,31 +1,209 @@
#define serial Serial
/* PWM signal */
#define PWM_FREQ 1000 // HZ (1000HZ=1ms)
#define PWM_FREQ 20000 // HZ (1000HZ=1ms)
#define PWM_DUTY 0.5 // %/100
/* Capture buffer */
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__)
#define BUFFER_LEN 1500
#endif
#if defined(__AVR_ATmega32U4__)
#define BUFFER_LEN 2000
#endif
#if defined(__AVR_ATmega2560__)
#define BUFFER_LEN 5000
#endif
/* Data bits */
#define DATABITS 8 // 8, (4), 1
/* ADC Prescaler */
#define PRESCALER 32 // 32, 16, 8, (4)
/* Mode */
#define REALTIME 0
#define CAPTURE 1
#define MODE REALTIME // REALTIME, CAPTURE
#define MS_TO_COMP(SCALER) (F_CPU / (SCALER * 1000.0))
#if defined(ARDUINO_ARCH_AVR)
volatile bool isBufferFull = false;
volatile uint8_t buffer[BUFFER_LEN];
ISR(ADC_vect) {
void (*ADC_vect_handlerP)() = NULL;
ISR(ADC_vect)
{
if (ADC_vect_handlerP)
ADC_vect_handlerP();
/*static uint16_t contByte = 0;
buffer[contByte] = ADCH;
if (contByte == BUFFER_LEN)
{
isBufferFull = true;
contByte = 0;
ADCSRA &= ~_BV(ADIE);
}
contByte++;*/
}
/* Capture */
void capture_8b()
{
static uint16_t contByte = 0;
buffer[contByte] = ADCH;
if (contByte == BUFFER_LEN)
{
isBufferFull = true;
contByte = 0;
ADCSRA &= ~_BV(ADIE);
}
contByte++;
}
void capture_4b()
{
static uint16_t contByte = 0;
static bool newByte = false;
if (newByte)
{
buffer[contByte] |= (ADCH & 0xF0);
contByte++;
}
else
buffer[contByte] = ADCH >> 4;
if (contByte == BUFFER_LEN)
{
isBufferFull = true;
contByte = 0;
ADCSRA &= ~_BV(ADIE);
}
newByte = !newByte;
}
void capture_1b()
{
static uint16_t contByte = 0;
static uint8_t data = 0;
static uint8_t contBit = 0;
data |= (ADCH & 0x80);
contBit++;
if (contBit == 8)
{
buffer[contByte] = data;
contBit = 0;
contByte++;
}
if (contByte == BUFFER_LEN)
{
isBufferFull = true;
contByte = 0;
ADCSRA &= ~_BV(ADIE);
}
data >>= 1;
}
/* Realtime */
void realtime_8b()
{
serial.write((uint8_t)ADCH);
}
void setup() {
serial.begin(1000000);
void realtime_4b()
{
static uint8_t data = 0;
static bool sendByte = false;
if (sendByte)
serial.write(data | (ADCH & 0xF0));
else
data = ADCH >> 4;
sendByte = !sendByte;
/* ADC init
Capture time: F_CPU / ADC_PRESCALER / 13 ADC TICKS:
Prescaler 32: 1.6M / 32 / 13 = 76923 -> 1 / 38461 = 26 us
Prescaler 16: 1.6M / 16 / 13 = 76923 -> 1 / 76923 = 13 us (this is too fast for some devices)
}
void realtime_1b()
{
static uint8_t data = 0;
static uint8_t cont;
data |= (ADCH & 0x80);
cont++;
if (cont == 8)
{
serial.write(data);
data = 0;
cont = 0;
}
data >>= 1;
}
void sendData()
{
for (uint16_t i = 0; i < BUFFER_LEN; i++) {
while (!serial.availableForWrite());
serial.write(buffer[i]);
}
isBufferFull = false;
delay(2000);
ADCSRA |= _BV(ADIE);
}
void setup() {
/*
ADC init
Capture time: F_CPU / ADC_PRESCALER / 13 ADC TICKS: (1 byte at 1000000 = 10us)
Prescaler 32: 1.6M / 32 / 13 = 38461 -> 1 / 38461 = 26 us -> realtime 8 data bits
Prescaler 16: 1.6M / 16 / 13 = 76923 -> 1 / 76923 = 13 us -> realtime 4 data bits
Prescaler 8: 1.6M / 8 / 13 = 153846 -> 1 / 153846 = 6.5 us -> capture
Prescaler 4: 1.6M / 4 / 13 = 307692-> 1 / 307692 = 3.25 us -> too fast
Prescaler 2: 1.6M / 2 / 13 = 615385-> 1 / 615385 = 1.62 us -> too fast
*/
switch (PRESCALER)
{
case 4:
ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS1);
break;
case 8:
ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS1) | _BV(ADPS0);
break;
case 16:
ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2);
break;
case 32:
ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS0);
break;
}
ADMUX = _BV(REFS0) | _BV(ADLAR);
//ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2); // prescaler 16
ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS0); // prescaler 32
ADCSRB = 0;
ADCSRA |= _BV(ADSC);
if (MODE == REALTIME)
{
serial.begin(1000000, SERIAL_8N1);
if (DATABITS == 8)
ADC_vect_handlerP = realtime_8b;
if (DATABITS == 4)
ADC_vect_handlerP = realtime_4b;
if (DATABITS == 1)
ADC_vect_handlerP = realtime_1b;
}
if (MODE == CAPTURE)
{
serial.begin(115200, SERIAL_8N1);
if (DATABITS == 8)
ADC_vect_handlerP = capture_8b;
if (DATABITS == 4)
ADC_vect_handlerP = capture_4b;
if (DATABITS == 1)
ADC_vect_handlerP = capture_1b;
}
/* PWM signal is available at pin OC1B. To test the Oscilloscope app connect pin OC1B to pin A0
Adjust PWM signal with PWM_FREQ and PWM_DUTY. Default: PWM 1000Hz, 50% DUTY
Pin OC1B:
@ -38,36 +216,25 @@ void setup() {
#else
DDRB |= _BV(DDB2);
#endif
DDRB |= _BV(DDB2);
TCCR1A = _BV(WGM11) | _BV(WGM10);
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11); // scaler 8
TCCR1A |= _BV(COM1B1);
// PWM signal
OCR1A = 1000.0 / PWM_FREQ * MS_TO_COMP(8);
OCR1B = PWM_DUTY * OCR1A;
/* // sinus signal (1Hz)
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // scaler 1
OCR1A = 1000.0 / 38000 * MS_TO_COMP(8);
OCR1B = PWM_DUTY * OCR1A;*/
//TIMSK1 = OCIE1A;
}
void loop() {
if (isBufferFull)
sendData();
}
#else
/* Interval between analog readings (for non ATmega boards. It has to be the same as defined in the Oscilloscope settings */
#define INTERVAL 200// microseconds (us). Minimun is 200
void setup() {
serial.begin(1000000);
}
void loop() {
static uint16_t ts = 0;
if ((uint16_t)micros() - ts > INTERVAL)
{
ts = micros();
uint8_t val = analogRead(A0) >> 2;
serial.write(val);
}
}
#endif

Wyświetl plik

@ -91,7 +91,11 @@ Item {
ListElement { text: "5ms/d"; value: 5000 }
ListElement { text: "1ms/d"; value: 1000 }
ListElement { text: "500μs/d"; value: 500 }
ListElement { text: "400μs/d"; value: 400 }
ListElement { text: "300μs/d"; value: 300 }
ListElement { text: "200μs/d"; value: 200 }
ListElement { text: "100μs/d"; value: 100 }
ListElement { text: "50μs/d"; value: 50 }
}
currentIndex: 2
onCurrentValueChanged: oscilloscope.setHDiv(currentValue)

Wyświetl plik

@ -110,7 +110,7 @@ Item {
ListElement { text: "500000" }
ListElement { text: "1000000" }
}
currentIndex: 7
currentIndex: 8
}
Label { text: "Data bits" }
ComboBox {
@ -139,7 +139,26 @@ Item {
SpinBox {
id: interval
Layout.fillWidth: true
value: 26
value: 2600
from: 0
to: 100 * 100
editable: true
property int decimals: 2
property real realValue: value / 100
validator: DoubleValidator {
bottom: Math.min(interval.from, interval.to)
top: Math.max(interval.from, interval.to)
}
textFromValue: function(value, locale) {
return Number(value / 100).toLocaleString(locale, 'f', interval.decimals)
}
valueFromText: function(text, locale) {
return Number.fromLocaleString(locale, text) * 100
}
}
}
}

Wyświetl plik

@ -24,7 +24,9 @@ Oscilloscope::Oscilloscope(qreal pixelRatio)
, pixmap(new QPixmap(pmWidth, pmHeight))
, paint(new QPainter(pixmap))
, serial(new QSerialPort())
, timer(new QTimer())
{
connect(timer, &QTimer::timeout, this, &Oscilloscope::timeOut);
}
#else
Oscilloscope::Oscilloscope(qreal pixelRatio)
@ -39,7 +41,8 @@ Oscilloscope::Oscilloscope(qreal pixelRatio)
jclass classId = env->FindClass("org/qtproject/qt/UsbSerialInterface");
usbSerial = QAndroidJniObject(classId);
JNINativeMethod methods[] { {"sendBuffer", "([B)V", reinterpret_cast<void *>(sendBuffer)}
, {"sendStatus", "(ILjava/lang/String;)V", reinterpret_cast<void *>(sendStatus)} };
, {"sendStatus", "(ILjava/lang/String;)V", reinterpret_cast<void *>(sendStatus)}
};
env->RegisterNatives(classId, methods, 2);
}
#endif
@ -65,7 +68,7 @@ QPixmap Oscilloscope::requestPixmap(const QString &id, QSize *size, const QSize
}
#ifndef Q_OS_ANDROID
void Oscilloscope::openSerialPort(QString portName, QString baudrate, QString dataBits, QString parity, QString interval)
void Oscilloscope::openSerialPort(QString portName, QString baudrate, QString dataBits, QString parity, QString intervalStr)
{
connect(serial, &QSerialPort::readyRead, this, &Oscilloscope::readData);
serial->setPortName(portName);
@ -74,11 +77,11 @@ void Oscilloscope::openSerialPort(QString portName, QString baudrate, QString da
serial->setParity((QSerialPort::Parity)parity.toUInt());
serial->setStopBits(QSerialPort::StopBits::OneStop);
serial->setFlowControl(QSerialPort::FlowControl::NoFlowControl);
this->interval = interval.toUInt();
interval = intervalStr.toUInt() / 100.0;
if (serial->open(QIODevice::ReadOnly)) {
status = connected;
emit sendStatusConn(status);
QString message("Connected (" + portName + " " + baudrate + "bps " + interval + "μs)");
QString message("Connected (" + portName + " " + baudrate + "bps " + QString::number(interval) + "μs)");
emit sendMessage(message);
} else {
status = disconnected;
@ -96,9 +99,9 @@ void Oscilloscope::openSerialPort(QString portName, QString baudrate, QString da
parity_android = parity.toUInt();
jstring name = env->NewStringUTF(portName.toStdString().c_str());
usbSerial.callMethod<void>
("openConnection"
, "(Landroid/content/Context;Ljava/lang/String;IIII)V"
, QtAndroid::androidContext().object(), name, baudrate.toUInt(), dataBits.toUInt(), 1, parity_android);
("openConnection"
, "(Landroid/content/Context;Ljava/lang/String;IIII)V"
, QtAndroid::androidContext().object(), name, baudrate.toUInt(), dataBits.toUInt(), 1, parity_android);
}
#endif
@ -119,12 +122,34 @@ void Oscilloscope::closeSerialPort()
emit isPausedChanged(false);
}
void Oscilloscope::timeOut()
{
timedOut = true;
isPixmapSent = false;
isDataStart = true;
processData(data);
}
#ifndef Q_OS_ANDROID
void Oscilloscope::readData()
{
QByteArray data = serial->readAll();
if (!isPaused)
processData(data);
if (isRealTime) {
data = serial->readAll();
if (!isPaused) {
processData(data);
}
} else {
if (!isPaused) {
timer->setSingleShot(true);
timer->start(500);
if (timedOut) {
data.clear();
timedOut = false;
}
data.append(serial->readAll());
timedOut = false;
}
}
}
#else
void Oscilloscope::readData(const QByteArray &data)
@ -173,6 +198,10 @@ QStringList Oscilloscope::fillPortsInfo()
QStringList list;
for (const QSerialPortInfo& info : infos) {
list.append(info.portName());
qDebug() << info.description();
qDebug() << info.manufacturer();
qDebug() << info.serialNumber();
}
return list;
}
@ -180,9 +209,9 @@ QStringList Oscilloscope::fillPortsInfo()
QStringList Oscilloscope::fillPortsInfo()
{
QAndroidJniObject drivers = usbSerial.callObjectMethod
("drivers"
, "(Landroid/content/Context;)Ljava/util/List;"
, QtAndroid::androidContext().object());
("drivers"
, "(Landroid/content/Context;)Ljava/util/List;"
, QtAndroid::androidContext().object());
QStringList list;
int size = drivers.callMethod<jint>("size");
for (int i = 0; i < size; i++) {
@ -211,101 +240,129 @@ void Oscilloscope::processData(const QByteArray &data)
quint16 width = pmWidth;
paint->setPen(QPen(QColor(signalColor), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
float xDelta = width * interval / 1000.0 / timeRange;
for (quint16 i = 0; i < data.size(); i++) {
// Find V limits
if ((quint8)data[i] > maxValue) {
maxValue = data[i];
}
if ((quint8)data[i] < minValue) {
minValue = data[i];
}
// Find triggers and signal properties
if ((quint8)data[i] - prevValue > 0) { // rising
deltaRising += (quint8)data[i] - prevValue;
deltaFalling = 0;
}
if ((quint8)data[i] - prevValue < 0) { // falling
deltaFalling += prevValue - (quint8)data[i];
deltaRising = 0;
}
prevValue = data[i];
if (((float)deltaRising) / 0xFF * 5 > triggerValue / 1000.0) {
if ((triggerType == rising || triggerType == none) && triggerCont - tsRising > 2) {
isTriggered = true;
rawFreq = triggerCont - tsRising;
rawDuty = triggerCont - tsFalling;
rawFreqAvg = 0.1 * rawFreq + 0.9 * rawFreqAvg;
rawDutyAvg = 0.1 * rawDuty + 0.9 * rawDutyAvg;
}
deltaRising = 0;
deltaFalling = 0;
tsRising = triggerCont;
}
if (((float)deltaFalling) / 0xFF * 5 > triggerValue / 1000.0) {
if (triggerType == falling && triggerCont - tsFalling > 2) {
isTriggered = true;
rawFreq = triggerCont - tsFalling;
rawDuty = triggerCont - tsRising;
rawFreqAvg = 0.1 * rawFreq + 0.9 * rawFreqAvg;
rawDutyAvg = 0.1 * rawDuty + 0.9 * rawDutyAvg;
}
deltaRising = 0;
deltaFalling = 0;
tsFalling = triggerCont;
}
triggerCont++;
// Capture
if (isCapturing) {
captureBuffer->append(data[i]);
}
// Draw new value
if (isTriggered == true || triggerType == none) {
float newxPos = oldxPos + xDelta;
qint16 newyPos = height + yZeroV - getYVal(data[i]);
// End of pixmap
if (newxPos > width) {
if (triggerType != none) {
isTriggered = false;
deltaRising = 0;
deltaFalling = 0;
}
emit sendPixmap();
static quint16 contX = 0;
if (pendingExport) {
savePixmap(filename);
pendingExport = false;
if (isDataStart) {
oldxPos = 0;
maxValue = 0;
minValue = 0;
drawBackground();
paint->setPen(QPen(QColor(signalColor), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
isDataStart =false;
isTriggered = false;
}
for (quint16 contByte = 0; contByte < data.size(); contByte++) {
for (quint16 contSubByte = 8 / dataBits; contSubByte > 0; contSubByte--) {
quint8 value = (data[contByte] << (contSubByte - 1) * dataBits) & ~(0xFF >> dataBits);
//quint8 value = data[contByte];
// Find V limits
if (value > maxValue) {
maxValue = value;
}
if (value < minValue) {
minValue = value;
}
// Find triggers and signal properties
if (value - prevValue > 0) { // rising
deltaRising += value - prevValue;
deltaFalling = 0;
}
if (value - prevValue < 0) { // falling
deltaFalling += prevValue - value;
deltaRising = 0;
}
prevValue = value;
if (((float)deltaRising) / 0xFF * 5 > triggerValue / 1000.0) {
if ((triggerType == rising || triggerType == none) && triggerCont - tsRising > 2) {
isTriggered = true;
rawFreq = triggerCont - tsRising;
rawDuty = triggerCont - tsFalling;
rawFreqAvg = 0.1 * rawFreq + 0.9 * rawFreqAvg;
rawDutyAvg = 0.1 * rawDuty + 0.9 * rawDutyAvg;
}
if (isCapturing) {
isCapturing = false;
saveCsv(filename);
delete captureBuffer;
deltaRising = 0;
deltaFalling = 0;
tsRising = triggerCont;
}
if (((float)deltaFalling) / 0xFF * 5 > triggerValue / 1000.0) {
if (triggerType == falling && triggerCont - tsFalling > 2) {
isTriggered = true;
rawFreq = triggerCont - tsFalling;
rawDuty = triggerCont - tsRising;
rawFreqAvg = 0.1 * rawFreq + 0.9 * rawFreqAvg;
rawDutyAvg = 0.1 * rawDuty + 0.9 * rawDutyAvg;
}
if (pendingCsv) {
isCapturing = true;
pendingCsv = false;
captureBuffer = new QByteArray(timeRange/interval+1, 0);
}
if (pendingPause) {
pendingPause = false;
isPaused = true;
emit isPausedChanged(true);
return;
}
drawBackground();
paint->setPen(QPen(QColor(signalColor), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
newxPos = 0;
maxValue = 0;
minValue = 0;
deltaRising = 0;
deltaFalling = 0;
tsFalling = triggerCont;
}
triggerCont++;
// Capture
if (isCapturing) {
captureBuffer->append(value);
}
// Draw new value
else {
paint->drawLine(newxPos + width * hAdjust, newyPos + height * vAdjust, oldxPos + width * hAdjust, oldyPos + height * vAdjust);
if (isTriggered == true || triggerType == none) {
float newxPos = contX * xDelta;
contX++;
qint16 newyPos = height + yZeroV - getYVal(value);
// End of pixmap
if (newxPos > width) {
if (triggerType != none) {
isTriggered = false;
deltaRising = 0;
deltaFalling = 0;
}
emit sendPixmap();
if (pendingExport) {
savePixmap(filename);
pendingExport = false;
}
if (isCapturing) {
isCapturing = false;
saveCsv(filename);
delete captureBuffer;
}
if (pendingCsv) {
isCapturing = true;
pendingCsv = false;
captureBuffer = new QByteArray(timeRange/interval+1, 0);
}
if (pendingPause) {
pendingPause = false;
isPaused = true;
emit isPausedChanged(true);
return;
}
if (!isRealTime) {
isPixmapSent = true;
newxPos = 0;
maxValue = 0;
minValue = 0;
contX = 0;
return;
}
drawBackground();
paint->setPen(QPen(QColor(signalColor), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
newxPos = 0;
maxValue = 0;
minValue = 0;
contX = 0;
}
// Draw new value
else {
paint->drawLine(newxPos + width * hAdjust, newyPos + height * vAdjust, oldxPos + width * hAdjust, oldyPos + height * vAdjust);
}
oldxPos = newxPos;
oldyPos = newyPos;
}
oldxPos = newxPos;
oldyPos = newyPos;
}
}
if (!isRealTime && !isPixmapSent)
emit sendPixmap();
}
qint16 Oscilloscope::getYZeroV()
@ -331,8 +388,8 @@ void Oscilloscope::drawBackground()
for (quint8 i = 0; i < 6; i++) { // horizontal lines
paint->drawLine(0, height * i / 6, width, height * i / 6);
}
for (quint8 i = 0; i < 10; i++) { // vertical lines
paint->drawLine(width * i / 10, 0, width * i / 10, height);
for (quint8 i = 0; i < 11; i++) { // vertical lines
paint->drawLine(width * i / 11, 0, width * i / 11, height);
}
QFont font = paint->font();
font.setPixelSize(14 * pixelRatio);
@ -404,8 +461,7 @@ void Oscilloscope::exportCsv(QUrl url)
void Oscilloscope::saveCsv(QString filename)
{
QFile data(filename);
if(data.open(QFile::WriteOnly | QFile::Truncate))
{
if(data.open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream output(&data);
output << "Interval\t" + QString::number(interval) + "\n";
for (quint16 i=0; i < captureBuffer->size(); i++) {
@ -416,11 +472,11 @@ void Oscilloscope::saveCsv(QString filename)
data.close();
}
void Oscilloscope::setIsPaused(const bool value) {
void Oscilloscope::setIsPaused(const bool value)
{
if (value == true)
pendingPause = true;
else
{
else {
isPaused = false;
pendingPause = false;
emit isPausedChanged(false);

Wyświetl plik

@ -16,59 +16,132 @@
#ifndef OSCILLOSCOPE_H
#define OSCILLOSCOPE_H
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QDebug>
#include <QFile>
#include <QPainter>
#include <QQuickImageProvider>
#include <QFile>
#include <QDebug>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QTime>
#include <QTimer>
#ifdef Q_OS_ANDROID
#include <QAndroidJniObject>
#include <QAndroidJniEnvironment>
#include <QAndroidJniObject>
#include <QtAndroid>
#endif
class Oscilloscope : public QObject, public QQuickImageProvider
{
Q_OBJECT
//Q_PROPERTY(bool isPaused READ getIsPaused WRITE setIsPaused NOTIFY isPausedChanged)
// Q_PROPERTY(bool isPaused READ getIsPaused WRITE setIsPaused NOTIFY
// isPausedChanged)
public:
enum TriggerType { none, rising, falling };
enum Status { connected, disconnected, permission_not_granted, error_connecting, error_opening, connection_lost, driver_not_found, permission_requested };
enum Status {
connected,
disconnected,
permission_not_granted,
error_connecting,
error_opening,
connection_lost,
driver_not_found,
permission_requested
};
Q_ENUM(Status)
Q_ENUM(TriggerType)
Oscilloscope(qreal pixelratio);
~Oscilloscope();
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
Q_INVOKABLE void openSerialPort(QString portName, QString baudrate, QString dataBits, QString parity, QString interval);
QPixmap requestPixmap(const QString &id, QSize *size,
const QSize &requestedSize) override;
Q_INVOKABLE void openSerialPort(QString portName, QString baudrate,
QString dataBits, QString parity,
QString interval);
Q_INVOKABLE void closeSerialPort();
Q_INVOKABLE QStringList fillPortsInfo();
Q_INVOKABLE void setBackgroundColor(const QString &color) { backgroundColor = color; drawBackground(); emit sendPixmap(); }
Q_INVOKABLE void setGridColor(const QString &color) { gridColor = color; drawBackground(); emit sendPixmap(); }
Q_INVOKABLE void setSignalColor(const QString &color) { signalColor = color; drawBackground(); emit sendPixmap(); }
Q_INVOKABLE void setTextColor(const QString &color) { textColor = color; drawBackground(); emit sendPixmap(); }
Q_INVOKABLE void setVDiv(const quint16 value) { vDiv = value; voltRange = value * 6 / 1000.0; yZeroV = getYZeroV(); drawBackground(); emit sendPixmap(); }
Q_INVOKABLE void setHDiv(const quint16 value) { hDiv = value; timeRange = value * 11 / 1000.0; drawBackground(); emit sendPixmap(); }
Q_INVOKABLE void setTriggerType(const quint16 value) { triggerType = (TriggerType)value; }
Q_INVOKABLE void setTriggerValue(const quint16 value) { triggerValue = value; }
Q_INVOKABLE void setVAdjust(const qint16 value) { vAdjust = 6/voltRange * value / 100.0; drawBackground(); emit sendPixmap(); }
Q_INVOKABLE void setHAdjust(const qint16 value) { hAdjust = 11/timeRange * value / 100.0 * 0.25; drawBackground(); emit sendPixmap(); }
Q_INVOKABLE void setBackgroundColor(const QString &color)
{
backgroundColor = color;
drawBackground();
emit sendPixmap();
}
Q_INVOKABLE void setGridColor(const QString &color)
{
gridColor = color;
drawBackground();
emit sendPixmap();
}
Q_INVOKABLE void setSignalColor(const QString &color)
{
signalColor = color;
drawBackground();
emit sendPixmap();
}
Q_INVOKABLE void setTextColor(const QString &color)
{
textColor = color;
drawBackground();
emit sendPixmap();
}
Q_INVOKABLE void setVDiv(const quint16 value)
{
vDiv = value;
voltRange = value * 6 / 1000.0;
yZeroV = getYZeroV();
drawBackground();
emit sendPixmap();
}
Q_INVOKABLE void setHDiv(const quint16 value)
{
hDiv = value;
timeRange = value * 11 / 1000.0;
drawBackground();
emit sendPixmap();
}
Q_INVOKABLE void setTriggerType(const quint16 value)
{
triggerType = (TriggerType)value;
}
Q_INVOKABLE void setTriggerValue(const quint16 value)
{
triggerValue = value;
}
Q_INVOKABLE void setVAdjust(const qint16 value)
{
vAdjust = 6 / voltRange * value / 100.0;
drawBackground();
emit sendPixmap();
}
Q_INVOKABLE void setHAdjust(const qint16 value)
{
hAdjust = 11 / timeRange * value / 100.0 * 0.25;
drawBackground();
emit sendPixmap();
}
Q_INVOKABLE void exportImage(QUrl filename);
Q_INVOKABLE void exportCsv(QUrl filename);
Q_INVOKABLE bool getIsPaused() { return isPaused; }
Q_INVOKABLE bool getIsPaused()
{
return isPaused;
}
Q_INVOKABLE void setIsPaused(const bool value);
Q_INVOKABLE QString getVersion() { return APP_VERSION; }
Q_INVOKABLE QString getVersion()
{
return APP_VERSION;
}
#ifdef Q_OS_ANDROID
static Oscilloscope *instance() { return m_instance; }
static Oscilloscope *instance()
{
return m_instance;
}
#endif
signals:
void isPausedChanged(bool isPaused);
void sendPixmap();
void sendStatusConn(Status status);
void sendMessage(QString message, quint16 duration=0);
void sendMessage(QString message, quint16 duration = 0);
#ifdef Q_OS_ANDROID
void receiveBuffer(const QByteArray &buffer);
void receiveStatus(int status, const QString &msg);
@ -76,8 +149,8 @@ signals:
private:
enum Edge { min, max };
quint16 pmHeight = 400; //230;
quint16 pmWidth = 800; //520;
quint16 pmHeight = 400;
quint16 pmWidth = 800;
quint8 maxValue = 0;
quint8 minValue = 0;
quint16 rawFreq = 0;
@ -88,7 +161,7 @@ private:
bool pendingCsv = false;
bool pendingPause = false;
QString filename;
quint16 interval = 26;
float interval = 26;
quint16 vDiv = 1000;
quint16 hDiv = 1000;
float voltRange = 1000 * 6 / 1000.0;
@ -125,9 +198,18 @@ private:
void savePixmap(QString filename);
void saveCsv(QString filename);
quint8 dataBits = 8;
bool isRealTime = true;
bool isPixmapSent = false;
bool isDataStart = false;
QTimer *timer;
QByteArray data;
bool timedOut = false;
public slots:
#ifndef Q_OS_ANDROID
void readData();
void timeOut();
#else
void readData(const QByteArray &data);
#endif