1157 lines
38 KiB
C++
1157 lines
38 KiB
C++
/*
|
|
PIP - Platform Independent Primitives
|
|
Console output/input
|
|
Copyright (C) 2018 Ivan Pelipenko peri4ko@yandex.ru
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "piconsole.h"
|
|
#include "piincludes_p.h"
|
|
#include "pipeer.h"
|
|
#include "pidiagnostics.h"
|
|
#include "pisystemmonitor.h"
|
|
#ifndef WINDOWS
|
|
# include <sys/ioctl.h>
|
|
# include <fcntl.h>
|
|
# include <termios.h>
|
|
#else
|
|
# include <wincon.h>
|
|
# define COMMON_LVB_UNDERSCORE 0x8000
|
|
#endif
|
|
|
|
|
|
/** \class PIConsole
|
|
* \brief Console output class
|
|
* \details
|
|
* \section PIConsole_sec0 Synopsis
|
|
* This class provides output to console with automatic alignment and update.
|
|
* It supports tabs, keyboard listening, formats and colors.
|
|
*
|
|
* \section PIConsole_sec1 Layout
|
|
* %PIConsole works with variable pointers. You should add your variables with
|
|
* functions \a addVariable() which receives label name, pointer to variable
|
|
* and optional column and format. Columns count is dynamically increased if
|
|
* new column used. E.g. if you add variable to empty tab to column 3, columns
|
|
* count will be increased to 3, but two firsts columns will be empty. Each column
|
|
* filled from top to bottom, but you can add just string with function
|
|
* \a addString() or add empty line with function \a addEmptyLine(). Layout scheme:
|
|
* \image html piconsole_layout.png
|
|
*
|
|
* \section PIConsole_sec2 Keyboard usage
|
|
* %PIConsole should to be single in application. %PIConsole aggregate PIKbdListener
|
|
* which grab keyboard and automatic switch tabs by theirs bind keys. If there is no
|
|
* tab binded to pressed key external function "slot" will be called
|
|
*
|
|
**/
|
|
|
|
|
|
PRIVATE_DEFINITION_START(PIConsole)
|
|
#ifdef WINDOWS
|
|
void getWinCurCoord() {GetConsoleScreenBufferInfo(hOut, &csbi); ccoord = csbi.dwCursorPosition;}
|
|
COORD & getWinCoord(int dx = 0, int dy = 0) {getWinCurCoord(); ccoord.X += dx; ccoord.Y += dy; return ccoord;}
|
|
void * hOut;
|
|
CONSOLE_SCREEN_BUFFER_INFO sbi, csbi;
|
|
CONSOLE_CURSOR_INFO curinfo;
|
|
COORD ccoord, ulcoord;
|
|
WORD dattr;
|
|
DWORD smode, written;
|
|
#endif
|
|
PRIVATE_DEFINITION_END(PIConsole)
|
|
|
|
|
|
PIConsole::PIConsole(bool startNow, PIKbdListener::KBFunc slot): PIThread() {
|
|
setName("console");
|
|
setPriority(piLow);
|
|
needLockRun(true);
|
|
ret_func = slot;
|
|
num_format = systime_format = 0;
|
|
vid = 0;
|
|
cur_tab = width = height = pwidth = pheight = max_y = 0;
|
|
def_align = Nothing;
|
|
tabs.reserve(16);
|
|
#ifdef WINDOWS
|
|
PRIVATE->ulcoord.X = 0;
|
|
PRIVATE->hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
|
PRIVATE->dattr = PRIVATE->sbi.wAttributes;
|
|
width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
|
|
height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
|
|
PRIVATE->ulcoord.Y = PRIVATE->sbi.srWindow.Top;
|
|
GetConsoleMode(PRIVATE->hOut, &PRIVATE->smode);
|
|
GetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
|
#else
|
|
winsize ws;
|
|
ioctl(0, TIOCGWINSZ, &ws);
|
|
width = ws.ws_col;
|
|
height = ws.ws_row;
|
|
#endif
|
|
tabs.reserve(16);
|
|
addTab("main");
|
|
listener = new PIKbdListener(key_event, this);
|
|
peer_timer = new PITimer();
|
|
peer = 0;
|
|
server_mode = pause_ = false;
|
|
state = Disconnected;
|
|
peer_timer->addDelimiter(20);
|
|
peer_timer->setName("__S__PIConsole::peer_timer");
|
|
CONNECT2(void, void * , int, peer_timer, tickEvent, this, peerTimer);
|
|
if (startNow) start();
|
|
}
|
|
|
|
|
|
PIConsole::~PIConsole() {
|
|
stopPeer();
|
|
if (isRunning())
|
|
stop();
|
|
clearTabs(false);
|
|
delete listener;
|
|
delete peer_timer;
|
|
#ifdef WINDOWS
|
|
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
|
|
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
|
|
#endif
|
|
}
|
|
|
|
|
|
int PIConsole::addTab(const PIString & name, char bind_key) {
|
|
if (isRunning()) lock();
|
|
tabs.push_back(Tab(name, bind_key));
|
|
cur_tab = tabs.size() - 1;
|
|
if (isRunning()) unlock();
|
|
return tabs.size();
|
|
}
|
|
|
|
|
|
void PIConsole::removeTab(uint index) {
|
|
if (index >= tabs.size()) return;
|
|
if (isRunning()) lock();
|
|
tabs.remove(index);
|
|
if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1;
|
|
if (isRunning()) unlock();
|
|
}
|
|
|
|
|
|
void PIConsole::removeTab(const PIString & name) {
|
|
uint index = tabs.size() + 1;
|
|
for (uint i = 0; i < tabs.size(); ++i) {
|
|
if (tabs[i].name == name) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
removeTab(index);
|
|
}
|
|
|
|
|
|
void PIConsole::clearTab(uint index) {
|
|
if (index >= tabs.size()) return;
|
|
lock();
|
|
tabs[index].columns.clear();
|
|
if (cur_tab == index) {
|
|
clearScreen();
|
|
fillLabels();
|
|
}
|
|
if (cur_tab >= tabs.size()) cur_tab = tabs.size() - 1;
|
|
unlock();
|
|
}
|
|
|
|
|
|
void PIConsole::clearTab(const PIString & name) {
|
|
uint index = tabs.size() + 1;
|
|
for (uint i = 0; i < tabs.size(); ++i) {
|
|
if (tabs[i].name == name) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
clearTab(index);
|
|
}
|
|
|
|
|
|
void PIConsole::update() {
|
|
lock();
|
|
fillLabels();
|
|
unlock();
|
|
}
|
|
|
|
|
|
bool PIConsole::setTab(uint index) {
|
|
if (index >= tabs.size())
|
|
return false;
|
|
if (!isRunning()) {
|
|
cur_tab = index;
|
|
return true;
|
|
}
|
|
lock();
|
|
PICout::__mutex__().lock();
|
|
cur_tab = index;
|
|
clearScreen();
|
|
fillLabels();
|
|
PICout::__mutex__().unlock();
|
|
unlock();
|
|
return true;
|
|
}
|
|
|
|
|
|
bool PIConsole::setTab(const PIString & name) {
|
|
uint index = tabs.size() + 1;
|
|
for (uint i = 0; i < tabs.size(); ++i) {
|
|
if (tabs[i].name == name) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
return setTab(index);
|
|
}
|
|
|
|
|
|
bool PIConsole::setTabBindKey(uint index, char bind_key) {
|
|
if (index >= tabs.size())
|
|
return false;
|
|
tabs[index].key = bind_key;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool PIConsole::setTabBindKey(const PIString & name, char bind_key) {
|
|
uint index =tabs.size() + 1;
|
|
for (uint i = 0; i < tabs.size(); ++i) {
|
|
if (tabs[i].name == name) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
return setTabBindKey(index, bind_key);
|
|
}
|
|
|
|
|
|
void PIConsole::key_event(PIKbdListener::KeyEvent key, void * t) {
|
|
PIConsole * p = (PIConsole * )t;
|
|
int ct = p->cur_tab;
|
|
if (key.key == PIKbdListener::LeftArrow) {
|
|
do {
|
|
ct--;
|
|
if (ct < 0) return;
|
|
} while (p->tabs[ct].key == 0);
|
|
p->setTab(ct);
|
|
return;
|
|
}
|
|
if (key.key == PIKbdListener::RightArrow) {
|
|
do {
|
|
ct++;
|
|
if (ct >= p->tabs.size_s()) return;
|
|
} while (p->tabs[ct].key == 0);
|
|
p->setTab(ct);
|
|
return;
|
|
}
|
|
for (uint i = 0; i < p->tabsCount(); ++i) {
|
|
if (p->tabs[i].key == key.key) {
|
|
p->setTab(i);
|
|
return;
|
|
}
|
|
}
|
|
if (p->ret_func != 0) p->ret_func(key, t);
|
|
p->keyPressed(key, t);
|
|
}
|
|
|
|
|
|
int PIConsole::couts(const PIString & v) {
|
|
return printf("%s", v.data());
|
|
}
|
|
|
|
|
|
int PIConsole::couts(const char * v) {
|
|
return printf("%s", v);
|
|
}
|
|
|
|
|
|
void PIConsole::clearVariables(bool clearScreen) {
|
|
if (isRunning()) lock();
|
|
if (clearScreen && isRunning()) {
|
|
toUpperLeft();
|
|
clearScreenLower();
|
|
}
|
|
columns().clear();
|
|
if (isRunning()) unlock();
|
|
}
|
|
|
|
|
|
void PIConsole::stop(bool clear) {
|
|
PIThread::stop(true);
|
|
if (clear) clearScreen();
|
|
moveTo(0, max_y + 4);
|
|
showCursor();
|
|
couts(fstr(Normal));
|
|
#ifdef WINDOWS
|
|
SetConsoleMode(PRIVATE->hOut, PRIVATE->smode);
|
|
SetConsoleTextAttribute(PRIVATE->hOut, PRIVATE->dattr);
|
|
#endif
|
|
fflush(0);
|
|
}
|
|
|
|
|
|
PIString PIConsole::fstr(FormatFlags f) {
|
|
num_format = systime_format = 0;
|
|
if (f[PIConsole::Dec]) num_format = 0;
|
|
if (f[PIConsole::Hex]) num_format = 1;
|
|
if (f[PIConsole::Oct]) num_format = 2;
|
|
if (f[PIConsole::Bin]) num_format = 4;
|
|
if (f[PIConsole::Scientific]) num_format = 3;
|
|
if (f[PIConsole::SystemTimeSplit]) systime_format = 0;
|
|
if (f[PIConsole::SystemTimeSeconds]) systime_format = 1;
|
|
|
|
#ifdef WINDOWS
|
|
WORD attr = 0;
|
|
|
|
if (f[PIConsole::Inverse]) {
|
|
if (f[PIConsole::Red]) attr |= BACKGROUND_RED;
|
|
if (f[PIConsole::Green]) attr |= BACKGROUND_GREEN;
|
|
if (f[PIConsole::Blue]) attr |= BACKGROUND_BLUE;
|
|
if (f[PIConsole::Yellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN);
|
|
if (f[PIConsole::Magenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE);
|
|
if (f[PIConsole::Cyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE);
|
|
if (f[PIConsole::White]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
|
if (f[PIConsole::BackRed]) attr |= FOREGROUND_RED;
|
|
if (f[PIConsole::BackGreen]) attr |= FOREGROUND_GREEN;
|
|
if (f[PIConsole::BackBlue]) attr |= FOREGROUND_BLUE;
|
|
if (f[PIConsole::BackYellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN);
|
|
if (f[PIConsole::BackMagenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE);
|
|
if (f[PIConsole::BackCyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE);
|
|
if (f[PIConsole::BackWhite]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
|
if ((attr & BACKGROUND_RED) + (attr & BACKGROUND_GREEN) + (attr & BACKGROUND_BLUE) == 0)
|
|
attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
|
} else {
|
|
if (f[PIConsole::Red]) attr |= FOREGROUND_RED;
|
|
if (f[PIConsole::Green]) attr |= FOREGROUND_GREEN;
|
|
if (f[PIConsole::Blue]) attr |= FOREGROUND_BLUE;
|
|
if (f[PIConsole::Yellow]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN);
|
|
if (f[PIConsole::Magenta]) attr |= (FOREGROUND_RED | FOREGROUND_BLUE);
|
|
if (f[PIConsole::Cyan]) attr |= (FOREGROUND_GREEN | FOREGROUND_BLUE);
|
|
if (f[PIConsole::White]) attr |= (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
|
if (f[PIConsole::BackRed]) attr |= BACKGROUND_RED;
|
|
if (f[PIConsole::BackGreen]) attr |= BACKGROUND_GREEN;
|
|
if (f[PIConsole::BackBlue]) attr |= BACKGROUND_BLUE;
|
|
if (f[PIConsole::BackYellow]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN);
|
|
if (f[PIConsole::BackMagenta]) attr |= (BACKGROUND_RED | BACKGROUND_BLUE);
|
|
if (f[PIConsole::BackCyan]) attr |= (BACKGROUND_GREEN | BACKGROUND_BLUE);
|
|
if (f[PIConsole::BackWhite]) attr |= (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
|
|
if ((attr & FOREGROUND_RED) + (attr & FOREGROUND_GREEN) + (attr & FOREGROUND_BLUE) == 0)
|
|
attr |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
|
}
|
|
if (f[PIConsole::Bold]) attr |= FOREGROUND_INTENSITY;
|
|
if (f[PIConsole::Underline]) attr |= COMMON_LVB_UNDERSCORE;
|
|
|
|
SetConsoleTextAttribute(PRIVATE->hOut, attr);
|
|
return PIString();
|
|
#else
|
|
PIString ts("\e[0");
|
|
|
|
if (f[PIConsole::Bold]) ts += ";1";
|
|
if (f[PIConsole::Faint]) ts += ";2";
|
|
if (f[PIConsole::Italic]) ts += ";3";
|
|
if (f[PIConsole::Underline]) ts += ";4";
|
|
if (f[PIConsole::Blink]) ts += ";5";
|
|
if (f[PIConsole::Inverse]) ts += ";7";
|
|
|
|
if (f[PIConsole::Black]) ts += ";30";
|
|
if (f[PIConsole::Red]) ts += ";31";
|
|
if (f[PIConsole::Green]) ts += ";32";
|
|
if (f[PIConsole::Yellow]) ts += ";33";
|
|
if (f[PIConsole::Blue]) ts += ";34";
|
|
if (f[PIConsole::Magenta]) ts += ";35";
|
|
if (f[PIConsole::Cyan]) ts += ";36";
|
|
if (f[PIConsole::White]) ts += ";37";
|
|
|
|
if (f[PIConsole::BackBlack]) ts += ";40";
|
|
if (f[PIConsole::BackRed]) ts += ";41";
|
|
if (f[PIConsole::BackGreen]) ts += ";42";
|
|
if (f[PIConsole::BackYellow]) ts += ";43";
|
|
if (f[PIConsole::BackBlue]) ts += ";44";
|
|
if (f[PIConsole::BackMagenta]) ts += ";45";
|
|
if (f[PIConsole::BackCyan]) ts += ";46";
|
|
if (f[PIConsole::BackWhite]) ts += ";47";
|
|
|
|
return ts + "m";
|
|
#endif
|
|
}
|
|
|
|
|
|
inline int PIConsole::couts(const bool v) {return (v ? printf("true") : printf("false"));}
|
|
inline int PIConsole::couts(const char v) {return printf("%c", v);}
|
|
inline int PIConsole::couts(const short v) {
|
|
switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hd", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const int v) {
|
|
switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%d", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const long v) {
|
|
switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%ld", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const llong v) {
|
|
switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lld", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const uchar v) {
|
|
switch (num_format) {case (1): return printf("0x%.2X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 1)); break; default: return printf("%u", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const ushort v) {
|
|
switch (num_format) {case (1): return printf("0x%.4hX", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 2)); break; default: return printf("%hu", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const uint v) {
|
|
switch (num_format) {case (1): return printf("0x%.8X", v); break; case (2): return printf("%o", v); break; case (4): return printf("%s", toBin(&v, 4)); break; default: return printf("%u", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const ulong v) {
|
|
switch (num_format) {case (1): return printf("0x%.16lX", v); break; case (2): return printf("%lo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%lu", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const ullong v) {
|
|
switch (num_format) {case (1): return printf("0x%.16llX", v); break; case (2): return printf("%llo", v); break; case (4): return printf("%s", toBin(&v, sizeof(v))); break; default: return printf("%llu", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const float v) {
|
|
switch (num_format) {case (3): return printf("%e", v); break; default: return printf("%.5g", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const double v) {
|
|
switch (num_format) {case (3): return printf("%le", v); break; default: return printf("%.5lg", v); break;}
|
|
}
|
|
inline int PIConsole::couts(const PISystemTime & v) {
|
|
switch (systime_format) {case (1): return printf("%.6lg", v.toSeconds()); break;
|
|
default: return couts(v.seconds) + printf(" s, ") + couts(v.nanoseconds) + printf(" ns"); break;}
|
|
}
|
|
|
|
|
|
void PIConsole::toUpperLeft() {
|
|
#ifdef WINDOWS
|
|
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ulcoord);
|
|
#else
|
|
printf("\e[H");
|
|
#endif
|
|
}
|
|
|
|
void PIConsole::moveRight(int n) {
|
|
#ifdef WINDOWS
|
|
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(n));
|
|
#else
|
|
if (n > 0) printf("\e[%dC", n);
|
|
#endif
|
|
}
|
|
|
|
void PIConsole::moveLeft(int n) {
|
|
#ifdef WINDOWS
|
|
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->getWinCoord(-n));
|
|
#else
|
|
if (n > 0) printf("\e[%dD", n);
|
|
#endif
|
|
}
|
|
|
|
void PIConsole::moveTo(int x, int y) {
|
|
#ifdef WINDOWS
|
|
PRIVATE->ccoord.X = x;
|
|
PRIVATE->ccoord.Y = PRIVATE->ulcoord.Y + y;
|
|
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
|
|
#else
|
|
printf("\e[%d;%dH", y, x);
|
|
#endif
|
|
}
|
|
|
|
void PIConsole::clearScreen() {
|
|
#ifdef WINDOWS
|
|
couts(fstr(Normal));
|
|
toUpperLeft();
|
|
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written);
|
|
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * (height + 1), PRIVATE->ulcoord, &PRIVATE->written);
|
|
#else
|
|
couts(fstr(Normal)); printf("\e[H\e[J");
|
|
#endif
|
|
}
|
|
|
|
void PIConsole::clearScreenLower() {
|
|
#ifdef WINDOWS
|
|
couts(fstr(Normal));
|
|
PRIVATE->getWinCurCoord();
|
|
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
|
|
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width * height - width * PRIVATE->ccoord.Y + PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
|
|
#else
|
|
couts(fstr(Normal)); printf("\e[J");
|
|
#endif
|
|
}
|
|
|
|
void PIConsole::clearLine() {
|
|
#ifdef WINDOWS
|
|
PRIVATE->getWinCurCoord();
|
|
FillConsoleOutputAttribute(PRIVATE->hOut, PRIVATE->dattr, width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
|
|
FillConsoleOutputCharacter(PRIVATE->hOut, ' ', width - PRIVATE->ccoord.X, PRIVATE->ccoord, &PRIVATE->written);
|
|
#else
|
|
printf("\e[K");
|
|
#endif
|
|
}
|
|
|
|
void PIConsole::newLine() {
|
|
#ifdef WINDOWS
|
|
PRIVATE->getWinCurCoord();
|
|
PRIVATE->ccoord.X = 0; PRIVATE->ccoord.Y++;
|
|
SetConsoleCursorPosition(PRIVATE->hOut, PRIVATE->ccoord);
|
|
#else
|
|
printf("\eE");
|
|
#endif
|
|
}
|
|
|
|
void PIConsole::hideCursor() {
|
|
#ifdef WINDOWS
|
|
PRIVATE->curinfo.bVisible = false;
|
|
SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
|
#else
|
|
printf("\e[?25l");
|
|
#endif
|
|
}
|
|
|
|
void PIConsole::showCursor() {
|
|
#ifdef WINDOWS
|
|
PRIVATE->curinfo.bVisible = true; SetConsoleCursorInfo(PRIVATE->hOut, &PRIVATE->curinfo);
|
|
#else
|
|
printf("\e[?25h");
|
|
#endif
|
|
}
|
|
|
|
|
|
void PIConsole::begin() {
|
|
#ifdef WINDOWS
|
|
SetConsoleMode(PRIVATE->hOut, ENABLE_WRAP_AT_EOL_OUTPUT);
|
|
#endif
|
|
max_y = 0;
|
|
PICout::__mutex__().lock();
|
|
clearScreen();
|
|
hideCursor();
|
|
fillLabels();
|
|
PICout::__mutex__().unlock();
|
|
}
|
|
|
|
|
|
void PIConsole::run() {
|
|
if (pause_) return;
|
|
uint cx, clen = 0;
|
|
int j;
|
|
#ifdef WINDOWS
|
|
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
|
width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
|
|
height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
|
|
#else
|
|
winsize ws;
|
|
ioctl(0, TIOCGWINSZ, &ws);
|
|
width = ws.ws_col;
|
|
height = ws.ws_row;
|
|
#endif
|
|
//fflush(0); return;
|
|
PICout::__mutex__().lock();
|
|
if (pwidth != width || pheight != height) {
|
|
clearScreen();
|
|
fillLabels();
|
|
}
|
|
pwidth = width;
|
|
pheight = height;
|
|
col_cnt = columns().size();
|
|
col_wid = (col_cnt > 0) ? width / col_cnt : width;
|
|
for (uint i = 0; i < col_cnt; ++i) {
|
|
PIVector<Variable> & cvars(tabs[cur_tab].columns[i].variables);
|
|
cx = col_wid * i;
|
|
toUpperLeft();
|
|
if (max_y < cvars.size()) max_y = cvars.size();
|
|
j = 0;
|
|
piForeachC (Variable & tv_, cvars) {
|
|
if (j > height - 3) continue;
|
|
j++;
|
|
moveRight(cx);
|
|
if (tv_.type == 15) {
|
|
newLine();
|
|
continue;
|
|
}
|
|
moveRight(tv_.offset);
|
|
const void * ptr = 0;
|
|
if (tv_.remote) {
|
|
if (tv_.type == 0) {
|
|
rstr.clear();
|
|
rba = tv_.rdata;
|
|
rba >> rstr;
|
|
rstr.trim();
|
|
ptr = &rstr;
|
|
} else
|
|
ptr = tv_.rdata.data();
|
|
} else
|
|
ptr = tv_.ptr;
|
|
switch (tv_.type) {
|
|
case 0: clen = printValue(ptr != 0 ? *(const PIString*)ptr : PIString(), tv_.format); break;
|
|
case 1: clen = printValue(ptr != 0 ? *(const bool*)ptr : false, tv_.format); break;
|
|
case 2: clen = printValue(ptr != 0 ? *(const int*)ptr : 0, tv_.format); break;
|
|
case 3: clen = printValue(ptr != 0 ? *(const long*)ptr : 0l, tv_.format); break;
|
|
case 4: clen = printValue(ptr != 0 ? *(const char*)ptr : char(0), tv_.format); break;
|
|
case 5: clen = printValue(ptr != 0 ? *(const float*)ptr : 0.f, tv_.format); break;
|
|
case 6: clen = printValue(ptr != 0 ? *(const double*)ptr : 0., tv_.format); break;
|
|
case 7: clen = printValue(ptr != 0 ? *(const short*)ptr : short(0), tv_.format); break;
|
|
case 8: clen = printValue(ptr != 0 ? *(const uint*)ptr : 0u, tv_.format); break;
|
|
case 9: clen = printValue(ptr != 0 ? *(const ulong*)ptr : 0ul, tv_.format); break;
|
|
case 10: clen = printValue(ptr != 0 ? *(const ushort*)ptr : ushort(0), tv_.format); break;
|
|
case 11: clen = printValue(ptr != 0 ? *(const uchar*)ptr : uchar(0), tv_.format); break;
|
|
case 12: clen = printValue(ptr != 0 ? *(const llong*)ptr : 0l, tv_.format); break;
|
|
case 13: clen = printValue(ptr != 0 ? *(const ullong*)ptr: 0ull, tv_.format); break;
|
|
case 20: clen = printValue(ptr != 0 ? *(const PISystemTime*)ptr: PISystemTime(), tv_.format); break;
|
|
case 14: clen = printValue(bitsValue(ptr, tv_.bitFrom, tv_.bitCount), tv_.format); break;
|
|
}
|
|
if (clen + tv_.offset < (uint)col_wid) {
|
|
PIString ts = PIString(
|
|
#if defined(QNX) || defined(FREE_BSD)
|
|
col_wid - clen - tv_.offset - 1, ' ');
|
|
#else
|
|
col_wid - clen - tv_.offset, ' ');
|
|
#endif
|
|
printf("%s", ts.data());
|
|
}
|
|
newLine();
|
|
}
|
|
}
|
|
#ifdef WINDOWS
|
|
moveTo(0, max_y + 1);
|
|
#else
|
|
moveTo(0, max_y + 2);
|
|
#endif
|
|
fflush(0);
|
|
PICout::__mutex__().unlock();
|
|
}
|
|
|
|
|
|
void PIConsole::fillLabels() {
|
|
if (!isRunning()) return;
|
|
uint cx, cy, mx = 0, dx;
|
|
#ifdef WINDOWS
|
|
GetConsoleScreenBufferInfo(PRIVATE->hOut, &PRIVATE->sbi);
|
|
width = PRIVATE->sbi.srWindow.Right - PRIVATE->sbi.srWindow.Left;
|
|
height = PRIVATE->sbi.srWindow.Bottom - PRIVATE->sbi.srWindow.Top;
|
|
#else
|
|
winsize ws;
|
|
ioctl(0, TIOCGWINSZ, &ws);
|
|
width = ws.ws_col;
|
|
height = ws.ws_row;
|
|
#endif
|
|
max_y = 0;
|
|
col_cnt = columns().size();
|
|
col_wid = (col_cnt > 0) ? width / col_cnt : width;
|
|
for (uint i = 0; i < col_cnt; ++i) {
|
|
Column & ccol(tabs[cur_tab].columns[i]);
|
|
PIVector<Variable> & cvars(ccol.variables);
|
|
if (ccol.alignment != Nothing) {
|
|
mx = 0;
|
|
piForeachC (Variable & j, cvars)
|
|
if (!j.isEmpty())
|
|
if (mx < j.name.size())
|
|
mx = j.name.size();
|
|
mx += 2;
|
|
}
|
|
cx = col_wid * i;
|
|
cy = 1;
|
|
toUpperLeft();
|
|
for (uint j = 0; j < cvars.size(); ++j) {
|
|
if (int(j) > height - 3) continue;
|
|
if (max_y < j) max_y = j;
|
|
moveRight(cx);
|
|
Variable & tv_(cvars[j]);
|
|
cvars[j].nx = cx;
|
|
cvars[j].ny = cy;
|
|
if (tv_.name.isEmpty()) {
|
|
cvars[j].offset = 0;
|
|
clearLine();
|
|
newLine();
|
|
cy++;
|
|
continue;
|
|
}
|
|
clearLine();
|
|
//piCout << tv_.name << tv_.type << tv_.ptr;
|
|
if (tv_.type == 15) {
|
|
cvars[j].offset = cvars[j].name.length();
|
|
cvars[j].nx += cvars[j].offset;
|
|
printLine(tv_.name, cx, tv_.format);
|
|
newLine();
|
|
cy++;
|
|
continue;
|
|
}
|
|
if (!tv_.isEmpty()) {
|
|
switch (ccol.alignment) {
|
|
case Nothing:
|
|
cvars[j].offset = (tv_.name + ": ").length();
|
|
cvars[j].nx += cvars[j].offset;
|
|
printValue(tv_.name + ": ", tv_.format);
|
|
break;
|
|
case Left:
|
|
cvars[j].offset = mx;
|
|
cvars[j].nx += cvars[j].offset;
|
|
printValue(tv_.name + ": ", tv_.format);
|
|
break;
|
|
case Right:
|
|
cvars[j].offset = mx;
|
|
cvars[j].nx += cvars[j].offset;
|
|
dx = mx - (tv_.name + ": ").length();
|
|
moveRight(dx);
|
|
printValue(tv_.name + ": ", tv_.format);
|
|
moveLeft(dx);
|
|
break;
|
|
}
|
|
}
|
|
newLine();
|
|
cy++;
|
|
}
|
|
}
|
|
#ifdef WINDOWS
|
|
moveTo(0, max_y + 1);
|
|
#else
|
|
moveTo(0, max_y + 2);
|
|
#endif
|
|
if (!tabs[cur_tab].status.isEmpty()) {
|
|
printValue(tabs[cur_tab].status);
|
|
newLine();
|
|
}
|
|
status();
|
|
//couts(fstr(Normal));
|
|
//fflush(0);
|
|
}
|
|
|
|
|
|
void PIConsole::status() {
|
|
Tab * ctab;
|
|
//clearLine();
|
|
for (uint i = 0; i < tabsCount(); ++i) {
|
|
ctab = &tabs[i];
|
|
if (ctab->key == 0) continue;
|
|
printValue(ctab->key, PIConsole::White | PIConsole::Bold);
|
|
if (i == cur_tab)
|
|
printValue(ctab->name + " ", PIConsole::BackYellow | PIConsole::Black);
|
|
else
|
|
printValue(ctab->name + " ", PIConsole::Cyan | PIConsole::Inverse);
|
|
printValue(" ");
|
|
}
|
|
newLine();
|
|
}
|
|
|
|
|
|
int PIConsole::bitsValue(const void * src, int offset, int count) const {
|
|
int ret = 0, stbyte = offset / 8, cbit = offset - stbyte * 8;
|
|
char cbyte = reinterpret_cast<const char * >(src)[stbyte];
|
|
for (int i = 0; i < count; i++) {
|
|
ret |= ((cbyte >> cbit & 1) << i);
|
|
cbit++;
|
|
if (cbit == 8) {
|
|
cbit = 0;
|
|
stbyte++;
|
|
cbyte = reinterpret_cast<const char * >(src)[stbyte];
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
const char * PIConsole::toBin(const void * d, int s) {
|
|
binstr.clear();
|
|
uchar cc, b;
|
|
for (int i = 0; i < s; ++i) {
|
|
cc = ((const uchar *)d)[i];
|
|
b = 1;
|
|
for (int j = 0; j < 8; ++j) {
|
|
binstr << (cc & b ? "1" : "0");
|
|
b <<= 1;
|
|
}
|
|
if (i < s - 1) binstr << " ";
|
|
}
|
|
binstr.reverse();
|
|
return binstr.data();
|
|
}
|
|
|
|
|
|
#define ADD_VAR_BODY vid++; tv.id = vid; tv.name = name; tv.bitFrom = tv.bitCount = 0; tv.format = format; tv.remote = false; checkColumn(col);
|
|
|
|
void PIConsole::addString(const PIString & name, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 15; tv.size = 0; tv.ptr = 0; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const PIString * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 0; tv.size = 0; tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const bool * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 1; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const int * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 2; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const long * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 3; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const char * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 4; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const float * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 5; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const double * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 6; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const short * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 7; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const uint * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 8; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const ulong * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 9; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const ushort * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 10; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const uchar * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 11; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const llong * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 12; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const ullong * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 13; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
void PIConsole::addVariable(const PIString & name, const PISystemTime * ptr, int col, FormatFlags format) {
|
|
ADD_VAR_BODY tv.type = 20; tv.size = sizeof(*ptr); tv.ptr = ptr; column(col).push_back(tv);}
|
|
/** \brief Add to current tab to column "column" variable with label "name", pointer "ptr" and format "format"
|
|
* \details This function add to column "column" next lines:
|
|
* * "<name> diagnostics"
|
|
* * "Received count": \a PIDiagnostics::receiveCount
|
|
* * "Invalid count": \a PIDiagnostics::wrongCount
|
|
* * "Sended count": \a PIDiagnostics::sendCount
|
|
* * "Immediate Frequency, Hz": \a PIDiagnostics::immediateFrequency
|
|
* * "Integral Frequency, Hz": \a PIDiagnostics::integralFrequency
|
|
* * "Receive speed": \a PIDiagnostics::receiveSpeed
|
|
* * "Send speed": \a PIDiagnostics::sendSpeed
|
|
* * "Quality": \a PIDiagnostics::quality
|
|
* */
|
|
void PIConsole::addVariable(const PIString & name, const PIDiagnostics * ptr, int col, FormatFlags format) {
|
|
addString(name + " diagnostics", col, format | PIConsole::Bold);
|
|
addVariable("Received count", ptr->receiveCount_ptr(), col, format);
|
|
addVariable("Invalid count", ptr->wrongCount_ptr(), col, format);
|
|
addVariable("Sended count", ptr->sendCount_ptr(), col, format);
|
|
addVariable("Immediate Frequency, Hz", ptr->immediateFrequency_ptr(), col, format);
|
|
addVariable("Integral Frequency, Hz", ptr->integralFrequency_ptr(), col, format);
|
|
addVariable("Receive speed", ptr->receiveSpeed_ptr(), col, format);
|
|
addVariable("Send speed", ptr->sendSpeed_ptr(), col, format);
|
|
addVariable("Quality", ptr->quality_ptr(), col, format);
|
|
}
|
|
void PIConsole::addVariable(const PIString & name, const PISystemMonitor * ptr, int col, FormatFlags format) {
|
|
addString("monitor " + name, col, format | PIConsole::Bold);
|
|
addVariable("PID", &(ptr->statistic().ID), col, format);
|
|
//addVariable("state", &(ptr->statistic().state), col, format);
|
|
addVariable("threads", &(ptr->statistic().threads), col, format);
|
|
addVariable("priority", &(ptr->statistic().priority), col, format);
|
|
addVariable("memory physical", &(ptr->statistic().physical_memsize_readable), col, format);
|
|
addVariable("memory shared", &(ptr->statistic().share_memsize_readable), col, format);
|
|
addVariable("cpu load kernel", &(ptr->statistic().cpu_load_system), col, format);
|
|
addVariable("cpu load user", &(ptr->statistic().cpu_load_user), col, format);
|
|
}
|
|
void PIConsole::addBitVariable(const PIString & name, const void * ptr, int fromBit, int bitCount, int col, FormatFlags format) {
|
|
vid++; tv.id = vid; tv.size = sizeof(ullong); tv.name = name; tv.bitFrom = fromBit; tv.bitCount = bitCount; tv.type = 14; tv.ptr = ptr; tv.format = format;
|
|
checkColumn(col); column(col).push_back(tv);}
|
|
void PIConsole::addEmptyLine(int col, uint count) {
|
|
tv.id = 0; tv.size = 0; tv.name = ""; tv.type = 0; tv.ptr = 0; tv.format = Normal;
|
|
for (uint i = 0; i < count; ++i) {
|
|
checkColumn(col);
|
|
column(col).push_back(tv);
|
|
}
|
|
}
|
|
|
|
|
|
PIString PIConsole::getString(int x, int y) {
|
|
bool run = isRunning();
|
|
if (run) PIThread::stop(true);
|
|
listener->setActive(false);
|
|
msleep(50);
|
|
#ifdef WINDOWS
|
|
moveTo(x - 1, y - 1);
|
|
#else
|
|
moveTo(x, y);
|
|
#endif
|
|
showCursor();
|
|
PIByteArray ba(4096);
|
|
#ifdef CC_VC
|
|
int ret = scanf_s(" %s", ba.data());
|
|
#else
|
|
int ret = scanf(" %s", ba.data());
|
|
#endif
|
|
listener->setActive(true);
|
|
if (run) start();
|
|
if (ret >= 1) return PIString(ba);
|
|
else return PIString();
|
|
}
|
|
|
|
|
|
PIString PIConsole::getString(const PIString & name) {
|
|
piForeachC (Column & i, tabs[cur_tab].columns)
|
|
piForeachC (Variable & j, i.variables)
|
|
if (j.name == name)
|
|
return getString(j.nx + 1, j.ny);
|
|
return PIString();
|
|
}
|
|
|
|
|
|
#define PRINT_VAR_BODY couts(fstr(format)); int ret = couts(value); couts(fstr(PIConsole::Dec)); return ret;
|
|
|
|
inline void PIConsole::printLine(const PIString & value, int dx, FormatFlags format) {
|
|
int i = width - value.length() - dx;
|
|
#if defined(QNX) || defined(FREE_BSD)
|
|
--i;
|
|
#endif
|
|
PIString ts = fstr(format);
|
|
couts(ts);
|
|
if (i >= 0) ts = value + PIString(i, ' ');
|
|
else ts = value.left(value.size() + i);
|
|
couts(ts);
|
|
couts(fstr(Dec));
|
|
}
|
|
inline int PIConsole::printValue(const PIString & value, FormatFlags format) {
|
|
couts(fstr(format));
|
|
int ret = couts(value);
|
|
fstr(PIConsole::Dec);
|
|
return ret;
|
|
}
|
|
inline int PIConsole::printValue(const char * value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const bool value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const int value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const long value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const llong value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const float value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const double value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const char value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const short value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const uchar value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const ushort value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const uint value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const ulong value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const ullong value, FormatFlags format) {PRINT_VAR_BODY}
|
|
inline int PIConsole::printValue(const PISystemTime & value, FormatFlags format) {PRINT_VAR_BODY}
|
|
|
|
|
|
|
|
void PIConsole::startServer(const PIString & name) {
|
|
stopPeer();
|
|
server_mode = true;
|
|
peer = new PIPeer("_rcs_:" + name);
|
|
CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived);
|
|
CONNECT1(void, const PIString & , peer, peerDisconnectedEvent, this, peerDisconnectedEvent);
|
|
peer_timer->start(50.);
|
|
serverSendInfo();
|
|
}
|
|
|
|
|
|
void PIConsole::stopPeer() {
|
|
remote_clients.clear();
|
|
peer_timer->stop();
|
|
if (peer != 0) delete peer;
|
|
peer = 0;
|
|
state = Disconnected;
|
|
}
|
|
|
|
|
|
PIStringList PIConsole::clients() const {
|
|
PIStringList sl;
|
|
if (peer == 0) return sl;
|
|
piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) {
|
|
if (i.name.left(6) != "_rcc_:") continue;
|
|
sl << i.name.right(i.name.length() - 6);
|
|
}
|
|
return sl;
|
|
}
|
|
|
|
|
|
void PIConsole::listenServers() {
|
|
stopPeer();
|
|
server_mode = false;
|
|
server_name.clear();
|
|
randomize();
|
|
peer = new PIPeer("_rcc_:" + PIDateTime::current().toString("hhmmssddMMyy_") + PIString::fromNumber(randomi()));
|
|
CONNECT2(void, const PIString & , const PIByteArray &, peer, dataReceivedEvent, this, peerReceived);
|
|
peer_timer->start(100.);
|
|
}
|
|
|
|
|
|
PIStringList PIConsole::availableServers() const {
|
|
PIStringList sl;
|
|
if (peer == 0) return sl;
|
|
piForeachC (PIPeer::PeerInfo & i, peer->allPeers()) {
|
|
if (i.name.left(6) != "_rcs_:") continue;
|
|
sl << i.name.right(i.name.length() - 6);
|
|
}
|
|
return sl;
|
|
}
|
|
|
|
|
|
void PIConsole::connectToServer(const PIString & name) {
|
|
if (peer == 0) listenServers();
|
|
server_name = name;
|
|
}
|
|
|
|
|
|
void PIConsole::disconnect() {
|
|
stopPeer();
|
|
}
|
|
|
|
|
|
void PIConsole::serverSendInfo() {
|
|
if (peer == 0) return;
|
|
PIByteArray ba;
|
|
ba << int(0xAA);
|
|
peer->sendToAll(ba);
|
|
}
|
|
|
|
|
|
void PIConsole::serverSendData() {
|
|
if (peer == 0) return;
|
|
PIByteArray ba;
|
|
PIVector<VariableContent> content;
|
|
piForeach (Tab & t, tabs)
|
|
piForeach (Column & c, t.columns)
|
|
piForeach (Variable & v, c.variables)
|
|
if (!v.isEmpty() && v.id > 0) {
|
|
VariableContent vc;
|
|
vc.id = v.id;
|
|
v.writeData(vc.rdata);
|
|
content << vc;
|
|
}
|
|
piForeach (RemoteClient & rc, remote_clients) {
|
|
ba.clear();
|
|
switch (rc.state) {
|
|
case FetchingData:
|
|
ba << int(0xCC) << tabs;
|
|
//piCout << "server send const data" << rc.name << ba.size_s();
|
|
break;
|
|
case Committing:
|
|
ba << int(0xDD);
|
|
break;
|
|
case Connected:
|
|
ba << int(0xEE) << content;
|
|
//piCout << "send data" << ba.size();
|
|
break;
|
|
default: break;
|
|
}
|
|
if (!ba.isEmpty())
|
|
peer->send(rc.name, ba);
|
|
}
|
|
}
|
|
|
|
|
|
PIConsole::RemoteClient & PIConsole::remoteClient(const PIString & fname) {
|
|
piForeach (RemoteClient & i, remote_clients)
|
|
if (i.name == fname)
|
|
return i;
|
|
remote_clients << RemoteClient(fname);
|
|
return remote_clients.back();
|
|
}
|
|
|
|
|
|
void PIConsole::peerReceived(const PIString & from, const PIByteArray & data) {
|
|
int type;
|
|
PIByteArray ba(data);
|
|
ba >> type;
|
|
//piCout << "rec packet from" << from << "type" << PICoutManipulators::Hex << type;
|
|
if (server_mode) {
|
|
if (from.left(5) != "_rcc_") return;
|
|
//PIString rcn = from.right(from.length() - 6);
|
|
RemoteClient & rc(remoteClient(from));
|
|
switch (type) {
|
|
case 0xBB: // fetch const data request
|
|
//piCout << "fetch data request from" << from << rc.state;
|
|
if (rc.state != Connected)
|
|
rc.state = FetchingData;
|
|
break;
|
|
case 0xCC: // const data commit
|
|
//piCout << "commit from" << from;
|
|
if (rc.state != Connected)
|
|
rc.state = Connected;
|
|
break;
|
|
default: break;
|
|
}
|
|
} else {
|
|
PIVector<VariableContent> content;
|
|
PIMap<int, Variable * > vids;
|
|
if (from.left(5) != "_rcs_") return;
|
|
//PIString rcn = from.right(from.length() - 6);
|
|
switch (type) {
|
|
case 0xAA: // new server
|
|
//piCout << "new server" << rcn;
|
|
break;
|
|
case 0xCC: // const data
|
|
//piCout << "received const data";
|
|
state = Committing;
|
|
ba >> tabs;
|
|
cur_tab = tabs.isEmpty() ? -1 : 0;
|
|
piForeach (Tab & t, tabs)
|
|
piForeach (Column & c, t.columns)
|
|
piForeach (Variable & v, c.variables)
|
|
v.remote = true;
|
|
break;
|
|
case 0xDD: // const data commit
|
|
//piCout << "received commit";
|
|
state = Connected;
|
|
break;
|
|
case 0xEE: // dynamic data
|
|
//piCout << "received data" << ba.size_s();
|
|
piForeach (Tab & t, tabs)
|
|
piForeach (Column & c, t.columns)
|
|
piForeach (Variable & v, c.variables)
|
|
if (!v.isEmpty() && v.id > 0)
|
|
vids[v.id] = &v;
|
|
ba >> content;
|
|
piForeach (VariableContent & vc, content) {
|
|
if (vc.id <= 0) continue;
|
|
Variable * v = vids.at(vc.id);
|
|
if (v == 0) continue;
|
|
//piCout << "read" << v->name << vc.rdata.size_s();
|
|
v->rdata = vc.rdata;
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void PIConsole::peerTimer(void * data, int delim) {
|
|
if (peer == 0) return;
|
|
//piCout << "timer" << delim;
|
|
if (server_mode) {
|
|
if (delim == 20)
|
|
serverSendInfo();
|
|
else
|
|
serverSendData();
|
|
} else {
|
|
if (delim != 1 || server_name.isEmpty()) return;
|
|
const PIPeer::PeerInfo * p = peer->getPeerByName("_rcs_:" + server_name);
|
|
if (p == 0) return;
|
|
PIByteArray ba;
|
|
switch (state) {
|
|
case Disconnected:
|
|
peer_tm.reset();
|
|
ba << int(0xBB);
|
|
//piCout << "send to" << server_name << "fetch request disc";
|
|
peer->send(p, ba);
|
|
state = FetchingData;
|
|
break;
|
|
case FetchingData:
|
|
if (peer_tm.elapsed_s() < 3.)
|
|
return;
|
|
peer_tm.reset();
|
|
ba << int(0xBB);
|
|
//piCout << "send to" << server_name << "fetch request fd";
|
|
peer->send(p, ba);
|
|
break;
|
|
case Committing:
|
|
peer_tm.reset();
|
|
ba << int(0xCC);
|
|
//piCout << "send to" << server_name << "committing";
|
|
state = Connected;
|
|
peer->send(p, ba);
|
|
break;
|
|
default: break;
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
void PIConsole::peerDisconnectedEvent(const PIString & name) {
|
|
for (int i = 0; i < remote_clients.size_s(); ++i)
|
|
if (remote_clients[i].name == name) {
|
|
remote_clients.remove(i);
|
|
--i;
|
|
}
|
|
}
|