2024-10-25 15:20:26 +02:00
|
|
|
#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) {
|
2024-10-26 14:32:07 +02:00
|
|
|
json msg;
|
|
|
|
msg["a"] = a;
|
|
|
|
msg["b"] = b;
|
|
|
|
return to_string(msg);
|
2024-10-25 15:20:26 +02:00
|
|
|
}
|
|
|
|
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);
|
2024-10-26 12:22:17 +02:00
|
|
|
const int r = ::write (fd, "?\r\n", 3);
|
|
|
|
(void) r;
|
2024-10-25 15:20:26 +02:00
|
|
|
running = true;
|
2024-10-25 19:58:06 +02:00
|
|
|
return running;
|
2024-10-25 15:20:26 +02:00
|
|
|
}
|
|
|
|
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) {
|
2024-10-26 12:22:17 +02:00
|
|
|
case '!':
|
|
|
|
state = StateReply;
|
|
|
|
packet_cnt = 0;
|
|
|
|
break;
|
2024-10-25 15:20:26 +02:00
|
|
|
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 ();
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
}
|
2024-10-26 12:22:17 +02:00
|
|
|
static uint8_t from_hex (const char * ptr) {
|
|
|
|
uint8_t result = 0u;
|
|
|
|
for (unsigned n=0; n<2u; n++) {
|
|
|
|
result *= 0x10;
|
|
|
|
const char c = ptr [n];
|
|
|
|
const uint8_t v = c > '9' ? c - 'A' + 10 : c - '0';
|
|
|
|
result += v;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
void WsClient::parse_reply(const char * data, const int len) {
|
|
|
|
printf("(%d):%s\n", len, data);
|
|
|
|
TrigerSettings ts;
|
|
|
|
AllSettings as (ts, 0);
|
|
|
|
const int bl = len >> 1;
|
|
|
|
int k = 0;
|
|
|
|
for (int n=0; n<bl; n++) {
|
|
|
|
as.common [n] = from_hex (data + k);
|
|
|
|
k += 2;
|
|
|
|
}
|
|
|
|
json msg;
|
|
|
|
msg["channel"] = as.part.trg.channel;
|
|
|
|
msg["mode"] = as.part.trg.mode;
|
|
|
|
msg["rising"] = as.part.trg.rising ? 1 : 0;
|
|
|
|
msg["offset"] = as.part.trg.offset;
|
|
|
|
msg["value"] = as.part.trg.value;
|
|
|
|
msg["tim"] = as.part.tim;
|
|
|
|
string s = to_string (msg);
|
|
|
|
cout << s << endl;
|
|
|
|
ws->send(s);
|
|
|
|
}
|
2024-10-25 15:20:26 +02:00
|
|
|
void WsClient::parse_packet() {
|
2024-10-26 12:22:17 +02:00
|
|
|
if (state == StateReply) {
|
|
|
|
packet_buf[packet_cnt] = '\0';
|
|
|
|
parse_reply(packet_buf, packet_cnt);
|
|
|
|
return;
|
|
|
|
}
|
2024-10-25 15:20:26 +02:00
|
|
|
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) {
|
2024-10-25 19:58:06 +02:00
|
|
|
if (!running) return 0;
|
2024-10-25 15:20:26 +02:00
|
|
|
string out (data, len);
|
|
|
|
cout << out;
|
|
|
|
int r = ::write (fd, data, len);
|
|
|
|
(void) r;
|
|
|
|
//ws->send(out);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
void WsClient::Start() {
|
|
|
|
}
|
|
|
|
|