b15f/driver/cli.cpp

330 lines
6.6 KiB
C++
Raw Normal View History

2019-04-05 06:33:31 +00:00
/** TODO
*
* - throw exception -> raise SIGINT
2019-04-05 06:47:06 +00:00
* - delete view stack
2019-04-05 06:33:31 +00:00
*/
2019-04-03 13:20:49 +00:00
#include <stdio.h>
#include <ncurses.h> // sudo apt-get install libncurses5-dev
2019-04-03 14:15:35 +00:00
#include <vector>
#include <string>
#include <iostream>
2019-04-04 14:16:28 +00:00
#include <signal.h>
2019-04-03 14:15:35 +00:00
#include <sys/ioctl.h>
#include <unistd.h>
2019-04-04 14:16:28 +00:00
#include <signal.h>
2019-04-05 11:29:14 +00:00
#include <future>
#include <thread>
#include <chrono>
2019-04-05 06:33:31 +00:00
#include "ui/view_selection.h"
2019-04-04 11:19:11 +00:00
#include "ui/view_info.h"
2019-04-05 06:47:06 +00:00
#include "ui/view_monitor.h"
2019-04-05 10:07:26 +00:00
#include "ui/view_promt.h"
2019-04-05 08:38:59 +00:00
#include "drv/b15f.h"
2019-04-03 13:20:49 +00:00
2019-04-04 14:16:28 +00:00
// global error message
std::string ERR_MSG;
2019-04-03 13:20:49 +00:00
2019-04-04 11:19:11 +00:00
std::vector<View*> win_stack;
2019-04-04 14:16:28 +00:00
2019-04-05 11:29:14 +00:00
volatile int win_changed_cooldown = 0;
volatile bool t_refresh_active = false;
std::thread t_refresh;
2019-04-04 14:16:28 +00:00
void cleanup()
{
2019-04-05 11:29:14 +00:00
if(t_refresh.joinable())
t_refresh.join();
2019-04-04 14:16:28 +00:00
clrtoeol();
refresh();
endwin();
}
void signal_handler(int signal)
{
if(signal == SIGWINCH)
{
2019-04-05 11:29:14 +00:00
win_changed_cooldown = 10; // 100ms
if (!t_refresh_active)
2019-04-04 14:16:28 +00:00
{
2019-04-05 11:29:14 +00:00
if(t_refresh.joinable())
t_refresh.join();
t_refresh_active = true;
t_refresh = std::thread([](){
while(win_changed_cooldown--)
std::this_thread::sleep_for(std::chrono::milliseconds(10));
t_refresh_active = false;
if(win_stack.size())
win_stack.back()->repaint();
});
2019-04-04 14:16:28 +00:00
}
2019-04-05 11:29:14 +00:00
2019-04-04 14:16:28 +00:00
}
else if(signal == SIGINT)
{
cleanup();
std::cout << "SIGINT - Abbruch." << std::endl;
if(ERR_MSG.length())
std::cout << "ERR_MSG: " << ERR_MSG << std::endl;
exit(EXIT_FAILURE);
}
}
2019-04-03 13:20:49 +00:00
2019-04-04 11:19:11 +00:00
void init()
2019-04-03 14:15:35 +00:00
{
2019-04-04 14:16:28 +00:00
// init b15 driver
2019-04-05 08:38:59 +00:00
B15F::getInstance();
2019-04-05 11:29:14 +00:00
std::cout << std::endl << "Starte in 3s ..." << std::endl;
2019-04-05 08:38:59 +00:00
//sleep(3);
2019-04-04 14:16:28 +00:00
// init all ncurses stuff
2019-04-04 11:19:11 +00:00
initscr();
start_color();
curs_set(0); // 0: invisible, 1: normal, 2: very visible
clear();
noecho();
cbreak(); // Line buffering disabled. pass on everything
mousemask(ALL_MOUSE_EVENTS, NULL);
2019-04-03 14:15:35 +00:00
2019-04-04 14:16:28 +00:00
// connect signals to handler
signal(SIGWINCH, signal_handler);
signal(SIGINT, signal_handler);
// set view context
2019-04-05 08:38:59 +00:00
View::setWinContext(newwin(25, 85, 0, 0));
2019-04-03 14:15:35 +00:00
}
2019-04-04 14:16:28 +00:00
void finish(int)
2019-04-04 11:19:11 +00:00
{
cleanup();
exit(EXIT_SUCCESS);
}
2019-04-03 14:15:35 +00:00
2019-04-05 10:07:26 +00:00
void view_back(int)
{
win_stack.pop_back();
if(win_stack.size())
win_stack.back()->repaint();
}
2019-04-04 14:16:28 +00:00
void input(int)
2019-04-04 11:19:11 +00:00
{
std::function<void(int)> nextCall;
int key;
do
{
key = wgetch(View::getWinContext());
2019-04-05 10:07:26 +00:00
win_stack.back()->repaint();
2019-04-04 11:19:11 +00:00
nextCall = win_stack.back()->keypress(key);
if(key == -1)
2019-04-05 10:07:26 +00:00
view_back(key);
2019-04-04 11:19:11 +00:00
if(nextCall)
nextCall(key);
2019-04-03 14:15:35 +00:00
}
2019-04-05 10:07:26 +00:00
while(win_stack.size());
2019-04-04 11:19:11 +00:00
}
2019-04-04 14:16:28 +00:00
void show_info(int)
2019-04-04 11:19:11 +00:00
{
2019-04-04 14:16:28 +00:00
ViewInfo* view = new ViewInfo();
2019-04-04 11:19:11 +00:00
view->setTitle("Info");
2019-04-04 14:16:28 +00:00
view->setText("Informationen zu Board 15 Famulus Edition\nEs war einmal");
view->setLabelClose("[ Zurueck ]");
2019-04-04 11:19:11 +00:00
view->repaint();
win_stack.push_back(view);
input(0);
}
2019-04-05 06:47:06 +00:00
void show_monitor(int)
{
ViewMonitor* view = new ViewMonitor();
view->setTitle("Monitor");
2019-04-05 08:38:59 +00:00
view->setText("\nErfasse Messwerte...");
2019-04-05 06:47:06 +00:00
view->setLabelClose("[ Zurueck ]");
view->repaint();
win_stack.push_back(view);
input(0);
}
2019-04-05 10:07:26 +00:00
void show_invalid_port_input(int)
{
ViewInfo* view = new ViewInfo();
view->setTitle("Falsche Eingabe");
2019-04-05 10:52:51 +00:00
view->setText("Bitte geben Sie einen Wert aus dem Intervall [0, FF] an.");
view->setLabelClose("[ Schliessen ]");
view->repaint();
win_stack.push_back(view);
input(0);
}
void show_invalid_dac_input(int)
{
ViewInfo* view = new ViewInfo();
view->setTitle("Falsche Eingabe");
view->setText("Bitte geben Sie einen Wert aus dem Intervall [0, 1023] an.");
2019-04-05 10:07:26 +00:00
view->setLabelClose("[ Schliessen ]");
view->repaint();
win_stack.push_back(view);
input(0);
}
void write_digital_output0(int)
{
try
{
uint8_t port = std::stoi(static_cast<ViewPromt*>(win_stack.back())->getInput(), 0, 16);
B15F& drv = B15F::getInstance();
drv.digitalWrite0(port);
view_back(0);
}
catch(std::invalid_argument& ex)
{
show_invalid_port_input(0);
}
}
void write_digital_output1(int)
{
try
{
uint8_t port = std::stoi(static_cast<ViewPromt*>(win_stack.back())->getInput(), 0, 16);
B15F& drv = B15F::getInstance();
drv.digitalWrite1(port);
view_back(0);
}
catch(std::invalid_argument& ex)
{
show_invalid_port_input(0);
}
}
2019-04-05 10:52:51 +00:00
void write_analog_output0(int)
{
try
{
uint16_t port = std::stoi(static_cast<ViewPromt*>(win_stack.back())->getInput());
if(port > 1023)
throw std::invalid_argument("bad value");
B15F& drv = B15F::getInstance();
drv.analogWrite0(port);
view_back(0);
}
catch(std::invalid_argument& ex)
{
show_invalid_dac_input(0);
}
}
void write_analog_output1(int)
{
try
{
uint16_t port = std::stoi(static_cast<ViewPromt*>(win_stack.back())->getInput());
if(port > 1023)
throw std::invalid_argument("bad value");
B15F& drv = B15F::getInstance();
drv.analogWrite1(port);
view_back(0);
}
catch(std::invalid_argument& ex)
{
show_invalid_dac_input(0);
}
}
2019-04-05 10:07:26 +00:00
void show_digital_output0(int)
{
ViewPromt* view = new ViewPromt();
view->setTitle("Digitale Ausgabe BE0");
view->setMessage("\nEingabe Port-Wert (hex): 0x");
view->setCancel("[ Zurueck ]", true);
view->setConfirm("[ OK ]", &write_digital_output0);
view->repaint();
win_stack.push_back(view);
input(0);
}
void show_digital_output1(int)
{
ViewPromt* view = new ViewPromt();
view->setTitle("Digitale Ausgabe BE1");
view->setMessage("\nEingabe Port-Wert (hex): 0x");
view->setCancel("[ Zurueck ]", true);
view->setConfirm("[ OK ]", &write_digital_output1);
view->repaint();
win_stack.push_back(view);
input(0);
}
2019-04-05 10:52:51 +00:00
void show_analog_output0(int)
{
ViewPromt* view = new ViewPromt();
view->setTitle("Analoge Ausgabe AA0");
view->setMessage("\nEingabe 10-Bit-Wert (0...1023): ");
view->setCancel("[ Zurueck ]", true);
view->setConfirm("[ OK ]", &write_analog_output0);
view->repaint();
win_stack.push_back(view);
input(0);
}
void show_analog_output1(int)
{
ViewPromt* view = new ViewPromt();
view->setTitle("Analoge Ausgabe AA1");
view->setMessage("\nEingabe 10-Bit-Wert (0...1023): ");
view->setCancel("[ Zurueck ]", true);
view->setConfirm("[ OK ]", &write_analog_output1);
view->repaint();
win_stack.push_back(view);
input(0);
}
2019-04-04 14:16:28 +00:00
void show_main(int)
2019-04-04 11:19:11 +00:00
{
2019-04-05 06:33:31 +00:00
ViewSelection* view = new ViewSelection();
2019-04-04 11:19:11 +00:00
view->setTitle("B15F - Command Line Interface");
2019-04-05 06:47:06 +00:00
view->addChoice("[ Monitor - Eingaben beobachten ]", &show_monitor);
2019-04-05 10:07:26 +00:00
view->addChoice("[ Digitale Ausgabe BE0 ]", &show_digital_output0);
view->addChoice("[ Digitale Ausgabe BE1 ]", &show_digital_output1);
2019-04-05 10:52:51 +00:00
view->addChoice("[ Analoge Ausgabe AA0 ]", &show_analog_output0);
view->addChoice("[ Analoge Ausgabe AA1 ]", &show_analog_output1);
2019-04-05 06:33:31 +00:00
view->addChoice("[ Informationen ]", &show_info);
view->addChoice("", nullptr);
view->addChoice("[ Beenden ]", &finish);
2019-04-04 11:19:11 +00:00
view->repaint();
win_stack.push_back(view);
input(0);
2019-04-03 14:15:35 +00:00
}
2019-04-03 13:20:49 +00:00
int main()
2019-04-04 11:19:11 +00:00
{
init();
2019-04-03 14:15:35 +00:00
2019-04-04 11:19:11 +00:00
show_main(0);
cleanup();
return EXIT_SUCCESS;
2019-04-03 13:20:49 +00:00
}