Compare commits

...

2 commits

Author SHA1 Message Date
Kizarm
1095da2bea add readme 2024-10-25 15:57:27 +02:00
Kizarm
b7b1a581f0 add server 2024-10-25 15:20:26 +02:00
10 changed files with 783 additions and 2 deletions

4
.gitignore vendored
View file

@ -15,7 +15,9 @@
V203/pwm/sin.c
V203/gsm/lib/libgsm.a
V203/usb/cdc/mystrings.inc
V203/usb/scope/bin/*
V203/usb/scope/bin/osciloscope
V203/usb/scope/bin/wserver
V203/usb/scope/server/*.o
V203/usb/scope/software/.qmake.stash
V203/usb/scope/software/Makefile
V203/usb/scope/software/moc/*

26
V203/usb/scope/README.md Normal file
View file

@ -0,0 +1,26 @@
# Osciloskop
Je to tak napůl hotový projekt, který začal na STM32L452.
Tady je to předěláno na CH32V203, který má pomalejší AD převodník, ale funguje na plných 12 bitů
rozlišení. Trigger, který musí skenovat vlastně úplně všechna data to na tomto čipu v pohodě
stíhá. Přenos dat po USB je zachován v hexadecimálním formátu.
## firmware
Omezení zde je poměrně malá RAM.
## software
Ovládací program je napsán v Qt5. Je třeba modul QSerialPort, jinak na tom není nic extra.
## server
Zkusil jsem doplnit ovládání přímo z browseru. Použil jsem knihovnu
https://github.com/mattgodbolt/seasocks, má i JSON takže lze komunikovat s klientem
tímto mechanizmem. Vypadá to, že webové sokety by to mohly zvládnout, zatím to není
úplně doděláno, ale zobrazení chodí. Funguje to jen na Linuxu.
## bin
Zde se nalézají binárky jak software, tak serveru a zároveň i klientská část v html a javascriptu.
Vše je tak jednoduché jak může, žádné frameworky nepoužívám.

View file

@ -0,0 +1,93 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Osciloskop</title>
<style>
html,
body {
height: 98%;
margin: 0;
padding: 0;
}
.canvas {
width: 98vw;
height: 78vh;
background-color:black;
}
.frame1 {
width: 90%;
margin: auto;
background-color: #FFFFC0;
border: 10px solid #F0C0F0;
}
fieldset {
background-color: #C0FFC0;
height: 100%;
}
tr,td {
height: 100%;
}
.start {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="canvas" class="canvas"></canvas>
<div class="frame1">
<table><tr>
<td>
<div><input type="button" value="Connect" id="Connect" onclick="Connect();" /></div>
<div><p id="Connected">Disconnected</p></div>
</td>
<td><fieldset>
<legend>Trigger</legend>
<div><select id="trigger_src" name="trigger_src">
<option value="0">Channel A</option>
<option value="1">Channel B</option>
</select></div>
<div><select id="trigger_mode" name="trigger_mode">
<option value="0">Auto </option>
<option value="1">Normal</option>
<option value="2">Single</option>
</select></div>
<div><select id="trigger_edge" name="trigger_edge">
<option value="0">Rissing</option>
<option value="1">Falling</option>
</select></div>
</fieldset></td>
<td><fieldset>
<legend>Time Base</legend>
<div><select id="time_base" name="time_base">
<option value="0">2μs</option> <option value="1">5μs</option> <option value="2">10μs</option>
<option value="3">20μs</option> <option value="4">50μs</option> <option value="5">100μs</option>
<option value="6">200μs</option><option value="7">500μs</option><option value="8">1ms</option>
<option value="9">2ms</option> <option value="10">5ms</option> <option value="11">10ms</option>
<option value="12">20ms</option> <option value="13">50ms</option> <option value="14">100ms</option>
<option value="15">200ms</option><option value="16">500ms</option><option value="17">1s</option>
</select></div>
</fieldset></td>
<td><fieldset>
<legend>Markers</legend>
<div><input type="radio" id="time" name="markers" value="time" checked /><labelfor="time">Time</label></div>
<div><input type="radio" id="volt" name="markers" value="volt" /><labelfor="volt">Voltage</label></div>
</fieldset></td>
<td><fieldset>
<legend>Item to move</legend>
<div><select id="move" name="move">
<option value="0">Trigger value</option>
<option value="1">Trigger offset</option>
<option value="2">Marker A</option>
<option value="3">Marker B</option>
<option value="4">Time base zoom</option>
</select></div>
</fieldset></td>
<td><input type="button" class="start" id="Start" value="Start" onclick="Start();" disabled></td>
</tr></table>
</div>
<script src="index.js"></script>
</body>
</html>

203
V203/usb/scope/bin/index.js Normal file
View file

@ -0,0 +1,203 @@
const TriggerSrc = document.getElementById ('trigger_src');
const TriggerMode = document.getElementById ('trigger_mode');
const TriggerEdge = document.getElementById ('trigger_edge');
const MarkerTime = document.getElementById ('time');
const MarkerVolt = document.getElementById ('volt');
const TimeBase = document.getElementById ('time_base');
const MoveElem = document.getElementById ('move');
const StartBut = document.getElementById ('Start');
const ConnectBut = document.getElementById ('Connect');
const Connected = document.getElementById ('Connected');
const Canvas = document.getElementById ('canvas');
const REF_Y = 3.3;
const MAX_Y = 4096.0;
const MAX_X = 1024.0;
var gMZ = { m11 : 1.0, m12 : 0.0, m21 : 0.0, m22 : 1.0, ox : 0.0, oy : 0.0 };
var gTC = { x : 100.0, y : 2048.0 };
const gTB = new Array ();
const gCA = new Array ();
const gCB = new Array ();
var gItemToMove = 0, gIndex = 512;
/************************************************************************/
var websocket = null;
var wsUri = null;
var connected = false;
function js_get_id () {
var host;
const locate = window.location;
if (locate.protocol == 'file:') host = 'ws://unknown';
else if (locate.port) host = 'ws://' + locate.hostname + ':' + (parseInt(locate.port, 10) + 0) + '/ws';
else host = 'ws://' + locate.hostname + '/ws';
console.log ('host is: ' + host);
return host;
}
function initWebSocket() {
try {
if (typeof MozWebSocket == 'function') WebSocket = MozWebSocket;
if ( websocket && websocket.readyState == 1 ) websocket.close();
websocket = new WebSocket( wsUri );
websocket.onopen = function (evt) {
ConnectBut.value = 'Disconnect';
Connected.innerHTML = 'CONNECTED';
connected = true;
};
websocket.onclose = function (evt) {
ConnectBut.value = 'Connect';
Connected.innerHTML = 'DISCONNECTED';
connected = false;
};
websocket.onmessage = function (evt) {
const obj = JSON.parse (evt.data);
DrawTrig ();
DrawPolyLine (0, obj.a, '#FF0000');
DrawPolyLine (1, obj.b, '#00FF00');
};
websocket.onerror = function (evt) {
console.log ('ERROR: ' + evt.data);
};
} catch (exception) {
console.log ('EXCEPT: ' + exception);
}
}
/************************************************************************/
function ReloadMatrix (sz) {
const xz = sz.x / MAX_X;
const yz = sz.y / MAX_Y;
gMZ.m11 = xz; gMZ.m22 = -yz; gMZ.oy = sz.y;
};
function TrPt (x, y) { // matice je diagonalni
const rx = (x * gMZ.m11 + gMZ.ox);
const ry = (y * gMZ.m22 + gMZ.oy);
return { x : rx, y : ry };
};
function InPt (x, y) { // matice je diagonalni
const rx = Math.round ((x - gMZ.ox) / gMZ.m11);
const ry = Math.round ((y - gMZ.oy) / gMZ.m22);
return { x : rx, y : ry };
};
function SendEvent (evt) {
console.log (evt);
if (!connected) return;
const reply = JSON.stringify(evt);
websocket.send (reply);
}
function DrawTrig () {
var ctx = Canvas.getContext('2d');
ctx.clearRect(0, 0, Canvas.width, Canvas.height);
ctx.lineWidth = 2.0;
ctx.strokeStyle = 'blue';
ctx.beginPath();
var b,e;
b = TrPt (24, gTC.y);
e = TrPt (1000, gTC.y);
ctx.moveTo(b.x, b.y);
ctx.lineTo(e.x, e.y);
ctx.stroke();
ctx.beginPath();
b = TrPt (gTC.x, 96);
e = TrPt (gTC.x, 4000);
ctx.moveTo(b.x, b.y);
ctx.lineTo(e.x, e.y);
ctx.stroke();
};
function DrawPolyLine (ch, data, col) {
var out = ch === 0 ? gCA : gCB;
if (data.length === 1) {
out [gIndex] = data [0];
if (ch === 1) {
gIndex += 1;
gIndex = gIndex % 1024;
}
} else {
const max = data.length < 1024 ? data.length : 1024;
for (let n=0; n<max; n++) {
out [n] = data [n];
}
}
var ctx = Canvas.getContext('2d');
ctx.lineWidth = 2.0;
ctx.strokeStyle = col;
ctx.beginPath();
ctx.moveTo (gTB[0], out[0] * gMZ.m22 + gMZ.oy);
for (let n=1; n<1024; n++) {
ctx.lineTo(gTB[n], out[n] * gMZ.m22 + gMZ.oy);
}
ctx.stroke();
};
Canvas.addEventListener ('click', function(event) {
const p = { x : event.clientX, y : event.clientY };
const q = InPt (p.x, p.y);
switch (gItemToMove) {
case 0: gTC.y = q.y; SendEvent ({ type : "trg_val", value: q.y }); break;
case 1: gTC.x = q.x; SendEvent ({ type : "trg_ofs", value: q.x }); break;
default: return;
};
DrawTrig ();
});
/************************************************************************/
TriggerSrc.onchange = (event) => {
const e = { type : "trg_src", value : parseInt(event.target.value, 10) };
SendEvent (e);
};
TriggerMode.onchange = (event) => {
const e = { type : "trg_mod", value : parseInt(event.target.value, 10) };
SendEvent (e);
const res = event.target.value;
if (e.value === 2) {
StartBut.disabled = false;
} else {
StartBut.disabled = true;
}
};
TriggerEdge.onchange = (event) => {
const e = { type : "trg_edg", value : parseInt(event.target.value, 10) };
SendEvent (e);
};
TimeBase.onchange = (event) => {
const e = { type : "tim_bas", value : parseInt(event.target.value, 10) };
SendEvent (e);
};
MoveElem.onchange = (event) => {
const e = { type : "mov_ele", value : parseInt(event.target.value, 10) };
gItemToMove = e.value;
console.log(e);
};
MarkerTime.onclick = (event) => {
console.log ('time_mark');
};
MarkerVolt.onclick = (event) => {
console.log ('volt_mark');
};
window.onload = (event) => {
const dim = { x : Canvas.clientWidth, y : Canvas.clientHeight };
Canvas.width = dim.x; Canvas.height = dim.y;
ReloadMatrix (dim);
for (let n=0; n<MAX_X; n++) {
gTB.push (n * gMZ.m11 + gMZ.ox);
gCA.push (2000);
gCB.push (1000);
}
wsUri = js_get_id ();
};
function Connect () {
if (connected) {
websocket.close();
} else {
initWebSocket ();
}
/*
DrawTrig ();
const d1 = [10,20,30,40,50];
const d2 = [3000];
DrawPolyLine (0, d1, '#FF0000');
DrawPolyLine (1, d2, '#00FF00');
*/
};
function Start () {
SendEvent ({ type : 'start', value : 1 });
};

