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 # 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> <p align="center"><img src="./images/img1.png" width="600"><br>
<i>Main window</i><br><br></p> <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. 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. Adjust PWM signal with PWM_FREQ and PWM_DUTY. Default is 1000Hz, 50% duty.
Pin OC1B location: Pin OC1B location:
@ -43,6 +43,9 @@ Supported OS:
## Change log: ## Change log:
v0.3
- Minor fixes
[v0.2](https://github.com/dgatf/Oscilloscope/releases/tag/v0.2) [v0.2](https://github.com/dgatf/Oscilloscope/releases/tag/v0.2)
- Upgrade to qml gui - Upgrade to qml gui
- Add csv export - Add csv export

Wyświetl plik

@ -1,31 +1,209 @@
#define serial Serial #define serial Serial
/* PWM signal */ /* PWM signal */
#define PWM_FREQ 1000 // HZ (1000HZ=1ms) #define PWM_FREQ 20000 // HZ (1000HZ=1ms)
#define PWM_DUTY 0.5 // %/100 #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)) #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); serial.write((uint8_t)ADCH);
} }
void setup() { void realtime_4b()
serial.begin(1000000); {
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 void realtime_1b()
Prescaler 16: 1.6M / 16 / 13 = 76923 -> 1 / 76923 = 13 us (this is too fast for some devices) {
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); 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; ADCSRB = 0;
ADCSRA |= _BV(ADSC); 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 /* 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 Adjust PWM signal with PWM_FREQ and PWM_DUTY. Default: PWM 1000Hz, 50% DUTY
Pin OC1B: Pin OC1B:
@ -38,36 +216,25 @@ void setup() {
#else #else
DDRB |= _BV(DDB2); DDRB |= _BV(DDB2);
#endif #endif
DDRB |= _BV(DDB2);
TCCR1A = _BV(WGM11) | _BV(WGM10); TCCR1A = _BV(WGM11) | _BV(WGM10);
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11); // scaler 8 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11); // scaler 8
TCCR1A |= _BV(COM1B1); TCCR1A |= _BV(COM1B1);
// PWM signal
OCR1A = 1000.0 / PWM_FREQ * MS_TO_COMP(8); OCR1A = 1000.0 / PWM_FREQ * MS_TO_COMP(8);
OCR1B = PWM_DUTY * OCR1A; 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() { 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: "5ms/d"; value: 5000 }
ListElement { text: "1ms/d"; value: 1000 } ListElement { text: "1ms/d"; value: 1000 }
ListElement { text: "500μs/d"; value: 500 } 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: "100μs/d"; value: 100 }
ListElement { text: "50μs/d"; value: 50 }
} }
currentIndex: 2 currentIndex: 2
onCurrentValueChanged: oscilloscope.setHDiv(currentValue) onCurrentValueChanged: oscilloscope.setHDiv(currentValue)

Wyświetl plik

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

Wyświetl plik

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