RISC-V/V203/usb/scope/server/wsclient.cpp
2024-10-26 14:32:07 +02:00

310 lines
8.2 KiB
C++

#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) {
json msg;
msg["a"] = a;
msg["b"] = b;
return to_string(msg);
}
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);
const int r = ::write (fd, "?\r\n", 3);
(void) r;
running = true;
return running;
}
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 = StateReply;
packet_cnt = 0;
break;
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 ();
}
*/
}
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);
}
void WsClient::parse_packet() {
if (state == StateReply) {
packet_buf[packet_cnt] = '\0';
parse_reply(packet_buf, packet_cnt);
return;
}
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) {
if (!running) return 0;
string out (data, len);
cout << out;
int r = ::write (fd, data, len);
(void) r;
//ws->send(out);
return len;
}
void WsClient::Start() {
}