View file

@ -0,0 +1,20 @@
PR = ../bin/wserver
CC = g++
AS = as
CFLAGS = -Wall -Os
CFLAGS+= -I$(HOME)/local/include
MFLAGS = -o $(PR)
LFLAGS = -L$(HOME)/local/lib -lseasocks -lz -lpthread
all: $(PR)
OBJECTS = main.o wsclient.o
$(PR): $(OBJECTS)
$(CC) $(AFLAGS) $(MFLAGS) $(OBJECTS) $(LFLAGS)
clean:
rm -f *.o *.lst *~
%.o: %.cpp
$(CC) -std=c++17 $(AFLAGS) -c $(CFLAGS) $< -o $@
%.o: %.S
$(AS) $< -o $@

View file

@ -0,0 +1,97 @@
#include "seasocks/PrintfLogger.h"
#include "seasocks/Server.h"
#include "seasocks/StringUtil.h"
#include "seasocks/WebSocket.h"
#include "seasocks/PageHandler.h"
#include "seasocks/SimpleResponse.h"
#include "seasocks/util/Json.h"
#include "wsclient.h"
#include <cstring>
#include <iostream>
#include <fstream>
#include <memory>
#include <map>
#include <sstream>
#include <string>
#include <thread>
#include <set>
#include <fcntl.h>
#include <unistd.h>
#include <sys/epoll.h>
using namespace seasocks;
class WsHandler : public WebSocket::Handler {
public:
explicit WsHandler (int & epollFd)
: _epollFd (epollFd) {
}
void onConnect (WebSocket * connection) override {
WsClient * dz = new WsClient (connection, _epollFd);
_connections.insert ( {connection, dz});
if (dz->start()) printf ("WsClient started\r\n");
std::cout << "Connected: " << connection->getRequestUri()
<< " : " << formatAddress (connection->getRemoteAddress())
<< "\r\nCredentials: " << * (connection->credentials()) << "\r\n";
}
void onData (WebSocket * connection, const char * data) override {
WsClient * dz = _connections.at (connection);
dz->send (data);
}
void onDisconnect (WebSocket * connection) override {
WsClient * dz = _connections.at (connection);
dz->stop();
delete dz;
_connections.erase (connection);
std::cout << "Disconnected: " << connection->getRequestUri()
<< " : " << formatAddress (connection->getRemoteAddress()) << "\r\n";
}
void poll (void * ptr) {
WsClient * dz = static_cast<WsClient*>(ptr);
if (dz) dz->receive();
}
private:
int & _epollFd;
std::map<WebSocket*, WsClient*> _connections;
};
int main (int /*argc*/, const char * /*argv*/[]) {
auto logger = std::make_shared<PrintfLogger> (Logger::Level::Info);
int myEpoll = epoll_create (10);
Server server (logger);
auto handler = std::make_shared<WsHandler> (myEpoll);
server.addWebSocketHandler ("/ws", handler);
server.setStaticPath (".");
if (!server.startListening (8080)) {
std::cerr << "couldn't start listening\n";
return 1;
}
epoll_event wakeSeasocks = {EPOLLIN | EPOLLOUT | EPOLLERR, {&server}};
epoll_ctl (myEpoll, EPOLL_CTL_ADD, server.fd(), &wakeSeasocks);
while (true) {
constexpr auto maxEvents = 2;
epoll_event events[maxEvents];
auto res = epoll_wait (myEpoll, events, maxEvents, -1);
if (res < 0) {
std::cerr << "epoll returned an error\n";
return 1;
}
for (auto i = 0; i < res; ++i) {
if (events[i].data.ptr == &server) {
auto seasocksResult = server.poll (0);
if (seasocksResult == Server::PollResult::Terminated) {
return 0;
}
if (seasocksResult == Server::PollResult::Error)
return 1;
} else {
handler->poll (events[i].data.ptr);
}
}
}
return 0;
}

