add scope
This commit is contained in:
parent
ffd68b990c
commit
5b32ee9eae
31 changed files with 1912 additions and 0 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -15,3 +15,11 @@
|
||||||
V203/pwm/sin.c
|
V203/pwm/sin.c
|
||||||
V203/gsm/lib/libgsm.a
|
V203/gsm/lib/libgsm.a
|
||||||
V203/usb/cdc/mystrings.inc
|
V203/usb/cdc/mystrings.inc
|
||||||
|
V203/usb/scope/bin/*
|
||||||
|
V203/usb/scope/software/.qmake.stash
|
||||||
|
V203/usb/scope/software/Makefile
|
||||||
|
V203/usb/scope/software/moc/*
|
||||||
|
V203/usb/scope/software/obj/*
|
||||||
|
V203/usb/scope/software/qrc_src.cpp
|
||||||
|
V203/usb/scope/software/ui_mainwindow.h
|
||||||
|
|
||||||
|
|
166
V203/usb/ch32v203/adcscope.cpp
Normal file
166
V203/usb/ch32v203/adcscope.cpp
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#include "system.h"
|
||||||
|
#include "adcscope.h"
|
||||||
|
#include "structures.h"
|
||||||
|
|
||||||
|
static AdcClass * AdcClassInstance = nullptr;
|
||||||
|
enum TRANSFER_SIZES {
|
||||||
|
XFER_BYTE = 0,
|
||||||
|
XFER_HALF,
|
||||||
|
XFER_WORD,
|
||||||
|
};
|
||||||
|
static const unsigned DmaLenTable [] = {
|
||||||
|
DATA_FULL_LEN * ADC_MAXCHANNELS, ADC_MAXCHANNELS * 2,
|
||||||
|
};
|
||||||
|
static constexpr unsigned LSH = 2u, DIVL = 36u, DIVH = 36'000u;
|
||||||
|
static const TimeBaseDescriptor BaseTable [] {
|
||||||
|
{(2u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 2us
|
||||||
|
{(5u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 5us
|
||||||
|
{(10u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 10us
|
||||||
|
{(20u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 20us
|
||||||
|
{(50u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 50us
|
||||||
|
{(100u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 100us
|
||||||
|
{(200u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 200us
|
||||||
|
{(500u << LSH) - 1u, DIVL - 1u, TIME_BASE_TRIGERED}, // 500us
|
||||||
|
|
||||||
|
{(1000u << LSH) - 1u, DIVL - 1u, TIME_BASE_CONTINUOUS}, // 1ms
|
||||||
|
{(2u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 2ms
|
||||||
|
{(5u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 5ms
|
||||||
|
{(10u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 10ms
|
||||||
|
{(20u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 20ms
|
||||||
|
{(50u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 50ms
|
||||||
|
{(100u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 100ms
|
||||||
|
{(200u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 200ms
|
||||||
|
|
||||||
|
{(500u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 500ms
|
||||||
|
{(1000u << LSH) - 1u, DIVH - 1u, TIME_BASE_CONTINUOUS}, // 1s
|
||||||
|
};
|
||||||
|
static inline void EnableClock (void) noexcept {
|
||||||
|
// Enable DMA
|
||||||
|
RCC.AHBPCENR.modify([](RCC_Type::AHBPCENR_DEF & r) -> auto {
|
||||||
|
r.B.SRAMEN = SET;
|
||||||
|
r.B.DMA1EN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
// Enable ADC + GPIOC
|
||||||
|
RCC.APB2PCENR.modify([](RCC_Type::APB2PCENR_DEF & r) -> auto {
|
||||||
|
r.B.ADC1EN = SET;
|
||||||
|
r.B.IOPAEN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
RCC.APB1PCENR.B.TIM3EN = SET; // Enable TIM3
|
||||||
|
RCC.CFGR0.B.ADCPRE = 3u; // PCLK2 divided by 8 as ADC clock (18 MHz, ! pretaktovano 14 MHz max).
|
||||||
|
// PIN PA2 / A2
|
||||||
|
GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto {
|
||||||
|
r.B.MODE2 = 0u;
|
||||||
|
r.B.CNF2 = 0u;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static inline void Timer3Init (const TimeBaseDescriptor & tb) noexcept {
|
||||||
|
TIM3.PSC.R = tb.presc; // 4 MHz Fs
|
||||||
|
TIM3.ATRLR.R = tb.divider;
|
||||||
|
// TRGO update for ADC
|
||||||
|
TIM3.CTLR2.B.MMS = 2u;
|
||||||
|
}
|
||||||
|
static inline void AdcCalibrate (void) noexcept {
|
||||||
|
// RESET
|
||||||
|
RCC.APB2PRSTR.B.ADC1RST = SET;
|
||||||
|
RCC.APB2PRSTR.B.ADC1RST = RESET;
|
||||||
|
// set channels
|
||||||
|
ADC1.RSQR3__CHANNEL.B.SQ1__CHSEL = 2u; // CH2
|
||||||
|
ADC1.RSQR3__CHANNEL.B.SQ2 = 3u; // CH3
|
||||||
|
ADC1.RSQR1.B.L = ADC_MAXCHANNELS - 1U; // 2 regular conversion
|
||||||
|
static constexpr unsigned ts = 0u;
|
||||||
|
ADC1.SAMPTR2_CHARGE2.B.SMP2_TKCG2 = ts;
|
||||||
|
ADC1.SAMPTR2_CHARGE2.B.SMP3_TKCG3 = ts;
|
||||||
|
ADC1.CTLR1.B.SCAN = SET;
|
||||||
|
|
||||||
|
ADC1.CTLR2.B.ADON = SET;
|
||||||
|
ADC1.CTLR2.B.RSTCAL = SET; // Launch the calibration by setting RSTCAL
|
||||||
|
while (ADC1.CTLR2.B.RSTCAL != RESET); // Wait until RSTCAL=0
|
||||||
|
ADC1.CTLR2.B.CAL = SET; // Launch the calibration by setting CAL
|
||||||
|
while (ADC1.CTLR2.B.CAL != RESET); // Wait until CAL=0
|
||||||
|
}
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
static inline void Dma1Ch1Init (const void * ptr, const unsigned n = 0u) noexcept {
|
||||||
|
// Configure the peripheral data register address
|
||||||
|
DMA1.PADDR1.R = reinterpret_cast<size_t> (& ADC1.RDATAR_DR_ACT_DCG);
|
||||||
|
// Configure the memory address
|
||||||
|
DMA1.MADDR1.R = reinterpret_cast<size_t> (ptr);
|
||||||
|
// Configure the number of DMA tranfer to be performs on DMA channel 1
|
||||||
|
DMA1.CNTR1 .R = DmaLenTable [n]; // DATA_FULL_LEN * ADC_MAXCHANNELS;
|
||||||
|
// Configure increment, size, interrupts and circular mode
|
||||||
|
DMA1.CFGR1.modify([] (DMA1_Type::CFGR1_DEF & r) -> auto {
|
||||||
|
r.B.PL = 3u; // highest priority
|
||||||
|
r.B.MEM2MEM = RESET; // periferal -> memory
|
||||||
|
r.B.MINC = SET; // memory increment
|
||||||
|
r.B.MSIZE = XFER_HALF;// 16-bit
|
||||||
|
r.B.PSIZE = XFER_HALF;// 16-bit
|
||||||
|
r.B.HTIE = SET; // INT Enable HALF
|
||||||
|
r.B.TCIE = SET; // INT Enable FULL
|
||||||
|
r.B.CIRC = SET; // Circular MODE
|
||||||
|
// Enable DMA Channel 1
|
||||||
|
r.B.EN = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
static inline void AdcPostInit (void) noexcept {
|
||||||
|
ADC1.CTLR2.modify([](ADC1_Type::CTLR2_DEF & r) -> auto {
|
||||||
|
r.B.DMA = SET;
|
||||||
|
r.B.EXTTRIG = SET;
|
||||||
|
r.B.EXTSEL = 4u; // TRGO event of timer 3
|
||||||
|
r.B.SWSTART = SET;
|
||||||
|
return r.R;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/* *********************************************************************************************/
|
||||||
|
void AdcClass::Init () {
|
||||||
|
AdcClassInstance = this;
|
||||||
|
EnableClock ();
|
||||||
|
Timer3Init (BaseTable [6]);
|
||||||
|
NVIC.EnableIRQ (DMA1_Channel1_IRQn);
|
||||||
|
AdcCalibrate();
|
||||||
|
Dma1Ch1Init (buffer);
|
||||||
|
AdcPostInit ();
|
||||||
|
// start timer
|
||||||
|
TIM3.CTLR1.B.CEN = SET;
|
||||||
|
}
|
||||||
|
// nekonzistentni, ale funkcni
|
||||||
|
void SampleRing::ReloadTimer(const unsigned int n) {
|
||||||
|
const TimeBaseDescriptor & tb = BaseTable [n];
|
||||||
|
TIM3.CTLR1.B.CEN = RESET;
|
||||||
|
TIM3.CNT.R = 0u;
|
||||||
|
TIM3.PSC.R = tb.presc;
|
||||||
|
TIM3.ATRLR.R = tb.divider;
|
||||||
|
TIM3.CTLR1.B.CEN = SET;
|
||||||
|
if (tb.mode != m_mode) {
|
||||||
|
if (!AdcClassInstance) return;
|
||||||
|
const DATA_BLOCK * buffer = AdcClassInstance->setPtrH (tb.mode);
|
||||||
|
DMA1.CFGR1.B.EN = RESET;
|
||||||
|
NVIC.DisableIRQ (DMA1_Channel1_IRQn);
|
||||||
|
Dma1Ch1Init (buffer, tb.mode);
|
||||||
|
// m_head = m_tail = m_lenght = 0u;
|
||||||
|
m_mode = tb.mode;
|
||||||
|
NVIC.EnableIRQ (DMA1_Channel1_IRQn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *********************************************************************************************/
|
||||||
|
|
||||||
|
void AdcClass::drq() {
|
||||||
|
led << false;
|
||||||
|
DMA1_Type::INTFR_DEF state (DMA1.INTFR);
|
||||||
|
DMA1.INTFCR.R = state.R; // clear all
|
||||||
|
if (state.B.HTIF1 != RESET) {
|
||||||
|
ring.write (ptrl);
|
||||||
|
} else if (state.B.TCIF1 != RESET) {
|
||||||
|
ring.write (ptrh);
|
||||||
|
}
|
||||||
|
led << true;
|
||||||
|
}
|
||||||
|
extern "C" {
|
||||||
|
[[gnu::interrupt]] extern void DMA1_Channel1_IRQHandler();
|
||||||
|
}
|
||||||
|
void DMA1_Channel1_IRQHandler( void ) {
|
||||||
|
if (AdcClassInstance) AdcClassInstance->drq();
|
||||||
|
}
|
46
V203/usb/common/adcscope.h
Normal file
46
V203/usb/common/adcscope.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef ADCCLASS_SCOPE_H
|
||||||
|
#define ADCCLASS_SCOPE_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "samplering.h"
|
||||||
|
#include "gpio.h"
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* @brief A/D převodník.
|
||||||
|
* */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class AdcClass
|
||||||
|
* @brief A/D převodník.
|
||||||
|
*
|
||||||
|
* Výhradně pro projekt osciloskopu.
|
||||||
|
* Původně to bylo pro STM32L452, ale v podstatě je to stejné pro CH32V203.
|
||||||
|
* Tedy deklarace třídy, nikoli její definice.
|
||||||
|
* */
|
||||||
|
|
||||||
|
class AdcClass {
|
||||||
|
public:
|
||||||
|
AdcClass(SampleRing & r) : ring(r), led(GPIOA, 1), ptrl (buffer), ptrh (buffer + DATA_HALF_LEN) {
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @brief Inicializace ADC.
|
||||||
|
*
|
||||||
|
* Včetně vstupů.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void Init ();
|
||||||
|
DATA_BLOCK * setPtrH (const int n) {
|
||||||
|
if (n) { ptrh = buffer + 1;
|
||||||
|
} else { ptrh = buffer + DATA_HALF_LEN; }
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
public: // UNUSABLE
|
||||||
|
void drq (); //!< obsluha přerušení, interní metoda, ale musí mít public atribut
|
||||||
|
private:
|
||||||
|
SampleRing & ring;
|
||||||
|
GpioClass led;
|
||||||
|
DATA_BLOCK * ptrl;
|
||||||
|
DATA_BLOCK * ptrh;
|
||||||
|
[[gnu::aligned(4)]]DATA_BLOCK buffer [DATA_FULL_LEN]; //!< data
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ADCCLASS_SCOPE_H
|
52
V203/usb/scope/firmware/Makefile
Normal file
52
V203/usb/scope/firmware/Makefile
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
TARGET?= ch32v203
|
||||||
|
TOOL ?= gcc
|
||||||
|
#TOOL ?= clang
|
||||||
|
|
||||||
|
PRJ = example
|
||||||
|
|
||||||
|
VPATH = . ./$(TARGET) ./common
|
||||||
|
BLD = ./build/
|
||||||
|
DFLAGS = -d
|
||||||
|
LFLAGS = -g
|
||||||
|
LDLIBS =
|
||||||
|
BFLAGS = --strip-unneeded
|
||||||
|
|
||||||
|
CFLAGS = -MMD -Wall -Wno-parentheses -ggdb -fno-exceptions -ffunction-sections -fdata-sections
|
||||||
|
CFLAGS+= -I. -I./$(TARGET) -I./common
|
||||||
|
DEL = rm -f
|
||||||
|
|
||||||
|
# zdrojaky
|
||||||
|
OBJS = main.o hack.o
|
||||||
|
OBJS += usb_desc.o cdc_class.o adcscope.o samplering.o
|
||||||
|
|
||||||
|
include $(TARGET)/$(TOOL).mk
|
||||||
|
BOBJS = $(addprefix $(BLD),$(OBJS))
|
||||||
|
|
||||||
|
all: $(BLD) $(PRJ).elf
|
||||||
|
# ... atd.
|
||||||
|
-include $(BLD)*.d
|
||||||
|
# linker
|
||||||
|
$(PRJ).elf: $(BOBJS)
|
||||||
|
-@echo [LD $(TOOL),$(TARGET)] $@
|
||||||
|
@$(LD) $(LFLAGS) -o $(PRJ).elf $(BOBJS) $(LDLIBS)
|
||||||
|
-@echo "size:"
|
||||||
|
@$(SIZE) $(PRJ).elf
|
||||||
|
-@echo "listing:"
|
||||||
|
$(DUMP) $(DFLAGS) $(PRJ).elf > $(PRJ).lst
|
||||||
|
-@echo "OK."
|
||||||
|
$(COPY) $(BFLAGS) -O binary $(PRJ).elf $(PRJ).bin
|
||||||
|
# preloz co je potreba
|
||||||
|
$(BLD)%.o: %.c
|
||||||
|
-@echo [CC $(TOOL),$(TARGET)] $@
|
||||||
|
@$(CC) -std=gnu99 -c $(CFLAGS) $< -o $@
|
||||||
|
$(BLD)%.o: %.cpp
|
||||||
|
-@echo [CX $(TOOL),$(TARGET)] $@
|
||||||
|
@$(CXX) -std=c++17 -fno-rtti -c $(CFLAGS) $< -o $@
|
||||||
|
$(BLD):
|
||||||
|
mkdir $(BLD)
|
||||||
|
flash: $(PRJ).elf
|
||||||
|
minichlink -w $(PRJ).bin flash -b
|
||||||
|
# vycisti
|
||||||
|
clean:
|
||||||
|
$(DEL) $(BLD)* *.lst *.bin *.elf *.map *~
|
||||||
|
.PHONY: all clean flash run
|
1
V203/usb/scope/firmware/ch32v203
Symbolic link
1
V203/usb/scope/firmware/ch32v203
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../ch32v203/
|
1
V203/usb/scope/firmware/common
Symbolic link
1
V203/usb/scope/firmware/common
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../../common/
|
21
V203/usb/scope/firmware/hack.c
Normal file
21
V203/usb/scope/firmware/hack.c
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
size_t strlen (const char *s) {
|
||||||
|
size_t l = 0;
|
||||||
|
while (*s++) l++;
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
void *memcpy (void *dest, const void *src, size_t n) {
|
||||||
|
const char *s = (const char *) src;
|
||||||
|
char *d = (char *) dest;
|
||||||
|
int i;
|
||||||
|
for (i=0; i<n; i++) d[i] = s[i];
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
void *memset (void *s, int c, size_t n) {
|
||||||
|
char *p = (char *) s;
|
||||||
|
int i;
|
||||||
|
for (i=0; i<n; i++) p[i] = c;
|
||||||
|
return s;
|
||||||
|
}
|
29
V203/usb/scope/firmware/main.cpp
Normal file
29
V203/usb/scope/firmware/main.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include "main.h"
|
||||||
|
/** USB osciloskop.
|
||||||
|
* Původně to byl projekt pro STM32L452, ale i na CH32V203 to celkem funguje.
|
||||||
|
* AD převodník zde je pomalejší, pro 1 kanál snese max 1 Mbps, zde 2 kanály,
|
||||||
|
* tedy 500kbps max, s tím, že doba vzorkování je ta nejmenší, tedy vstupy se
|
||||||
|
* musí krmit z co nejmenší impedance (výstup externího OZ). Dál nejde omezit
|
||||||
|
* počet bitů na 10, musí zůstat 12.
|
||||||
|
* Komunikace po USB CDC je v hexadecimálním formátu - písmenka lze snadno
|
||||||
|
* číst a propustnost celkem vyhovuje - data 2*12 bitů zaberou 6 bytů, celkem
|
||||||
|
* nic by se stejně neušetřilo, binárně by se předávaly stejně 4 byty.
|
||||||
|
* Je zde aplikován trigger, zhruba jako normálního osciloskopu, nastavuje se
|
||||||
|
* povely po USB, stejně jako časová základna. Formát povelů je patrný ze
|
||||||
|
* zdrojáků.
|
||||||
|
* Bylo jen potřeba dopsat kontinuální běh pro časy vzorkování větší než 1ms.
|
||||||
|
* Zobrazování má za úkol aplikace v Qt5 v adresáři software.
|
||||||
|
* */
|
||||||
|
static SampleRing ring;
|
||||||
|
static AdcClass adc (ring);
|
||||||
|
static cdc_class cdc;
|
||||||
|
|
||||||
|
int main () {
|
||||||
|
cdc.init();
|
||||||
|
adc.Init();
|
||||||
|
ring += cdc;
|
||||||
|
for (;;) {
|
||||||
|
ring.pass ();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
8
V203/usb/scope/firmware/main.h
Normal file
8
V203/usb/scope/firmware/main.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef MAIN_H
|
||||||
|
#define MAIN_H
|
||||||
|
|
||||||
|
#include "adcscope.h"
|
||||||
|
#include "cdc_class.h"
|
||||||
|
#include "samplering.h"
|
||||||
|
|
||||||
|
#endif // MAIN_H
|
182
V203/usb/scope/firmware/samplering.cpp
Normal file
182
V203/usb/scope/firmware/samplering.cpp
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
#include "samplering.h"
|
||||||
|
|
||||||
|
static const char * const hexstr = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
uint32_t SampleRing::Up (const char * data, const uint32_t len) {
|
||||||
|
for (unsigned n=0; n<len; n++) {
|
||||||
|
const char c = data [n];
|
||||||
|
switch (c) {
|
||||||
|
case '$':
|
||||||
|
rcvd_counter = 0;
|
||||||
|
rcvd_status = RCVD_DATA;
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
CmdReceived ();
|
||||||
|
rcvd_counter = 0;
|
||||||
|
rcvd_status = RCVD_IDLE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (rcvd_status == RCVD_DATA) {
|
||||||
|
rcvd_buffer [rcvd_counter] = c;
|
||||||
|
rcvd_counter += 1u;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
void SampleRing::CmdReceived() {
|
||||||
|
if (rcvd_counter == 0u) return;
|
||||||
|
unsigned result = 0u;
|
||||||
|
for (unsigned n=0; n<rcvd_counter; n++) {
|
||||||
|
const char c = rcvd_buffer [n];
|
||||||
|
result *= 16;
|
||||||
|
if ((c >= '0') and (c <= '9')) {
|
||||||
|
result += (unsigned) (c - '0');
|
||||||
|
} else if ((c >= 'A') and (c <= 'F')) {
|
||||||
|
result += (unsigned) (c - 'A' + 10);
|
||||||
|
} else if ((c >= 'a') and (c <= 'f')) {
|
||||||
|
result += (unsigned) (c - 'a' + 10);
|
||||||
|
} else {
|
||||||
|
// chyba : nech byt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandPass (result);
|
||||||
|
}
|
||||||
|
void SampleRing::CommandPass(const unsigned int cmd) {
|
||||||
|
RcvdHeader header;
|
||||||
|
header.common = cmd & 0xFFFF;
|
||||||
|
const DESTINATION dest = static_cast<DESTINATION> (header.bits.destinat);
|
||||||
|
switch (dest) {
|
||||||
|
case DEST_CHA:
|
||||||
|
case DEST_CHB:
|
||||||
|
break;
|
||||||
|
case DEST_BASE:
|
||||||
|
ReloadTimer (header.bits.cmd_value);
|
||||||
|
break;
|
||||||
|
case DEST_TRIG: {
|
||||||
|
const TRIGGER_CMD command = static_cast<TRIGGER_CMD> (header.bits.cmd_type);
|
||||||
|
switch (command) {
|
||||||
|
case TRIGGER_CMD_OFSET: m_settings.offset = header.bits.cmd_value; break;
|
||||||
|
case TRIGGER_CMD_VALUE: m_settings.value = header.bits.cmd_value; break;
|
||||||
|
case TRIGGER_CMD_MODE: {
|
||||||
|
TriggerModeUnion new_mode_union;
|
||||||
|
new_mode_union.common = header.bits.cmd_value;
|
||||||
|
const TRIGER_MODE new_mode = static_cast<TRIGER_MODE> (new_mode_union.bits.mode);
|
||||||
|
if (m_settings.mode != new_mode) m_settings.mode = new_mode;
|
||||||
|
const ADC_CHANNELS new_channel = static_cast<ADC_CHANNELS>(new_mode_union.bits.channel);
|
||||||
|
if (m_settings.channel != new_channel) m_settings.channel = new_channel;
|
||||||
|
const bool new_rising = new_mode_union.bits.rissing ? true : false;
|
||||||
|
if (m_settings.rising != new_rising) m_settings.rising = new_rising;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleRing::write(DATA_BLOCK const * data) {
|
||||||
|
if (m_finished) return;
|
||||||
|
unsigned t_head = m_head; // dočasné proměnné kvůli zrychlení
|
||||||
|
unsigned t_lenght = m_lenght; // následujícího cyklu
|
||||||
|
if (m_mode == TIME_BASE_TRIGERED) {
|
||||||
|
for (unsigned n=0u; n<DATA_HALF_LEN; n++) {
|
||||||
|
const DATA_BLOCK & sample = data [n];
|
||||||
|
ring_buffer [t_head].common_data = sample.common_data;
|
||||||
|
t_head += 1u;
|
||||||
|
t_head &= RING_MSK;
|
||||||
|
t_lenght += 1u;
|
||||||
|
const bool compare = m_settings.rising != (sample.channels[m_settings.channel] > m_settings.value);
|
||||||
|
if (compare and m_old_triger and !m_trigered) { // TRIGERED
|
||||||
|
if (t_lenght >= m_settings.offset) {
|
||||||
|
t_lenght = m_settings.offset;
|
||||||
|
m_trigered = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_old_triger = !compare;
|
||||||
|
if (t_lenght >= RING_LEN) {
|
||||||
|
// zastavit odesílání dat, pokud není AUTO a není splněna podmínka trigeru
|
||||||
|
if ((m_settings.mode != TRIGER_MODE_AUTO) and !m_trigered) continue;
|
||||||
|
t_lenght = RING_LEN;
|
||||||
|
m_tail = t_head;
|
||||||
|
m_finished = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const DATA_BLOCK & sample = data [0];
|
||||||
|
ring_buffer [t_head].common_data = sample.common_data;
|
||||||
|
t_head += 1u;
|
||||||
|
t_head &= RING_MSK;
|
||||||
|
t_lenght += 1u;
|
||||||
|
m_finished = true;
|
||||||
|
}
|
||||||
|
m_head = t_head; // vrať zpátky hodnoty
|
||||||
|
m_lenght = t_lenght;
|
||||||
|
}
|
||||||
|
bool SampleRing::read(DATA_BLOCK & sample) {
|
||||||
|
if (!m_finished) return false;
|
||||||
|
if (!m_lenght) {
|
||||||
|
m_head = m_tail = m_lenght = 0u;
|
||||||
|
m_trigered = false;
|
||||||
|
m_finished = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sample = ring_buffer [m_tail];
|
||||||
|
m_tail += 1u;
|
||||||
|
m_tail &= RING_MSK;
|
||||||
|
m_lenght -= 1u;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
uint32_t SampleRing::BlockSend (const char * buf, const uint32_t len) {
|
||||||
|
uint32_t n, ofs = 0, req = len;
|
||||||
|
for (;;) {
|
||||||
|
// spodní vrstva může vrátit i nulu, pokud je FIFO plné
|
||||||
|
n = BaseLayer::Down (buf + ofs, req);
|
||||||
|
ofs += n; // Posuneme ukazatel
|
||||||
|
req -= n; // Zmenšíme další požadavek
|
||||||
|
if (!req) break;
|
||||||
|
}
|
||||||
|
return ofs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SampleRing::pass() {
|
||||||
|
if (!m_finished) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SendPrefix();
|
||||||
|
DATA_BLOCK data;
|
||||||
|
while (read(data)) {
|
||||||
|
SendData (data);
|
||||||
|
}
|
||||||
|
BlockSend("\r\n", 2);
|
||||||
|
}
|
||||||
|
static int to_str (char * buffer, const uint16_t data, const int len = 3) {
|
||||||
|
unsigned val = data;
|
||||||
|
for (int i=len-1; i>=0; --i) {
|
||||||
|
buffer [i] = hexstr [val & 0xF];
|
||||||
|
val >>= 4;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
uint32_t SampleRing::SendPrefix() {
|
||||||
|
const int buflen = 8;
|
||||||
|
char buffer [buflen];
|
||||||
|
int n = 0;
|
||||||
|
buffer [n++] = '$';
|
||||||
|
SendHeader sh;
|
||||||
|
sh.bits.trig_flg = m_trigered ? 1 : 0;
|
||||||
|
sh.bits.pack_len = m_lenght;
|
||||||
|
n += to_str (buffer + n, sh.common, 4);
|
||||||
|
buffer [n++] = '#';
|
||||||
|
return BlockSend (buffer, n);
|
||||||
|
}
|
||||||
|
uint32_t SampleRing::SendData (const DATA_BLOCK & data) {
|
||||||
|
const int buflen = 8;
|
||||||
|
char buffer [buflen];
|
||||||
|
int n = 0;
|
||||||
|
n += to_str (buffer + n, data.channels[0]);
|
||||||
|
n += to_str (buffer + n, data.channels[1]);
|
||||||
|
return BlockSend (buffer, n);
|
||||||
|
}
|
||||||
|
|
50
V203/usb/scope/firmware/samplering.h
Normal file
50
V203/usb/scope/firmware/samplering.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef SAMPLERING_H
|
||||||
|
#define SAMPLERING_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "structures.h"
|
||||||
|
#include "baselayer.h"
|
||||||
|
|
||||||
|
static constexpr unsigned RING_BIT = 10;
|
||||||
|
static constexpr unsigned RING_LEN = 1u << RING_BIT;
|
||||||
|
static constexpr unsigned RING_MSK = RING_LEN - 1u;
|
||||||
|
|
||||||
|
static constexpr unsigned DATA_HALF_LEN = 1024u;
|
||||||
|
static constexpr unsigned DATA_FULL_LEN = DATA_HALF_LEN * 2u;
|
||||||
|
|
||||||
|
static constexpr unsigned RCVD_BUFLEN = 16;
|
||||||
|
enum RCVD_STATUS {
|
||||||
|
RCVD_IDLE = 0,
|
||||||
|
RCVD_DATA,
|
||||||
|
};
|
||||||
|
|
||||||
|
class SampleRing : public BaseLayer {
|
||||||
|
[[gnu::aligned(4)]]DATA_BLOCK ring_buffer [RING_LEN];
|
||||||
|
TrigerSettings m_settings;
|
||||||
|
volatile unsigned m_head, m_tail;
|
||||||
|
volatile unsigned m_lenght;
|
||||||
|
bool m_old_triger;
|
||||||
|
bool m_trigered;
|
||||||
|
volatile bool m_finished;
|
||||||
|
TIME_BASE_MODE m_mode;
|
||||||
|
|
||||||
|
[[gnu::aligned(4)]]char rcvd_buffer [RCVD_BUFLEN];
|
||||||
|
unsigned rcvd_counter;
|
||||||
|
RCVD_STATUS rcvd_status;
|
||||||
|
public:
|
||||||
|
explicit SampleRing () noexcept : BaseLayer(), m_settings(), m_head(0), m_tail(0), m_lenght(0),
|
||||||
|
m_old_triger(false), m_trigered(false), m_finished(false), m_mode (TIME_BASE_TRIGERED),
|
||||||
|
rcvd_counter(0u), rcvd_status (RCVD_IDLE) {};
|
||||||
|
uint32_t Up (const char * data, const uint32_t len) override;
|
||||||
|
void write (DATA_BLOCK const * data);
|
||||||
|
void pass ();
|
||||||
|
protected:
|
||||||
|
uint32_t BlockSend (const char * buf, const uint32_t len);
|
||||||
|
uint32_t SendPrefix ();
|
||||||
|
uint32_t SendData (const DATA_BLOCK & data);
|
||||||
|
bool read (DATA_BLOCK & sample);
|
||||||
|
void CmdReceived ();
|
||||||
|
void CommandPass (const unsigned cmd);
|
||||||
|
void ReloadTimer (const unsigned n);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SAMPLERING_H
|
88
V203/usb/scope/firmware/structures.h
Normal file
88
V203/usb/scope/firmware/structures.h
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
#ifndef STRUCTURES_DEFINE_H
|
||||||
|
#define STRUCTURES_DEFINE_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum ADC_CHANNELS : uint16_t {
|
||||||
|
V1_VSENSE = 0,
|
||||||
|
V2_VSENSE,
|
||||||
|
|
||||||
|
ADC_MAXCHANNELS, // interní konstanta - počet kanálů
|
||||||
|
};
|
||||||
|
typedef uint16_t SAMPLE;
|
||||||
|
union DATA_BLOCK {
|
||||||
|
SAMPLE channels [ADC_MAXCHANNELS];
|
||||||
|
uint32_t common_data;
|
||||||
|
};
|
||||||
|
enum TRIGER_MODE : uint16_t {
|
||||||
|
TRIGER_MODE_AUTO = 0,
|
||||||
|
TRIGER_MODE_NORMAL,
|
||||||
|
TRIGER_MODE_SINGLE
|
||||||
|
};
|
||||||
|
struct TrigerSettings {
|
||||||
|
uint16_t value;
|
||||||
|
uint16_t offset;
|
||||||
|
TRIGER_MODE mode;
|
||||||
|
ADC_CHANNELS channel;
|
||||||
|
bool rising;
|
||||||
|
explicit TrigerSettings () noexcept : value(0x80u), offset(100u), mode(TRIGER_MODE_AUTO), channel(V1_VSENSE), rising(false) {}
|
||||||
|
};
|
||||||
|
static_assert (sizeof(TrigerSettings) == 10, "TrigerSettings error");
|
||||||
|
union SendHeader {
|
||||||
|
struct s_bits {
|
||||||
|
uint16_t pack_len : 15;
|
||||||
|
uint16_t trig_flg : 1;
|
||||||
|
} bits;
|
||||||
|
uint16_t common;
|
||||||
|
};
|
||||||
|
static_assert (sizeof(SendHeader) == 2, "SendHeader error");
|
||||||
|
enum DESTINATION {
|
||||||
|
DEST_CHA = 0,
|
||||||
|
DEST_CHB,
|
||||||
|
DEST_TRIG,
|
||||||
|
DEST_BASE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TRIGGER_CMD {
|
||||||
|
TRIGGER_CMD_MODE = 0,
|
||||||
|
TRIGGER_CMD_VALUE,
|
||||||
|
TRIGGER_CMD_OFSET,
|
||||||
|
};
|
||||||
|
union TriggerModeUnion {
|
||||||
|
struct s_bits {
|
||||||
|
uint16_t mode : 2;
|
||||||
|
uint16_t channel : 1;
|
||||||
|
uint16_t rissing : 1;
|
||||||
|
uint16_t unused : 12;
|
||||||
|
} bits;
|
||||||
|
uint16_t common;
|
||||||
|
};
|
||||||
|
static_assert (sizeof(TriggerModeUnion) == 2, "TriggerModeUnion error");
|
||||||
|
|
||||||
|
union RcvdHeader {
|
||||||
|
struct s_bits {
|
||||||
|
uint16_t cmd_value : 12;
|
||||||
|
uint16_t cmd_type : 2;
|
||||||
|
uint16_t destinat : 2;
|
||||||
|
} bits;
|
||||||
|
uint16_t common;
|
||||||
|
};
|
||||||
|
static_assert (sizeof(RcvdHeader) == 2, "RcvdHeader error");
|
||||||
|
|
||||||
|
enum MOVE_ITEMS {
|
||||||
|
MOVE_VALUE = 0,
|
||||||
|
MOVE_OFSET,
|
||||||
|
MOVE_MARKERA,
|
||||||
|
MOVE_MARKERB,
|
||||||
|
TIME_ZOOM,
|
||||||
|
};
|
||||||
|
enum TIME_BASE_MODE {
|
||||||
|
TIME_BASE_TRIGERED = 0,
|
||||||
|
TIME_BASE_CONTINUOUS,
|
||||||
|
};
|
||||||
|
struct TimeBaseDescriptor {
|
||||||
|
uint16_t divider;
|
||||||
|
uint16_t presc;
|
||||||
|
TIME_BASE_MODE mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // STRUCTURES_DEFINE_H
|
83
V203/usb/scope/firmware/usb_desc.cpp
Normal file
83
V203/usb/scope/firmware/usb_desc.cpp
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/********************************** (C) COPYRIGHT *******************************
|
||||||
|
* File Name : usb_desc.c
|
||||||
|
* Author : WCH
|
||||||
|
* Version : V1.0.0
|
||||||
|
* Date : 2022/08/20
|
||||||
|
* Description : usb device descriptor,configuration descriptor,
|
||||||
|
* string descriptors and other descriptors.
|
||||||
|
*********************************************************************************
|
||||||
|
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||||
|
* Attention: This software (modified or not) and binary are used for
|
||||||
|
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include "usb_desc.h"
|
||||||
|
|
||||||
|
/* Device Descriptor */
|
||||||
|
const uint8_t MyDevDescr[] =
|
||||||
|
{
|
||||||
|
0x12, // bLength
|
||||||
|
0x01, // bDescriptorType (Device)
|
||||||
|
0x10, 0x01, // bcdUSB 1.10
|
||||||
|
0x02, // bDeviceClass
|
||||||
|
0x00, // bDeviceSubClass
|
||||||
|
0x00, // bDeviceProtocol
|
||||||
|
DEF_USBD_UEP0_SIZE, // bMaxPacketSize0 64
|
||||||
|
(uint8_t)DEF_USB_VID, (uint8_t)(DEF_USB_VID >> 8), // idVendor 0x1A86
|
||||||
|
(uint8_t)DEF_USB_PID, (uint8_t)(DEF_USB_PID >> 8), // idProduct 0x5537
|
||||||
|
DEF_IC_PRG_VER, 0x00, // bcdDevice 0.01
|
||||||
|
0x01, // iManufacturer (String Index)
|
||||||
|
0x02, // iProduct (String Index)
|
||||||
|
0x03, // iSerialNumber (String Index)
|
||||||
|
0x01, // bNumConfigurations 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Configuration Descriptor */
|
||||||
|
const uint8_t MyCfgDescr[] =
|
||||||
|
{
|
||||||
|
/* Configure descriptor */
|
||||||
|
0x09, 0x02, 0x43, 0x00, 0x02, 0x01, 0x00, 0x80, 0x32,
|
||||||
|
|
||||||
|
/* Interface 0 (CDC) descriptor */
|
||||||
|
0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x01, 0x00,
|
||||||
|
|
||||||
|
/* Functional Descriptors */
|
||||||
|
0x05, 0x24, 0x00, 0x10, 0x01,
|
||||||
|
|
||||||
|
/* Length/management descriptor (data class interface 1) */
|
||||||
|
0x05, 0x24, 0x01, 0x00, 0x01,
|
||||||
|
0x04, 0x24, 0x02, 0x02,
|
||||||
|
0x05, 0x24, 0x06, 0x00, 0x01,
|
||||||
|
|
||||||
|
/* Interrupt upload endpoint descriptor */
|
||||||
|
0x07, 0x05, 0x81, 0x03, (uint8_t)DEF_USBD_ENDP1_SIZE, (uint8_t)( DEF_USBD_ENDP1_SIZE >> 8 ), 0x01,
|
||||||
|
|
||||||
|
/* Interface 1 (data interface) descriptor */
|
||||||
|
0x09, 0x04, 0x01, 0x00, 0x02, 0x0A, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
|
/* Endpoint descriptor */
|
||||||
|
0x07, 0x05, 0x02, 0x02, (uint8_t)DEF_USBD_ENDP2_SIZE, (uint8_t)( DEF_USBD_ENDP2_SIZE >> 8 ), 0x00,
|
||||||
|
|
||||||
|
/* Endpoint descriptor */
|
||||||
|
0x07, 0x05, 0x83, 0x02, (uint8_t)DEF_USBD_ENDP3_SIZE, (uint8_t)( DEF_USBD_ENDP3_SIZE >> 8 ), 0x00,
|
||||||
|
};
|
||||||
|
#define DEF_STRDESC(p,n) w_text<(sizeof(p)>>1)>n={sizeof(n)-2u,3u,{p}}
|
||||||
|
template<const unsigned N> struct w_text {
|
||||||
|
uint8_t len, typ;
|
||||||
|
const char16_t str [N];
|
||||||
|
};
|
||||||
|
static const DEF_STRDESC((u"Kizarm Labs."), str_1);
|
||||||
|
static const DEF_STRDESC((u"USB Osciloscope"),str_2);
|
||||||
|
static const DEF_STRDESC((u"00001"), str_3);
|
||||||
|
/* Language Descriptor */
|
||||||
|
static const uint8_t LangDescr[] = {
|
||||||
|
0x04, 0x03, 0x09, 0x04
|
||||||
|
};
|
||||||
|
const uint8_t * StringDescArray [DEF_MAX_STRINGS] = {
|
||||||
|
LangDescr,
|
||||||
|
reinterpret_cast<const uint8_t*> (&str_1),
|
||||||
|
reinterpret_cast<const uint8_t*> (&str_2),
|
||||||
|
reinterpret_cast<const uint8_t*> (&str_3),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
66
V203/usb/scope/firmware/usb_desc.h
Normal file
66
V203/usb/scope/firmware/usb_desc.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/********************************** (C) COPYRIGHT *******************************
|
||||||
|
* File Name : usb_desc.h
|
||||||
|
* Author : WCH
|
||||||
|
* Version : V1.0.0
|
||||||
|
* Date : 2022/08/20
|
||||||
|
* Description : header file of usb_desc.c
|
||||||
|
*********************************************************************************
|
||||||
|
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
|
||||||
|
* Attention: This software (modified or not) and binary are used for
|
||||||
|
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef USER_USB_DESC_H_
|
||||||
|
#define USER_USB_DESC_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* global define */
|
||||||
|
/* file version */
|
||||||
|
#define DEF_FILE_VERSION 0x01
|
||||||
|
/* usb device info define */
|
||||||
|
#define DEF_USB_VID 0x1A86
|
||||||
|
#define DEF_USB_PID 0xFE0C
|
||||||
|
/* USB device descriptor, device serial number(bcdDevice) */
|
||||||
|
#define DEF_IC_PRG_VER DEF_FILE_VERSION
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* usb device endpoint size define */
|
||||||
|
#define DEF_USBD_UEP0_SIZE 64 /* usb hs/fs device end-point 0 size */
|
||||||
|
/* FS */
|
||||||
|
#define DEF_USBD_FS_PACK_SIZE 64 /* usb fs device max bluk/int pack size */
|
||||||
|
#define DEF_USBD_FS_ISO_PACK_SIZE 1023 /* usb fs device max iso pack size */
|
||||||
|
/* LS */
|
||||||
|
#define DEF_USBD_LS_UEP0_SIZE 8 /* usb ls device end-point 0 size */
|
||||||
|
#define DEF_USBD_LS_PACK_SIZE 64 /* usb ls device max int pack size */
|
||||||
|
|
||||||
|
/* Pack size */
|
||||||
|
#define DEF_USBD_ENDP1_SIZE DEF_USBD_FS_PACK_SIZE
|
||||||
|
#define DEF_USBD_ENDP2_SIZE DEF_USBD_FS_PACK_SIZE
|
||||||
|
#define DEF_USBD_ENDP3_SIZE DEF_USBD_FS_PACK_SIZE
|
||||||
|
#define DEF_USBD_ENDP4_SIZE DEF_USBD_FS_PACK_SIZE
|
||||||
|
#define DEF_USBD_ENDP5_SIZE DEF_USBD_FS_PACK_SIZE
|
||||||
|
#define DEF_USBD_ENDP6_SIZE DEF_USBD_FS_PACK_SIZE
|
||||||
|
#define DEF_USBD_ENDP7_SIZE DEF_USBD_FS_PACK_SIZE
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* usb device Descriptor length, length of usb descriptors, if one descriptor not
|
||||||
|
* exists , set the length to 0 */
|
||||||
|
#define DEF_USBD_DEVICE_DESC_LEN ((uint8_t)MyDevDescr[0])
|
||||||
|
#define DEF_USBD_CONFIG_DESC_LEN ((uint16_t)MyCfgDescr[2] + (uint16_t)(MyCfgDescr[3] << 8))
|
||||||
|
#define DEF_USBD_REPORT_DESC_LEN 0
|
||||||
|
|
||||||
|
#define DEF_MAX_STRINGS (4)
|
||||||
|
/******************************************************************************/
|
||||||
|
/* external variables */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
extern const uint8_t MyDevDescr[ ];
|
||||||
|
extern const uint8_t MyCfgDescr[ ];
|
||||||
|
extern const uint8_t * StringDescArray [DEF_MAX_STRINGS];
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif // __cplusplus
|
||||||
|
#endif /* USER_USB_DESC_H_ */
|
177
V203/usb/scope/software/datasource.cpp
Normal file
177
V203/usb/scope/software/datasource.cpp
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
#include "datasource.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
|
static constexpr unsigned DATASIZE = 0x2000;
|
||||||
|
|
||||||
|
DataSource::DataSource(QObject * p) : QObject (p),
|
||||||
|
usart (QString("/dev/serial/by-id/usb-Kizarm_Labs._USB_Osciloscope_00001-if00")),
|
||||||
|
trigerSettings () {
|
||||||
|
in_buffer = new char [DATASIZE];
|
||||||
|
packet_buf = new char [DATASIZE];
|
||||||
|
packet_cnt = 0;
|
||||||
|
state = StateIdle;
|
||||||
|
catching = true;
|
||||||
|
|
||||||
|
connect (&usart, SIGNAL (readyRead()), this, SLOT (read_data()));
|
||||||
|
usart.open (QIODevice::ReadWrite);
|
||||||
|
}
|
||||||
|
DataSource::~DataSource() {
|
||||||
|
usart.close();
|
||||||
|
delete [] in_buffer;
|
||||||
|
delete [] packet_buf;
|
||||||
|
}
|
||||||
|
void DataSource::Start() {
|
||||||
|
catching = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataSource::read_data() {
|
||||||
|
const long numRead = usart.read(in_buffer, DATASIZE);
|
||||||
|
if (numRead == 0) return;
|
||||||
|
// qDebug ("readen = %ld", numRead);
|
||||||
|
parse_input (in_buffer, numRead);
|
||||||
|
}
|
||||||
|
void DataSource::parse_input(const char * data, const long len) {
|
||||||
|
for (long i=0; i<len; i++) {
|
||||||
|
const char c = data [i];
|
||||||
|
switch (c) {
|
||||||
|
case '$':
|
||||||
|
state = StateHeader;
|
||||||
|
packet_cnt = 0;
|
||||||
|
break;
|
||||||
|
case '#':
|
||||||
|
parse_header();
|
||||||
|
state = StateData;
|
||||||
|
packet_cnt = 0;
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
case '\n':
|
||||||
|
parse_packet();
|
||||||
|
state = StateIdle;
|
||||||
|
packet_cnt = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
packet_buf [packet_cnt] = c;
|
||||||
|
packet_cnt += 1;
|
||||||
|
if (packet_cnt >= (int) DATASIZE) {
|
||||||
|
packet_cnt = 0;
|
||||||
|
qDebug ("Buffer overflow");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DataSource::parse_header() {
|
||||||
|
if (packet_cnt != 4) return;
|
||||||
|
packet_buf [4] = '\0';
|
||||||
|
QString h (packet_buf);
|
||||||
|
bool ok = false;
|
||||||
|
const unsigned hdr = h.toUInt(&ok, 16);
|
||||||
|
if (!ok) return;
|
||||||
|
header.common = hdr;
|
||||||
|
//qDebug ("header:%04X", hdr);
|
||||||
|
if (header.bits.trig_flg) {
|
||||||
|
emit PaketTriggered ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DataSource::parse_packet() {
|
||||||
|
QVector<int> ChA, ChB;
|
||||||
|
if (state != StateData) return;
|
||||||
|
bool ok = false;
|
||||||
|
int k=0;
|
||||||
|
for (int n=0; n<packet_cnt; n+=3) {
|
||||||
|
char buf [4];
|
||||||
|
memcpy (buf, packet_buf+n, 3);
|
||||||
|
buf[3] = '\0';
|
||||||
|
QString s (buf);
|
||||||
|
const unsigned sample = s.toUInt(&ok, 16);
|
||||||
|
if (ok) {
|
||||||
|
if (k & 1) {
|
||||||
|
ChB.push_back (sample);
|
||||||
|
} else {
|
||||||
|
ChA.push_back (sample);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
k += 1;
|
||||||
|
}
|
||||||
|
bool sok = true;
|
||||||
|
if (ChA.size() != (int) header.bits.pack_len) sok = false;
|
||||||
|
if (ChB.size() != (int) header.bits.pack_len) sok = false;
|
||||||
|
if (sok) {
|
||||||
|
if (trigerSettings.mode == TRIGER_MODE_SINGLE) {
|
||||||
|
if (catching) {
|
||||||
|
catching = false;
|
||||||
|
emit Channels_received (ChA, ChB);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emit Channels_received (ChA, ChB);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug ("packet error: ChA=%d, ChB=%d, size=%d", ChA.size(), ChB.size(), header.bits.pack_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DataSource::SendTrigerMode(int n) {
|
||||||
|
trigerSettings.mode = static_cast<TRIGER_MODE> (n);
|
||||||
|
send_trig_mode();
|
||||||
|
}
|
||||||
|
void DataSource::SendTrigerEdge(int n) {
|
||||||
|
trigerSettings.rising = n ? true : false;
|
||||||
|
send_trig_mode();
|
||||||
|
}
|
||||||
|
void DataSource::SendTrigerChan(int n) {
|
||||||
|
trigerSettings.channel = static_cast<ADC_CHANNELS> (n);
|
||||||
|
send_trig_mode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataSource::send_trig_mode () {
|
||||||
|
RcvdHeader hdr;
|
||||||
|
hdr.common = 0u;
|
||||||
|
hdr.bits.destinat = DEST_TRIG;
|
||||||
|
hdr.bits.cmd_type = TRIGGER_CMD_MODE;
|
||||||
|
TriggerModeUnion tmu;
|
||||||
|
tmu.common = 0u;
|
||||||
|
tmu.bits.mode = trigerSettings.mode;
|
||||||
|
tmu.bits.channel = trigerSettings.channel;
|
||||||
|
tmu.bits.rissing = trigerSettings.rising ? 1u : 0u;
|
||||||
|
hdr.bits.cmd_value = tmu.common;
|
||||||
|
|
||||||
|
const unsigned len = 64;
|
||||||
|
char buffer [len];
|
||||||
|
int r = snprintf(buffer, len, "$%04X\r\n", (int) hdr.common);
|
||||||
|
buffer [r] = '\0';
|
||||||
|
usart.write (buffer, r);
|
||||||
|
qDebug ("%d:%s", r, strip_eol(buffer));
|
||||||
|
}
|
||||||
|
void DataSource::SettingChanged(int n) {
|
||||||
|
const MOVE_ITEMS items = static_cast<MOVE_ITEMS>(n);
|
||||||
|
RcvdHeader hdr;
|
||||||
|
hdr.common = 0u;
|
||||||
|
hdr.bits.destinat = DEST_TRIG;
|
||||||
|
switch (items) {
|
||||||
|
case MOVE_VALUE: hdr.bits.cmd_type = TRIGGER_CMD_VALUE; hdr.bits.cmd_value = trigerSettings.value; break;
|
||||||
|
case MOVE_OFSET: hdr.bits.cmd_type = TRIGGER_CMD_OFSET; hdr.bits.cmd_value = trigerSettings.offset; break;
|
||||||
|
default : break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned len = 64;
|
||||||
|
char buffer [len];
|
||||||
|
int r = snprintf(buffer, len, "$%04X\r\n", (int) hdr.common);
|
||||||
|
buffer [r] = '\0';
|
||||||
|
usart.write (buffer, r);
|
||||||
|
// qDebug ("%d::%d:%s", n, r, strip_eol(buffer));
|
||||||
|
}
|
||||||
|
void DataSource::SendBaseRange (int n) {
|
||||||
|
RcvdHeader hdr;
|
||||||
|
hdr.common = 0u;
|
||||||
|
hdr.bits.destinat = DEST_BASE;
|
||||||
|
hdr.bits.cmd_value = n;
|
||||||
|
const unsigned len = 64;
|
||||||
|
char buffer [len];
|
||||||
|
int r = snprintf(buffer, len, "$%04X\r\n", (int) hdr.common);
|
||||||
|
buffer [r] = '\0';
|
||||||
|
usart.write (buffer, r);
|
||||||
|
qDebug ("%d:%s", r, strip_eol(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
52
V203/usb/scope/software/datasource.h
Normal file
52
V203/usb/scope/software/datasource.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#ifndef DATASOURCE_H
|
||||||
|
#define DATASOURCE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QSerialPort>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QPoint>
|
||||||
|
#include "structures.h"
|
||||||
|
|
||||||
|
enum ParserState {
|
||||||
|
StateIdle = 0,
|
||||||
|
StateHeader,
|
||||||
|
StateData,
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
class DataSource : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
QSerialPort usart;
|
||||||
|
TrigerSettings trigerSettings;
|
||||||
|
char * in_buffer;
|
||||||
|
ParserState state;
|
||||||
|
char * packet_buf;
|
||||||
|
int packet_cnt;
|
||||||
|
SendHeader header;
|
||||||
|
bool catching;
|
||||||
|
public:
|
||||||
|
explicit DataSource (QObject * p = nullptr);
|
||||||
|
virtual ~DataSource ();
|
||||||
|
TrigerSettings * getTrigger () {
|
||||||
|
return & trigerSettings;
|
||||||
|
}
|
||||||
|
void SendTrigerMode (int n);
|
||||||
|
void SendTrigerEdge (int n);
|
||||||
|
void SendTrigerChan (int n);
|
||||||
|
void SendBaseRange (int n);
|
||||||
|
void Start ();
|
||||||
|
public slots:
|
||||||
|
void read_data ();
|
||||||
|
void SettingChanged (int n);
|
||||||
|
signals:
|
||||||
|
void Channels_received(QVector<int>, QVector<int>);
|
||||||
|
void PaketTriggered ();
|
||||||
|
protected:
|
||||||
|
void parse_input (const char * data, const long len);
|
||||||
|
void parse_packet ();
|
||||||
|
void parse_header ();
|
||||||
|
protected:
|
||||||
|
void send_trig_mode ();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DATASOURCE_H
|
277
V203/usb/scope/software/displaywidget.cpp
Normal file
277
V203/usb/scope/software/displaywidget.cpp
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QWheelEvent>
|
||||||
|
#include <QSettings>
|
||||||
|
#include <math.h>
|
||||||
|
#include "displaywidget.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
|
static const double TimeBaseSteps [] = {
|
||||||
|
2.0e-6, 5.0e-6, 1.0e-5, 2.0e-5, 5.0e-5, 1.0e-4, 2.0e-4, 5.0e-4,
|
||||||
|
1.0e-3, 2.0e-3, 5.0e-3, 1.0e-2, 2.0e-2, 5.0e-2, 1.0e-1, 2.0e-1,
|
||||||
|
|
||||||
|
5.0e-1, 1.0,
|
||||||
|
};
|
||||||
|
static const double ChannelsSteps [] = {
|
||||||
|
1.0, 2.0, 5.0,
|
||||||
|
};
|
||||||
|
static constexpr double REF_Y = 3.3; // maximum napětí převodníku
|
||||||
|
static constexpr double MAX_Y = double (1 << 12); // 12. bit rozlišení - 4096 steps
|
||||||
|
static constexpr double STEP_Y = REF_Y / MAX_Y; // jeden krok ve Voltech
|
||||||
|
|
||||||
|
DisplayWidget::DisplayWidget(QWidget * p) : QWidget(p), ACopy(), BCopy(), m_forward(), m_inverse(), background(), m_ts(nullptr),
|
||||||
|
ChA (1024), ChB(1024), m_items (MOVE_VALUE), m_timeBase(6), m_ChBase(0), m_timeCount(0u) {
|
||||||
|
x_lenght = 1024;
|
||||||
|
m_time.a = 200.0;
|
||||||
|
m_time.b = 300.0;
|
||||||
|
m_volt.a = 1.0 / STEP_Y;
|
||||||
|
m_volt.b = 2.0 / STEP_Y;
|
||||||
|
marker_type = MARKER_TIME;
|
||||||
|
int n = 0;
|
||||||
|
for (QPointF & e : ChA) { const QPointF p (n++, 0); e = p; }
|
||||||
|
n = 0;
|
||||||
|
for (QPointF & e : ChB) { const QPointF p (n++, 0); e = p; }
|
||||||
|
}
|
||||||
|
DisplayWidget::~DisplayWidget() {
|
||||||
|
}
|
||||||
|
void DisplayWidget::MarkerChanged (bool b) {
|
||||||
|
// qDebug ("Marker : %s", b ? "Time" : "Volt"); // OK
|
||||||
|
if (b) marker_type = MARKER_TIME;
|
||||||
|
else marker_type = MARKER_VOLT;
|
||||||
|
drawBackground();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayWidget::TriggerValues(int n) {
|
||||||
|
m_items = static_cast<MOVE_ITEMS>(n);
|
||||||
|
}
|
||||||
|
static constexpr double FMULT = 1.189207115002721;
|
||||||
|
static constexpr double IMULT = 1.0 / FMULT;
|
||||||
|
void DisplayWidget::wheelEvent(QWheelEvent * event) {
|
||||||
|
if (m_ts == nullptr) return;
|
||||||
|
const QPoint d = event->angleDelta();
|
||||||
|
const int increment = d.y() > 0 ? +1 : -1;
|
||||||
|
switch (m_items) {
|
||||||
|
case MOVE_VALUE: {
|
||||||
|
m_ts->value += increment * 4;
|
||||||
|
emit SettingsChanged (m_items);
|
||||||
|
} break;
|
||||||
|
case MOVE_OFSET: {
|
||||||
|
m_ts->offset += increment;
|
||||||
|
emit SettingsChanged (m_items);
|
||||||
|
} break;
|
||||||
|
case MOVE_MARKERA: {
|
||||||
|
if (marker_type == MARKER_TIME) m_time.a += increment;
|
||||||
|
else m_volt.a += increment;
|
||||||
|
} break;
|
||||||
|
case MOVE_MARKERB: {
|
||||||
|
if (marker_type == MARKER_TIME) m_time.b += increment;
|
||||||
|
else m_volt.b += increment;
|
||||||
|
} break;
|
||||||
|
case TIME_ZOOM: {
|
||||||
|
const double mx = FMULT * double (size().width()) / x_lenght;
|
||||||
|
if ((m_forward.m11() > mx) or (increment > 0)) { // limit to window
|
||||||
|
const QMatrix m = increment > 0 ? QMatrix (FMULT,0,0,1,0,0) : QMatrix (IMULT,0,0,1,0,0);
|
||||||
|
m_forward *= m;
|
||||||
|
m_inverse = m_forward.inverted();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default : {
|
||||||
|
qDebug ("wheelEvent : %d", int (m_items));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
drawBackground();
|
||||||
|
update();
|
||||||
|
QWidget::wheelEvent(event);
|
||||||
|
}
|
||||||
|
void DisplayWidget::mousePressEvent(QMouseEvent * event) {
|
||||||
|
if (m_ts == nullptr) return;
|
||||||
|
const QPointF dp = m_inverse.map (event->pos ());
|
||||||
|
// qDebug ("dp:[%g, %g]", dp.x(), dp.y());
|
||||||
|
switch (m_items) {
|
||||||
|
case MOVE_VALUE: {
|
||||||
|
m_ts->value = dp.y();
|
||||||
|
emit SettingsChanged (m_items);
|
||||||
|
} break;
|
||||||
|
case MOVE_OFSET: {
|
||||||
|
m_ts->offset = dp.x();
|
||||||
|
emit SettingsChanged (m_items);
|
||||||
|
} break;
|
||||||
|
case MOVE_MARKERA: {
|
||||||
|
if (marker_type == MARKER_TIME) m_time.a = dp.x();
|
||||||
|
else m_volt.a = dp.y();
|
||||||
|
} break;
|
||||||
|
case MOVE_MARKERB: {
|
||||||
|
if (marker_type == MARKER_TIME) m_time.b = dp.x();
|
||||||
|
else m_volt.b = dp.y();
|
||||||
|
} break;
|
||||||
|
case TIME_ZOOM: QWidget::mousePressEvent(event); return;
|
||||||
|
default : {
|
||||||
|
qDebug ("mousePressEvent : %d", int (m_items));
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
drawBackground();
|
||||||
|
update();
|
||||||
|
QWidget::mousePressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayWidget::resizeEvent(QResizeEvent * event) {
|
||||||
|
const QSize sz = event->size();
|
||||||
|
reloadMatrix (sz);
|
||||||
|
QImage tmpi (sz, QImage::Format_ARGB32);
|
||||||
|
background = tmpi;
|
||||||
|
drawBackground();
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
}
|
||||||
|
void DisplayWidget::paintEvent(QPaintEvent * event) {
|
||||||
|
QPainter p (this);
|
||||||
|
p.drawImage(event->rect(), background);
|
||||||
|
QPen pa (QColor(0,255, 0,255), 2);
|
||||||
|
QPen pb (QColor(255,64,0,255), 2);
|
||||||
|
p.setPen(pb);
|
||||||
|
p.drawPolyline (m_forward.map(ChB));
|
||||||
|
p.setPen(pa);
|
||||||
|
p.drawPolyline (m_forward.map(ChA));
|
||||||
|
}
|
||||||
|
void DisplayWidget::setTrigger(TrigerSettings * ts) {
|
||||||
|
m_ts = ts;
|
||||||
|
}
|
||||||
|
void DisplayWidget::DispChannels(QVector<int> cha, QVector<int> chb) {
|
||||||
|
ACopy = cha;
|
||||||
|
BCopy = chb;
|
||||||
|
reloadData();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
static constexpr unsigned T_SIZE = 1u << 10;
|
||||||
|
static constexpr unsigned T_MASK = T_SIZE - 1u;
|
||||||
|
void DisplayWidget::reloadData () {
|
||||||
|
const int Alen = ACopy.size();
|
||||||
|
const int Blen = BCopy.size();
|
||||||
|
QVector<QPointF> va (Alen), vb (Blen);
|
||||||
|
if (Alen == 1 and Blen == 1) { // kontinuální mód
|
||||||
|
if (ChA.size() != T_SIZE) { ChA = QPolygonF (T_SIZE); }
|
||||||
|
if (ChB.size() != T_SIZE) { ChB = QPolygonF (T_SIZE); }
|
||||||
|
const QPointF pta (m_timeCount, ACopy [0]), ptb (m_timeCount, BCopy [0]);
|
||||||
|
ChA[m_timeCount] = pta;
|
||||||
|
ChB[m_timeCount] = ptb;
|
||||||
|
// printf("mode continuum\n");
|
||||||
|
m_timeCount += 1u;
|
||||||
|
m_timeCount &= T_MASK;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int n=0u; n<Alen; n++) {
|
||||||
|
const double x = (double (n));
|
||||||
|
const double y = ( ACopy [n]);
|
||||||
|
va [n] = QPointF (x,y);
|
||||||
|
}
|
||||||
|
ChA = QPolygonF (va);
|
||||||
|
for (int n=0u; n<Blen; n++) {
|
||||||
|
const double x = (double (n));
|
||||||
|
const double y = ( BCopy [n]);
|
||||||
|
vb [n] = QPointF (x,y);
|
||||||
|
}
|
||||||
|
ChB = QPolygonF (vb);
|
||||||
|
const int l = Alen > Blen ? Alen : Blen;
|
||||||
|
if (l != x_lenght) {
|
||||||
|
x_lenght = l;
|
||||||
|
reloadMatrix (size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void DisplayWidget::reloadMatrix(const QSize & sz) {
|
||||||
|
const double xm = sz.width();
|
||||||
|
const double ym = sz.height();
|
||||||
|
const double xz = xm / (x_lenght); // převod zpět ma pixely
|
||||||
|
const double yz = ym / (MAX_Y);
|
||||||
|
const QMatrix tm (xz,0,0,-yz, 0, ym);
|
||||||
|
m_forward = tm;
|
||||||
|
m_inverse = m_forward.inverted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayWidget::TimeBaseRange(int n) {
|
||||||
|
m_timeBase = n;
|
||||||
|
reloadMatrix (size());
|
||||||
|
drawBackground();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisplayWidget::drawBackground() {
|
||||||
|
QPainter p (&background);
|
||||||
|
QRect r = background.rect();
|
||||||
|
p.fillRect (r, QBrush(Qt::black, Qt::SolidPattern));
|
||||||
|
if (!m_ts) return;
|
||||||
|
const double yb = 0.0, ye = MAX_Y;
|
||||||
|
const double xb = 0.0, xe = x_lenght;
|
||||||
|
// rastr
|
||||||
|
QPen pg (QColor(64,64,64), 1);
|
||||||
|
p.setPen(pg);
|
||||||
|
const double dx = 100.0;
|
||||||
|
for (double x=xb; x<xe; x+=dx) {
|
||||||
|
const QLineF yline (x, yb, x, ye);
|
||||||
|
p.drawLine (m_forward.map(yline));
|
||||||
|
}
|
||||||
|
const double dv = 0.5;
|
||||||
|
const double dy = dv / STEP_Y;
|
||||||
|
for (double y=yb; y<ye; y+=dy) {
|
||||||
|
const QLineF xline (xb, y, xe, y);
|
||||||
|
p.drawLine (m_forward.map(xline));
|
||||||
|
}
|
||||||
|
// triger
|
||||||
|
QPointF trg (m_ts->offset, m_ts->value);
|
||||||
|
QPen pc (QColor(0,0,255), 1);
|
||||||
|
p.setPen(pc);
|
||||||
|
const QLineF hline (xb, trg.y(), xe, trg.y());
|
||||||
|
const QLineF vline (trg.x(), yb, trg.x(), ye);
|
||||||
|
p.drawLine (m_forward.map(hline));
|
||||||
|
p.drawLine (m_forward.map(vline));
|
||||||
|
// markers
|
||||||
|
QPen pm (QColor(255,255,0,196), 2);
|
||||||
|
p.setPen(pm);
|
||||||
|
if (marker_type == MARKER_TIME) {
|
||||||
|
const QLineF ma (m_time.a, yb, m_time.a, ye);
|
||||||
|
const QLineF mb (m_time.b, yb, m_time.b, ye);
|
||||||
|
p.drawLine (m_forward.map(ma));
|
||||||
|
p.drawLine (m_forward.map(mb));
|
||||||
|
} else {
|
||||||
|
const QLineF ma (xb, m_volt.a, xe, m_volt.a);
|
||||||
|
const QLineF mb (xb, m_volt.b, xe, m_volt.b);
|
||||||
|
p.drawLine (m_forward.map(ma));
|
||||||
|
p.drawLine (m_forward.map(mb));
|
||||||
|
}
|
||||||
|
// text
|
||||||
|
p.setPen (QPen (QColor(255,255,0)));
|
||||||
|
QFont font = p.font();
|
||||||
|
font.setPixelSize(16);
|
||||||
|
p.setFont (font);
|
||||||
|
QString desc;
|
||||||
|
const double xz = TimeBaseSteps [m_timeBase];
|
||||||
|
const double yz = STEP_Y;
|
||||||
|
const int my = r.size().height() - 10;
|
||||||
|
desc.sprintf("T=%ss/d; A,B=%gV/d", ing_fmt (xz * dx).c_str() , dv);
|
||||||
|
p.drawText(10,20, desc);
|
||||||
|
|
||||||
|
if (marker_type == MARKER_TIME) {
|
||||||
|
const double delta = xz * (m_time.b - m_time.a);
|
||||||
|
const double freq = delta == 0.0 ? 0.0 : 1.0 / delta;
|
||||||
|
desc.sprintf("Marker A: %ss, Marker B: %ss, Δ=%ss, f=%sHz", ing_fmt(xz * m_time.a).c_str(), ing_fmt(xz * m_time.b).c_str(),
|
||||||
|
ing_fmt(delta).c_str(), ing_fmt(freq).c_str());
|
||||||
|
} else {
|
||||||
|
const double delta = yz * (m_volt.b - m_volt.a);
|
||||||
|
desc.sprintf("Marker A: %sV, Marker B: %sV, Δ=%sV", ing_fmt(yz * m_volt.a).c_str(), ing_fmt(yz * m_volt.b).c_str(),
|
||||||
|
ing_fmt(delta).c_str());
|
||||||
|
}
|
||||||
|
p.drawText(10,my, desc);
|
||||||
|
}
|
||||||
|
void DisplayWidget::saveSettings(QSettings & setting) {
|
||||||
|
setting.setValue("TimeBaseIndex", m_timeBase);
|
||||||
|
setting.setValue("TimeA", m_time.a);
|
||||||
|
setting.setValue("TimeB", m_time.b);
|
||||||
|
setting.setValue("VoltA", m_volt.a);
|
||||||
|
setting.setValue("VoltB", m_volt.b);
|
||||||
|
}
|
||||||
|
void DisplayWidget::restSettings(QSettings & setting) {
|
||||||
|
m_time.a = setting.value("TimeA").toDouble();
|
||||||
|
m_time.b = setting.value("TimeB").toDouble();
|
||||||
|
m_volt.a = setting.value("VoltA").toDouble();
|
||||||
|
m_volt.b = setting.value("VoltB").toDouble();
|
||||||
|
}
|
58
V203/usb/scope/software/displaywidget.h
Normal file
58
V203/usb/scope/software/displaywidget.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef DISPLAYWIDGET_H
|
||||||
|
#define DISPLAYWIDGET_H
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QPoint>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QMatrix>
|
||||||
|
#include "structures.h"
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
class QSettings;
|
||||||
|
class DisplayWidget : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
QVector<int> ACopy;
|
||||||
|
QVector<int> BCopy;
|
||||||
|
QMatrix m_forward;
|
||||||
|
QMatrix m_inverse;
|
||||||
|
QImage background;
|
||||||
|
TrigerSettings * m_ts;
|
||||||
|
QPolygonF ChA, ChB;
|
||||||
|
MOVE_ITEMS m_items;
|
||||||
|
int m_timeBase;
|
||||||
|
int m_ChBase;
|
||||||
|
double x_lenght;
|
||||||
|
struct MarkSetting {
|
||||||
|
double a,b;
|
||||||
|
} m_time, m_volt;
|
||||||
|
enum MARKER_ENUM {
|
||||||
|
MARKER_TIME = 0,
|
||||||
|
MARKER_VOLT,
|
||||||
|
} marker_type;
|
||||||
|
unsigned m_timeCount;
|
||||||
|
public:
|
||||||
|
explicit DisplayWidget (QWidget * p);
|
||||||
|
virtual ~DisplayWidget ();
|
||||||
|
void setTrigger (TrigerSettings * ts);
|
||||||
|
void TriggerValues (int n);
|
||||||
|
void TimeBaseRange (int n);
|
||||||
|
void MarkerChanged (bool);
|
||||||
|
void saveSettings (QSettings & setting);
|
||||||
|
void restSettings (QSettings & setting);
|
||||||
|
|
||||||
|
void resizeEvent (QResizeEvent * event) override;
|
||||||
|
void paintEvent (QPaintEvent * event) override;
|
||||||
|
void wheelEvent (QWheelEvent * event) override;
|
||||||
|
void mousePressEvent(QMouseEvent * event) override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void DispChannels (QVector<int>, QVector<int>);
|
||||||
|
signals:
|
||||||
|
void SettingsChanged (int n);
|
||||||
|
protected:
|
||||||
|
void drawBackground ();
|
||||||
|
void reloadData ();
|
||||||
|
void reloadMatrix (const QSize & sz);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DISPLAYWIDGET_H
|
47
V203/usb/scope/software/helpers.cpp
Normal file
47
V203/usb/scope/software/helpers.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cmath>
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
|
char * strip_eol (char * str) {
|
||||||
|
char * ptr = str;
|
||||||
|
for (;;) {
|
||||||
|
const char c = * ptr;
|
||||||
|
if (c == '\0') break;
|
||||||
|
else if (c == '\r') * ptr = '\0';
|
||||||
|
else if (c == '\n') * ptr = '\0';
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
std::string ing_fmt (const double par, const unsigned dnum) {
|
||||||
|
const char * suffixes [] = {"a", "f", "p", "n", "μ", "m", " ", "k", "M", "G", "T", "P", "E"};
|
||||||
|
bool sign = false;
|
||||||
|
double value = par;
|
||||||
|
if (par < 0.0) {
|
||||||
|
value = - par;
|
||||||
|
sign = true;
|
||||||
|
}
|
||||||
|
if (value < 1.0e-18) return std::string ("0");
|
||||||
|
if (value > 1.0e+18) return std::string ("hafo");
|
||||||
|
|
||||||
|
const double dlog = log10 (value) + 18.0;
|
||||||
|
double fractional, integer;
|
||||||
|
fractional = modf (dlog, & integer);
|
||||||
|
const double mult = pow (10.0, double (dnum - 1));
|
||||||
|
double avgf = pow (10.0, fractional); // do mezí 1.0 až 9.9999...
|
||||||
|
avgf *= mult;
|
||||||
|
avgf = round (avgf); // a teď zaokrouhli
|
||||||
|
avgf /= mult;
|
||||||
|
div_t dt = div (int(integer), 3);
|
||||||
|
avgf *= pow (10.0, double (dt.rem));
|
||||||
|
// printf("%g:%g (%f) [%d:%d]{%s}\n", integer, fractional, avgf, dt.quot, dt.rem, suffixes[dt.quot]);
|
||||||
|
|
||||||
|
const unsigned buflen = 64;
|
||||||
|
char buffer [buflen];
|
||||||
|
const int r = snprintf(buffer, buflen, "%g%s", avgf, suffixes [dt.quot]);
|
||||||
|
buffer [r] = '\0';
|
||||||
|
|
||||||
|
std::string result (buffer, r);
|
||||||
|
if (sign) result = std::string("-") + result;
|
||||||
|
return result;
|
||||||
|
}
|
8
V203/usb/scope/software/helpers.h
Normal file
8
V203/usb/scope/software/helpers.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef HELPERS_H
|
||||||
|
#define HELPERS_H
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
extern char * strip_eol (char * str);
|
||||||
|
extern std::string ing_fmt (const double par, const unsigned dnum = 3u);
|
||||||
|
|
||||||
|
#endif // HELPERS_H
|
BIN
V203/usb/scope/software/ico.png
Normal file
BIN
V203/usb/scope/software/ico.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
9
V203/usb/scope/software/main.cpp
Normal file
9
V203/usb/scope/software/main.cpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
// QApplication::setStyle("plastique");
|
||||||
|
QApplication a (argc, argv);
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
return a.exec();
|
||||||
|
}
|
11
V203/usb/scope/software/main.h
Normal file
11
V203/usb/scope/software/main.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef _MAIN_H_
|
||||||
|
#define _MAIN_H_
|
||||||
|
#include <QApplication>
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include <qstyle.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
|
||||||
|
#endif // _MAIN_H_
|
151
V203/usb/scope/software/mainwindow.cpp
Normal file
151
V203/usb/scope/software/mainwindow.cpp
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QSettings>
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
/*
|
||||||
|
#undef qDebug
|
||||||
|
#define qDebug(p, ...)
|
||||||
|
*/
|
||||||
|
static const char * TrigerChannelTexts [] = {
|
||||||
|
"Channel A", "Channel B"
|
||||||
|
};
|
||||||
|
static const char * TrigerModeTexts [] = {
|
||||||
|
"Auto", "Normal", "Single"
|
||||||
|
};
|
||||||
|
static const char * TrigerEdgeTexts [] = {
|
||||||
|
"Rising", "Faling"
|
||||||
|
};
|
||||||
|
static const char * TrigerSelectTexts [] = {
|
||||||
|
"Trig.Value", "Trig.Offset", "Marker A", "Marker B", "Time Zoom"
|
||||||
|
};
|
||||||
|
static const char * TimeBaseTexts [] = {
|
||||||
|
"2μs", "5μs", "10μs", "20μs", "50μs", "100μs", "200μs","500μs",
|
||||||
|
"1ms", "2ms", "5ms", "10ms", "20ms", "50ms", "100ms", "200ms",
|
||||||
|
"500ms", "1s",
|
||||||
|
};
|
||||||
|
|
||||||
|
MainWindow::MainWindow (QWidget * parent)
|
||||||
|
: QMainWindow (parent), firmware(parent) {
|
||||||
|
ui = new Ui_MainWindow;
|
||||||
|
ui->setupUi (this);
|
||||||
|
ui->radio_a->setChecked(true);
|
||||||
|
ui->Display->setTrigger (firmware.getTrigger());
|
||||||
|
for (auto & e: TrigerModeTexts) ui->comboMode ->addItem(QString(e));
|
||||||
|
for (auto & e: TrigerChannelTexts) ui->comboChannel ->addItem(QString(e));
|
||||||
|
for (auto & e: TrigerEdgeTexts) ui->comboRissing ->addItem(QString(e));
|
||||||
|
for (auto & e: TrigerSelectTexts) ui->comboValue ->addItem(QString(e));
|
||||||
|
for (auto & e: TimeBaseTexts) ui->comboTimeRange->addItem(QString(e));
|
||||||
|
|
||||||
|
setWindowTitle ("Scope");
|
||||||
|
setWindowIcon (QIcon(":ico"));
|
||||||
|
//setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
|
||||||
|
connect (&firmware, SIGNAL (Channels_received(QVector<int>, QVector<int>)),
|
||||||
|
ui->Display, SLOT (DispChannels (QVector<int>, QVector<int>)));
|
||||||
|
connect (&firmware, SIGNAL (PaketTriggered()), this, SLOT(PaketTriggered()));
|
||||||
|
|
||||||
|
connect (ui->Display, SIGNAL(SettingsChanged(int)), &firmware, SLOT(SettingChanged(int)));
|
||||||
|
connect (ui->buttonStart,SIGNAL(pressed()), this, SLOT(Started()));
|
||||||
|
connect (ui->actionQuit, SIGNAL(triggered(bool)), this, SLOT(close()));
|
||||||
|
connect (ui->radio_a, SIGNAL(toggled(bool)), this, SLOT(MarkerChanged(bool)));
|
||||||
|
connect (ui->actionExport_Image, SIGNAL(triggered(bool)), this, SLOT(ExportImage (bool)));
|
||||||
|
connect (ui->actionSaveSet, SIGNAL(triggered(bool)), this, SLOT(SaveSettings(bool)));
|
||||||
|
connect (ui->actionRestSet, SIGNAL(triggered(bool)), this, SLOT(RestSettings(bool)));
|
||||||
|
|
||||||
|
connect (ui->comboMode, SIGNAL(activated(int)), this, SLOT(SendTrigerMode(int)));
|
||||||
|
connect (ui->comboRissing, SIGNAL(activated(int)), this, SLOT(SendTrigerEdge(int)));
|
||||||
|
connect (ui->comboChannel, SIGNAL(activated(int)), this, SLOT(SendTrigerChan(int)));
|
||||||
|
connect (ui->comboValue, SIGNAL(activated(int)), this, SLOT(TriggerValues (int)));
|
||||||
|
connect (ui->comboTimeRange, SIGNAL(activated(int)), this, SLOT(TimeBaseRange (int)));
|
||||||
|
|
||||||
|
ui->comboTimeRange->setCurrentIndex(6);
|
||||||
|
ui->buttonStart->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow () {
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
void MainWindow::Started() {
|
||||||
|
firmware.Start();
|
||||||
|
}
|
||||||
|
void MainWindow::MarkerChanged(bool b) {
|
||||||
|
ui->Display->MarkerChanged (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::TriggerValues (int n) {
|
||||||
|
ui->Display->TriggerValues(n);
|
||||||
|
}
|
||||||
|
void MainWindow::SendTrigerMode (int n) {
|
||||||
|
if (n == TRIGER_MODE_SINGLE) ui->buttonStart->setEnabled(true);
|
||||||
|
else ui->buttonStart->setEnabled(false);
|
||||||
|
firmware.SendTrigerMode(n);
|
||||||
|
}
|
||||||
|
void MainWindow::SendTrigerEdge (int n) {
|
||||||
|
firmware.SendTrigerEdge(n);
|
||||||
|
}
|
||||||
|
void MainWindow::SendTrigerChan (int n) {
|
||||||
|
firmware.SendTrigerChan(n);
|
||||||
|
}
|
||||||
|
void MainWindow::TimeBaseRange (int n) {
|
||||||
|
firmware.SendBaseRange(n);
|
||||||
|
ui->Display->TimeBaseRange(n);
|
||||||
|
}
|
||||||
|
void MainWindow::PaketTriggered () {
|
||||||
|
statusBar()->showMessage(QString("TRIGER"), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::ExportImage (bool) {
|
||||||
|
QWidget * pw = ui->Display;
|
||||||
|
QString fileName = QFileDialog::getSaveFileName (this,
|
||||||
|
tr ("Save File"), ".", "Images Files(*.png)");
|
||||||
|
if (!fileName.isEmpty()) {
|
||||||
|
QImage img (pw->width(), pw->height(), QImage::Format_ARGB32_Premultiplied);
|
||||||
|
QPainter painter(&img);
|
||||||
|
pw->render (&painter);
|
||||||
|
img.save (fileName, "png", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MainWindow::SaveSettings(bool) {
|
||||||
|
qDebug ("Save Settings");
|
||||||
|
QSettings setting ("Kizarm", "Scope");
|
||||||
|
setting.beginGroup("Trigger");
|
||||||
|
const TrigerSettings * const ts = firmware.getTrigger();
|
||||||
|
setting.setValue("Value", ts->value);
|
||||||
|
setting.setValue("Offset", ts->offset);
|
||||||
|
setting.setValue("Mode", ts->mode);
|
||||||
|
setting.setValue("Channel", ts->channel);
|
||||||
|
setting.setValue("Edge", ts->rising);
|
||||||
|
setting.endGroup();
|
||||||
|
setting.beginGroup("Markers");
|
||||||
|
ui->Display->saveSettings (setting);
|
||||||
|
setting.endGroup();
|
||||||
|
}
|
||||||
|
void MainWindow::RestSettings(bool) {
|
||||||
|
qDebug ("Restore Settings");
|
||||||
|
QSettings setting ("Kizarm", "Scope");
|
||||||
|
setting.beginGroup("Trigger");
|
||||||
|
TrigerSettings ts;
|
||||||
|
ts.value = setting.value ("Value").toInt();
|
||||||
|
ts.offset = setting.value ("Offset").toInt();
|
||||||
|
ts.mode = static_cast<TRIGER_MODE> (setting.value ("Mode").toInt());
|
||||||
|
ui->comboMode->setCurrentIndex(ts.mode);
|
||||||
|
ts.channel = static_cast<ADC_CHANNELS> (setting.value ("Channel").toInt());
|
||||||
|
ui->comboChannel->setCurrentIndex(ts.channel);
|
||||||
|
ts.rising = setting.value ("Edge").toBool();
|
||||||
|
ui->comboRissing->setCurrentIndex(ts.value ? 1 : 0);
|
||||||
|
memcpy (firmware.getTrigger(), & ts, sizeof(TrigerSettings));
|
||||||
|
setting.endGroup();
|
||||||
|
|
||||||
|
SendTrigerMode (ts.mode);
|
||||||
|
firmware.SettingChanged(MOVE_VALUE);
|
||||||
|
firmware.SettingChanged(MOVE_OFSET);
|
||||||
|
|
||||||
|
setting.beginGroup("Markers");
|
||||||
|
ui->Display->restSettings (setting);
|
||||||
|
const int n = setting.value("TimeBaseIndex").toInt();
|
||||||
|
TimeBaseRange(n);
|
||||||
|
ui->comboTimeRange->setCurrentIndex(n);
|
||||||
|
setting.endGroup();
|
||||||
|
}
|
||||||
|
|
33
V203/usb/scope/software/mainwindow.h
Normal file
33
V203/usb/scope/software/mainwindow.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include "datasource.h"
|
||||||
|
|
||||||
|
class Ui_MainWindow;
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MainWindow (QWidget *parent = 0);
|
||||||
|
~MainWindow ();
|
||||||
|
protected:
|
||||||
|
public slots:
|
||||||
|
void SendTrigerMode (int n);
|
||||||
|
void SendTrigerEdge (int n);
|
||||||
|
void SendTrigerChan (int n);
|
||||||
|
void TriggerValues (int n);
|
||||||
|
void TimeBaseRange (int n);
|
||||||
|
void ExportImage (bool);
|
||||||
|
void MarkerChanged (bool);
|
||||||
|
void SaveSettings (bool);
|
||||||
|
void RestSettings (bool);
|
||||||
|
void PaketTriggered ();
|
||||||
|
void Started ();
|
||||||
|
private:
|
||||||
|
Ui_MainWindow * ui;
|
||||||
|
DataSource firmware;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
238
V203/usb/scope/software/mainwindow.ui
Normal file
238
V203/usb/scope/software/mainwindow.ui
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>966</width>
|
||||||
|
<height>660</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="DisplayWidget" name="Display" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupTriger">
|
||||||
|
<property name="title">
|
||||||
|
<string>Trigger</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QComboBox" name="comboRissing"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QComboBox" name="comboMode"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QComboBox" name="comboChannel"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBase">
|
||||||
|
<property name="title">
|
||||||
|
<string>Time Base</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QComboBox" name="comboTimeRange"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupMarkers">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>121</width>
|
||||||
|
<height>61</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="title">
|
||||||
|
<string>Markers</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="layoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>30</y>
|
||||||
|
<width>106</width>
|
||||||
|
<height>25</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<property name="sizeConstraint">
|
||||||
|
<enum>QLayout::SetMinimumSize</enum>
|
||||||
|
</property>
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QRadioButton" name="radio_a">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="src.qrc">
|
||||||
|
<normaloff>:/time</normaloff>:/time</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QRadioButton" name="radio_b">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="src.qrc">
|
||||||
|
<normaloff>:/volt</normaloff>:/volt</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="labelA">
|
||||||
|
<property name="text">
|
||||||
|
<string>Item to move:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboValue"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="buttonStart">
|
||||||
|
<property name="text">
|
||||||
|
<string>Start</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>966</width>
|
||||||
|
<height>22</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenu" name="menuMenu">
|
||||||
|
<property name="title">
|
||||||
|
<string>Menu</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionQuit"/>
|
||||||
|
<addaction name="actionExport_Image"/>
|
||||||
|
<addaction name="actionSaveSet"/>
|
||||||
|
<addaction name="actionRestSet"/>
|
||||||
|
</widget>
|
||||||
|
<addaction name="menuMenu"/>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
<action name="actionQuit">
|
||||||
|
<property name="text">
|
||||||
|
<string>Quit</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Alt+X</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionExport_Image">
|
||||||
|
<property name="text">
|
||||||
|
<string>Export Image</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionSaveSet">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save Settings</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+S</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRestSet">
|
||||||
|
<property name="text">
|
||||||
|
<string>Restore Settings</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+R</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>DisplayWidget</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">displaywidget.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources>
|
||||||
|
<include location="src.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
41
V203/usb/scope/software/src.pro
Normal file
41
V203/usb/scope/software/src.pro
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#CONFIG += qt debug
|
||||||
|
QT += core gui
|
||||||
|
QT += serialport
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
|
||||||
|
QMAKE_CXXFLAGS += -std=c++14
|
||||||
|
|
||||||
|
TARGET = osciloscope
|
||||||
|
TEMPLATE = app
|
||||||
|
|
||||||
|
|
||||||
|
SOURCES = main.cpp
|
||||||
|
SOURCES += mainwindow.cpp
|
||||||
|
SOURCES += helpers.cpp
|
||||||
|
SOURCES += datasource.cpp
|
||||||
|
SOURCES += displaywidget.cpp
|
||||||
|
|
||||||
|
HEADERS = mainwindow.h
|
||||||
|
HEADERS += helpers.h
|
||||||
|
HEADERS += datasource.h
|
||||||
|
HEADERS += structures.h
|
||||||
|
HEADERS += displaywidget.h
|
||||||
|
|
||||||
|
FORMS = mainwindow.ui
|
||||||
|
|
||||||
|
#INCLUDEPATH +=
|
||||||
|
#LIBS +=
|
||||||
|
RESOURCES += src.qrc
|
||||||
|
|
||||||
|
MOC_DIR = moc
|
||||||
|
OBJECTS_DIR = obj
|
||||||
|
DESTDIR = ../bin
|
||||||
|
|
||||||
|
unix {
|
||||||
|
DEFINES += UNIX
|
||||||
|
}
|
||||||
|
|
||||||
|
win32 {
|
||||||
|
DEFINES += QT_DLL WIN32
|
||||||
|
}
|
||||||
|
|
||||||
|
|
8
V203/usb/scope/software/src.qrc
Normal file
8
V203/usb/scope/software/src.qrc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE RCC>
|
||||||
|
<RCC version="1.0">
|
||||||
|
<qresource prefix="/" >
|
||||||
|
<file alias="ico">ico.png</file>
|
||||||
|
<file alias="time">time.png</file>
|
||||||
|
<file alias="volt">volt.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
1
V203/usb/scope/software/structures.h
Symbolic link
1
V203/usb/scope/software/structures.h
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../firmware/structures.h
|
BIN
V203/usb/scope/software/time.png
Normal file
BIN
V203/usb/scope/software/time.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 606 B |
BIN
V203/usb/scope/software/volt.png
Normal file
BIN
V203/usb/scope/software/volt.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 595 B |
Loading…
Reference in a new issue