Compare commits
No commits in common. "1095da2beaa8196c4b82fdce9b2275cdd5344937" and "b2c0bc43feab4b816c06512d319065cd79fb571d" have entirely different histories.
1095da2bea
...
b2c0bc43fe
10 changed files with 2 additions and 783 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -15,9 +15,7 @@
|
|||
V203/pwm/sin.c
|
||||
V203/gsm/lib/libgsm.a
|
||||
V203/usb/cdc/mystrings.inc
|
||||
V203/usb/scope/bin/osciloscope
|
||||
V203/usb/scope/bin/wserver
|
||||
V203/usb/scope/server/*.o
|
||||
V203/usb/scope/bin/*
|
||||
V203/usb/scope/software/.qmake.stash
|
||||
V203/usb/scope/software/Makefile
|
||||
V203/usb/scope/software/moc/*
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
# 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.
|
|
@ -1,93 +0,0 @@
|
|||
<!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>
|
|
@ -1,203 +0,0 @@
|
|||
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 });
|
||||
};
|
|
@ -1,20 +0,0 @@
|
|||
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 $@
|
|
@ -1,97 +0,0 @@
|
|||
#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;
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
../firmware/structures.h
|
|
@ -1,275 +0,0 @@
|
|||
#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() {
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
#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
|
|
@ -101,9 +101,7 @@ 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 ((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 (trigerSettings.mode == TRIGER_MODE_SINGLE) {
|
||||
if (catching) {
|
||||
catching = false;
|
||||
emit Channels_received (ChA, ChB);
|
||||
|
|
Loading…
Reference in a new issue