View file

@ -0,0 +1 @@
../firmware/structures.h

View file

@ -0,0 +1,275 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <termios.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <nlohmann/json.hpp>
#include "wsclient.h"
using json = nlohmann::json;
using namespace std;
using namespace seasocks;
static string channels_to_json (const vector<int> & a, const vector<int> & b) {
string res ("{\"a\":[");
for (const int e: a) {
res += to_string(e) + ",";
}
res = res.substr(0, res.length() - 1);
res+= "],\"b\":[";
for (const int e: b) {
res += to_string(e) + ",";
}
res = res.substr(0, res.length() - 1);
res+= "]}";
return res;
}
bool WsClient::start() {
cout << "Client Start\n";
const char * name = "/dev/serial/by-id/usb-Kizarm_Labs._USB_Osciloscope_00001-if00";
running = false;
fd = ::open (name, O_RDWR);
if (fd < 0) return running;
epoll_event wakeUsart = {EPOLLIN, {this}};
epoll_ctl (pollfd, EPOLL_CTL_ADD, fd, &wakeUsart);
struct termios LineFlags;
int attr = tcgetattr (fd, &LineFlags);
if (attr) {
printf ("Nelze zjistit parametry portu %s\r\n", name);
::close (fd);
return running;
}
// nastaveni komunikacnich parametru do struct termios
LineFlags.c_iflag = IGNPAR /* | IXON | IXOFF*/; // ignoruj chyby parity
LineFlags.c_oflag = 0; // normalni nastaveni
LineFlags.c_cflag = CS8 | CREAD | CLOCAL; // 8-bit, povol prijem
LineFlags.c_lflag = 0; // Raw input bez echa
LineFlags.c_cc [VMIN] = 1; // minimalni pocet znaku pro cteni
LineFlags.c_cc [VTIME] = 1; // read timeout 0.1 s
tcsetattr (fd, TCSANOW, &LineFlags);
fcntl (fd, F_SETFL, 0);
int flag = TIOCM_DTR;
ioctl(fd, TIOCMBIS, & flag);
printf ("Port %s opened (%d)\r\n", name, fd);
usleep (1000);
running = true;
return true;
}
void WsClient::stop() {
cout << "Client Stop\n";
epoll_ctl (pollfd, EPOLL_CTL_DEL, fd, nullptr);
int flag = TIOCM_DTR;
ioctl(fd, TIOCMBIC, & flag);
::close (fd);
running = false;
}
void WsClient::receive() {
if (!running) return;
const int recmax = 64;
char tmpbuf [recmax];
ssize_t r = ::read (fd, tmpbuf, recmax);
bool end = false;
for (int n=0; n<r; n++) {
const char c = tmpbuf [n];
if (c == '\r') continue;
if (c == '\n') {end = true; break;}
recbuff [recindex++] = c;
}
if (end) {
recbuff [recindex++] = '@';
recbuff [recindex ] = '\0';
received_pack();
}
}
void WsClient::received_pack() {
//printf("(%d)received:%s\n", recindex, recbuff);
parse_input (recbuff, recindex);
recindex = 0;
}
void WsClient::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 '@':
parse_packet();
state = StateIdle;
packet_cnt = 0;
break;
default:
packet_buf [packet_cnt] = c;
packet_cnt += 1;
if (packet_cnt >= DATASIZE) {
packet_cnt = 0;
printf ("Buffer overflow\n");
}
break;
}
}
}
void WsClient::parse_header() {
if (packet_cnt != 4) return;
packet_buf [4] = '\0';
const long hdr = strtoul (packet_buf, nullptr, 16);
header.common = hdr;
/*
//qDebug ("header:%04X", hdr);
if (header.bits.trig_flg) {
emit PaketTriggered ();
}
*/
}
void WsClient::parse_packet() {
vector<int> ChA, ChB;
if (state != StateData) return;
int k=0;
for (int n=0; n<packet_cnt; n+=3) {
char buf [4];
memcpy (buf, packet_buf + n, 3);
buf[3] = '\0';
const int sample = strtol (buf, nullptr, 16);
if (k & 1) {
ChB.push_back (sample);
} else {
ChA.push_back (sample);
}
k += 1;
}
bool sok = true;
const int Al = ChA.size(), Bl = ChB.size();
if (Al != (int) header.bits.pack_len) sok = false;
if (Bl != (int) header.bits.pack_len) sok = false;
if (sok) {
string outs = channels_to_json(ChA, ChB);
// cout << outs << endl;
ws->send(outs);
/*
if (trigerSettings.mode == TRIGER_MODE_SINGLE) {
if (catching) {
catching = false;
emit Channels_received (ChA, ChB);
}
} else {
emit Channels_received (ChA, ChB);
}
*/
} else {
printf ("packet error: ChA=%d, ChB=%d, size=%d\n", Al, Bl, header.bits.pack_len);
}
}
/*******************************************************************/
void WsClient::send(const char * data) {
// cout << "data is \"" << data << "\"\n"; // prijata data
json received = json::parse (string (data));
int value = 0;
if (!received["value"].is_null()) {
received["value"].get_to (value);
}
string type;
if (!received["type"].is_null()) {
received["type"].get_to (type);
if (type == "trg_src") {
SendTrigerChan(value);
} else if (type == "trg_mod") {
SendTrigerMode(value);
} else if (type == "trg_edg") {
SendTrigerEdge(value);
} else if (type == "trg_val") {
trigerSettings.value = value;
SettingChanged(0);
} else if (type == "trg_ofs") {
trigerSettings.offset = value;
SettingChanged(1);
} else if (type == "tim_bas") {
SendBaseRange(value);
} else if (type == "start") {
Start ();
}
}
// cout << "type=" << type << ", value=" << value << endl;
}
void WsClient::SendTrigerChan(int n) {
trigerSettings.channel = static_cast<ADC_CHANNELS> (n);
send_trig_mode();
}
void WsClient::SendTrigerMode(int n) {
trigerSettings.mode = static_cast<TRIGER_MODE> (n);
send_trig_mode();
}
void WsClient::SendTrigerEdge(int n) {
trigerSettings.rising = n ? true : false;
send_trig_mode();
}
void WsClient::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';
write (buffer, r);
}
void WsClient::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';
write (buffer, r);
}
void WsClient::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';
write (buffer, r);
}
int WsClient::write(const char * data, const int len) {
string out (data, len);
cout << out;
int r = ::write (fd, data, len);
(void) r;
//ws->send(out);
return len;
}
void WsClient::Start() {
}

View file

@ -0,0 +1,62 @@
#ifndef WSCLIENT_H
#define WSCLIENT_H
#include "seasocks/Server.h"
#include "seasocks/WebSocket.h"
#include <filesystem>
#include <chrono>
#include <string>
#include "structures.h"
static constexpr int DATASIZE = 0x2000;
enum ParserState {
StateIdle = 0,
StateHeader,
StateData,
};
class WsClient {
seasocks::WebSocket * ws;
int & pollfd;
TrigerSettings trigerSettings;
bool running;
int fd;
const size_t reclen;
char * recbuff;
int recindex;
ParserState state;
int packet_cnt;
char * packet_buf;
SendHeader header;
public:
explicit WsClient(seasocks::WebSocket * p, int & fd) : ws (p), pollfd (fd),
trigerSettings(), running(false), fd(0), reclen(0x4000ul),
recindex(0), state(StateIdle), packet_cnt(0) {
recbuff = new char [reclen];
packet_buf = new char [DATASIZE];
}
virtual ~WsClient() {
delete [] recbuff;
delete [] packet_buf;
};
bool start ();
void stop ();
void send (const char * data);
void receive ();
protected:
void SendTrigerMode (int n);
void SendTrigerEdge (int n);
void SendTrigerChan (int n);
void SendBaseRange (int n);
void SettingChanged (int n);
void Start ();
void send_trig_mode ();
int write (const char * data, const int len);
void received_pack ();
void parse_input (const char * data, const long len);
void parse_header ();
void parse_packet ();
};
#endif // WSCLIENT_H

View file

@ -101,7 +101,9 @@ void DataSource::parse_packet() {
if ((al != 1ul) and (al != 1024ul)) { qDebug ("A packet len = %zd", al); }
if ((bl != 1ul) and (bl != 1024ul)) { qDebug ("B packet len = %zd", bl); }
if (sok) {
if (trigerSettings.mode == TRIGER_MODE_SINGLE) {
if ((al == 1ul) or (bl == 1ul)) { // v kontinuálním módu odešli vždy
emit Channels_received (ChA, ChB);
} else if (trigerSettings.mode == TRIGER_MODE_SINGLE) {
if (catching) {
catching = false;
emit Channels_received (ChA, ChB);