doc update
This commit is contained in:
parent
90e62b739b
commit
5f48849c4e
117 changed files with 3780 additions and 2135 deletions
|
@ -38,7 +38,7 @@ OBJECTS_CLI = cli.o ui/view.o ui/view_selection.o ui/view_promt.o ui/view_info
|
|||
|
||||
# *** TARGETS ***
|
||||
|
||||
all: drv cli doc
|
||||
all: drv cli style doc
|
||||
|
||||
drv: $(OBJECTS_DRV) $(OUT_TMP_DRV)
|
||||
|
||||
|
@ -50,8 +50,13 @@ cli: drv $(OBJECTS_CLI)
|
|||
@bash -c 'if [ ! -f "$(OUT_DRV)" ]; then echo -e "\n*** Warning ***: driver not installed\nType \"sudo make install\" to install or update b15fdrv."; fi'
|
||||
|
||||
doc:
|
||||
@echo "Creating documentation with doxygen.."
|
||||
@echo "Creating documentation with doxygen..."
|
||||
$(PATH_DOXYGEN) doxygen-cfg
|
||||
@echo problems found: `($(PATH_DOXYGEN) doxygen-cfg 3>&2 2>&1 1>&3) 2>/dev/null | wc -l`
|
||||
|
||||
style:
|
||||
@echo "Formatting source code with astyle..."
|
||||
astyle --recursive --style=allman *.cpp,*.h,*.c,*.hpp
|
||||
|
||||
install:
|
||||
@echo "Installing driver..."
|
||||
|
@ -78,6 +83,7 @@ clean:
|
|||
@echo "Cleaning..."
|
||||
rm -f $(OBJECTS_DRV) $(OBJECTS_CLI) $(OUT_TMP_CLI) $(OUT_TMP_DRV)
|
||||
rm -rf $(OUT_DOC)
|
||||
find . -type f -name '*.orig' -delete
|
||||
|
||||
.cpp.o:
|
||||
$(PATH_COMPILER) $(CFLAGS) -c $< -o $@
|
||||
|
|
|
@ -24,91 +24,92 @@ volatile bool t_refresh_active = false;
|
|||
|
||||
void signal_handler(int signal)
|
||||
{
|
||||
if(signal == SIGWINCH)
|
||||
{
|
||||
win_changed_cooldown = 10; // 100ms
|
||||
|
||||
if (!t_refresh_active)
|
||||
{
|
||||
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();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
else if(signal == SIGINT)
|
||||
{
|
||||
cleanup();
|
||||
std::cout << "SIGINT - Abbruch." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(signal == SIGWINCH)
|
||||
{
|
||||
win_changed_cooldown = 10; // 100ms
|
||||
|
||||
if (!t_refresh_active)
|
||||
{
|
||||
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();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
else if(signal == SIGINT)
|
||||
{
|
||||
cleanup();
|
||||
std::cout << "SIGINT - Abbruch." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void abort_handler(std::exception& ex)
|
||||
{
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Fehler");
|
||||
std::string msg(ex.what());
|
||||
msg += "\n\nBeende in 5 Sekunden.";
|
||||
view->setText(msg.c_str());
|
||||
view->setLabelClose("");
|
||||
view->repaint();
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
|
||||
|
||||
cleanup();
|
||||
std::cerr << std::endl << "*** EXCEPTION ***" << std::endl << ex.what() << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Fehler");
|
||||
std::string msg(ex.what());
|
||||
msg += "\n\nBeende in 5 Sekunden.";
|
||||
view->setText(msg.c_str());
|
||||
view->setLabelClose("");
|
||||
view->repaint();
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
|
||||
|
||||
cleanup();
|
||||
std::cerr << std::endl << "*** EXCEPTION ***" << std::endl << ex.what() << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
// init b15 driver
|
||||
B15F::getInstance();
|
||||
// init b15 driver
|
||||
B15F::getInstance();
|
||||
#ifndef B15F_CLI_DEBUG
|
||||
std::cout << std::endl << "Starte in 3s ..." << std::endl;
|
||||
sleep(3);
|
||||
std::cout << std::endl << "Starte in 3s ..." << std::endl;
|
||||
sleep(3);
|
||||
#endif
|
||||
B15F::setAbortHandler(&abort_handler);
|
||||
|
||||
// init all ncurses stuff
|
||||
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);
|
||||
|
||||
// connect signals to handler
|
||||
signal(SIGWINCH, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
|
||||
// set view context
|
||||
View::setWinContext(newwin(25, 85, 0, 0));
|
||||
B15F::setAbortHandler(&abort_handler);
|
||||
|
||||
// init all ncurses stuff
|
||||
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);
|
||||
|
||||
// connect signals to handler
|
||||
signal(SIGWINCH, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
|
||||
// set view context
|
||||
View::setWinContext(newwin(25, 85, 0, 0));
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
init();
|
||||
|
||||
int exit_code = EXIT_SUCCESS;
|
||||
|
||||
show_main(0);
|
||||
|
||||
cleanup();
|
||||
|
||||
return exit_code;
|
||||
init();
|
||||
|
||||
int exit_code = EXIT_SUCCESS;
|
||||
|
||||
show_main(0);
|
||||
|
||||
cleanup();
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
|
|
@ -1260,7 +1260,7 @@ HTML_COLORSTYLE_GAMMA = 80
|
|||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_TIMESTAMP = YES
|
||||
|
||||
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
|
||||
# documentation will contain a main index with vertical navigation menus that
|
||||
|
@ -1279,7 +1279,7 @@ HTML_DYNAMIC_MENUS = YES
|
|||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
HTML_DYNAMIC_SECTIONS = YES
|
||||
|
||||
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
|
||||
# shown in the various tree structured indices initially; the user can expand
|
||||
|
|
|
@ -5,315 +5,320 @@ errorhandler_t B15F::errorhandler = nullptr;
|
|||
|
||||
B15F::B15F()
|
||||
{
|
||||
init();
|
||||
init();
|
||||
}
|
||||
|
||||
void B15F::init()
|
||||
{
|
||||
|
||||
std::string device = exec("bash -c 'ls /dev/ttyUSB*'");
|
||||
while(device.find(' ') != std::string::npos || device.find('\n') != std::string::npos || device.find('\t') != std::string::npos)
|
||||
device.pop_back();
|
||||
|
||||
if(device.length() == 0)
|
||||
abort("Adapter nicht gefunden");
|
||||
|
||||
std::cout << PRE << "Verwende Adapter: " << device << std::endl;
|
||||
|
||||
|
||||
|
||||
std::cout << PRE << "Stelle Verbindung mit Adapter her... " << std::flush;
|
||||
usart.setBaudrate(BAUDRATE);
|
||||
usart.openDevice(device);
|
||||
std::cout << "OK" << std::endl;
|
||||
|
||||
|
||||
|
||||
std::cout << PRE << "Teste Verbindung... " << std::flush;
|
||||
uint8_t tries = 3;
|
||||
while(tries--)
|
||||
{
|
||||
// verwerfe Daten, die µC noch hat
|
||||
//discard();
|
||||
|
||||
if(!testConnection())
|
||||
continue;
|
||||
|
||||
if(!testIntConv())
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
if(tries == 0)
|
||||
abort("Verbindungstest fehlgeschlagen. Neueste Version im Einsatz?");
|
||||
std::cout << "OK" << std::endl;
|
||||
|
||||
|
||||
// Gib board info aus
|
||||
std::vector<std::string> info = getBoardInfo();
|
||||
std::cout << PRE << "AVR Firmware Version: " << info[0] << " um " << info[1] << " Uhr (" << info[2] << ")" << std::endl;
|
||||
std::string device = exec("bash -c 'ls /dev/ttyUSB*'");
|
||||
while(device.find(' ') != std::string::npos || device.find('\n') != std::string::npos || device.find('\t') != std::string::npos)
|
||||
device.pop_back();
|
||||
|
||||
if(device.length() == 0)
|
||||
abort("Adapter nicht gefunden");
|
||||
|
||||
std::cout << PRE << "Verwende Adapter: " << device << std::endl;
|
||||
|
||||
|
||||
|
||||
std::cout << PRE << "Stelle Verbindung mit Adapter her... " << std::flush;
|
||||
usart.setBaudrate(BAUDRATE);
|
||||
usart.openDevice(device);
|
||||
std::cout << "OK" << std::endl;
|
||||
|
||||
|
||||
|
||||
std::cout << PRE << "Teste Verbindung... " << std::flush;
|
||||
uint8_t tries = 3;
|
||||
while(tries--)
|
||||
{
|
||||
// verwerfe Daten, die µC noch hat
|
||||
//discard();
|
||||
|
||||
if(!testConnection())
|
||||
continue;
|
||||
|
||||
if(!testIntConv())
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
if(tries == 0)
|
||||
abort("Verbindungstest fehlgeschlagen. Neueste Version im Einsatz?");
|
||||
std::cout << "OK" << std::endl;
|
||||
|
||||
|
||||
// Gib board info aus
|
||||
std::vector<std::string> info = getBoardInfo();
|
||||
std::cout << PRE << "AVR Firmware Version: " << info[0] << " um " << info[1] << " Uhr (" << info[2] << ")" << std::endl;
|
||||
}
|
||||
|
||||
void B15F::reconnect()
|
||||
{
|
||||
uint8_t tries = RECONNECT_TRIES;
|
||||
while(tries--)
|
||||
{
|
||||
delay_ms(RECONNECT_TIMEOUT);
|
||||
discard();
|
||||
|
||||
if(testConnection())
|
||||
return;
|
||||
}
|
||||
|
||||
abort("Verbindung kann nicht repariert werden");
|
||||
uint8_t tries = RECONNECT_TRIES;
|
||||
while(tries--)
|
||||
{
|
||||
delay_ms(RECONNECT_TIMEOUT);
|
||||
discard();
|
||||
|
||||
if(testConnection())
|
||||
return;
|
||||
}
|
||||
|
||||
abort("Verbindung kann nicht repariert werden");
|
||||
}
|
||||
|
||||
void B15F::discard(void)
|
||||
{
|
||||
try
|
||||
{
|
||||
usart.clearOutputBuffer();
|
||||
for(uint8_t i = 0; i < 16; i++)
|
||||
{
|
||||
usart.writeByte(RQ_DISC); // sende discard Befehl (verwerfe input)
|
||||
delay_ms(4);
|
||||
}
|
||||
usart.clearInputBuffer();
|
||||
}
|
||||
catch(std::exception& ex)
|
||||
{
|
||||
abort(ex);
|
||||
}
|
||||
try
|
||||
{
|
||||
usart.clearOutputBuffer();
|
||||
for(uint8_t i = 0; i < 16; i++)
|
||||
{
|
||||
usart.writeByte(RQ_DISC); // sende discard Befehl (verwerfe input)
|
||||
delay_ms(4);
|
||||
}
|
||||
usart.clearInputBuffer();
|
||||
}
|
||||
catch(std::exception& ex)
|
||||
{
|
||||
abort(ex);
|
||||
}
|
||||
}
|
||||
|
||||
bool B15F::testConnection()
|
||||
{
|
||||
// erzeuge zufälliges Byte
|
||||
srand(time(NULL));
|
||||
uint8_t dummy = rand() % 256;
|
||||
|
||||
usart.writeByte(RQ_TEST);
|
||||
usart.writeByte(dummy);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
uint8_t mirror = usart.readByte();
|
||||
|
||||
return aw == MSG_OK && mirror == dummy;
|
||||
// erzeuge zufälliges Byte
|
||||
srand(time(NULL));
|
||||
uint8_t dummy = rand() % 256;
|
||||
|
||||
usart.writeByte(RQ_TEST);
|
||||
usart.writeByte(dummy);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
uint8_t mirror = usart.readByte();
|
||||
|
||||
return aw == MSG_OK && mirror == dummy;
|
||||
}
|
||||
|
||||
bool B15F::testIntConv()
|
||||
{
|
||||
srand(time(NULL));
|
||||
uint16_t dummy = rand() % (0xFFFF / 3);
|
||||
|
||||
usart.writeByte(RQ_INT);
|
||||
usart.writeInt(dummy);
|
||||
|
||||
uint16_t aw = usart.readInt();
|
||||
return aw == dummy * 3;
|
||||
srand(time(NULL));
|
||||
uint16_t dummy = rand() % (0xFFFF / 3);
|
||||
|
||||
usart.writeByte(RQ_INT);
|
||||
usart.writeInt(dummy);
|
||||
|
||||
uint16_t aw = usart.readInt();
|
||||
return aw == dummy * 3;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> B15F::getBoardInfo(void)
|
||||
{
|
||||
std::vector<std::string> info;
|
||||
|
||||
usart.writeByte(RQ_INFO);
|
||||
|
||||
uint8_t n = usart.readByte();
|
||||
while(n--)
|
||||
{
|
||||
uint8_t len = usart.readByte();
|
||||
std::string str;
|
||||
|
||||
while(len--) {
|
||||
str += static_cast<char>(usart.readByte());
|
||||
}
|
||||
|
||||
info.push_back(str);
|
||||
}
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
if(aw != MSG_OK)
|
||||
abort("Board Info fehlerhalft: code " + std::to_string((int) aw));
|
||||
|
||||
return info;
|
||||
std::vector<std::string> info;
|
||||
|
||||
usart.writeByte(RQ_INFO);
|
||||
|
||||
uint8_t n = usart.readByte();
|
||||
while(n--)
|
||||
{
|
||||
uint8_t len = usart.readByte();
|
||||
std::string str;
|
||||
|
||||
while(len--)
|
||||
{
|
||||
str += static_cast<char>(usart.readByte());
|
||||
}
|
||||
|
||||
info.push_back(str);
|
||||
}
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
if(aw != MSG_OK)
|
||||
abort("Board Info fehlerhalft: code " + std::to_string((int) aw));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
bool B15F::activateSelfTestMode()
|
||||
{
|
||||
usart.writeByte(RQ_ST);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
return aw == MSG_OK;
|
||||
usart.writeByte(RQ_ST);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
return aw == MSG_OK;
|
||||
}
|
||||
|
||||
bool B15F::digitalWrite0(uint8_t port)
|
||||
{
|
||||
usart.writeByte(RQ_BA0);
|
||||
usart.writeByte(port);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
delay_us(10);
|
||||
return aw == MSG_OK;
|
||||
usart.writeByte(RQ_BA0);
|
||||
usart.writeByte(port);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
delay_us(10);
|
||||
return aw == MSG_OK;
|
||||
}
|
||||
|
||||
bool B15F::digitalWrite1(uint8_t port)
|
||||
{
|
||||
usart.writeByte(RQ_BA1);
|
||||
usart.writeByte(port);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
delay_us(10);
|
||||
return aw == MSG_OK;
|
||||
usart.writeByte(RQ_BA1);
|
||||
usart.writeByte(port);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
delay_us(10);
|
||||
return aw == MSG_OK;
|
||||
}
|
||||
|
||||
uint8_t B15F::digitalRead0()
|
||||
{
|
||||
usart.clearInputBuffer();
|
||||
usart.writeByte(RQ_BE0);
|
||||
uint8_t byte = usart.readByte();
|
||||
delay_us(10);
|
||||
return byte;
|
||||
usart.clearInputBuffer();
|
||||
usart.writeByte(RQ_BE0);
|
||||
uint8_t byte = usart.readByte();
|
||||
delay_us(10);
|
||||
return byte;
|
||||
}
|
||||
|
||||
uint8_t B15F::digitalRead1()
|
||||
{
|
||||
usart.clearInputBuffer();
|
||||
usart.writeByte(RQ_BE1);
|
||||
uint8_t byte = usart.readByte();
|
||||
delay_us(10);
|
||||
return byte;
|
||||
usart.clearInputBuffer();
|
||||
usart.writeByte(RQ_BE1);
|
||||
uint8_t byte = usart.readByte();
|
||||
delay_us(10);
|
||||
return byte;
|
||||
}
|
||||
|
||||
uint8_t B15F::readDipSwitch()
|
||||
{
|
||||
usart.clearInputBuffer();
|
||||
usart.writeByte(RQ_DSW);
|
||||
uint8_t byte = usart.readByte();
|
||||
delay_us(10);
|
||||
return byte;
|
||||
usart.clearInputBuffer();
|
||||
usart.writeByte(RQ_DSW);
|
||||
uint8_t byte = usart.readByte();
|
||||
delay_us(10);
|
||||
return byte;
|
||||
}
|
||||
|
||||
bool B15F::analogWrite0(uint16_t value)
|
||||
{
|
||||
usart.writeByte(RQ_AA0);
|
||||
usart.writeInt(value);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
delay_us(10);
|
||||
return aw == MSG_OK;
|
||||
usart.writeByte(RQ_AA0);
|
||||
usart.writeInt(value);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
delay_us(10);
|
||||
return aw == MSG_OK;
|
||||
}
|
||||
|
||||
bool B15F::analogWrite1(uint16_t value)
|
||||
{
|
||||
usart.writeByte(RQ_AA1);
|
||||
usart.writeInt(value);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
delay_us(10);
|
||||
return aw == MSG_OK;
|
||||
usart.writeByte(RQ_AA1);
|
||||
usart.writeInt(value);
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
delay_us(10);
|
||||
return aw == MSG_OK;
|
||||
}
|
||||
|
||||
uint16_t B15F::analogRead(uint8_t channel)
|
||||
{
|
||||
usart.clearInputBuffer();
|
||||
if(channel > 7)
|
||||
abort("Bad ADC channel: " + std::to_string(channel));
|
||||
|
||||
uint8_t rq[] = {
|
||||
RQ_ADC,
|
||||
channel
|
||||
};
|
||||
|
||||
int n_sent = usart.write_timeout(&rq[0], 0, sizeof(rq), 1000);
|
||||
if(n_sent != sizeof(rq))
|
||||
abort("Sent failed");
|
||||
|
||||
uint16_t adc = usart.readInt();
|
||||
|
||||
if(adc > 1023)
|
||||
abort("Bad ADC data detected (1)");
|
||||
return adc;
|
||||
usart.clearInputBuffer();
|
||||
if(channel > 7)
|
||||
abort("Bad ADC channel: " + std::to_string(channel));
|
||||
|
||||
uint8_t rq[] =
|
||||
{
|
||||
RQ_ADC,
|
||||
channel
|
||||
};
|
||||
|
||||
int n_sent = usart.write_timeout(&rq[0], 0, sizeof(rq), 1000);
|
||||
if(n_sent != sizeof(rq))
|
||||
abort("Sent failed");
|
||||
|
||||
uint16_t adc = usart.readInt();
|
||||
|
||||
if(adc > 1023)
|
||||
abort("Bad ADC data detected (1)");
|
||||
return adc;
|
||||
}
|
||||
|
||||
void B15F::analogSequence(uint8_t channel_a, uint16_t* buffer_a, uint32_t offset_a, uint8_t channel_b, uint16_t* buffer_b, uint32_t offset_b, uint16_t start, int16_t delta, uint16_t count)
|
||||
{
|
||||
// check pointers
|
||||
buffer_a += offset_a;
|
||||
buffer_b += offset_b;
|
||||
|
||||
|
||||
usart.clearInputBuffer();
|
||||
usart.writeByte(RQ_ADC_DAC_STROKE);
|
||||
usart.writeByte(channel_a);
|
||||
usart.writeByte(channel_b);
|
||||
usart.writeInt(start);
|
||||
usart.writeInt(static_cast<uint16_t>(delta));
|
||||
usart.writeInt(count);
|
||||
|
||||
for(uint16_t i = 0; i < count; i++)
|
||||
{
|
||||
if(buffer_a)
|
||||
{
|
||||
buffer_a[i] = usart.readInt();
|
||||
|
||||
if(buffer_a[i] > 1023) // check for broken usart connection
|
||||
abort("Bad ADC data detected (2)");
|
||||
}
|
||||
else
|
||||
{
|
||||
usart.readInt();
|
||||
}
|
||||
|
||||
if(buffer_b)
|
||||
{
|
||||
buffer_b[i] = usart.readInt();
|
||||
|
||||
if(buffer_b[i] > 1023) // check for broken usart connection
|
||||
abort("Bad ADC data detected (3)");
|
||||
}
|
||||
else
|
||||
{
|
||||
usart.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
if(aw != MSG_OK)
|
||||
abort("Sequenz unterbrochen");
|
||||
|
||||
delay_us(10);
|
||||
// check pointers
|
||||
buffer_a += offset_a;
|
||||
buffer_b += offset_b;
|
||||
|
||||
|
||||
usart.clearInputBuffer();
|
||||
usart.writeByte(RQ_ADC_DAC_STROKE);
|
||||
usart.writeByte(channel_a);
|
||||
usart.writeByte(channel_b);
|
||||
usart.writeInt(start);
|
||||
usart.writeInt(static_cast<uint16_t>(delta));
|
||||
usart.writeInt(count);
|
||||
|
||||
for(uint16_t i = 0; i < count; i++)
|
||||
{
|
||||
if(buffer_a)
|
||||
{
|
||||
buffer_a[i] = usart.readInt();
|
||||
|
||||
if(buffer_a[i] > 1023) // check for broken usart connection
|
||||
abort("Bad ADC data detected (2)");
|
||||
}
|
||||
else
|
||||
{
|
||||
usart.readInt();
|
||||
}
|
||||
|
||||
if(buffer_b)
|
||||
{
|
||||
buffer_b[i] = usart.readInt();
|
||||
|
||||
if(buffer_b[i] > 1023) // check for broken usart connection
|
||||
abort("Bad ADC data detected (3)");
|
||||
}
|
||||
else
|
||||
{
|
||||
usart.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t aw = usart.readByte();
|
||||
if(aw != MSG_OK)
|
||||
abort("Sequenz unterbrochen");
|
||||
|
||||
delay_us(10);
|
||||
}
|
||||
|
||||
void B15F::delay_ms(uint16_t ms)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
void B15F::delay_us(uint16_t us)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(us));
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(us));
|
||||
}
|
||||
|
||||
|
||||
B15F& B15F::getInstance(void)
|
||||
{
|
||||
if(!instance)
|
||||
instance = new B15F();
|
||||
if(!instance)
|
||||
instance = new B15F();
|
||||
|
||||
return *instance;
|
||||
return *instance;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/478960
|
||||
std::string B15F::exec(std::string cmd) {
|
||||
std::string B15F::exec(std::string cmd)
|
||||
{
|
||||
std::array<char, 128> buffer;
|
||||
std::string result;
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
|
||||
if (!pipe) {
|
||||
if (!pipe)
|
||||
{
|
||||
throw std::runtime_error("popen() failed!");
|
||||
}
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
|
||||
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
|
||||
{
|
||||
result += buffer.data();
|
||||
}
|
||||
return result;
|
||||
|
@ -321,22 +326,22 @@ std::string B15F::exec(std::string cmd) {
|
|||
|
||||
void B15F::abort(std::string msg)
|
||||
{
|
||||
DriverException ex(msg);
|
||||
abort(ex);
|
||||
DriverException ex(msg);
|
||||
abort(ex);
|
||||
}
|
||||
void B15F::abort(std::exception& ex)
|
||||
{
|
||||
if(errorhandler)
|
||||
errorhandler(ex);
|
||||
else
|
||||
{
|
||||
std::cerr << "NOTICE: B15F::errorhandler not set" << std::endl;
|
||||
std::cout << ex.what() << std::endl;
|
||||
throw DriverException(ex.what());
|
||||
}
|
||||
if(errorhandler)
|
||||
errorhandler(ex);
|
||||
else
|
||||
{
|
||||
std::cerr << "NOTICE: B15F::errorhandler not set" << std::endl;
|
||||
std::cout << ex.what() << std::endl;
|
||||
throw DriverException(ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void B15F::setAbortHandler(errorhandler_t func)
|
||||
{
|
||||
errorhandler = func;
|
||||
errorhandler = func;
|
||||
}
|
||||
|
|
|
@ -21,216 +21,218 @@
|
|||
typedef std::function<void(std::exception&)> errorhandler_t;
|
||||
|
||||
|
||||
/*! main driver class */
|
||||
|
||||
class B15F
|
||||
{
|
||||
private:
|
||||
// privater Konstruktor
|
||||
B15F(void);
|
||||
// privater Konstruktor
|
||||
B15F(void);
|
||||
public:
|
||||
|
||||
/*************************************
|
||||
* Grundfunktionen des B15F Treibers *
|
||||
*************************************/
|
||||
|
||||
/**
|
||||
* Versucht die Verbindung zum B15 wiederherzustellen
|
||||
* \throws DriverException
|
||||
*/
|
||||
void reconnect(void);
|
||||
|
||||
/**
|
||||
* Verwirft Daten im USART Puffer auf dieser Maschine und B15
|
||||
* \throws DriverException
|
||||
*/
|
||||
void discard(void);
|
||||
|
||||
/**
|
||||
* Testet die USART Verbindung auf Funktion
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool testConnection(void);
|
||||
|
||||
/**
|
||||
* Testet die Integer Konvertierung der USART Verbindung
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool testIntConv(void);
|
||||
|
||||
/**
|
||||
* Liefert Informationen zur aktuellen Firmware des B15
|
||||
* \throws DriverException
|
||||
*/
|
||||
std::vector<std::string> getBoardInfo(void);
|
||||
|
||||
/**
|
||||
* Lässt den Treiber für eine angegebene Zeit pausieren
|
||||
* \param ms Verzögerung in Millisekunden
|
||||
*/
|
||||
void delay_ms(uint16_t ms);
|
||||
|
||||
/**
|
||||
* Lässt den Treiber für eine angegebene Zeit pausieren
|
||||
* \param us Verzögerung in Microsekunden
|
||||
*/
|
||||
void delay_us(uint16_t us);
|
||||
|
||||
/**
|
||||
* Liefert eine Referenz zur aktuellen Treiber-Instanz
|
||||
* @throws DriverException
|
||||
*/
|
||||
static B15F& getInstance(void);
|
||||
|
||||
/**
|
||||
* Führt ein Befehl auf dieser Maschine aus und liefert stdout zurück
|
||||
* \param cmd Der Befehl
|
||||
*/
|
||||
static std::string exec(std::string cmd);
|
||||
|
||||
/**
|
||||
* Multithread sicherer Abbruch des B15F-Treibers
|
||||
* \param msg Beschreibung der Abbruchursache
|
||||
*/
|
||||
static void abort(std::string msg);
|
||||
/*************************************
|
||||
* Grundfunktionen des B15F Treibers *
|
||||
*************************************/
|
||||
|
||||
/**
|
||||
* Multithread sicherer Abbruch des B15F-Treibers
|
||||
* \param ex Exception als Abbruchursache
|
||||
*/
|
||||
static void abort(std::exception& ex);
|
||||
/**
|
||||
* Versucht die Verbindung zum B15 wiederherzustellen
|
||||
* \throws DriverException
|
||||
*/
|
||||
void reconnect(void);
|
||||
|
||||
/**
|
||||
* Setzt eine Fehlerbehandlungsroutine für den Treiberabbruch (abort)
|
||||
* \param func Funktion, die Exception als Parameter bekommt
|
||||
*/
|
||||
static void setAbortHandler(errorhandler_t func);
|
||||
/**
|
||||
* Verwirft Daten im USART Puffer auf dieser Maschine und B15
|
||||
* \throws DriverException
|
||||
*/
|
||||
void discard(void);
|
||||
|
||||
/*************************************/
|
||||
|
||||
|
||||
|
||||
/*************************
|
||||
* Steuerbefehle für B15 *
|
||||
*************************/
|
||||
|
||||
/**
|
||||
* Versetzt das Board in den Selbsttest-Modus
|
||||
* WICHTIG: Es darf dabei nichts an den Klemmen angeschlossen sein!
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool activateSelfTestMode(void);
|
||||
|
||||
/**
|
||||
* Setzt den Wert des digitalen Ausgabeports 0
|
||||
* \param port Wert für gesamten Port
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool digitalWrite0(uint8_t);
|
||||
|
||||
/**
|
||||
* Setzt den Wert des digitalen Ausgabeports 1
|
||||
* \param port Wert für gesamten Port
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool digitalWrite1(uint8_t);
|
||||
|
||||
/**
|
||||
* Liest den Wert des digitalen Eingabeports 0
|
||||
* \return Wert für gesamten Port
|
||||
* \throws DriverException
|
||||
*/
|
||||
uint8_t digitalRead0(void);
|
||||
|
||||
/**
|
||||
* Liest den Wert des digitalen Eingabeports 1
|
||||
* \return Wert für gesamten Port
|
||||
* \throws DriverException
|
||||
*/
|
||||
uint8_t digitalRead1(void);
|
||||
|
||||
/**
|
||||
* Liest den Wert des digitalen Eingabeports, an dem der DIP-switch angeschlossen ist (S7)
|
||||
* \return Wert für gesamten Port
|
||||
* \throws DriverException
|
||||
*/
|
||||
uint8_t readDipSwitch(void);
|
||||
|
||||
/**
|
||||
* Setzt den Wert des Digital-Analog-Converters (DAC / DAU) 0
|
||||
* \param port 10-Bit Wert
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool analogWrite0(uint16_t);
|
||||
|
||||
/**
|
||||
* Setzt den Wert des Digital-Analog-Converters (DAC / DAU) 1
|
||||
* \param port 10-Bit Wert
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool analogWrite1(uint16_t);
|
||||
|
||||
/**
|
||||
* Liest den Wert des Analog-Digital-Converters (ADC / ADU)
|
||||
* \param channel Kanalwahl von 0 - 7
|
||||
* \throws DriverException
|
||||
*/
|
||||
uint16_t analogRead(uint8_t channel);
|
||||
|
||||
/**
|
||||
* DAC 0 wird auf den Startwert gesetzt und dann schrittweise um Delta inkrementiert.
|
||||
* Für jeden eingestelleten DAC-Wert werden zwei ADCs (channel_a und channel_b) angesprochen und die Werte übermittelt.
|
||||
* Die Werte werden in buffer_a für Kanal a und buffer_b für Kanal b gespeichert.
|
||||
* \param channel_a Auswahl des ADC a, von 0 - 7
|
||||
* \param buffer_a Speichertort für Werte des Kanals a
|
||||
* \param offset_a Anzahl an Werten des Kanals a, die im Speicher übersprungen werden sollen
|
||||
* \param channel_b Auswahl des ADC b, von 0 - 7
|
||||
* \param buffer_b Speichertort für Werte des Kanals b
|
||||
* \param offset_b Anzahl an Werten des Kanals b, die im Speicher übersprungen werden
|
||||
* \param start Startwert des DACs
|
||||
* \param delta Schrittweite, mit welcher der DAC inkrementiert wird
|
||||
* \param count Anzahl an Inkrementierungen
|
||||
* \throws DriverException
|
||||
*/
|
||||
void analogSequence(uint8_t channel_a, uint16_t* buffer_a, uint32_t offset_a, uint8_t channel_b, uint16_t* buffer_b, uint32_t offset_b, uint16_t start, int16_t delta, uint16_t count);
|
||||
|
||||
/*************************/
|
||||
/**
|
||||
* Testet die USART Verbindung auf Funktion
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool testConnection(void);
|
||||
|
||||
/**
|
||||
* Testet die Integer Konvertierung der USART Verbindung
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool testIntConv(void);
|
||||
|
||||
/**
|
||||
* Liefert Informationen zur aktuellen Firmware des B15
|
||||
* \throws DriverException
|
||||
*/
|
||||
std::vector<std::string> getBoardInfo(void);
|
||||
|
||||
/**
|
||||
* Lässt den Treiber für eine angegebene Zeit pausieren
|
||||
* \param ms Verzögerung in Millisekunden
|
||||
*/
|
||||
void delay_ms(uint16_t ms);
|
||||
|
||||
/**
|
||||
* Lässt den Treiber für eine angegebene Zeit pausieren
|
||||
* \param us Verzögerung in Microsekunden
|
||||
*/
|
||||
void delay_us(uint16_t us);
|
||||
|
||||
/**
|
||||
* Liefert eine Referenz zur aktuellen Treiber-Instanz
|
||||
* @throws DriverException
|
||||
*/
|
||||
static B15F& getInstance(void);
|
||||
|
||||
/**
|
||||
* Führt ein Befehl auf dieser Maschine aus und liefert stdout zurück
|
||||
* \param cmd Der Befehl
|
||||
*/
|
||||
static std::string exec(std::string cmd);
|
||||
|
||||
/**
|
||||
* Multithread sicherer Abbruch des B15F-Treibers
|
||||
* \param msg Beschreibung der Abbruchursache
|
||||
*/
|
||||
static void abort(std::string msg);
|
||||
|
||||
/**
|
||||
* Multithread sicherer Abbruch des B15F-Treibers
|
||||
* \param ex Exception als Abbruchursache
|
||||
*/
|
||||
static void abort(std::exception& ex);
|
||||
|
||||
/**
|
||||
* Setzt eine Fehlerbehandlungsroutine für den Treiberabbruch (abort)
|
||||
* \param func Funktion, die Exception als Parameter bekommt
|
||||
*/
|
||||
static void setAbortHandler(errorhandler_t func);
|
||||
|
||||
/*************************************/
|
||||
|
||||
|
||||
// CONSTANTS
|
||||
const std::string PRE = "[B15F] ";
|
||||
constexpr static uint8_t MSG_OK = 0xFF;
|
||||
constexpr static uint8_t MSG_FAIL = 0xFE;
|
||||
constexpr static uint16_t RECONNECT_TIMEOUT = 64; // ms
|
||||
constexpr static uint16_t WDT_TIMEOUT = 15; // ms
|
||||
constexpr static uint8_t RECONNECT_TRIES = 3;
|
||||
constexpr static uint32_t BAUDRATE = 57600;
|
||||
|
||||
/*************************
|
||||
* Steuerbefehle für B15 *
|
||||
*************************/
|
||||
|
||||
/**
|
||||
* Versetzt das Board in den Selbsttest-Modus
|
||||
* WICHTIG: Es darf dabei nichts an den Klemmen angeschlossen sein!
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool activateSelfTestMode(void);
|
||||
|
||||
/**
|
||||
* Setzt den Wert des digitalen Ausgabeports 0
|
||||
* \param port Wert für gesamten Port
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool digitalWrite0(uint8_t);
|
||||
|
||||
/**
|
||||
* Setzt den Wert des digitalen Ausgabeports 1
|
||||
* \param port Wert für gesamten Port
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool digitalWrite1(uint8_t);
|
||||
|
||||
/**
|
||||
* Liest den Wert des digitalen Eingabeports 0
|
||||
* \return Wert für gesamten Port
|
||||
* \throws DriverException
|
||||
*/
|
||||
uint8_t digitalRead0(void);
|
||||
|
||||
/**
|
||||
* Liest den Wert des digitalen Eingabeports 1
|
||||
* \return Wert für gesamten Port
|
||||
* \throws DriverException
|
||||
*/
|
||||
uint8_t digitalRead1(void);
|
||||
|
||||
/**
|
||||
* Liest den Wert des digitalen Eingabeports, an dem der DIP-switch angeschlossen ist (S7)
|
||||
* \return Wert für gesamten Port
|
||||
* \throws DriverException
|
||||
*/
|
||||
uint8_t readDipSwitch(void);
|
||||
|
||||
/**
|
||||
* Setzt den Wert des Digital-Analog-Converters (DAC / DAU) 0
|
||||
* \param port 10-Bit Wert
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool analogWrite0(uint16_t port);
|
||||
|
||||
/**
|
||||
* Setzt den Wert des Digital-Analog-Converters (DAC / DAU) 1
|
||||
* \param port 10-Bit Wert
|
||||
* \throws DriverException
|
||||
*/
|
||||
bool analogWrite1(uint16_t port);
|
||||
|
||||
/**
|
||||
* Liest den Wert des Analog-Digital-Converters (ADC / ADU)
|
||||
* \param channel Kanalwahl von 0 - 7
|
||||
* \throws DriverException
|
||||
*/
|
||||
uint16_t analogRead(uint8_t channel);
|
||||
|
||||
/**
|
||||
* DAC 0 wird auf den Startwert gesetzt und dann schrittweise um Delta inkrementiert.
|
||||
* Für jeden eingestelleten DAC-Wert werden zwei ADCs (channel_a und channel_b) angesprochen und die Werte übermittelt.
|
||||
* Die Werte werden in buffer_a für Kanal a und buffer_b für Kanal b gespeichert.
|
||||
* \param channel_a Auswahl des ADC a, von 0 - 7
|
||||
* \param buffer_a Speichertort für Werte des Kanals a
|
||||
* \param offset_a Anzahl an Werten des Kanals a, die im Speicher übersprungen werden sollen
|
||||
* \param channel_b Auswahl des ADC b, von 0 - 7
|
||||
* \param buffer_b Speichertort für Werte des Kanals b
|
||||
* \param offset_b Anzahl an Werten des Kanals b, die im Speicher übersprungen werden
|
||||
* \param start Startwert des DACs
|
||||
* \param delta Schrittweite, mit welcher der DAC inkrementiert wird
|
||||
* \param count Anzahl an Inkrementierungen
|
||||
* \throws DriverException
|
||||
*/
|
||||
void analogSequence(uint8_t channel_a, uint16_t* buffer_a, uint32_t offset_a, uint8_t channel_b, uint16_t* buffer_b, uint32_t offset_b, uint16_t start, int16_t delta, uint16_t count);
|
||||
|
||||
/*************************/
|
||||
|
||||
|
||||
// CONSTANTS
|
||||
const std::string PRE = "[B15F] "; //!< B15F stdout prefix
|
||||
constexpr static uint8_t MSG_OK = 0xFF; //!< Value to acknowledge a received command
|
||||
constexpr static uint8_t MSG_FAIL = 0xFE; //!< Value to reject a received command
|
||||
constexpr static uint16_t RECONNECT_TIMEOUT = 64; //!< Time in ms after which a reconnect attempt aborts
|
||||
constexpr static uint16_t WDT_TIMEOUT = 15; //!< Time in ms after which the watch dog timer resets the MCU
|
||||
constexpr static uint8_t RECONNECT_TRIES = 3; //!< Maximum count of reconnect attempts after which the driver stops
|
||||
constexpr static uint32_t BAUDRATE = 57600; //!< USART baudrate for communication with the MCU
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Initialisiert und testet die Verbindung zum B15
|
||||
* \throws DriverException
|
||||
*/
|
||||
void init(void);
|
||||
|
||||
USART usart;
|
||||
static B15F* instance;
|
||||
static errorhandler_t errorhandler;
|
||||
|
||||
// REQUESTS
|
||||
constexpr static uint8_t RQ_DISC = 0;
|
||||
constexpr static uint8_t RQ_TEST = 1;
|
||||
constexpr static uint8_t RQ_INFO = 2;
|
||||
constexpr static uint8_t RQ_INT = 3;
|
||||
constexpr static uint8_t RQ_ST = 4;
|
||||
constexpr static uint8_t RQ_BA0 = 5;
|
||||
constexpr static uint8_t RQ_BA1 = 6;
|
||||
constexpr static uint8_t RQ_BE0 = 7;
|
||||
constexpr static uint8_t RQ_BE1 = 8;
|
||||
constexpr static uint8_t RQ_DSW = 9;
|
||||
constexpr static uint8_t RQ_AA0 = 10;
|
||||
constexpr static uint8_t RQ_AA1 = 11;
|
||||
constexpr static uint8_t RQ_ADC = 12;
|
||||
constexpr static uint8_t RQ_ADC_DAC_STROKE = 13;
|
||||
/**
|
||||
* Initialisiert und testet die Verbindung zum B15
|
||||
* \throws DriverException
|
||||
*/
|
||||
void init(void);
|
||||
|
||||
USART usart;
|
||||
static B15F* instance;
|
||||
static errorhandler_t errorhandler;
|
||||
|
||||
// REQUESTS
|
||||
constexpr static uint8_t RQ_DISC = 0;
|
||||
constexpr static uint8_t RQ_TEST = 1;
|
||||
constexpr static uint8_t RQ_INFO = 2;
|
||||
constexpr static uint8_t RQ_INT = 3;
|
||||
constexpr static uint8_t RQ_ST = 4;
|
||||
constexpr static uint8_t RQ_BA0 = 5;
|
||||
constexpr static uint8_t RQ_BA1 = 6;
|
||||
constexpr static uint8_t RQ_BE0 = 7;
|
||||
constexpr static uint8_t RQ_BE1 = 8;
|
||||
constexpr static uint8_t RQ_DSW = 9;
|
||||
constexpr static uint8_t RQ_AA0 = 10;
|
||||
constexpr static uint8_t RQ_AA1 = 11;
|
||||
constexpr static uint8_t RQ_ADC = 12;
|
||||
constexpr static uint8_t RQ_ADC_DAC_STROKE = 13;
|
||||
};
|
||||
|
||||
#endif // B15F_H
|
||||
|
|
|
@ -2,21 +2,21 @@
|
|||
|
||||
Dot::Dot(uint16_t x, uint16_t y, uint8_t curve) : x(x), y(y), curve(curve)
|
||||
{
|
||||
if(curve >= 64)
|
||||
throw std::range_error("Kurvenindex muss im Bereich [0, 63] liegen");
|
||||
if(curve >= 64)
|
||||
throw std::range_error("Kurvenindex muss im Bereich [0, 63] liegen");
|
||||
}
|
||||
|
||||
uint16_t Dot::getX() const
|
||||
{
|
||||
return x;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint16_t Dot::getY() const
|
||||
{
|
||||
return y;
|
||||
return y;
|
||||
}
|
||||
|
||||
uint8_t Dot::getCurve(void) const
|
||||
{
|
||||
return curve;
|
||||
return curve;
|
||||
}
|
||||
|
|
|
@ -4,17 +4,37 @@
|
|||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
/**
|
||||
* Immutable dot class with x and y coordinate and curve index.
|
||||
* Dots with the same curve index get the same color by plotty.
|
||||
*/
|
||||
|
||||
class Dot
|
||||
{
|
||||
public:
|
||||
Dot(uint16_t x, uint16_t y, uint8_t curve);
|
||||
uint16_t getX(void) const;
|
||||
uint16_t getY(void) const;
|
||||
uint8_t getCurve(void) const;
|
||||
|
||||
/**
|
||||
* Constructor with x and y coordinate and curve index.
|
||||
*/
|
||||
Dot(uint16_t x, uint16_t y, uint8_t curve);
|
||||
|
||||
/**
|
||||
* Returns the x coordinate.
|
||||
*/
|
||||
uint16_t getX(void) const;
|
||||
|
||||
/**
|
||||
* Returns the y coordinate.
|
||||
*/
|
||||
uint16_t getY(void) const;
|
||||
|
||||
/**
|
||||
* Returns the curve index.
|
||||
*/
|
||||
uint8_t getCurve(void) const;
|
||||
|
||||
private:
|
||||
uint16_t x, y;
|
||||
uint8_t curve;
|
||||
uint16_t x, y;
|
||||
uint8_t curve;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -5,28 +5,30 @@
|
|||
|
||||
// SOURCE: https://stackoverflow.com/a/8152888
|
||||
|
||||
/*! Exception driver problems, for instance incompatible firmware version. */
|
||||
|
||||
class DriverException: public std::exception
|
||||
{
|
||||
public:
|
||||
explicit DriverException(const char* message) : msg_(message)
|
||||
{
|
||||
}
|
||||
explicit DriverException(const char* message) : msg_(message)
|
||||
{
|
||||
}
|
||||
|
||||
explicit DriverException(const std::string& message) : msg_(message)
|
||||
{
|
||||
}
|
||||
explicit DriverException(const std::string& message) : msg_(message)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~DriverException() throw ()
|
||||
{
|
||||
}
|
||||
virtual ~DriverException() throw ()
|
||||
{
|
||||
}
|
||||
|
||||
virtual const char* what() const throw ()
|
||||
{
|
||||
return msg_.c_str();
|
||||
}
|
||||
virtual const char* what() const throw ()
|
||||
{
|
||||
return msg_.c_str();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string msg_;
|
||||
std::string msg_;
|
||||
};
|
||||
|
||||
#endif // DRIVEREXCEPTION_H
|
||||
|
|
|
@ -2,197 +2,197 @@
|
|||
|
||||
void PlottyFile::addDot(Dot& dot)
|
||||
{
|
||||
dots.push_back(dot);
|
||||
dots.push_back(dot);
|
||||
}
|
||||
|
||||
void PlottyFile::addDot(Dot dot)
|
||||
{
|
||||
dots.push_back(dot);
|
||||
dots.push_back(dot);
|
||||
}
|
||||
|
||||
void PlottyFile::setFunctionType(FunctionType function_type)
|
||||
{
|
||||
this->function_type = function_type;
|
||||
this->function_type = function_type;
|
||||
}
|
||||
|
||||
void PlottyFile::setQuadrant(uint8_t quadrant)
|
||||
{
|
||||
if(quadrant < 1 || quadrant > 4)
|
||||
throw std::range_error("Ungueltiger Quadrant");
|
||||
this->quadrant = quadrant;
|
||||
if(quadrant < 1 || quadrant > 4)
|
||||
throw std::range_error("Ungueltiger Quadrant");
|
||||
this->quadrant = quadrant;
|
||||
}
|
||||
|
||||
void PlottyFile::setRefX(uint16_t ref_x)
|
||||
{
|
||||
this->ref_x = ref_x;
|
||||
this->ref_x = ref_x;
|
||||
}
|
||||
|
||||
void PlottyFile::setRefY(uint16_t ref_y)
|
||||
{
|
||||
this->ref_y = ref_y;
|
||||
this->ref_y = ref_y;
|
||||
}
|
||||
|
||||
void PlottyFile::setParaFirstCurve(uint16_t para_first)
|
||||
{
|
||||
this->para_first = para_first;
|
||||
this->para_first = para_first;
|
||||
}
|
||||
|
||||
void PlottyFile::setParaStepWidth(uint16_t para_stepwidth)
|
||||
{
|
||||
this->para_stepwidth = para_stepwidth;
|
||||
this->para_stepwidth = para_stepwidth;
|
||||
}
|
||||
|
||||
void PlottyFile::setUnitX(std::string unit_x)
|
||||
{
|
||||
this->unit_x = unit_x;
|
||||
this->unit_x = unit_x;
|
||||
}
|
||||
|
||||
void PlottyFile::setDescX(std::string desc_x)
|
||||
{
|
||||
this->desc_x = desc_x;
|
||||
this->desc_x = desc_x;
|
||||
}
|
||||
|
||||
void PlottyFile::setUnitY(std::string unit_y)
|
||||
{
|
||||
this->unit_y = unit_y;
|
||||
this->unit_y = unit_y;
|
||||
}
|
||||
|
||||
void PlottyFile::setDescY(std::string desc_y)
|
||||
{
|
||||
this->desc_y = desc_y;
|
||||
this->desc_y = desc_y;
|
||||
}
|
||||
|
||||
void PlottyFile::setUnitPara(std::string unit_para)
|
||||
{
|
||||
this->unit_para = unit_para;
|
||||
this->unit_para = unit_para;
|
||||
}
|
||||
|
||||
void PlottyFile::setDescPara(std::string desc_para)
|
||||
{
|
||||
this->desc_para = desc_para;
|
||||
this->desc_para = desc_para;
|
||||
}
|
||||
|
||||
|
||||
FunctionType PlottyFile::getFunctionType() const
|
||||
{
|
||||
return function_type;
|
||||
return function_type;
|
||||
}
|
||||
|
||||
uint8_t PlottyFile::getQuadrant() const
|
||||
{
|
||||
return quadrant;
|
||||
return quadrant;
|
||||
}
|
||||
|
||||
uint16_t PlottyFile::getRefX() const
|
||||
{
|
||||
return ref_x;
|
||||
return ref_x;
|
||||
}
|
||||
|
||||
uint16_t PlottyFile::getRefY() const
|
||||
{
|
||||
return ref_y;
|
||||
return ref_y;
|
||||
}
|
||||
|
||||
uint16_t PlottyFile::getParaFirstCurve() const
|
||||
{
|
||||
return para_first;
|
||||
return para_first;
|
||||
}
|
||||
|
||||
uint16_t PlottyFile::getParaStepWidth() const
|
||||
{
|
||||
return para_stepwidth;
|
||||
return para_stepwidth;
|
||||
}
|
||||
|
||||
std::string PlottyFile::getUnitX() const
|
||||
{
|
||||
return unit_x;
|
||||
return unit_x;
|
||||
}
|
||||
|
||||
std::string PlottyFile::getDescX() const
|
||||
{
|
||||
return desc_x;
|
||||
return desc_x;
|
||||
}
|
||||
|
||||
std::string PlottyFile::getUnitY() const
|
||||
{
|
||||
return unit_y;
|
||||
return unit_y;
|
||||
}
|
||||
|
||||
std::string PlottyFile::getDescY() const
|
||||
{
|
||||
return desc_y;
|
||||
return desc_y;
|
||||
}
|
||||
|
||||
std::string PlottyFile::getUnitPara() const
|
||||
{
|
||||
return unit_para;
|
||||
return unit_para;
|
||||
}
|
||||
|
||||
std::string PlottyFile::getDescPara() const
|
||||
{
|
||||
return desc_para;
|
||||
return desc_para;
|
||||
}
|
||||
|
||||
void PlottyFile::prepStr(std::string& str, uint8_t len)
|
||||
{
|
||||
if(str.length() > len)
|
||||
throw std::runtime_error("Zu grosser String.");
|
||||
|
||||
if(str.length() != len)
|
||||
str += '\n';
|
||||
|
||||
while(str.length() < len)
|
||||
str += '\0';
|
||||
if(str.length() > len)
|
||||
throw std::runtime_error("Zu grosser String.");
|
||||
|
||||
if(str.length() != len)
|
||||
str += '\n';
|
||||
|
||||
while(str.length() < len)
|
||||
str += '\0';
|
||||
}
|
||||
|
||||
void PlottyFile::writeToFile(std::string filename)
|
||||
{
|
||||
prepStr(unit_x, STR_LEN_SHORT);
|
||||
prepStr(desc_x, STR_LEN_LARGE);
|
||||
prepStr(unit_y, STR_LEN_SHORT);
|
||||
prepStr(desc_y, STR_LEN_LARGE);
|
||||
prepStr(unit_para, STR_LEN_SHORT);
|
||||
prepStr(desc_para, STR_LEN_LARGE);
|
||||
|
||||
std::ofstream file(filename);
|
||||
|
||||
// write file header
|
||||
file.write(reinterpret_cast<char*>(&command), 1);
|
||||
file.write(head.c_str(), head.length());
|
||||
file.write(filetype.c_str(), filetype.length());
|
||||
file.write(reinterpret_cast<char*>(&version), 2);
|
||||
file.write(reinterpret_cast<char*>(&subversion), 2);
|
||||
file.put(static_cast<uint8_t>(function_type));
|
||||
file.write(reinterpret_cast<char*>(&quadrant), 1);
|
||||
file.write(reinterpret_cast<char*>(&ref_x), 2);
|
||||
file.write(reinterpret_cast<char*>(&ref_y), 2);
|
||||
file.write(reinterpret_cast<char*>(¶_first), 2);
|
||||
file.write(reinterpret_cast<char*>(¶_stepwidth), 2);
|
||||
file.write(unit_x.c_str(), unit_x.length());
|
||||
file.write(desc_x.c_str(), desc_x.length());
|
||||
file.write(unit_y.c_str(), unit_y.length());
|
||||
file.write(desc_y.c_str(), desc_y.length());
|
||||
file.write(unit_para.c_str(), unit_para.length());
|
||||
file.write(desc_para.c_str(), desc_para.length());
|
||||
file.write(reinterpret_cast<const char*>(&eof), 1);
|
||||
|
||||
// make sure header size is 256 Byte
|
||||
while(file.tellp() < 256)
|
||||
file.put(0);
|
||||
|
||||
for(Dot& dot : dots)
|
||||
{
|
||||
file.put((dot.getX() >> 8) | (static_cast<uint8_t>(dot.getCurve()) << 2));
|
||||
file.put(dot.getX() & 0xFF);
|
||||
file.put(dot.getY() >> 8);
|
||||
file.put(dot.getY() & 0xFF);
|
||||
}
|
||||
|
||||
file.close();
|
||||
{
|
||||
prepStr(unit_x, STR_LEN_SHORT);
|
||||
prepStr(desc_x, STR_LEN_LARGE);
|
||||
prepStr(unit_y, STR_LEN_SHORT);
|
||||
prepStr(desc_y, STR_LEN_LARGE);
|
||||
prepStr(unit_para, STR_LEN_SHORT);
|
||||
prepStr(desc_para, STR_LEN_LARGE);
|
||||
|
||||
std::ofstream file(filename);
|
||||
|
||||
// write file header
|
||||
file.write(reinterpret_cast<char*>(&command), 1);
|
||||
file.write(head.c_str(), head.length());
|
||||
file.write(filetype.c_str(), filetype.length());
|
||||
file.write(reinterpret_cast<char*>(&version), 2);
|
||||
file.write(reinterpret_cast<char*>(&subversion), 2);
|
||||
file.put(static_cast<uint8_t>(function_type));
|
||||
file.write(reinterpret_cast<char*>(&quadrant), 1);
|
||||
file.write(reinterpret_cast<char*>(&ref_x), 2);
|
||||
file.write(reinterpret_cast<char*>(&ref_y), 2);
|
||||
file.write(reinterpret_cast<char*>(¶_first), 2);
|
||||
file.write(reinterpret_cast<char*>(¶_stepwidth), 2);
|
||||
file.write(unit_x.c_str(), unit_x.length());
|
||||
file.write(desc_x.c_str(), desc_x.length());
|
||||
file.write(unit_y.c_str(), unit_y.length());
|
||||
file.write(desc_y.c_str(), desc_y.length());
|
||||
file.write(unit_para.c_str(), unit_para.length());
|
||||
file.write(desc_para.c_str(), desc_para.length());
|
||||
file.write(reinterpret_cast<const char*>(&eof), 1);
|
||||
|
||||
// make sure header size is 256 Byte
|
||||
while(file.tellp() < 256)
|
||||
file.put(0);
|
||||
|
||||
for(Dot& dot : dots)
|
||||
{
|
||||
file.put((dot.getX() >> 8) | (static_cast<uint8_t>(dot.getCurve()) << 2));
|
||||
file.put(dot.getX() & 0xFF);
|
||||
file.put(dot.getY() >> 8);
|
||||
file.put(dot.getY() & 0xFF);
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void PlottyFile::startPlotty(std::string filename)
|
||||
{
|
||||
int code = system(("plotty --in " + filename).c_str());
|
||||
if(code)
|
||||
throw std::runtime_error("Fehler beim Aufruf von plotty");
|
||||
int code = system(("plotty --in " + filename).c_str());
|
||||
if(code)
|
||||
throw std::runtime_error("Fehler beim Aufruf von plotty");
|
||||
}
|
||||
|
|
|
@ -9,71 +9,200 @@
|
|||
|
||||
enum FunctionType
|
||||
{
|
||||
CurveFamily = 'S',
|
||||
Curve = 'C',
|
||||
Level = 'P'
|
||||
};
|
||||
CurveFamily = 'S',
|
||||
Curve = 'C',
|
||||
Level = 'P'
|
||||
};
|
||||
|
||||
/*! Wrapper class for convenient plot file creation, needed to display graphs using plotty. */
|
||||
|
||||
class PlottyFile
|
||||
{
|
||||
public:
|
||||
void addDot(Dot& dot);
|
||||
void addDot(Dot dot);
|
||||
|
||||
void setFunctionType(FunctionType);
|
||||
void setQuadrant(uint8_t);
|
||||
void setRefX(uint16_t);
|
||||
void setRefY(uint16_t);
|
||||
void setParaFirstCurve(uint16_t);
|
||||
void setParaStepWidth(uint16_t);
|
||||
void setUnitX(std::string);
|
||||
void setDescX(std::string);
|
||||
void setUnitY(std::string);
|
||||
void setDescY(std::string);
|
||||
void setUnitPara(std::string);
|
||||
void setDescPara(std::string);
|
||||
|
||||
FunctionType getFunctionType(void) const;
|
||||
uint8_t getQuadrant(void) const;
|
||||
uint16_t getRefX(void) const;
|
||||
uint16_t getRefY(void) const;
|
||||
uint16_t getParaFirstCurve(void) const;
|
||||
uint16_t getParaStepWidth(void) const;
|
||||
std::string getUnitX(void) const;
|
||||
std::string getDescX(void) const;
|
||||
std::string getUnitY(void) const;
|
||||
std::string getDescY(void) const;
|
||||
std::string getUnitPara(void) const;
|
||||
std::string getDescPara(void) const;
|
||||
|
||||
void writeToFile(std::string filename);
|
||||
void startPlotty(std::string filename);
|
||||
/**
|
||||
* Adds a dot to the plotty file.
|
||||
* \param dot the dot
|
||||
*/
|
||||
void addDot(Dot& dot);
|
||||
|
||||
/**
|
||||
* Adds a dot by reference to the plotty file.
|
||||
* \param dot the dot
|
||||
*/
|
||||
void addDot(Dot dot);
|
||||
|
||||
/**
|
||||
* Sets the FunctionType of this plotty file.
|
||||
* \param function_type enum value
|
||||
*/
|
||||
void setFunctionType(FunctionType function_type);
|
||||
|
||||
/**
|
||||
* Sets the quadrant of this plot.
|
||||
* \param quadrant quadrant number (1..4)
|
||||
*/
|
||||
void setQuadrant(uint8_t quadrant);
|
||||
|
||||
/**
|
||||
* Sets reference (max) value of the x axis
|
||||
* \param ref_x reference value
|
||||
*/
|
||||
void setRefX(uint16_t ref_x);
|
||||
|
||||
/**
|
||||
* Sets reference (max) value of the y axis
|
||||
* \param ref_y reference value
|
||||
*/
|
||||
void setRefY(uint16_t ref_y);
|
||||
|
||||
/**
|
||||
* Sets initial value of the parameter.
|
||||
* Gets used together with the stepwith to label the curves.
|
||||
* \param para_first initial parameter value
|
||||
*/
|
||||
void setParaFirstCurve(uint16_t para_first);
|
||||
|
||||
/**
|
||||
* Sets the stepwith the parameter got increased with each curve.
|
||||
* \param para_first parameter stepwith
|
||||
*/
|
||||
void setParaStepWidth(uint16_t para_stepwidth);
|
||||
|
||||
/**
|
||||
* Sets the unit of the x axis.
|
||||
* \param para_first unit
|
||||
*/
|
||||
void setUnitX(std::string unit_x);
|
||||
|
||||
/**
|
||||
* Sets the description of the x axis.
|
||||
* \param para_first description
|
||||
*/
|
||||
void setDescX(std::string desc_x);
|
||||
|
||||
/**
|
||||
* Sets the unit of the y axis.
|
||||
* \param para_first unit
|
||||
*/
|
||||
void setUnitY(std::string unit_y);
|
||||
|
||||
/**
|
||||
* Sets the description of the y axis.
|
||||
* \param para_first description
|
||||
*/
|
||||
void setDescY(std::string desc_y);
|
||||
|
||||
/**
|
||||
* Sets the unit of the parameter.
|
||||
* \param para_first unit
|
||||
*/
|
||||
void setUnitPara(std::string unit_para);
|
||||
/**
|
||||
* Sets the description of the parameter.
|
||||
* \param para_first description
|
||||
*/
|
||||
void setDescPara(std::string desc_para);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \return the FunctionType
|
||||
*/
|
||||
FunctionType getFunctionType(void) const;
|
||||
|
||||
/**
|
||||
* \return the quadrant
|
||||
*/
|
||||
uint8_t getQuadrant(void) const;
|
||||
|
||||
/**
|
||||
* \return x reference (max) value
|
||||
*/
|
||||
uint16_t getRefX(void) const;
|
||||
|
||||
/**
|
||||
* \return y reference (max) value
|
||||
*/
|
||||
uint16_t getRefY(void) const;
|
||||
|
||||
/**
|
||||
* \return initial parameter value
|
||||
*/
|
||||
uint16_t getParaFirstCurve(void) const;
|
||||
|
||||
/**
|
||||
* \return parameter stepwith
|
||||
*/
|
||||
uint16_t getParaStepWidth(void) const;
|
||||
|
||||
/**
|
||||
* \return unit of x axis
|
||||
*/
|
||||
std::string getUnitX(void) const;
|
||||
|
||||
/**
|
||||
* \return description of x axis
|
||||
*/
|
||||
std::string getDescX(void) const;
|
||||
|
||||
/**
|
||||
* \return unit of y axis
|
||||
*/
|
||||
std::string getUnitY(void) const;
|
||||
|
||||
/**
|
||||
* \return description of y axis
|
||||
*/
|
||||
std::string getDescY(void) const;
|
||||
|
||||
/**
|
||||
* \return unit of parameter
|
||||
*/
|
||||
std::string getUnitPara(void) const;
|
||||
|
||||
/**
|
||||
* \return description of parameter
|
||||
*/
|
||||
std::string getDescPara(void) const;
|
||||
|
||||
|
||||
/**
|
||||
* Saves the PlottyFile in a binary format, ready to open with plotty.
|
||||
* \param filename desired plot path
|
||||
*/
|
||||
void writeToFile(std::string filename);
|
||||
|
||||
/**
|
||||
* Starts plotty with a plot file.
|
||||
* \param filename plot path
|
||||
*/
|
||||
void startPlotty(std::string filename);
|
||||
private:
|
||||
void prepStr(std::string& str, uint8_t len);
|
||||
void prepStr(std::string& str, uint8_t len);
|
||||
|
||||
std::vector<Dot> dots;
|
||||
std::vector<Dot> dots;
|
||||
|
||||
int8_t command = 0x1D;
|
||||
const std::string head = "HTWK-HWLab";
|
||||
const std::string filetype = "MD";
|
||||
int16_t version = 1;
|
||||
int16_t subversion = 0;
|
||||
FunctionType function_type = FunctionType::Curve;
|
||||
uint8_t quadrant = 1;
|
||||
uint16_t ref_x = 1023;
|
||||
uint16_t ref_y = 1023;
|
||||
uint16_t para_first = 1;
|
||||
uint16_t para_stepwidth = 1;
|
||||
std::string unit_x;
|
||||
std::string desc_x;
|
||||
std::string unit_y;
|
||||
std::string desc_y;
|
||||
std::string unit_para;
|
||||
std::string desc_para;
|
||||
const uint8_t eof = 0xD;
|
||||
|
||||
constexpr static uint8_t STR_LEN_SHORT = 10;
|
||||
constexpr static uint8_t STR_LEN_LARGE = 20;
|
||||
int8_t command = 0x1D;
|
||||
const std::string head = "HTWK-HWLab";
|
||||
const std::string filetype = "MD";
|
||||
int16_t version = 1;
|
||||
int16_t subversion = 0;
|
||||
FunctionType function_type = FunctionType::Curve;
|
||||
uint8_t quadrant = 1;
|
||||
uint16_t ref_x = 1023;
|
||||
uint16_t ref_y = 1023;
|
||||
uint16_t para_first = 1;
|
||||
uint16_t para_stepwidth = 1;
|
||||
std::string unit_x;
|
||||
std::string desc_x;
|
||||
std::string unit_y;
|
||||
std::string desc_y;
|
||||
std::string unit_para;
|
||||
std::string desc_para;
|
||||
const uint8_t eof = 0xD;
|
||||
|
||||
constexpr static uint8_t STR_LEN_SHORT = 10;
|
||||
constexpr static uint8_t STR_LEN_LARGE = 20;
|
||||
};
|
||||
|
||||
#endif // PLOTTYFILE_H
|
||||
|
|
|
@ -5,31 +5,33 @@
|
|||
|
||||
// SOURCE: https://stackoverflow.com/a/8152888
|
||||
|
||||
/*! Exception for USART related timeouts. */
|
||||
|
||||
class TimeoutException: public std::exception
|
||||
{
|
||||
public:
|
||||
explicit TimeoutException(const char* message, int timeout) : TimeoutException(std::string(message), timeout)
|
||||
{
|
||||
}
|
||||
explicit TimeoutException(const char* message, int timeout) : TimeoutException(std::string(message), timeout)
|
||||
{
|
||||
}
|
||||
|
||||
explicit TimeoutException(const std::string& message, int timeout) : msg(message), m_timeout(timeout)
|
||||
{
|
||||
if(!msg.length())
|
||||
msg = "Timeout reached (" + std::to_string(m_timeout) + ")";
|
||||
}
|
||||
explicit TimeoutException(const std::string& message, int timeout) : msg(message), m_timeout(timeout)
|
||||
{
|
||||
if(!msg.length())
|
||||
msg = "Timeout reached (" + std::to_string(m_timeout) + ")";
|
||||
}
|
||||
|
||||
virtual ~TimeoutException() throw ()
|
||||
{
|
||||
}
|
||||
virtual ~TimeoutException() throw ()
|
||||
{
|
||||
}
|
||||
|
||||
virtual const char* what() const throw ()
|
||||
{
|
||||
return msg.c_str();
|
||||
}
|
||||
virtual const char* what() const throw ()
|
||||
{
|
||||
return msg.c_str();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string msg;
|
||||
int m_timeout;
|
||||
std::string msg;
|
||||
int m_timeout;
|
||||
};
|
||||
|
||||
#endif // TIMEOUTEXCEPTION_H
|
||||
|
|
|
@ -2,323 +2,324 @@
|
|||
|
||||
void USART::openDevice(std::string device)
|
||||
{
|
||||
file_desc = open(device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY /* | O_NONBLOCK*/);
|
||||
if(file_desc <= 0)
|
||||
throw USARTException("Fehler beim Öffnen des Gerätes");
|
||||
|
||||
struct termios options;
|
||||
int code = tcgetattr(file_desc, &options);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Lesen der Geräteparameter");
|
||||
|
||||
options.c_cflag = CS8 | CLOCAL | CREAD;
|
||||
options.c_iflag = IGNPAR;
|
||||
options.c_oflag = 0;
|
||||
options.c_lflag = 0;
|
||||
options.c_cc[VMIN] = 0; // #bytes read returns at least
|
||||
options.c_cc[VTIME] = timeout;
|
||||
file_desc = open(device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY /* | O_NONBLOCK*/);
|
||||
if(file_desc <= 0)
|
||||
throw USARTException("Fehler beim Öffnen des Gerätes");
|
||||
|
||||
struct termios options;
|
||||
int code = tcgetattr(file_desc, &options);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Lesen der Geräteparameter");
|
||||
|
||||
options.c_cflag = CS8 | CLOCAL | CREAD;
|
||||
options.c_iflag = IGNPAR;
|
||||
options.c_oflag = 0;
|
||||
options.c_lflag = 0;
|
||||
options.c_cc[VMIN] = 0; // #bytes read returns at least
|
||||
options.c_cc[VTIME] = timeout;
|
||||
code = cfsetspeed(&options, baudrate);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Setzen der Baudrate");
|
||||
|
||||
code = tcsetattr(file_desc, TCSANOW, &options);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Setzen der Geräteparameter");
|
||||
|
||||
clearOutputBuffer();
|
||||
clearInputBuffer();
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Setzen der Baudrate");
|
||||
|
||||
code = tcsetattr(file_desc, TCSANOW, &options);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Setzen der Geräteparameter");
|
||||
|
||||
clearOutputBuffer();
|
||||
clearInputBuffer();
|
||||
}
|
||||
|
||||
|
||||
void USART::closeDevice()
|
||||
{
|
||||
int code = close(file_desc);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Schließen des Gerätes");
|
||||
int code = close(file_desc);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Schließen des Gerätes");
|
||||
}
|
||||
|
||||
|
||||
void USART::clearInputBuffer()
|
||||
{
|
||||
int code = tcflush(file_desc, TCIFLUSH);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Leeren des Eingangspuffers");
|
||||
int code = tcflush(file_desc, TCIFLUSH);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Leeren des Eingangspuffers");
|
||||
}
|
||||
|
||||
|
||||
void USART::clearOutputBuffer()
|
||||
{
|
||||
int code = tcflush(file_desc, TCOFLUSH);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Leeren des Ausgangspuffers");
|
||||
int code = tcflush(file_desc, TCOFLUSH);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Leeren des Ausgangspuffers");
|
||||
}
|
||||
|
||||
|
||||
void USART::flushOutputBuffer()
|
||||
{
|
||||
int code = tcdrain(file_desc);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Versenden des Ausgangspuffers");
|
||||
int code = tcdrain(file_desc);
|
||||
if(code)
|
||||
throw USARTException("Fehler beim Versenden des Ausgangspuffers");
|
||||
}
|
||||
|
||||
void USART::printStatistics()
|
||||
{
|
||||
double pz = 1e2 * n_blocks_failed / n_blocks_total;
|
||||
pz = std::round(pz * 1e2) / 1e2;
|
||||
std::cout << "blocks total: " << n_blocks_total << " ok: " << (n_blocks_total - n_blocks_failed) << " failed: " << n_blocks_failed << " (" << pz << "%)" << std::endl;
|
||||
double pz = 1e2 * n_blocks_failed / n_blocks_total;
|
||||
pz = std::round(pz * 1e2) / 1e2;
|
||||
std::cout << "blocks total: " << n_blocks_total << " ok: " << (n_blocks_total - n_blocks_failed) << " failed: " << n_blocks_failed << " (" << pz << "%)" << std::endl;
|
||||
}
|
||||
|
||||
void USART::writeByte(uint8_t b)
|
||||
{
|
||||
int sent = write(file_desc, &b, 1);
|
||||
if(sent != 1)
|
||||
{
|
||||
std::cout << "WARNUNG: Fehler beim Senden (" << sent << "): writeByte(), wiederhole..." << std::endl;
|
||||
usleep(100000);
|
||||
sent = write(file_desc, &b, 1);
|
||||
if(sent != 1)
|
||||
throw USARTException("Fehler beim Senden: writeByte()");
|
||||
}
|
||||
|
||||
int sent = write(file_desc, &b, 1);
|
||||
if(sent != 1)
|
||||
{
|
||||
std::cout << "WARNUNG: Fehler beim Senden (" << sent << "): writeByte(), wiederhole..." << std::endl;
|
||||
usleep(100000);
|
||||
sent = write(file_desc, &b, 1);
|
||||
if(sent != 1)
|
||||
throw USARTException("Fehler beim Senden: writeByte()");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void USART::writeInt(uint16_t d)
|
||||
{
|
||||
int sent = write(file_desc, reinterpret_cast<char*>(&d), 2);
|
||||
if(sent != 2)
|
||||
throw USARTException("Fehler beim Senden: writeInt()");
|
||||
int sent = write(file_desc, reinterpret_cast<char*>(&d), 2);
|
||||
if(sent != 2)
|
||||
throw USARTException("Fehler beim Senden: writeInt()");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int USART::read_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout)
|
||||
{
|
||||
uint32_t elapsed = 0;
|
||||
int n_read = -1;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto end = start;
|
||||
while(elapsed < timeout)
|
||||
{
|
||||
n_read = read(file_desc, buffer + offset, len);
|
||||
if (n_read == len)
|
||||
return n_read;
|
||||
|
||||
end = std::chrono::steady_clock::now();
|
||||
elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
|
||||
}
|
||||
|
||||
return 0;
|
||||
uint32_t elapsed = 0;
|
||||
int n_read = -1;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto end = start;
|
||||
while(elapsed < timeout)
|
||||
{
|
||||
n_read = read(file_desc, buffer + offset, len);
|
||||
if (n_read == len)
|
||||
return n_read;
|
||||
|
||||
end = std::chrono::steady_clock::now();
|
||||
elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int USART::write_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout)
|
||||
{
|
||||
uint32_t elapsed = 0;
|
||||
int n_sent = -1;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto end = start;
|
||||
while(elapsed < timeout)
|
||||
{
|
||||
n_sent = write(file_desc, buffer + offset, len);
|
||||
flushOutputBuffer();
|
||||
if (n_sent == len)
|
||||
return n_sent;
|
||||
|
||||
end = std::chrono::steady_clock::now();
|
||||
elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
|
||||
}
|
||||
|
||||
return n_sent;
|
||||
uint32_t elapsed = 0;
|
||||
int n_sent = -1;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto end = start;
|
||||
while(elapsed < timeout)
|
||||
{
|
||||
n_sent = write(file_desc, buffer + offset, len);
|
||||
flushOutputBuffer();
|
||||
if (n_sent == len)
|
||||
return n_sent;
|
||||
|
||||
end = std::chrono::steady_clock::now();
|
||||
elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
|
||||
}
|
||||
|
||||
return n_sent;
|
||||
}
|
||||
|
||||
void USART::writeBlock(uint8_t* buffer, uint16_t offset, uint8_t len)
|
||||
{
|
||||
uint8_t crc;
|
||||
uint8_t aw;
|
||||
const uint16_t us_per_bit = (1000000 / baudrate) * 16;
|
||||
const uint16_t n_total = len + 3;
|
||||
|
||||
n_blocks_total++;
|
||||
bool failed = false;
|
||||
|
||||
do
|
||||
{
|
||||
// calc crc
|
||||
crc = 0;
|
||||
for(uint8_t i = 0; i < len; i++)
|
||||
{
|
||||
crc ^= buffer[i];
|
||||
for (uint8_t k = 0; k < 8; k++)
|
||||
{
|
||||
if (crc & 1)
|
||||
crc ^= CRC7_POLY;
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// construct block
|
||||
block_buffer[0] = len;
|
||||
std::memcpy(&block_buffer[1], buffer + offset, len);
|
||||
block_buffer[len + 1] = crc;
|
||||
block_buffer[len + 2] = BLOCK_END;
|
||||
|
||||
// send block
|
||||
clearOutputBuffer();
|
||||
clearInputBuffer();
|
||||
int n_sent = write_timeout(&block_buffer[0], 0, len + 3, us_per_bit * n_total);
|
||||
if(n_sent != n_total)
|
||||
throw std::runtime_error("fatal (send): " + std::to_string(n_sent));
|
||||
|
||||
/*for(uint8_t i = 0; i < len + 3; i++)
|
||||
{
|
||||
write_timeout(&block_buffer[i], 0, 1, us_per_bit * n_total);
|
||||
//tcdrain(file_desc);
|
||||
//usleep(1000);
|
||||
}*/
|
||||
|
||||
// flush output data
|
||||
tcdrain(file_desc);
|
||||
|
||||
//usleep(us_per_bit * n_total * 10);
|
||||
|
||||
// check response
|
||||
int n_read = read_timeout(&aw, 0, 1, us_per_bit * n_blocks_total * 10);
|
||||
for(uint16_t i = 0; i < 255 && n_read != 1; i++)
|
||||
{
|
||||
writeByte(0x80); // Stoppzeichen für Block
|
||||
if(tcdrain(file_desc))
|
||||
{
|
||||
std::cout << "drain failed" << std::endl;
|
||||
}
|
||||
std::cout << "WARNING: read error (" << n_read << "), retry #" << (int) i << std::endl;
|
||||
usleep(us_per_bit*100);
|
||||
n_read = read_timeout(&aw, 0, 1, us_per_bit);
|
||||
}
|
||||
|
||||
if(n_read != 1)
|
||||
throw std::runtime_error("fatal: " + std::to_string(n_read));
|
||||
|
||||
//clearInputBuffer();
|
||||
|
||||
if(aw != 0xFF) {
|
||||
if(!failed)
|
||||
n_blocks_failed++;
|
||||
failed = true;
|
||||
std::cout << "block failed, retry" << std::endl;
|
||||
}
|
||||
}
|
||||
while(aw != 0xFF);
|
||||
|
||||
//std::cout << "OK" << std::endl;
|
||||
uint8_t crc;
|
||||
uint8_t aw;
|
||||
const uint16_t us_per_bit = (1000000 / baudrate) * 16;
|
||||
const uint16_t n_total = len + 3;
|
||||
|
||||
n_blocks_total++;
|
||||
bool failed = false;
|
||||
|
||||
do
|
||||
{
|
||||
// calc crc
|
||||
crc = 0;
|
||||
for(uint8_t i = 0; i < len; i++)
|
||||
{
|
||||
crc ^= buffer[i];
|
||||
for (uint8_t k = 0; k < 8; k++)
|
||||
{
|
||||
if (crc & 1)
|
||||
crc ^= CRC7_POLY;
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// construct block
|
||||
block_buffer[0] = len;
|
||||
std::memcpy(&block_buffer[1], buffer + offset, len);
|
||||
block_buffer[len + 1] = crc;
|
||||
block_buffer[len + 2] = BLOCK_END;
|
||||
|
||||
// send block
|
||||
clearOutputBuffer();
|
||||
clearInputBuffer();
|
||||
int n_sent = write_timeout(&block_buffer[0], 0, len + 3, us_per_bit * n_total);
|
||||
if(n_sent != n_total)
|
||||
throw std::runtime_error("fatal (send): " + std::to_string(n_sent));
|
||||
|
||||
/*for(uint8_t i = 0; i < len + 3; i++)
|
||||
{
|
||||
write_timeout(&block_buffer[i], 0, 1, us_per_bit * n_total);
|
||||
//tcdrain(file_desc);
|
||||
//usleep(1000);
|
||||
}*/
|
||||
|
||||
// flush output data
|
||||
tcdrain(file_desc);
|
||||
|
||||
//usleep(us_per_bit * n_total * 10);
|
||||
|
||||
// check response
|
||||
int n_read = read_timeout(&aw, 0, 1, us_per_bit * n_blocks_total * 10);
|
||||
for(uint16_t i = 0; i < 255 && n_read != 1; i++)
|
||||
{
|
||||
writeByte(0x80); // Stoppzeichen für Block
|
||||
if(tcdrain(file_desc))
|
||||
{
|
||||
std::cout << "drain failed" << std::endl;
|
||||
}
|
||||
std::cout << "WARNING: read error (" << n_read << "), retry #" << (int) i << std::endl;
|
||||
usleep(us_per_bit*100);
|
||||
n_read = read_timeout(&aw, 0, 1, us_per_bit);
|
||||
}
|
||||
|
||||
if(n_read != 1)
|
||||
throw std::runtime_error("fatal: " + std::to_string(n_read));
|
||||
|
||||
//clearInputBuffer();
|
||||
|
||||
if(aw != 0xFF)
|
||||
{
|
||||
if(!failed)
|
||||
n_blocks_failed++;
|
||||
failed = true;
|
||||
std::cout << "block failed, retry" << std::endl;
|
||||
}
|
||||
}
|
||||
while(aw != 0xFF);
|
||||
|
||||
//std::cout << "OK" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
uint8_t USART::readByte(void)
|
||||
{
|
||||
char b;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto end = start;
|
||||
uint16_t elapsed = 0;
|
||||
while(elapsed < timeout * 100)
|
||||
{
|
||||
int code = read(file_desc, &b, 1);
|
||||
if (code > 0)
|
||||
return static_cast<uint8_t>(b);
|
||||
|
||||
end = std::chrono::steady_clock::now();
|
||||
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
|
||||
}
|
||||
|
||||
throw TimeoutException("Verbindung unterbrochen.", timeout);
|
||||
char b;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto end = start;
|
||||
uint16_t elapsed = 0;
|
||||
while(elapsed < timeout * 100)
|
||||
{
|
||||
int code = read(file_desc, &b, 1);
|
||||
if (code > 0)
|
||||
return static_cast<uint8_t>(b);
|
||||
|
||||
end = std::chrono::steady_clock::now();
|
||||
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
|
||||
}
|
||||
|
||||
throw TimeoutException("Verbindung unterbrochen.", timeout);
|
||||
}
|
||||
|
||||
uint16_t USART::readInt(void)
|
||||
{
|
||||
return readByte() | readByte() << 8;
|
||||
return readByte() | readByte() << 8;
|
||||
}
|
||||
|
||||
bool USART::readBlock(uint8_t* buffer, uint16_t offset)
|
||||
{
|
||||
uint8_t len = readByte();
|
||||
uint8_t crc = 0;
|
||||
buffer += offset;
|
||||
|
||||
uint32_t block_timeout = timeout / 10;
|
||||
|
||||
// wait for block
|
||||
int n_ready;
|
||||
uint16_t elapsed = 0;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto end = start;
|
||||
while(elapsed < block_timeout)
|
||||
{
|
||||
int code = ioctl(file_desc, FIONREAD, &n_ready);
|
||||
if(code != 0)
|
||||
{
|
||||
std::cout << "n_ready code: " << code << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(n_ready >= len + 1)
|
||||
break;
|
||||
|
||||
end = std::chrono::steady_clock::now();
|
||||
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
|
||||
}
|
||||
if(elapsed >= timeout)
|
||||
{
|
||||
std::cout << "block timeout: " << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
while(len--)
|
||||
{
|
||||
*buffer = readByte();
|
||||
|
||||
crc ^= *buffer++;
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (crc & 1)
|
||||
crc ^= CRC7_POLY;
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
crc ^= readByte();
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (crc & 1)
|
||||
crc ^= CRC7_POLY;
|
||||
crc >>= 1;
|
||||
}
|
||||
|
||||
if(TEST == 1)
|
||||
crc = 1;
|
||||
if(TEST > 100)
|
||||
TEST = 0;
|
||||
|
||||
if (crc == 0)
|
||||
{
|
||||
writeByte(0xFF);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeByte(0xFE);
|
||||
return false;
|
||||
}
|
||||
uint8_t len = readByte();
|
||||
uint8_t crc = 0;
|
||||
buffer += offset;
|
||||
|
||||
uint32_t block_timeout = timeout / 10;
|
||||
|
||||
// wait for block
|
||||
int n_ready;
|
||||
uint16_t elapsed = 0;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto end = start;
|
||||
while(elapsed < block_timeout)
|
||||
{
|
||||
int code = ioctl(file_desc, FIONREAD, &n_ready);
|
||||
if(code != 0)
|
||||
{
|
||||
std::cout << "n_ready code: " << code << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(n_ready >= len + 1)
|
||||
break;
|
||||
|
||||
end = std::chrono::steady_clock::now();
|
||||
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
|
||||
}
|
||||
if(elapsed >= timeout)
|
||||
{
|
||||
std::cout << "block timeout: " << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
while(len--)
|
||||
{
|
||||
*buffer = readByte();
|
||||
|
||||
crc ^= *buffer++;
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (crc & 1)
|
||||
crc ^= CRC7_POLY;
|
||||
crc >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
crc ^= readByte();
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
if (crc & 1)
|
||||
crc ^= CRC7_POLY;
|
||||
crc >>= 1;
|
||||
}
|
||||
|
||||
if(TEST == 1)
|
||||
crc = 1;
|
||||
if(TEST > 100)
|
||||
TEST = 0;
|
||||
|
||||
if (crc == 0)
|
||||
{
|
||||
writeByte(0xFF);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeByte(0xFE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t USART::getBaudrate()
|
||||
{
|
||||
return baudrate;
|
||||
return baudrate;
|
||||
}
|
||||
|
||||
uint8_t USART::getTimeout()
|
||||
{
|
||||
return timeout;
|
||||
return timeout;
|
||||
}
|
||||
|
||||
|
||||
void USART::setBaudrate(uint32_t baudrate)
|
||||
{
|
||||
this->baudrate = baudrate;
|
||||
this->baudrate = baudrate;
|
||||
}
|
||||
|
||||
void USART::setTimeout(uint8_t timeout)
|
||||
{
|
||||
this->timeout = timeout;
|
||||
this->timeout = timeout;
|
||||
}
|
||||
|
|
|
@ -13,137 +13,139 @@
|
|||
#include "usartexception.h"
|
||||
#include "timeoutexception.h"
|
||||
|
||||
/*! C++ Wrapper class for termios usart library. */
|
||||
|
||||
class USART
|
||||
{
|
||||
public:
|
||||
|
||||
/*************************************************
|
||||
* Methoden für die Verwaltung der Schnittstelle *
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* Öffnet die USART Schnittstelle
|
||||
* \param device Linux-Gerätepfad
|
||||
* \throws USARTException
|
||||
*/
|
||||
void openDevice(std::string device);
|
||||
|
||||
/**
|
||||
* Schließt die USART Schnittstelle
|
||||
* \throws USARTException
|
||||
*/
|
||||
void closeDevice(void);
|
||||
|
||||
/**
|
||||
* Verwirft Daten, die bereits im Puffer liegen, aber noch nicht gelesen wurden
|
||||
* \throws USARTException
|
||||
*/
|
||||
void clearInputBuffer(void);
|
||||
|
||||
/**
|
||||
* Verwirft Daten, die bereits im Puffer liegen, aber noch nicht gesendet wurden
|
||||
* \throws USARTException
|
||||
*/
|
||||
void clearOutputBuffer(void);
|
||||
|
||||
/**
|
||||
* Schreibt Daten, die bereits im Puffer liegen, aber noch nicht gesendet wurden
|
||||
* \throws USARTException
|
||||
*/
|
||||
void flushOutputBuffer(void);
|
||||
|
||||
/**
|
||||
* Gibt Anzahl an erfolgreichen und fehlgeschlagenen Block-Übertragungen an
|
||||
*/
|
||||
void printStatistics(void);
|
||||
|
||||
/*************************************************/
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
* Methoden für die Datenübertragung *
|
||||
*************************************/
|
||||
|
||||
/**
|
||||
* Sendet ein Byte über die USART Schnittstelle
|
||||
* \param b das zu sendende Byte
|
||||
* \throws USARTException
|
||||
*/
|
||||
void writeByte(uint8_t b);
|
||||
|
||||
/**
|
||||
* Sendet ein Integer über die USART Schnittstelle
|
||||
* \param b das zu sendende Byte
|
||||
* \throws USARTException
|
||||
*/
|
||||
void writeInt(uint16_t d);
|
||||
|
||||
/**
|
||||
* Empfängt ein Byte über die USART Schnittstelle
|
||||
* \throws USARTException
|
||||
*/
|
||||
uint8_t readByte(void);
|
||||
|
||||
/**
|
||||
* Empfängt ein Integer über die USART Schnittstelle
|
||||
* \throws USARTException
|
||||
*/
|
||||
uint16_t readInt(void);
|
||||
|
||||
int read_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout);
|
||||
int write_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout);
|
||||
void writeBlock(uint8_t* buffer, uint16_t offset, uint8_t len);
|
||||
bool readBlock(uint8_t* buffer, uint16_t offset);
|
||||
|
||||
/*************************************/
|
||||
|
||||
|
||||
|
||||
/***************************************
|
||||
* Methoden für einstellbare Parameter *
|
||||
***************************************/
|
||||
|
||||
/**
|
||||
* Liefert die eingestellte Baudrate
|
||||
* <b>Änderungen werden erst nach einem open() wirksam</b>
|
||||
*/
|
||||
uint32_t getBaudrate(void);
|
||||
|
||||
/**
|
||||
* Liefert den eingestellten Timeout (in Dezisekunden)
|
||||
* <b>Änderungen werden erst nach einem open() wirksam</b>
|
||||
*/
|
||||
uint8_t getTimeout(void);
|
||||
|
||||
/**
|
||||
* Setzt die Baudrate
|
||||
* <b>Änderungen werden erst nach einem open() wirksam</b>
|
||||
*/
|
||||
void setBaudrate(uint32_t baudrate);
|
||||
|
||||
/**
|
||||
* Setzt den Timeout (in Dezisekunden)
|
||||
* <b>Änderungen werden erst nach einem open() wirksam</b>
|
||||
*/
|
||||
void setTimeout(uint8_t timeout);
|
||||
|
||||
/***************************************/
|
||||
|
||||
constexpr static uint8_t CRC7_POLY = 0x91;
|
||||
constexpr static uint8_t MAX_BLOCK_SIZE = 64;
|
||||
constexpr static uint8_t BLOCK_END = 0x80;
|
||||
|
||||
/*************************************************
|
||||
* Methoden für die Verwaltung der Schnittstelle *
|
||||
*************************************************/
|
||||
|
||||
/**
|
||||
* Öffnet die USART Schnittstelle
|
||||
* \param device Linux-Gerätepfad
|
||||
* \throws USARTException
|
||||
*/
|
||||
void openDevice(std::string device);
|
||||
|
||||
/**
|
||||
* Schließt die USART Schnittstelle
|
||||
* \throws USARTException
|
||||
*/
|
||||
void closeDevice(void);
|
||||
|
||||
/**
|
||||
* Verwirft Daten, die bereits im Puffer liegen, aber noch nicht gelesen wurden
|
||||
* \throws USARTException
|
||||
*/
|
||||
void clearInputBuffer(void);
|
||||
|
||||
/**
|
||||
* Verwirft Daten, die bereits im Puffer liegen, aber noch nicht gesendet wurden
|
||||
* \throws USARTException
|
||||
*/
|
||||
void clearOutputBuffer(void);
|
||||
|
||||
/**
|
||||
* Schreibt Daten, die bereits im Puffer liegen, aber noch nicht gesendet wurden
|
||||
* \throws USARTException
|
||||
*/
|
||||
void flushOutputBuffer(void);
|
||||
|
||||
/**
|
||||
* Gibt Anzahl an erfolgreichen und fehlgeschlagenen Block-Übertragungen an
|
||||
*/
|
||||
void printStatistics(void);
|
||||
|
||||
/*************************************************/
|
||||
|
||||
|
||||
|
||||
/*************************************
|
||||
* Methoden für die Datenübertragung *
|
||||
*************************************/
|
||||
|
||||
/**
|
||||
* Sendet ein Byte über die USART Schnittstelle
|
||||
* \param b das zu sendende Byte
|
||||
* \throws USARTException
|
||||
*/
|
||||
void writeByte(uint8_t b);
|
||||
|
||||
/**
|
||||
* Sendet ein Integer über die USART Schnittstelle
|
||||
* \param b das zu sendende Byte
|
||||
* \throws USARTException
|
||||
*/
|
||||
void writeInt(uint16_t d);
|
||||
|
||||
/**
|
||||
* Empfängt ein Byte über die USART Schnittstelle
|
||||
* \throws USARTException
|
||||
*/
|
||||
uint8_t readByte(void);
|
||||
|
||||
/**
|
||||
* Empfängt ein Integer über die USART Schnittstelle
|
||||
* \throws USARTException
|
||||
*/
|
||||
uint16_t readInt(void);
|
||||
|
||||
int read_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout);
|
||||
int write_timeout(uint8_t* buffer, uint16_t offset, uint8_t len, uint32_t timeout);
|
||||
void writeBlock(uint8_t* buffer, uint16_t offset, uint8_t len);
|
||||
bool readBlock(uint8_t* buffer, uint16_t offset);
|
||||
|
||||
/*************************************/
|
||||
|
||||
|
||||
|
||||
/***************************************
|
||||
* Methoden für einstellbare Parameter *
|
||||
***************************************/
|
||||
|
||||
/**
|
||||
* Liefert die eingestellte Baudrate
|
||||
* <b>Änderungen werden erst nach einem open() wirksam</b>
|
||||
*/
|
||||
uint32_t getBaudrate(void);
|
||||
|
||||
/**
|
||||
* Liefert den eingestellten Timeout (in Dezisekunden)
|
||||
* <b>Änderungen werden erst nach einem open() wirksam</b>
|
||||
*/
|
||||
uint8_t getTimeout(void);
|
||||
|
||||
/**
|
||||
* Setzt die Baudrate
|
||||
* <b>Änderungen werden erst nach einem open() wirksam</b>
|
||||
*/
|
||||
void setBaudrate(uint32_t baudrate);
|
||||
|
||||
/**
|
||||
* Setzt den Timeout (in Dezisekunden)
|
||||
* <b>Änderungen werden erst nach einem open() wirksam</b>
|
||||
*/
|
||||
void setTimeout(uint8_t timeout);
|
||||
|
||||
/***************************************/
|
||||
|
||||
constexpr static uint8_t CRC7_POLY = 0x91;
|
||||
constexpr static uint8_t MAX_BLOCK_SIZE = 64;
|
||||
constexpr static uint8_t BLOCK_END = 0x80;
|
||||
private:
|
||||
|
||||
int file_desc = -1; // Linux Dateideskriptor
|
||||
uint32_t baudrate = 9600; // Standard-Baudrate, sollte mit setBaudrate() überschrieben werden!
|
||||
int TEST = 0;
|
||||
uint8_t timeout = 10; // in Dezisekunden
|
||||
uint8_t block_buffer[MAX_BLOCK_SIZE + 3];
|
||||
|
||||
// debug statistics
|
||||
uint32_t n_blocks_total = 0;
|
||||
uint32_t n_blocks_failed = 0;
|
||||
|
||||
int file_desc = -1; // Linux Dateideskriptor
|
||||
uint32_t baudrate = 9600; // Standard-Baudrate, sollte mit setBaudrate() überschrieben werden!
|
||||
int TEST = 0;
|
||||
uint8_t timeout = 10; // in Dezisekunden
|
||||
uint8_t block_buffer[MAX_BLOCK_SIZE + 3];
|
||||
|
||||
// debug statistics
|
||||
uint32_t n_blocks_total = 0;
|
||||
uint32_t n_blocks_failed = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -6,28 +6,30 @@
|
|||
|
||||
// SOURCE: https://stackoverflow.com/a/8152888
|
||||
|
||||
/*! Exception for USART problems, for instance buffer overflow. */
|
||||
|
||||
class USARTException: public std::exception
|
||||
{
|
||||
public:
|
||||
explicit USARTException(const char* message) : msg(message)
|
||||
{
|
||||
}
|
||||
explicit USARTException(const char* message) : msg(message)
|
||||
{
|
||||
}
|
||||
|
||||
explicit USARTException(const std::string& message) : msg(message)
|
||||
{
|
||||
}
|
||||
explicit USARTException(const std::string& message) : msg(message)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~USARTException() throw ()
|
||||
{
|
||||
}
|
||||
virtual ~USARTException() throw ()
|
||||
{
|
||||
}
|
||||
|
||||
virtual const char* what() const throw ()
|
||||
{
|
||||
return msg.c_str();
|
||||
}
|
||||
virtual const char* what() const throw ()
|
||||
{
|
||||
return msg.c_str();
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string msg;
|
||||
std::string msg;
|
||||
};
|
||||
|
||||
#endif // USARTEXCEPTION_H
|
||||
|
|
|
@ -6,277 +6,277 @@ std::thread t_refresh;
|
|||
|
||||
void show_main(int)
|
||||
{
|
||||
ViewSelection* view = new ViewSelection();
|
||||
view->setTitle("B15F - Command Line Interface");
|
||||
view->addChoice("[ Monitor - Eingaben beobachten ]", &show_monitor);
|
||||
view->addChoice("[ Digitale Ausgabe BE0 ]", &show_digital_output0);
|
||||
view->addChoice("[ Digitale Ausgabe BE1 ]", &show_digital_output1);
|
||||
view->addChoice("[ Analoge Ausgabe AA0 ]", &show_analog_output0);
|
||||
view->addChoice("[ Analoge Ausgabe AA1 ]", &show_analog_output1);
|
||||
view->addChoice("[ Selbsttest des B15 ]", &show_selftest_info);
|
||||
view->addChoice("[ Informationen ]", &show_info);
|
||||
view->addChoice("", nullptr);
|
||||
view->addChoice("[ Beenden ]", &finish);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
ViewSelection* view = new ViewSelection();
|
||||
view->setTitle("B15F - Command Line Interface");
|
||||
view->addChoice("[ Monitor - Eingaben beobachten ]", &show_monitor);
|
||||
view->addChoice("[ Digitale Ausgabe BE0 ]", &show_digital_output0);
|
||||
view->addChoice("[ Digitale Ausgabe BE1 ]", &show_digital_output1);
|
||||
view->addChoice("[ Analoge Ausgabe AA0 ]", &show_analog_output0);
|
||||
view->addChoice("[ Analoge Ausgabe AA1 ]", &show_analog_output1);
|
||||
view->addChoice("[ Selbsttest des B15 ]", &show_selftest_info);
|
||||
view->addChoice("[ Informationen ]", &show_info);
|
||||
view->addChoice("", nullptr);
|
||||
view->addChoice("[ Beenden ]", &finish);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
}
|
||||
|
||||
void input(int)
|
||||
{
|
||||
call_t nextCall;
|
||||
int key;
|
||||
do
|
||||
{
|
||||
key = wgetch(View::getWinContext());
|
||||
win_stack.back()->repaint();
|
||||
nextCall = win_stack.back()->keypress(key);
|
||||
|
||||
if(key == -1)
|
||||
view_back(key);
|
||||
|
||||
if(nextCall)
|
||||
nextCall(key);
|
||||
}
|
||||
while(win_stack.size());
|
||||
call_t nextCall;
|
||||
int key;
|
||||
do
|
||||
{
|
||||
key = wgetch(View::getWinContext());
|
||||
win_stack.back()->repaint();
|
||||
nextCall = win_stack.back()->keypress(key);
|
||||
|
||||
if(key == -1)
|
||||
view_back(key);
|
||||
|
||||
if(nextCall)
|
||||
nextCall(key);
|
||||
}
|
||||
while(win_stack.size());
|
||||
}
|
||||
|
||||
void view_back(int)
|
||||
{
|
||||
if(win_stack.size())
|
||||
{
|
||||
delete win_stack.back();
|
||||
win_stack.pop_back();
|
||||
}
|
||||
if(win_stack.size())
|
||||
win_stack.back()->repaint();
|
||||
if(win_stack.size())
|
||||
{
|
||||
delete win_stack.back();
|
||||
win_stack.pop_back();
|
||||
}
|
||||
if(win_stack.size())
|
||||
win_stack.back()->repaint();
|
||||
}
|
||||
|
||||
void finish(int)
|
||||
{
|
||||
cleanup();
|
||||
exit(EXIT_SUCCESS);
|
||||
cleanup();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if(t_refresh.joinable())
|
||||
t_refresh.join();
|
||||
clrtoeol();
|
||||
refresh();
|
||||
endwin();
|
||||
if(t_refresh.joinable())
|
||||
t_refresh.join();
|
||||
clrtoeol();
|
||||
refresh();
|
||||
endwin();
|
||||
}
|
||||
|
||||
void show_info(int)
|
||||
{
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Info");
|
||||
view->setText("Informationen zu Board 15 Famulus Edition\nEs war einmal...");
|
||||
view->setLabelClose("[ Zurueck ]");
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Info");
|
||||
view->setText("Informationen zu Board 15 Famulus Edition\nEs war einmal...");
|
||||
view->setLabelClose("[ Zurueck ]");
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
}
|
||||
|
||||
void show_monitor(int)
|
||||
{
|
||||
ViewMonitor* view = new ViewMonitor();
|
||||
view->setTitle("Monitor");
|
||||
view->setText("\nErfasse Messwerte...");
|
||||
view->setLabelClose("[ Zurueck ]");
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
ViewMonitor* view = new ViewMonitor();
|
||||
view->setTitle("Monitor");
|
||||
view->setText("\nErfasse Messwerte...");
|
||||
view->setLabelClose("[ Zurueck ]");
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
}
|
||||
|
||||
void show_invalid_port_input(int)
|
||||
{
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Falsche Eingabe");
|
||||
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);
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Falsche Eingabe");
|
||||
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.");
|
||||
view->setLabelClose("[ Schliessen ]");
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Falsche Eingabe");
|
||||
view->setText("Bitte geben Sie einen Wert aus dem Intervall [0, 1023] an.");
|
||||
view->setLabelClose("[ Schliessen ]");
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
}
|
||||
|
||||
void write_digital_output0(int)
|
||||
{
|
||||
try
|
||||
{
|
||||
int d = std::stoi(static_cast<ViewPromt*>(win_stack.back())->getInput(), 0, 16);
|
||||
if(d > 255 || 0 > d)
|
||||
throw std::invalid_argument("bad value");
|
||||
uint8_t port = static_cast<uint8_t>(d);
|
||||
|
||||
B15F& drv = B15F::getInstance();
|
||||
drv.digitalWrite0(port);
|
||||
view_back(0);
|
||||
}
|
||||
catch(std::invalid_argument& ex)
|
||||
{
|
||||
show_invalid_port_input(0);
|
||||
}
|
||||
try
|
||||
{
|
||||
int d = std::stoi(static_cast<ViewPromt*>(win_stack.back())->getInput(), 0, 16);
|
||||
if(d > 255 || 0 > d)
|
||||
throw std::invalid_argument("bad value");
|
||||
uint8_t port = static_cast<uint8_t>(d);
|
||||
|
||||
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
|
||||
{
|
||||
int d = std::stoi(static_cast<ViewPromt*>(win_stack.back())->getInput(), 0, 16);
|
||||
if(d > 255 || 0 > d)
|
||||
throw std::invalid_argument("bad value");
|
||||
uint8_t port = static_cast<uint8_t>(d);
|
||||
|
||||
B15F& drv = B15F::getInstance();
|
||||
drv.digitalWrite1(port);
|
||||
view_back(0);
|
||||
}
|
||||
catch(std::invalid_argument& ex)
|
||||
{
|
||||
show_invalid_port_input(0);
|
||||
}
|
||||
try
|
||||
{
|
||||
int d = std::stoi(static_cast<ViewPromt*>(win_stack.back())->getInput(), 0, 16);
|
||||
if(d > 255 || 0 > d)
|
||||
throw std::invalid_argument("bad value");
|
||||
uint8_t port = static_cast<uint8_t>(d);
|
||||
|
||||
B15F& drv = B15F::getInstance();
|
||||
drv.digitalWrite1(port);
|
||||
view_back(0);
|
||||
}
|
||||
catch(std::invalid_argument& ex)
|
||||
{
|
||||
show_invalid_port_input(0);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void show_digital_output0(int)
|
||||
{
|
||||
ViewPromt* view = new ViewPromt();
|
||||
view->setTitle("Digitale Ausgabe BE0");
|
||||
view->setMessage("\nAusgabe Port-Wert (hex): 0x");
|
||||
view->setCancel("[ Zurueck ]", true);
|
||||
view->setConfirm("[ OK ]", &write_digital_output0);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
ViewPromt* view = new ViewPromt();
|
||||
view->setTitle("Digitale Ausgabe BE0");
|
||||
view->setMessage("\nAusgabe 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("\nAusgabe Port-Wert (hex): 0x");
|
||||
view->setCancel("[ Zurueck ]", true);
|
||||
view->setConfirm("[ OK ]", &write_digital_output1);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
ViewPromt* view = new ViewPromt();
|
||||
view->setTitle("Digitale Ausgabe BE1");
|
||||
view->setMessage("\nAusgabe Port-Wert (hex): 0x");
|
||||
view->setCancel("[ Zurueck ]", true);
|
||||
view->setConfirm("[ OK ]", &write_digital_output1);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
}
|
||||
|
||||
void show_analog_output0(int)
|
||||
{
|
||||
ViewPromt* view = new ViewPromt();
|
||||
view->setTitle("Analoge Ausgabe AA0");
|
||||
view->setMessage("\nAusgabe 10-Bit-Wert (0...1023): ");
|
||||
view->setCancel("[ Zurueck ]", true);
|
||||
view->setConfirm("[ OK ]", &write_analog_output0);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
ViewPromt* view = new ViewPromt();
|
||||
view->setTitle("Analoge Ausgabe AA0");
|
||||
view->setMessage("\nAusgabe 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("\nAusgabe 10-Bit-Wert (0...1023): ");
|
||||
view->setCancel("[ Zurueck ]", true);
|
||||
view->setConfirm("[ OK ]", &write_analog_output1);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
ViewPromt* view = new ViewPromt();
|
||||
view->setTitle("Analoge Ausgabe AA1");
|
||||
view->setMessage("\nAusgabe 10-Bit-Wert (0...1023): ");
|
||||
view->setCancel("[ Zurueck ]", true);
|
||||
view->setConfirm("[ OK ]", &write_analog_output1);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
}
|
||||
|
||||
void start_selftest(int)
|
||||
{
|
||||
B15F& drv = B15F::getInstance();
|
||||
drv.activateSelfTestMode();
|
||||
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Selbsttest aktiv");
|
||||
view->setText("Das B15 befindet sich jetzt im Selbsttestmodus.\n \nSelbsttest:\nZu Beginn geht der Reihe nach jede LED von BA0 bis BA1 an.\nDanach leuchten die LEDs an AA0 und AA1 kurz auf.\nZum Schluss spiegelt in einer Endlosschleife:\n* BA0 Port BE0\n* BA1 die DIP-Schalter S7\n* AA0 ADC0\n* AA1 ADC1");
|
||||
view->setLabelClose("[ Selbsttest Beenden ]");
|
||||
view->setCall(&stop_selftest);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
B15F& drv = B15F::getInstance();
|
||||
drv.activateSelfTestMode();
|
||||
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Selbsttest aktiv");
|
||||
view->setText("Das B15 befindet sich jetzt im Selbsttestmodus.\n \nSelbsttest:\nZu Beginn geht der Reihe nach jede LED von BA0 bis BA1 an.\nDanach leuchten die LEDs an AA0 und AA1 kurz auf.\nZum Schluss spiegelt in einer Endlosschleife:\n* BA0 Port BE0\n* BA1 die DIP-Schalter S7\n* AA0 ADC0\n* AA1 ADC1");
|
||||
view->setLabelClose("[ Selbsttest Beenden ]");
|
||||
view->setCall(&stop_selftest);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
}
|
||||
|
||||
void stop_selftest(int)
|
||||
{
|
||||
B15F& drv = B15F::getInstance();
|
||||
drv.discard();
|
||||
drv.delay_ms(B15F::WDT_TIMEOUT);
|
||||
drv.reconnect();
|
||||
drv.digitalWrite0(0);
|
||||
drv.digitalWrite1(0);
|
||||
B15F& drv = B15F::getInstance();
|
||||
drv.discard();
|
||||
drv.delay_ms(B15F::WDT_TIMEOUT);
|
||||
drv.reconnect();
|
||||
drv.digitalWrite0(0);
|
||||
drv.digitalWrite1(0);
|
||||
}
|
||||
|
||||
void show_selftest_info(int)
|
||||
{
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Selbsttest");
|
||||
view->setText("Bitte entfernen Sie jetzt alle Draehte von den Anschlussklemmen und bestaetigen\nmit Enter.");
|
||||
view->setLabelClose("[ Weiter ]");
|
||||
view->setCall(&start_selftest);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
ViewInfo* view = new ViewInfo();
|
||||
view->setTitle("Selbsttest");
|
||||
view->setText("Bitte entfernen Sie jetzt alle Draehte von den Anschlussklemmen und bestaetigen\nmit Enter.");
|
||||
view->setLabelClose("[ Weiter ]");
|
||||
view->setCall(&start_selftest);
|
||||
view->repaint();
|
||||
|
||||
win_stack.push_back(view);
|
||||
input(0);
|
||||
}
|
||||
|
|
|
@ -4,12 +4,12 @@ WINDOW* View::win = nullptr;
|
|||
|
||||
View::View()
|
||||
{
|
||||
if(!win)
|
||||
{
|
||||
B15F::abort("View::win not initialized, missing context");
|
||||
}
|
||||
getmaxyx(win, height, width); // init width and height
|
||||
keypad(win, TRUE);
|
||||
if(!win)
|
||||
{
|
||||
B15F::abort("View::win not initialized, missing context");
|
||||
}
|
||||
getmaxyx(win, height, width); // init width and height
|
||||
keypad(win, TRUE);
|
||||
}
|
||||
|
||||
View::~View()
|
||||
|
@ -18,12 +18,12 @@ View::~View()
|
|||
|
||||
void View::setWinContext(WINDOW* win)
|
||||
{
|
||||
View::win = win;
|
||||
View::win = win;
|
||||
}
|
||||
|
||||
WINDOW* View::getWinContext()
|
||||
{
|
||||
return win;
|
||||
return win;
|
||||
}
|
||||
|
||||
// from: https://stackoverflow.com/a/37454181
|
||||
|
@ -46,33 +46,33 @@ std::vector<std::string> View::str_split(const std::string& str, const std::stri
|
|||
|
||||
void View::setTitle(std::string title)
|
||||
{
|
||||
this->title = title;
|
||||
this->title = title;
|
||||
}
|
||||
|
||||
void View::repaint()
|
||||
{
|
||||
// get screen size
|
||||
struct winsize size;
|
||||
if (ioctl(0, TIOCGWINSZ, (char *) &size) < 0)
|
||||
throw std::runtime_error("TIOCGWINSZ error");
|
||||
|
||||
|
||||
start_x = floor((size.ws_col - width) / 2.);
|
||||
start_y = floor((size.ws_row - height) / 2.);
|
||||
|
||||
curs_set(0); // hide cursor
|
||||
mvwin(win, start_y, start_x);
|
||||
clear();
|
||||
wclear(win);
|
||||
|
||||
// generic draw
|
||||
box(win, 0, 0);
|
||||
int offset_x = (width - title.length()) / 2;
|
||||
mvwprintw(win, 1, offset_x, "%s", title.c_str());
|
||||
|
||||
// specific draw
|
||||
draw();
|
||||
// get screen size
|
||||
struct winsize size;
|
||||
if (ioctl(0, TIOCGWINSZ, (char *) &size) < 0)
|
||||
throw std::runtime_error("TIOCGWINSZ error");
|
||||
|
||||
refresh();
|
||||
wrefresh(win);
|
||||
|
||||
start_x = floor((size.ws_col - width) / 2.);
|
||||
start_y = floor((size.ws_row - height) / 2.);
|
||||
|
||||
curs_set(0); // hide cursor
|
||||
mvwin(win, start_y, start_x);
|
||||
clear();
|
||||
wclear(win);
|
||||
|
||||
// generic draw
|
||||
box(win, 0, 0);
|
||||
int offset_x = (width - title.length()) / 2;
|
||||
mvwprintw(win, 1, offset_x, "%s", title.c_str());
|
||||
|
||||
// specific draw
|
||||
draw();
|
||||
|
||||
refresh();
|
||||
wrefresh(win);
|
||||
}
|
||||
|
|
|
@ -14,32 +14,34 @@
|
|||
extern std::string ERR_MSG;
|
||||
typedef std::function<void(int)> call_t;
|
||||
|
||||
/*! Base class for multiple views with the ncurses user interface. */
|
||||
|
||||
class View
|
||||
{
|
||||
public:
|
||||
View(void);
|
||||
virtual ~View(void);
|
||||
|
||||
static void setWinContext(WINDOW* win);
|
||||
static WINDOW* getWinContext(void);
|
||||
static std::vector<std::string> str_split(const std::string& str, const std::string delim);
|
||||
|
||||
virtual void setTitle(std::string title);
|
||||
|
||||
virtual void repaint(void);
|
||||
|
||||
virtual void draw(void) = 0;
|
||||
virtual call_t keypress(int& key) = 0;
|
||||
|
||||
|
||||
View(void);
|
||||
virtual ~View(void);
|
||||
|
||||
static void setWinContext(WINDOW* win);
|
||||
static WINDOW* getWinContext(void);
|
||||
static std::vector<std::string> str_split(const std::string& str, const std::string delim);
|
||||
|
||||
virtual void setTitle(std::string title);
|
||||
|
||||
virtual void repaint(void);
|
||||
|
||||
virtual void draw(void) = 0;
|
||||
virtual call_t keypress(int& key) = 0;
|
||||
|
||||
|
||||
protected:
|
||||
int width, height;
|
||||
int start_x = 0, start_y = 0;
|
||||
std::string title;
|
||||
std::vector<call_t> calls;
|
||||
|
||||
static WINDOW* win;
|
||||
constexpr static int KEY_ENT = 10;
|
||||
int width, height;
|
||||
int start_x = 0, start_y = 0;
|
||||
std::string title;
|
||||
std::vector<call_t> calls;
|
||||
|
||||
static WINDOW* win;
|
||||
constexpr static int KEY_ENT = 10;
|
||||
};
|
||||
|
||||
#endif // VIEW_H
|
||||
|
|
|
@ -2,62 +2,62 @@
|
|||
|
||||
ViewInfo::ViewInfo()
|
||||
{
|
||||
calls.push_back(nullptr);
|
||||
calls.push_back(nullptr);
|
||||
}
|
||||
|
||||
void ViewInfo::setText(std::string text)
|
||||
{
|
||||
this->text = text;
|
||||
this->text = text;
|
||||
}
|
||||
|
||||
void ViewInfo::setLabelClose(std::string label)
|
||||
{
|
||||
this->label_close = label;
|
||||
this->label_close = label;
|
||||
}
|
||||
|
||||
void ViewInfo::setCall(call_t call)
|
||||
{
|
||||
calls[0] = call;
|
||||
calls[0] = call;
|
||||
}
|
||||
|
||||
void ViewInfo::draw()
|
||||
{
|
||||
int li = 0;
|
||||
for(std::string line : str_split(text, "\n"))
|
||||
mvwprintw(win, text_offset_y + li++, text_offset_x, "%s", line.c_str());
|
||||
|
||||
close_offset_x = (width - label_close.length()) / 2;
|
||||
close_offset_y = height - 2;
|
||||
|
||||
wattron(win, A_REVERSE);
|
||||
mvwprintw(win, close_offset_y, close_offset_x, "%s", label_close.c_str());
|
||||
wattroff(win, A_REVERSE);
|
||||
int li = 0;
|
||||
for(std::string line : str_split(text, "\n"))
|
||||
mvwprintw(win, text_offset_y + li++, text_offset_x, "%s", line.c_str());
|
||||
|
||||
close_offset_x = (width - label_close.length()) / 2;
|
||||
close_offset_y = height - 2;
|
||||
|
||||
wattron(win, A_REVERSE);
|
||||
mvwprintw(win, close_offset_y, close_offset_x, "%s", label_close.c_str());
|
||||
wattroff(win, A_REVERSE);
|
||||
}
|
||||
|
||||
call_t ViewInfo::keypress(int& key)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
|
||||
case KEY_MOUSE:
|
||||
{
|
||||
// http://pronix.linuxdelta.de/C/Linuxprogrammierung/Linuxsystemprogrammieren_C_Kurs_Kapitel10b.shtml
|
||||
MEVENT event;
|
||||
if(getmouse(&event) == OK && event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))
|
||||
{
|
||||
size_t column = start_x + close_offset_x;
|
||||
size_t row = start_y + close_offset_y;
|
||||
size_t mouse_x = event.x, mouse_y = event.y;
|
||||
if(mouse_y == row && mouse_x >= column && mouse_x < column + label_close.length())
|
||||
key = -1; // do return from view
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KEY_ENT:
|
||||
key = -1; // do return from view
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return calls[0];
|
||||
switch(key)
|
||||
{
|
||||
|
||||
case KEY_MOUSE:
|
||||
{
|
||||
// http://pronix.linuxdelta.de/C/Linuxprogrammierung/Linuxsystemprogrammieren_C_Kurs_Kapitel10b.shtml
|
||||
MEVENT event;
|
||||
if(getmouse(&event) == OK && event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))
|
||||
{
|
||||
size_t column = start_x + close_offset_x;
|
||||
size_t row = start_y + close_offset_y;
|
||||
size_t mouse_x = event.x, mouse_y = event.y;
|
||||
if(mouse_y == row && mouse_x >= column && mouse_x < column + label_close.length())
|
||||
key = -1; // do return from view
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KEY_ENT:
|
||||
key = -1; // do return from view
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return calls[0];
|
||||
}
|
||||
|
|
|
@ -3,23 +3,25 @@
|
|||
|
||||
#include "view.h"
|
||||
|
||||
/*! View for simple text message output. */
|
||||
|
||||
class ViewInfo : public View
|
||||
{
|
||||
public:
|
||||
ViewInfo(void);
|
||||
virtual void setText(std::string text);
|
||||
virtual void setLabelClose(std::string label);;
|
||||
virtual void setCall(call_t call);
|
||||
virtual void draw(void) override;
|
||||
virtual call_t keypress(int& key) override;
|
||||
ViewInfo(void);
|
||||
virtual void setText(std::string text);
|
||||
virtual void setLabelClose(std::string label);;
|
||||
virtual void setCall(call_t call);
|
||||
virtual void draw(void) override;
|
||||
virtual call_t keypress(int& key) override;
|
||||
|
||||
protected:
|
||||
std::string text;
|
||||
std::string label_close;
|
||||
int close_offset_x = 0;
|
||||
int close_offset_y = 0;
|
||||
constexpr static int text_offset_x = 2;
|
||||
constexpr static int text_offset_y = 3;
|
||||
std::string text;
|
||||
std::string label_close;
|
||||
int close_offset_x = 0;
|
||||
int close_offset_y = 0;
|
||||
constexpr static int text_offset_x = 2;
|
||||
constexpr static int text_offset_y = 3;
|
||||
};
|
||||
|
||||
#endif // VIEW_INFO
|
||||
|
|
|
@ -1,139 +1,139 @@
|
|||
#include "view_monitor.h"
|
||||
|
||||
ViewMonitor::ViewMonitor() : t_worker(&ViewMonitor::worker, this)
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
call_t ViewMonitor::keypress(int& key)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
|
||||
case KEY_MOUSE:
|
||||
{
|
||||
// http://pronix.linuxdelta.de/C/Linuxprogrammierung/Linuxsystemprogrammieren_C_Kurs_Kapitel10b.shtml
|
||||
MEVENT event;
|
||||
bool hit = false;
|
||||
if(getmouse(&event) == OK && event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))
|
||||
{
|
||||
size_t column = start_x + close_offset_x;
|
||||
size_t row = start_y + close_offset_y;
|
||||
size_t mouse_x = event.x, mouse_y = event.y;
|
||||
if(mouse_y == row && mouse_x >= column && mouse_x < column + label_close.length())
|
||||
hit = true;
|
||||
}
|
||||
if(!hit)
|
||||
break;
|
||||
|
||||
// fall through to next case
|
||||
[[fallthrough]];
|
||||
}
|
||||
case KEY_ENT:
|
||||
run_worker = false;
|
||||
key = -1; // do return from view
|
||||
wclear(win);
|
||||
wrefresh(win);
|
||||
t_worker.join();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return calls[0];
|
||||
switch(key)
|
||||
{
|
||||
|
||||
case KEY_MOUSE:
|
||||
{
|
||||
// http://pronix.linuxdelta.de/C/Linuxprogrammierung/Linuxsystemprogrammieren_C_Kurs_Kapitel10b.shtml
|
||||
MEVENT event;
|
||||
bool hit = false;
|
||||
if(getmouse(&event) == OK && event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))
|
||||
{
|
||||
size_t column = start_x + close_offset_x;
|
||||
size_t row = start_y + close_offset_y;
|
||||
size_t mouse_x = event.x, mouse_y = event.y;
|
||||
if(mouse_y == row && mouse_x >= column && mouse_x < column + label_close.length())
|
||||
hit = true;
|
||||
}
|
||||
if(!hit)
|
||||
break;
|
||||
|
||||
// fall through to next case
|
||||
[[fallthrough]];
|
||||
}
|
||||
case KEY_ENT:
|
||||
run_worker = false;
|
||||
key = -1; // do return from view
|
||||
wclear(win);
|
||||
wrefresh(win);
|
||||
t_worker.join();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return calls[0];
|
||||
}
|
||||
|
||||
std::string ViewMonitor::fancyDigitalString(uint8_t& b)
|
||||
{
|
||||
std::stringstream str;
|
||||
str << std::bitset<8>(b).to_string();
|
||||
str << " ";
|
||||
str << "0x" << std::setfill ('0') << std::setw(2) << std::hex << (int) b << std::dec;
|
||||
return str.str();
|
||||
std::stringstream str;
|
||||
str << std::bitset<8>(b).to_string();
|
||||
str << " ";
|
||||
str << "0x" << std::setfill ('0') << std::setw(2) << std::hex << (int) b << std::dec;
|
||||
return str.str();
|
||||
}
|
||||
|
||||
std::string ViewMonitor::fancyAnalogString(uint16_t& v)
|
||||
{
|
||||
std::stringstream str;
|
||||
double volt = round(v * 100.0 * 5.0 / 1023.0) / 100.0;
|
||||
|
||||
str << std::setfill ('0') << std::setw(4) << (int) v << " " << std::fixed << std::setprecision(2) << volt << " V ";
|
||||
|
||||
str << "[";
|
||||
uint8_t p = round(v * 40.0 / 1023.0);
|
||||
for(uint8_t i = 0; i < p; i++)
|
||||
str << "X";
|
||||
for(uint8_t i = 0; i < 40 - p; i++)
|
||||
str << " ";
|
||||
str << "]" << std::endl;
|
||||
|
||||
return str.str();
|
||||
std::stringstream str;
|
||||
double volt = round(v * 100.0 * 5.0 / 1023.0) / 100.0;
|
||||
|
||||
str << std::setfill ('0') << std::setw(4) << (int) v << " " << std::fixed << std::setprecision(2) << volt << " V ";
|
||||
|
||||
str << "[";
|
||||
uint8_t p = round(v * 40.0 / 1023.0);
|
||||
for(uint8_t i = 0; i < p; i++)
|
||||
str << "X";
|
||||
for(uint8_t i = 0; i < 40 - p; i++)
|
||||
str << " ";
|
||||
str << "]" << std::endl;
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
void ViewMonitor::worker()
|
||||
{
|
||||
B15F& drv = B15F::getInstance();
|
||||
while(run_worker)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
uint8_t be0 = drv.digitalRead0();
|
||||
uint8_t be1 = drv.digitalRead1();
|
||||
uint8_t dsw = drv.readDipSwitch();
|
||||
uint16_t adc[8];
|
||||
for(uint8_t i = 0; i < sizeof(adc) / sizeof(adc[0]); i++)
|
||||
adc[i] = drv.analogRead(i);
|
||||
|
||||
|
||||
std::stringstream str;
|
||||
|
||||
// hline
|
||||
for(uint8_t i = 0; i < width - 2 * text_offset_x; i++)
|
||||
if(i % 2 == 0)
|
||||
str << "-";
|
||||
else
|
||||
str << " ";
|
||||
str << std::endl;
|
||||
|
||||
str << "Digitale Enigaenge:" << std::endl;
|
||||
str << "Binaere Eingabe 0: " << fancyDigitalString(be0) << std::endl;
|
||||
str << "Binaere Eingabe 1: " << fancyDigitalString(be1) << std::endl;
|
||||
str << "Dip Schalter (S7): " << fancyDigitalString(dsw) << std::endl;
|
||||
|
||||
// hline
|
||||
for(uint8_t i = 0; i < width - 2 * text_offset_x; i++)
|
||||
if(i % 2 == 0)
|
||||
str << "-";
|
||||
else
|
||||
str << " ";
|
||||
str << std::endl;
|
||||
|
||||
str << "Analoge Eingaenge:" << std::endl;
|
||||
for(uint8_t i = 0; i < sizeof(adc) / sizeof(adc[0]); i++)
|
||||
{
|
||||
str << "Kanal " << std::to_string((int) i) << ": ";
|
||||
str << fancyAnalogString(adc[i]) << std::endl;
|
||||
}
|
||||
|
||||
text = str.str();
|
||||
repaint();
|
||||
}
|
||||
catch(DriverException& ex)
|
||||
{
|
||||
std::cout << "DriverException: " << ex.what() << std::endl;
|
||||
drv.delay_ms(1000);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
try
|
||||
{
|
||||
drv.reconnect();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
B15F::abort("yoho meine dudes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
B15F& drv = B15F::getInstance();
|
||||
while(run_worker)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
uint8_t be0 = drv.digitalRead0();
|
||||
uint8_t be1 = drv.digitalRead1();
|
||||
uint8_t dsw = drv.readDipSwitch();
|
||||
uint16_t adc[8];
|
||||
for(uint8_t i = 0; i < sizeof(adc) / sizeof(adc[0]); i++)
|
||||
adc[i] = drv.analogRead(i);
|
||||
|
||||
|
||||
std::stringstream str;
|
||||
|
||||
// hline
|
||||
for(uint8_t i = 0; i < width - 2 * text_offset_x; i++)
|
||||
if(i % 2 == 0)
|
||||
str << "-";
|
||||
else
|
||||
str << " ";
|
||||
str << std::endl;
|
||||
|
||||
str << "Digitale Enigaenge:" << std::endl;
|
||||
str << "Binaere Eingabe 0: " << fancyDigitalString(be0) << std::endl;
|
||||
str << "Binaere Eingabe 1: " << fancyDigitalString(be1) << std::endl;
|
||||
str << "Dip Schalter (S7): " << fancyDigitalString(dsw) << std::endl;
|
||||
|
||||
// hline
|
||||
for(uint8_t i = 0; i < width - 2 * text_offset_x; i++)
|
||||
if(i % 2 == 0)
|
||||
str << "-";
|
||||
else
|
||||
str << " ";
|
||||
str << std::endl;
|
||||
|
||||
str << "Analoge Eingaenge:" << std::endl;
|
||||
for(uint8_t i = 0; i < sizeof(adc) / sizeof(adc[0]); i++)
|
||||
{
|
||||
str << "Kanal " << std::to_string((int) i) << ": ";
|
||||
str << fancyAnalogString(adc[i]) << std::endl;
|
||||
}
|
||||
|
||||
text = str.str();
|
||||
repaint();
|
||||
}
|
||||
catch(DriverException& ex)
|
||||
{
|
||||
std::cout << "DriverException: " << ex.what() << std::endl;
|
||||
drv.delay_ms(1000);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
try
|
||||
{
|
||||
drv.reconnect();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
B15F::abort("yoho meine dudes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,22 +8,24 @@
|
|||
#include "view_info.h"
|
||||
#include "../drv/b15f.h"
|
||||
|
||||
/*! View to display all B15 inputs. */
|
||||
|
||||
class ViewMonitor : public ViewInfo
|
||||
{
|
||||
|
||||
|
||||
public:
|
||||
ViewMonitor(void);
|
||||
virtual call_t keypress(int& key) override;
|
||||
ViewMonitor(void);
|
||||
virtual call_t keypress(int& key) override;
|
||||
|
||||
private:
|
||||
std::string fancyDigitalString(uint8_t& b);
|
||||
std::string fancyAnalogString(uint16_t& v);
|
||||
std::string fancyDigitalString(uint8_t& b);
|
||||
std::string fancyAnalogString(uint16_t& v);
|
||||
|
||||
protected:
|
||||
virtual void worker(void);
|
||||
volatile bool run_worker = true;
|
||||
std::thread t_worker;
|
||||
|
||||
virtual void worker(void);
|
||||
volatile bool run_worker = true;
|
||||
std::thread t_worker;
|
||||
|
||||
};
|
||||
|
||||
#endif // VIEW_MONITOR_H
|
||||
|
|
|
@ -2,120 +2,120 @@
|
|||
|
||||
void ViewPromt::draw()
|
||||
{
|
||||
curs_set(1); // show cursor
|
||||
|
||||
int li = text_offset_y;
|
||||
int ci = 0;
|
||||
for(std::string line : str_split(message + input, "\n"))
|
||||
{
|
||||
mvwprintw(win, ++li, text_offset_x, "%s", line.c_str());
|
||||
ci = line.length() + text_offset_x;
|
||||
}
|
||||
|
||||
button_offset_x = (width - label_cancel.length() - sep.length() - label_confirm.length()) / 2;
|
||||
button_offset_y = height - text_offset_y;
|
||||
|
||||
if(selection == 0)
|
||||
{
|
||||
wattron(win, A_REVERSE);
|
||||
mvwprintw(win, button_offset_y, button_offset_x, "%s", label_cancel.c_str());
|
||||
wattroff(win, A_REVERSE);
|
||||
mvwprintw(win, button_offset_y, button_offset_x + label_cancel.length(), "%s", sep.c_str());
|
||||
mvwprintw(win, button_offset_y, button_offset_x + label_cancel.length() + sep.length(), "%s", label_confirm.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
mvwprintw(win, button_offset_y, button_offset_x, "%s", label_cancel.c_str());
|
||||
mvwprintw(win, button_offset_y, button_offset_x + label_cancel.length(), "%s", sep.c_str());
|
||||
wattron(win, A_REVERSE);
|
||||
mvwprintw(win, button_offset_y, button_offset_x + label_cancel.length() + sep.length(), "%s", label_confirm.c_str());
|
||||
wattroff(win, A_REVERSE);
|
||||
}
|
||||
wmove(win, li, ci);
|
||||
curs_set(1); // show cursor
|
||||
|
||||
int li = text_offset_y;
|
||||
int ci = 0;
|
||||
for(std::string line : str_split(message + input, "\n"))
|
||||
{
|
||||
mvwprintw(win, ++li, text_offset_x, "%s", line.c_str());
|
||||
ci = line.length() + text_offset_x;
|
||||
}
|
||||
|
||||
button_offset_x = (width - label_cancel.length() - sep.length() - label_confirm.length()) / 2;
|
||||
button_offset_y = height - text_offset_y;
|
||||
|
||||
if(selection == 0)
|
||||
{
|
||||
wattron(win, A_REVERSE);
|
||||
mvwprintw(win, button_offset_y, button_offset_x, "%s", label_cancel.c_str());
|
||||
wattroff(win, A_REVERSE);
|
||||
mvwprintw(win, button_offset_y, button_offset_x + label_cancel.length(), "%s", sep.c_str());
|
||||
mvwprintw(win, button_offset_y, button_offset_x + label_cancel.length() + sep.length(), "%s", label_confirm.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
mvwprintw(win, button_offset_y, button_offset_x, "%s", label_cancel.c_str());
|
||||
mvwprintw(win, button_offset_y, button_offset_x + label_cancel.length(), "%s", sep.c_str());
|
||||
wattron(win, A_REVERSE);
|
||||
mvwprintw(win, button_offset_y, button_offset_x + label_cancel.length() + sep.length(), "%s", label_confirm.c_str());
|
||||
wattroff(win, A_REVERSE);
|
||||
}
|
||||
wmove(win, li, ci);
|
||||
}
|
||||
|
||||
void ViewPromt::setMessage(std::string message)
|
||||
{
|
||||
this->message = message;
|
||||
this->message = message;
|
||||
}
|
||||
|
||||
void ViewPromt::setConfirm(std::string name, std::function<void(int)> call)
|
||||
{
|
||||
label_confirm = name;
|
||||
call_confirm = call;
|
||||
label_confirm = name;
|
||||
call_confirm = call;
|
||||
}
|
||||
|
||||
void ViewPromt::setCancel(std::string name, bool cancelable)
|
||||
{
|
||||
label_cancel = name;
|
||||
this->cancelable = cancelable;
|
||||
label_cancel = name;
|
||||
this->cancelable = cancelable;
|
||||
}
|
||||
|
||||
std::string ViewPromt::getInput()
|
||||
{
|
||||
return input;
|
||||
return input;
|
||||
}
|
||||
|
||||
std::function<void(int)> ViewPromt::keypress(int& key)
|
||||
{
|
||||
std::function<void(int)> ret = nullptr;
|
||||
switch(key)
|
||||
{
|
||||
case KEY_BACKSPACE:
|
||||
if(input.length())
|
||||
input.pop_back();
|
||||
break;
|
||||
case '\t':
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
selection = (selection + 1 ) % 2;
|
||||
break;
|
||||
case KEY_MOUSE:
|
||||
{
|
||||
// http://pronix.linuxdelta.de/C/Linuxprogrammierung/Linuxsystemprogrammieren_C_Kurs_Kapitel10b.shtml
|
||||
MEVENT event;
|
||||
bool hit = false;
|
||||
if(getmouse(&event) == OK && event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))
|
||||
{
|
||||
size_t column_start = start_x + button_offset_x;
|
||||
size_t row_start = start_y + button_offset_y;
|
||||
size_t mouse_x = event.x, mouse_y = event.y;
|
||||
if(mouse_y == row_start)
|
||||
{
|
||||
if(cancelable && mouse_x >= column_start && mouse_x < column_start + label_cancel.length())
|
||||
{
|
||||
if(selection == 0 || event.bstate & BUTTON1_DOUBLE_CLICKED)
|
||||
hit = true;
|
||||
selection = 0;
|
||||
}
|
||||
if(mouse_x >= column_start + label_cancel.length() + sep.length() && mouse_x < column_start + label_cancel.length() + sep.length() + label_confirm.length())
|
||||
{
|
||||
if(selection == 1 || event.bstate & BUTTON1_DOUBLE_CLICKED)
|
||||
hit = true;
|
||||
selection = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!hit)
|
||||
break;
|
||||
|
||||
// fall through to next case
|
||||
[[fallthrough]];
|
||||
}
|
||||
case KEY_ENT:
|
||||
if(selection == 0) // exit
|
||||
key = -1; // do return from view
|
||||
else
|
||||
ret = call_confirm;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(key >= ' ' && key <= '~')
|
||||
input += (char) key;
|
||||
|
||||
if(key != KEY_ENT)
|
||||
{
|
||||
std::function<void(int)> ret = nullptr;
|
||||
switch(key)
|
||||
{
|
||||
case KEY_BACKSPACE:
|
||||
if(input.length())
|
||||
input.pop_back();
|
||||
break;
|
||||
case '\t':
|
||||
case KEY_LEFT:
|
||||
case KEY_RIGHT:
|
||||
selection = (selection + 1 ) % 2;
|
||||
break;
|
||||
case KEY_MOUSE:
|
||||
{
|
||||
// http://pronix.linuxdelta.de/C/Linuxprogrammierung/Linuxsystemprogrammieren_C_Kurs_Kapitel10b.shtml
|
||||
MEVENT event;
|
||||
bool hit = false;
|
||||
if(getmouse(&event) == OK && event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))
|
||||
{
|
||||
size_t column_start = start_x + button_offset_x;
|
||||
size_t row_start = start_y + button_offset_y;
|
||||
size_t mouse_x = event.x, mouse_y = event.y;
|
||||
if(mouse_y == row_start)
|
||||
{
|
||||
if(cancelable && mouse_x >= column_start && mouse_x < column_start + label_cancel.length())
|
||||
{
|
||||
if(selection == 0 || event.bstate & BUTTON1_DOUBLE_CLICKED)
|
||||
hit = true;
|
||||
selection = 0;
|
||||
}
|
||||
if(mouse_x >= column_start + label_cancel.length() + sep.length() && mouse_x < column_start + label_cancel.length() + sep.length() + label_confirm.length())
|
||||
{
|
||||
if(selection == 1 || event.bstate & BUTTON1_DOUBLE_CLICKED)
|
||||
hit = true;
|
||||
selection = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!hit)
|
||||
break;
|
||||
|
||||
// fall through to next case
|
||||
[[fallthrough]];
|
||||
}
|
||||
case KEY_ENT:
|
||||
if(selection == 0) // exit
|
||||
key = -1; // do return from view
|
||||
else
|
||||
ret = call_confirm;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(key >= ' ' && key <= '~')
|
||||
input += (char) key;
|
||||
|
||||
if(key != KEY_ENT)
|
||||
repaint();
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -5,28 +5,30 @@
|
|||
#include <string>
|
||||
#include "view.h"
|
||||
|
||||
/*! View for basic user text input. */
|
||||
|
||||
class ViewPromt : public View
|
||||
{
|
||||
public:
|
||||
virtual void draw(void) override;
|
||||
virtual void setMessage(std::string message);
|
||||
virtual void setConfirm(std::string name, call_t call);
|
||||
virtual void setCancel(std::string name, bool cancelable);
|
||||
virtual std::string getInput(void);
|
||||
virtual call_t keypress(int& key) override;
|
||||
virtual void draw(void) override;
|
||||
virtual void setMessage(std::string message);
|
||||
virtual void setConfirm(std::string name, call_t call);
|
||||
virtual void setCancel(std::string name, bool cancelable);
|
||||
virtual std::string getInput(void);
|
||||
virtual call_t keypress(int& key) override;
|
||||
|
||||
protected:
|
||||
size_t selection = 1;
|
||||
std::string input;
|
||||
std::string message = "Input";
|
||||
std::string label_confirm = "[ OK ]";
|
||||
std::string sep = " ";
|
||||
std::string label_cancel = "[ Cancel ]";
|
||||
call_t call_confirm = nullptr;
|
||||
bool cancelable = true;
|
||||
int button_offset_x = 0, button_offset_y = 0;
|
||||
constexpr static int text_offset_x = 2;
|
||||
constexpr static int text_offset_y = 2;
|
||||
size_t selection = 1;
|
||||
std::string input;
|
||||
std::string message = "Input";
|
||||
std::string label_confirm = "[ OK ]";
|
||||
std::string sep = " ";
|
||||
std::string label_cancel = "[ Cancel ]";
|
||||
call_t call_confirm = nullptr;
|
||||
bool cancelable = true;
|
||||
int button_offset_x = 0, button_offset_y = 0;
|
||||
constexpr static int text_offset_x = 2;
|
||||
constexpr static int text_offset_y = 2;
|
||||
};
|
||||
|
||||
#endif // VIEW_PROMT_H
|
||||
|
|
|
@ -2,75 +2,75 @@
|
|||
|
||||
void ViewSelection::draw()
|
||||
{
|
||||
//curs_set(0); // hide cursor
|
||||
for(size_t i = 0; i < choices.size(); i++)
|
||||
{
|
||||
if(selection == i)
|
||||
wattron(win, A_REVERSE);
|
||||
mvwprintw(win, i + choice_offset_y, choice_offset_x, "%s", choices[i].c_str());
|
||||
if(selection == i)
|
||||
wattroff(win, A_REVERSE);
|
||||
}
|
||||
//curs_set(0); // hide cursor
|
||||
for(size_t i = 0; i < choices.size(); i++)
|
||||
{
|
||||
if(selection == i)
|
||||
wattron(win, A_REVERSE);
|
||||
mvwprintw(win, i + choice_offset_y, choice_offset_x, "%s", choices[i].c_str());
|
||||
if(selection == i)
|
||||
wattroff(win, A_REVERSE);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewSelection::addChoice(std::string name, call_t call)
|
||||
{
|
||||
choices.push_back(name);
|
||||
calls.push_back(call);
|
||||
choices.push_back(name);
|
||||
calls.push_back(call);
|
||||
}
|
||||
|
||||
call_t ViewSelection::keypress(int& key)
|
||||
{
|
||||
call_t ret = nullptr;
|
||||
switch(key)
|
||||
{
|
||||
case KEY_UP:
|
||||
do
|
||||
selection = (selection - 1 + choices.size()) % choices.size();
|
||||
while(!choices[selection].length() && choices.size());
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
case KEY_DOWN:
|
||||
do
|
||||
selection = (selection + 1) % choices.size();
|
||||
while(!choices[selection].length() && choices.size());
|
||||
break;
|
||||
|
||||
case KEY_MOUSE:
|
||||
{
|
||||
// http://pronix.linuxdelta.de/C/Linuxprogrammierung/Linuxsystemprogrammieren_C_Kurs_Kapitel10b.shtml
|
||||
MEVENT event;
|
||||
bool hit = false;
|
||||
if(getmouse(&event) == OK && event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))
|
||||
{
|
||||
size_t column_start = start_x + choice_offset_x;
|
||||
size_t row_start = start_y + choice_offset_y;
|
||||
size_t mouse_x = event.x, mouse_y = event.y;
|
||||
for(size_t i = 0; i < choices.size(); i++)
|
||||
if(choices[i].length() && mouse_y == row_start + i && mouse_x >= column_start && mouse_x < column_start + choices[i].length())
|
||||
{
|
||||
if(selection == i || event.bstate & BUTTON1_DOUBLE_CLICKED)
|
||||
hit = true;
|
||||
selection = i;
|
||||
}
|
||||
}
|
||||
if(!hit)
|
||||
break;
|
||||
|
||||
// fall through to next case
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case KEY_ENT:
|
||||
if(selection == choices.size() - 1) // exit
|
||||
key = -1; // do return from view
|
||||
else
|
||||
ret = calls[selection];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
repaint();
|
||||
return ret;
|
||||
call_t ret = nullptr;
|
||||
switch(key)
|
||||
{
|
||||
case KEY_UP:
|
||||
do
|
||||
selection = (selection - 1 + choices.size()) % choices.size();
|
||||
while(!choices[selection].length() && choices.size());
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
case KEY_DOWN:
|
||||
do
|
||||
selection = (selection + 1) % choices.size();
|
||||
while(!choices[selection].length() && choices.size());
|
||||
break;
|
||||
|
||||
case KEY_MOUSE:
|
||||
{
|
||||
// http://pronix.linuxdelta.de/C/Linuxprogrammierung/Linuxsystemprogrammieren_C_Kurs_Kapitel10b.shtml
|
||||
MEVENT event;
|
||||
bool hit = false;
|
||||
if(getmouse(&event) == OK && event.bstate & (BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED))
|
||||
{
|
||||
size_t column_start = start_x + choice_offset_x;
|
||||
size_t row_start = start_y + choice_offset_y;
|
||||
size_t mouse_x = event.x, mouse_y = event.y;
|
||||
for(size_t i = 0; i < choices.size(); i++)
|
||||
if(choices[i].length() && mouse_y == row_start + i && mouse_x >= column_start && mouse_x < column_start + choices[i].length())
|
||||
{
|
||||
if(selection == i || event.bstate & BUTTON1_DOUBLE_CLICKED)
|
||||
hit = true;
|
||||
selection = i;
|
||||
}
|
||||
}
|
||||
if(!hit)
|
||||
break;
|
||||
|
||||
// fall through to next case
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
||||
case KEY_ENT:
|
||||
if(selection == choices.size() - 1) // exit
|
||||
key = -1; // do return from view
|
||||
else
|
||||
ret = calls[selection];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
repaint();
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -5,20 +5,22 @@
|
|||
#include <string>
|
||||
#include "view.h"
|
||||
|
||||
/*! View for user selection input. */
|
||||
|
||||
class ViewSelection : public View
|
||||
{
|
||||
public:
|
||||
virtual void draw(void) override;
|
||||
virtual void addChoice(std::string name, call_t call);
|
||||
virtual call_t keypress(int& key) override;
|
||||
|
||||
virtual void draw(void) override;
|
||||
virtual void addChoice(std::string name, call_t call);
|
||||
virtual call_t keypress(int& key) override;
|
||||
|
||||
|
||||
protected:
|
||||
size_t selection = 0;
|
||||
std::vector<std::string> choices;
|
||||
|
||||
constexpr static int choice_offset_x = 2;
|
||||
constexpr static int choice_offset_y = 3;
|
||||
size_t selection = 0;
|
||||
std::vector<std::string> choices;
|
||||
|
||||
constexpr static int choice_offset_x = 2;
|
||||
constexpr static int choice_offset_y = 3;
|
||||
};
|
||||
|
||||
#endif // VIEW_SELECTION_H
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue